From 17bc023d48221507858738f5fe671487a8c31156 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Wed, 1 May 2024 11:34:53 +0200 Subject: [PATCH 01/52] fix: Added missing `platform` folder ignore to 2 workflows (#1788) ## Description Added missing `platform` folder ignore to 2 workflows ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting changes) - [x] 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. - [ ] 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 --- .github/workflows/avm.res.network.application-gateway.yml | 1 + .github/workflows/avm.res.sql.managed-instance.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/avm.res.network.application-gateway.yml b/.github/workflows/avm.res.network.application-gateway.yml index e55979ee5e4..c2c4c9f4645 100644 --- a/.github/workflows/avm.res.network.application-gateway.yml +++ b/.github/workflows/avm.res.network.application-gateway.yml @@ -30,6 +30,7 @@ on: - ".github/workflows/avm.res.network.application-gateway.yml" - "avm/res/network/application-gateway/**" - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" - "!*/**/README.md" env: diff --git a/.github/workflows/avm.res.sql.managed-instance.yml b/.github/workflows/avm.res.sql.managed-instance.yml index 54bb6be4395..3e9ebac6f28 100644 --- a/.github/workflows/avm.res.sql.managed-instance.yml +++ b/.github/workflows/avm.res.sql.managed-instance.yml @@ -29,6 +29,7 @@ on: - ".github/workflows/avm.res.sql.managed-instance.yml" - "avm/res/sql/managed-instance/**" - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" - "!*/**/README.md" env: From 817153bbba13366eaf2d85fceccf6e583b85a335 Mon Sep 17 00:00:00 2001 From: JFolberth Date: Wed, 1 May 2024 06:40:57 -0400 Subject: [PATCH 02/52] feat: Replications and WAF alignment for App Store - `avm/res/app-configuration/configuration-store` (#1696) ## Description - Added replicas - Update settings per pester results - ReadMes Update - Configured replicas for WAF alignment - Removed orphan Markdown Fixes #1502 Closes #1502 --> ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.app-configuration.configuration-store](https://github.com/JFolberth/bicep-registry-modules/actions/workflows/avm.res.app-configuration.configuration-store.yml/badge.svg)](https://github.com/JFolberth/bicep-registry-modules/actions/workflows/avm.res.app-configuration.configuration-store.yml)| ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting changes) - [x] 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`. - [x] 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 --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- .../configuration-store/ORPHANED.md | 4 - .../configuration-store/README.md | 78 ++++++++---- .../configuration-store/key-value/main.json | 4 +- .../configuration-store/main.bicep | 19 ++- .../configuration-store/main.json | 115 ++++++++++++++++-- .../configuration-store/replicas/README.md | 70 +++++++++++ .../configuration-store/replicas/main.bicep | 31 +++++ .../configuration-store/replicas/main.json | 65 ++++++++++ .../tests/e2e/defaults/main.test.bicep | 1 + .../tests/e2e/encr/main.test.bicep | 7 +- .../tests/e2e/max/main.test.bicep | 8 +- .../tests/e2e/pe/main.test.bicep | 3 +- .../tests/e2e/waf-aligned/main.test.bicep | 8 +- .../configuration-store/version.json | 4 +- .../psrule/.ps-rule/min-suppress.Rule.yaml | 3 + .../staticValidation/psrule/ps-rule.yaml | 1 + 16 files changed, 368 insertions(+), 53 deletions(-) delete mode 100644 avm/res/app-configuration/configuration-store/ORPHANED.md create mode 100644 avm/res/app-configuration/configuration-store/replicas/README.md create mode 100644 avm/res/app-configuration/configuration-store/replicas/main.bicep create mode 100644 avm/res/app-configuration/configuration-store/replicas/main.json diff --git a/avm/res/app-configuration/configuration-store/ORPHANED.md b/avm/res/app-configuration/configuration-store/ORPHANED.md deleted file mode 100644 index ef8fa911d2b..00000000000 --- a/avm/res/app-configuration/configuration-store/ORPHANED.md +++ /dev/null @@ -1,4 +0,0 @@ -⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️ - -- Only security and bug fixes are being handled by the AVM core team at present. -- If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)! \ No newline at end of file diff --git a/avm/res/app-configuration/configuration-store/README.md b/avm/res/app-configuration/configuration-store/README.md index c7d931c2253..b02e2bf3bef 100644 --- a/avm/res/app-configuration/configuration-store/README.md +++ b/avm/res/app-configuration/configuration-store/README.md @@ -1,10 +1,5 @@ # App Configuration Stores `[Microsoft.AppConfiguration/configurationStores]` -> ⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️ -> -> - Only security and bug fixes are being handled by the AVM core team at present. -> - If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)! - This module deploys an App Configuration Store. ## Navigation @@ -22,6 +17,7 @@ This module deploys an App Configuration Store. | :-- | :-- | | `Microsoft.AppConfiguration/configurationStores` | [2023-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.AppConfiguration/2023-03-01/configurationStores) | | `Microsoft.AppConfiguration/configurationStores/keyValues` | [2023-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.AppConfiguration/2023-03-01/configurationStores/keyValues) | +| `Microsoft.AppConfiguration/configurationStores/replicas` | [2023-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.AppConfiguration/2023-03-01/configurationStores/replicas) | | `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | | `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | | `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | @@ -58,6 +54,7 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto // Required parameters name: 'accmin001' // Non-required parameters + enablePurgeProtection: '' location: '' } } @@ -80,6 +77,9 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto "value": "accmin001" }, // Non-required parameters + "enablePurgeProtection": { + "value": "" + }, "location": { "value": "" } @@ -112,8 +112,8 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto keyVaultResourceId: '' userAssignedIdentityResourceId: '' } - disableLocalAuth: false - enablePurgeProtection: false + disableLocalAuth: '' + enablePurgeProtection: '' keyValues: [ { contentType: 'contentType' @@ -167,10 +167,10 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto } }, "disableLocalAuth": { - "value": false + "value": "" }, "enablePurgeProtection": { - "value": false + "value": "" }, "keyValues": { "value": [ @@ -239,8 +239,8 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto workspaceResourceId: '' } ] - disableLocalAuth: false - enablePurgeProtection: false + disableLocalAuth: '' + enablePurgeProtection: '' keyValues: [ { contentType: 'contentType' @@ -270,6 +270,10 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto '' ] } + replicaLocations: [ + 'centralus' + 'westus' + ] roleAssignments: [ { principalId: '' @@ -334,10 +338,10 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto ] }, "disableLocalAuth": { - "value": false + "value": "" }, "enablePurgeProtection": { - "value": false + "value": "" }, "keyValues": { "value": [ @@ -376,6 +380,12 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto ] } }, + "replicaLocations": { + "value": [ + "centralus", + "westus" + ] + }, "roleAssignments": { "value": [ { @@ -429,8 +439,7 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto name: 'accpe001' // Non-required parameters createMode: 'Default' - disableLocalAuth: false - enablePurgeProtection: false + enablePurgeProtection: '' location: '' privateEndpoints: [ { @@ -476,11 +485,8 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto "createMode": { "value": "Default" }, - "disableLocalAuth": { - "value": false - }, "enablePurgeProtection": { - "value": false + "value": "" }, "location": { "value": "" @@ -541,8 +547,8 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto workspaceResourceId: '' } ] - disableLocalAuth: false - enablePurgeProtection: false + disableLocalAuth: '' + enablePurgeProtection: '' keyValues: [ { contentType: 'contentType' @@ -551,6 +557,10 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto } ] location: '' + replicaLocations: [ + 'centralus' + 'westus' + ] softDeleteRetentionInDays: 1 tags: { Environment: 'Non-Prod' @@ -592,10 +602,10 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto ] }, "disableLocalAuth": { - "value": false + "value": "" }, "enablePurgeProtection": { - "value": false + "value": "" }, "keyValues": { "value": [ @@ -609,6 +619,12 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto "location": { "value": "" }, + "replicaLocations": { + "value": [ + "centralus", + "westus" + ] + }, "softDeleteRetentionInDays": { "value": 1 }, @@ -643,7 +659,7 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto | [`customerManagedKey`](#parameter-customermanagedkey) | object | The customer managed key definition. | | [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | | [`disableLocalAuth`](#parameter-disablelocalauth) | bool | Disables all authentication methods other than AAD authentication. | -| [`enablePurgeProtection`](#parameter-enablepurgeprotection) | bool | Property specifying whether protection against purge is enabled for this configuration store. | +| [`enablePurgeProtection`](#parameter-enablepurgeprotection) | bool | Property specifying whether protection against purge is enabled for this configuration store. Defaults to true unless sku is set to Free, since purge protection is not available in Free tier. | | [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | | [`keyValues`](#parameter-keyvalues) | array | All Key / Values to create. Requires local authentication to be enabled. | | [`location`](#parameter-location) | string | Location for all Resources. | @@ -651,6 +667,7 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto | [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | | [`privateEndpoints`](#parameter-privateendpoints) | array | Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. | | [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set. | +| [`replicaLocations`](#parameter-replicalocations) | array | All Replicas to create. | | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`sku`](#parameter-sku) | string | Pricing tier of App Configuration. | | [`softDeleteRetentionInDays`](#parameter-softdeleteretentionindays) | int | The amount of time in days that the configuration store will be retained when it is soft deleted. | @@ -858,15 +875,15 @@ Disables all authentication methods other than AAD authentication. - Required: No - Type: bool -- Default: `False` +- Default: `True` ### Parameter: `enablePurgeProtection` -Property specifying whether protection against purge is enabled for this configuration store. +Property specifying whether protection against purge is enabled for this configuration store. Defaults to true unless sku is set to Free, since purge protection is not available in Free tier. - Required: No - Type: bool -- Default: `False` +- Default: `True` ### Parameter: `enableTelemetry` @@ -1296,6 +1313,13 @@ Whether or not public network access is allowed for this resource. For security ] ``` +### Parameter: `replicaLocations` + +All Replicas to create. + +- Required: No +- Type: array + ### Parameter: `roleAssignments` Array of role assignments to create. diff --git a/avm/res/app-configuration/configuration-store/key-value/main.json b/avm/res/app-configuration/configuration-store/key-value/main.json index cc5f75de777..e214bc0fa3a 100644 --- a/avm/res/app-configuration/configuration-store/key-value/main.json +++ b/avm/res/app-configuration/configuration-store/key-value/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "8492150446155311380" + "version": "0.26.170.59819", + "templateHash": "4987655092014889247" }, "name": "App Configuration Stores Key Values", "description": "This module deploys an App Configuration Store Key Value.", diff --git a/avm/res/app-configuration/configuration-store/main.bicep b/avm/res/app-configuration/configuration-store/main.bicep index 124481d13b8..013c815a69b 100644 --- a/avm/res/app-configuration/configuration-store/main.bicep +++ b/avm/res/app-configuration/configuration-store/main.bicep @@ -26,10 +26,10 @@ param sku string = 'Standard' param createMode string = 'Default' @description('Optional. Disables all authentication methods other than AAD authentication.') -param disableLocalAuth bool = false +param disableLocalAuth bool = true -@description('Optional. Property specifying whether protection against purge is enabled for this configuration store.') -param enablePurgeProtection bool = false +@description('Optional. Property specifying whether protection against purge is enabled for this configuration store. Defaults to true unless sku is set to Free, since purge protection is not available in Free tier.') +param enablePurgeProtection bool = true @description('Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set.') @allowed([ @@ -49,6 +49,9 @@ param customerManagedKey customerManagedKeyType @description('Optional. All Key / Values to create. Requires local authentication to be enabled.') param keyValues array? +@description('Optional. All Replicas to create.') +param replicaLocations array? + @description('Optional. The diagnostic settings of the service.') param diagnosticSettings diagnosticSettingType @@ -198,6 +201,16 @@ module configurationStore_keyValues 'key-value/main.bicep' = [ } ] +module configurationStore_replicas 'replicas/main.bicep' = [ + for (replicaLocation, index) in (replicaLocations ?? []): { + name: '${uniqueString(deployment().name, location)}-AppConfig-Replicas-${index}' + params: { + appConfigurationName: configurationStore.name + replicaLocation: replicaLocation + name: '${replicaLocation}replica' + } + } +] resource configurationStore_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { name: lock.?name ?? 'lock-${name}' diff --git a/avm/res/app-configuration/configuration-store/main.json b/avm/res/app-configuration/configuration-store/main.json index 9f862cd382f..86cf5395bb4 100644 --- a/avm/res/app-configuration/configuration-store/main.json +++ b/avm/res/app-configuration/configuration-store/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "17308644596595948852" + "version": "0.26.170.59819", + "templateHash": "5307828183746392063" }, "name": "App Configuration Stores", "description": "This module deploys an App Configuration Store.", @@ -492,16 +492,16 @@ }, "disableLocalAuth": { "type": "bool", - "defaultValue": false, + "defaultValue": true, "metadata": { "description": "Optional. Disables all authentication methods other than AAD authentication." } }, "enablePurgeProtection": { "type": "bool", - "defaultValue": false, + "defaultValue": true, "metadata": { - "description": "Optional. Property specifying whether protection against purge is enabled for this configuration store." + "description": "Optional. Property specifying whether protection against purge is enabled for this configuration store. Defaults to true unless sku is set to Free, since purge protection is not available in Free tier." } }, "publicNetworkAccess": { @@ -537,6 +537,13 @@ "description": "Optional. All Key / Values to create. Requires local authentication to be enabled." } }, + "replicaLocations": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. All Replicas to create." + } + }, "diagnosticSettings": { "$ref": "#/definitions/diagnosticSettingType", "metadata": { @@ -779,8 +786,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "8492150446155311380" + "version": "0.26.170.59819", + "templateHash": "4987655092014889247" }, "name": "App Configuration Stores Key Values", "description": "This module deploys an App Configuration Store Key Value.", @@ -870,6 +877,100 @@ "configurationStore" ] }, + "configurationStore_replicas": { + "copy": { + "name": "configurationStore_replicas", + "count": "[length(coalesce(parameters('replicaLocations'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppConfig-Replicas-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appConfigurationName": { + "value": "[parameters('name')]" + }, + "replicaLocation": { + "value": "[coalesce(parameters('replicaLocations'), createArray())[copyIndex()]]" + }, + "name": { + "value": "[format('{0}replica', coalesce(parameters('replicaLocations'), createArray())[copyIndex()])]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.26.170.59819", + "templateHash": "3867721314598368740" + }, + "name": "App Configuration Replicas", + "description": "This module deploys an App Configuration Replica.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the replica." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the parent app configuration store." + } + }, + "replicaLocation": { + "type": "string", + "metadata": { + "description": "Optional. Location of the replica." + } + } + }, + "resources": [ + { + "type": "Microsoft.AppConfiguration/configurationStores/replicas", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "location": "[parameters('replicaLocation')]" + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the app configuration was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the replica that was deployed." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the replica that was deployed." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/replicas', parameters('appConfigurationName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + }, "configurationStore_privateEndpoints": { "copy": { "name": "configurationStore_privateEndpoints", diff --git a/avm/res/app-configuration/configuration-store/replicas/README.md b/avm/res/app-configuration/configuration-store/replicas/README.md new file mode 100644 index 00000000000..cdc6e702a25 --- /dev/null +++ b/avm/res/app-configuration/configuration-store/replicas/README.md @@ -0,0 +1,70 @@ +# App Configuration Replicas `[Microsoft.AppConfiguration/configurationStores/replicas]` + +This module deploys an App Configuration Replica. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.AppConfiguration/configurationStores/replicas` | [2023-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.AppConfiguration/2023-03-01/configurationStores/replicas) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the replica. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`appConfigurationName`](#parameter-appconfigurationname) | string | The name of the parent app configuration store. | +| [`replicaLocation`](#parameter-replicalocation) | string | Location of the replica. | + +### Parameter: `name` + +Name of the replica. + +- Required: Yes +- Type: string + +### Parameter: `appConfigurationName` + +The name of the parent app configuration store. + +- Required: Yes +- Type: string + +### Parameter: `replicaLocation` + +Location of the replica. + +- Required: Yes +- Type: string + + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the replica that was deployed. | +| `resourceGroupName` | string | The resource group the app configuration was deployed into. | +| `resourceId` | string | The resource ID of the replica that was deployed. | + +## Cross-referenced modules + +_None_ + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/res/app-configuration/configuration-store/replicas/main.bicep b/avm/res/app-configuration/configuration-store/replicas/main.bicep new file mode 100644 index 00000000000..43e37d6d8da --- /dev/null +++ b/avm/res/app-configuration/configuration-store/replicas/main.bicep @@ -0,0 +1,31 @@ +metadata name = 'App Configuration Replicas' +metadata description = 'This module deploys an App Configuration Replica.' +metadata owner = 'Azure/module-maintainers' + +@description('Required. Name of the replica.') +param name string + +@description('Optional. The name of the parent app configuration store.') +param appConfigurationName string + +@description('Optional. Location of the replica.') +param replicaLocation string + +resource appConfiguration 'Microsoft.AppConfiguration/configurationStores@2023-03-01' existing = { + name: appConfigurationName +} + +resource replica 'Microsoft.AppConfiguration/configurationStores/replicas@2023-03-01' = { + name: name + parent: appConfiguration + location: replicaLocation +} + +@description('The resource group the app configuration was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the replica that was deployed.') +output name string = replica.name + +@description('The resource ID of the replica that was deployed.') +output resourceId string = replica.id diff --git a/avm/res/app-configuration/configuration-store/replicas/main.json b/avm/res/app-configuration/configuration-store/replicas/main.json new file mode 100644 index 00000000000..62607f00361 --- /dev/null +++ b/avm/res/app-configuration/configuration-store/replicas/main.json @@ -0,0 +1,65 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.26.170.59819", + "templateHash": "3867721314598368740" + }, + "name": "App Configuration Replicas", + "description": "This module deploys an App Configuration Replica.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the replica." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the parent app configuration store." + } + }, + "replicaLocation": { + "type": "string", + "metadata": { + "description": "Optional. Location of the replica." + } + } + }, + "resources": [ + { + "type": "Microsoft.AppConfiguration/configurationStores/replicas", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "location": "[parameters('replicaLocation')]" + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the app configuration was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the replica that was deployed." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the replica that was deployed." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/replicas', parameters('appConfigurationName'), parameters('name'))]" + } + } +} \ No newline at end of file diff --git a/avm/res/app-configuration/configuration-store/tests/e2e/defaults/main.test.bicep b/avm/res/app-configuration/configuration-store/tests/e2e/defaults/main.test.bicep index 990968dd9ad..c53e510fbd5 100644 --- a/avm/res/app-configuration/configuration-store/tests/e2e/defaults/main.test.bicep +++ b/avm/res/app-configuration/configuration-store/tests/e2e/defaults/main.test.bicep @@ -43,6 +43,7 @@ module testDeployment '../../../main.bicep' = [ params: { name: '${namePrefix}${serviceShort}001' location: resourceLocation + enablePurgeProtection: false //Only for Testing purposes. Waf Aligned is true } } ] diff --git a/avm/res/app-configuration/configuration-store/tests/e2e/encr/main.test.bicep b/avm/res/app-configuration/configuration-store/tests/e2e/encr/main.test.bicep index 6c8874859ba..0ff83adbcc8 100644 --- a/avm/res/app-configuration/configuration-store/tests/e2e/encr/main.test.bicep +++ b/avm/res/app-configuration/configuration-store/tests/e2e/encr/main.test.bicep @@ -23,6 +23,9 @@ param baseTime string = utcNow('u') @description('Optional. A token to inject into the name of each resource.') param namePrefix string = '#_namePrefix_#' +@description('Optional. Disables all authentication methods other than AAD authentication.') +param disableLocalAuth bool = false + // ============ // // Dependencies // // ============ // @@ -57,9 +60,9 @@ module testDeployment '../../../main.bicep' = [ params: { name: '${namePrefix}${serviceShort}001' location: resourceLocation + disableLocalAuth: disableLocalAuth createMode: 'Default' - disableLocalAuth: false - enablePurgeProtection: false + enablePurgeProtection: false //Only for Testing purposes. Waf Aligned is true keyValues: [ { contentType: 'contentType' diff --git a/avm/res/app-configuration/configuration-store/tests/e2e/max/main.test.bicep b/avm/res/app-configuration/configuration-store/tests/e2e/max/main.test.bicep index 5028ef09295..be0d37803b8 100644 --- a/avm/res/app-configuration/configuration-store/tests/e2e/max/main.test.bicep +++ b/avm/res/app-configuration/configuration-store/tests/e2e/max/main.test.bicep @@ -20,6 +20,9 @@ param serviceShort string = 'accmax' @description('Optional. A token to inject into the name of each resource.') param namePrefix string = '#_namePrefix_#' +@description('Optional. Disables all authentication methods other than AAD authentication.') +param disableLocalAuth bool = false + // ============ // // Dependencies // // ============ // @@ -66,7 +69,10 @@ module testDeployment '../../../main.bicep' = [ params: { name: '${namePrefix}${serviceShort}001' location: resourceLocation + disableLocalAuth: disableLocalAuth createMode: 'Default' + replicaLocations: ['centralus', 'westus'] + enablePurgeProtection: false //Only for Testing purposes. Waf Aligned is true diagnosticSettings: [ { name: 'customSetting' @@ -81,8 +87,6 @@ module testDeployment '../../../main.bicep' = [ workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId } ] - disableLocalAuth: false - enablePurgeProtection: false keyValues: [ { contentType: 'contentType' diff --git a/avm/res/app-configuration/configuration-store/tests/e2e/pe/main.test.bicep b/avm/res/app-configuration/configuration-store/tests/e2e/pe/main.test.bicep index 569c308146a..b3221b87952 100644 --- a/avm/res/app-configuration/configuration-store/tests/e2e/pe/main.test.bicep +++ b/avm/res/app-configuration/configuration-store/tests/e2e/pe/main.test.bicep @@ -53,8 +53,7 @@ module testDeployment '../../../main.bicep' = [ name: '${namePrefix}${serviceShort}001' location: resourceLocation createMode: 'Default' - disableLocalAuth: false - enablePurgeProtection: false + enablePurgeProtection: false //Only for Testing purposes. Waf Aligned is true privateEndpoints: [ { privateDnsZoneResourceIds: [ diff --git a/avm/res/app-configuration/configuration-store/tests/e2e/waf-aligned/main.test.bicep b/avm/res/app-configuration/configuration-store/tests/e2e/waf-aligned/main.test.bicep index 6d3b70e64c2..eb10d5c8c42 100644 --- a/avm/res/app-configuration/configuration-store/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/app-configuration/configuration-store/tests/e2e/waf-aligned/main.test.bicep @@ -20,6 +20,9 @@ param serviceShort string = 'accwaf' @description('Optional. A token to inject into the name of each resource.') param namePrefix string = '#_namePrefix_#' +@description('Optional. Disables all authentication methods other than AAD authentication.') +param disableLocalAuth bool = false + // ============ // // Dependencies // // ============ // @@ -57,7 +60,10 @@ module testDeployment '../../../main.bicep' = [ params: { name: '${namePrefix}${serviceShort}001' location: resourceLocation + disableLocalAuth: disableLocalAuth createMode: 'Default' + replicaLocations: ['centralus', 'westus'] + enablePurgeProtection: false //Only for Testing purposes. Waf Aligned is true diagnosticSettings: [ { eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName @@ -66,8 +72,6 @@ module testDeployment '../../../main.bicep' = [ workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId } ] - disableLocalAuth: false - enablePurgeProtection: false keyValues: [ { contentType: 'contentType' diff --git a/avm/res/app-configuration/configuration-store/version.json b/avm/res/app-configuration/configuration-store/version.json index 83083db6945..9481fea58ee 100644 --- a/avm/res/app-configuration/configuration-store/version.json +++ b/avm/res/app-configuration/configuration-store/version.json @@ -1,7 +1,7 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.1", + "version": "0.2", "pathFilters": [ "./main.json" ] -} \ No newline at end of file +} diff --git a/avm/utilities/pipelines/staticValidation/psrule/.ps-rule/min-suppress.Rule.yaml b/avm/utilities/pipelines/staticValidation/psrule/.ps-rule/min-suppress.Rule.yaml index ed2666de727..b15a2d0b3e3 100644 --- a/avm/utilities/pipelines/staticValidation/psrule/.ps-rule/min-suppress.Rule.yaml +++ b/avm/utilities/pipelines/staticValidation/psrule/.ps-rule/min-suppress.Rule.yaml @@ -31,6 +31,9 @@ spec: # Azure App Service - Azure.AppService.WebProbe # Supressed as the probe path is specific to the app - Azure.AppService.WebProbePath # Supressed as the probe path is specific to the app + # Azure App Configuration Store + - Azure.AppConfig.GeoReplica # Suppressed as geo-replication is WAF requirement but not required for min + - Azure.AppConfig.AuditLogs # Suppressed as Audit Logs are not required for min # Azure Front Door - Azure.FrontDoor.Probe # Supressed as the probe is being provided as parameter and we are not able to enforce as default value - Azure.FrontDoor.ProbeMethod # Supressed as the probe method is being provided as parameter and we are not able to enforce as default value diff --git a/avm/utilities/pipelines/staticValidation/psrule/ps-rule.yaml b/avm/utilities/pipelines/staticValidation/psrule/ps-rule.yaml index b241ac0b1ab..75282bb02e4 100644 --- a/avm/utilities/pipelines/staticValidation/psrule/ps-rule.yaml +++ b/avm/utilities/pipelines/staticValidation/psrule/ps-rule.yaml @@ -80,3 +80,4 @@ rule: - Azure.KeyVault.PurgeProtect - Azure.VM.UseHybridUseBenefit - Azure.Storage.UseReplication + - Azure.AppConfig.PurgeProtect From 0341ab60d8bf033bde6faf6764edafecf72f2e59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Barab=C3=A1s?= Date: Wed, 1 May 2024 14:00:23 -0700 Subject: [PATCH 03/52] chore: shortening module statuses (#1809) --- .../pipelines/platform/Set-AvmGitHubIssueOwnerConfig.ps1 | 4 ++-- .../pipelines/platform/Set-AvmGithubIssueForWorkflow.ps1 | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/avm/utilities/pipelines/platform/Set-AvmGitHubIssueOwnerConfig.ps1 b/avm/utilities/pipelines/platform/Set-AvmGitHubIssueOwnerConfig.ps1 index d2d7b20cb12..3b43dcd595d 100644 --- a/avm/utilities/pipelines/platform/Set-AvmGitHubIssueOwnerConfig.ps1 +++ b/avm/utilities/pipelines/platform/Set-AvmGitHubIssueOwnerConfig.ps1 @@ -60,7 +60,7 @@ function Set-AvmGitHubIssueOwnerConfig { "@ } # orphaned module - elseif ($module.ModuleStatus -eq 'Module Orphaned :eyes:') { + elseif ($module.ModuleStatus -eq 'Orphaned :eyes:') { $reply = @" **@$($issue.author.login), thanks for submitting this issue for the ``$moduleName`` module!** @@ -91,7 +91,7 @@ function Set-AvmGitHubIssueOwnerConfig { gh issue comment $issue.url --body $reply --repo $Repo } - if (($module.ModuleStatus -ne 'Module Orphaned :eyes:') -and (-not ([string]::IsNullOrEmpty($module.PrimaryModuleOwnerGHHandle)))) { + if (($module.ModuleStatus -ne 'Orphaned :eyes:') -and (-not ([string]::IsNullOrEmpty($module.PrimaryModuleOwnerGHHandle)))) { if ($PSCmdlet.ShouldProcess(("owner [{0}] to issue [$($issue.title)]" -f $module.PrimaryModuleOwnerGHHandle), 'Assign')) { # assign owner $assign = gh issue edit $issue.url --add-assignee $module.PrimaryModuleOwnerGHHandle --repo $Repo diff --git a/avm/utilities/pipelines/platform/Set-AvmGithubIssueForWorkflow.ps1 b/avm/utilities/pipelines/platform/Set-AvmGithubIssueForWorkflow.ps1 index 03f5f4f95c1..4a6308339d1 100644 --- a/avm/utilities/pipelines/platform/Set-AvmGithubIssueForWorkflow.ps1 +++ b/avm/utilities/pipelines/platform/Set-AvmGithubIssueForWorkflow.ps1 @@ -105,7 +105,7 @@ function Set-AvmGithubIssueForWorkflow { # get CSV data $module = Get-AvmCsvData -ModuleIndex $moduleIndex | Where-Object ModuleName -EQ $moduleName - if (($module.ModuleStatus -ne 'Module Orphaned :eyes:') -and (-not ([string]::IsNullOrEmpty($module.PrimaryModuleOwnerGHHandle)))) { + if (($module.ModuleStatus -ne 'Orphaned :eyes:') -and (-not ([string]::IsNullOrEmpty($module.PrimaryModuleOwnerGHHandle)))) { $ProjectNumber = 566 # AVM - Module Issues $comment = @" > [!IMPORTANT] From 2ccb5518bd965dd51141215c4964dc049f91f8e4 Mon Sep 17 00:00:00 2001 From: Rainer Halanek <61878316+rahalan@users.noreply.github.com> Date: Thu, 2 May 2024 14:18:18 +0200 Subject: [PATCH 04/52] fix: repair automatic assignment of issues (#1817) This PR fixes the issue, that failed workflows were not assigned to the correct owner --- .../pipelines/platform/Set-AvmGithubIssueForWorkflow.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/avm/utilities/pipelines/platform/Set-AvmGithubIssueForWorkflow.ps1 b/avm/utilities/pipelines/platform/Set-AvmGithubIssueForWorkflow.ps1 index 4a6308339d1..66dde35f182 100644 --- a/avm/utilities/pipelines/platform/Set-AvmGithubIssueForWorkflow.ps1 +++ b/avm/utilities/pipelines/platform/Set-AvmGithubIssueForWorkflow.ps1 @@ -112,16 +112,16 @@ function Set-AvmGithubIssueForWorkflow { > @Azure/$($module.ModuleOwnersGHTeam), the workflow for the ``$moduleName`` module has failed. Please investigate the failed workflow run. If you are not able to do so, please inform the AVM core team to take over. "@ # assign owner - $assign = gh issue edit $issue.url --add-assignee $module.PrimaryModuleOwnerGHHandle --repo $Repo + $assign = gh issue edit $issueUrl --add-assignee $module.PrimaryModuleOwnerGHHandle --repo $Repo if ([String]::IsNullOrEmpty($assign)) { - if ($PSCmdlet.ShouldProcess("missing user comment to issue [$($issue.title)]", 'Add')) { + if ($PSCmdlet.ShouldProcess("missing user comment to issue [$($issueName)]", 'Add')) { $comment = @" > [!WARNING] > This issue couldn't be assigend due to an internal error. @$($module.PrimaryModuleOwnerGHHandle), please make sure this issue is assigned to you and please provide an initial response as soon as possible, in accordance with the [AVM Support statement](https://aka.ms/AVM/Support). "@ - gh issue comment $issue.url --body $comment --repo $Repo + gh issue comment $issueUrl --body $comment --repo $Repo } } } From a65ce78a06853ae1edab995a4e683876480fdf52 Mon Sep 17 00:00:00 2001 From: JFolberth Date: Thu, 2 May 2024 13:01:53 -0400 Subject: [PATCH 05/52] fix: Removed orphaned file & reference (#1822) ## Description ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.insights.webtest](https://github.com/JFolberth/bicep-registry-modules/actions/workflows/avm.res.insights.webtest.yml/badge.svg)](https://github.com/JFolberth/bicep-registry-modules/actions/workflows/avm.res.insights.webtest.yml) | ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting 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. - [ ] 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`. - [x] 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 --- avm/res/insights/webtest/ORPHANED.md | 4 ---- avm/res/insights/webtest/README.md | 5 ----- avm/res/insights/webtest/main.json | 4 ++-- 3 files changed, 2 insertions(+), 11 deletions(-) delete mode 100644 avm/res/insights/webtest/ORPHANED.md diff --git a/avm/res/insights/webtest/ORPHANED.md b/avm/res/insights/webtest/ORPHANED.md deleted file mode 100644 index ef8fa911d2b..00000000000 --- a/avm/res/insights/webtest/ORPHANED.md +++ /dev/null @@ -1,4 +0,0 @@ -⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️ - -- Only security and bug fixes are being handled by the AVM core team at present. -- If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)! \ No newline at end of file diff --git a/avm/res/insights/webtest/README.md b/avm/res/insights/webtest/README.md index 7b9a2349a06..e0acaac4bb1 100644 --- a/avm/res/insights/webtest/README.md +++ b/avm/res/insights/webtest/README.md @@ -1,10 +1,5 @@ # Web Tests `[Microsoft.Insights/webtests]` -> ⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️ -> -> - Only security and bug fixes are being handled by the AVM core team at present. -> - If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)! - This module deploys a Web Test. ## Navigation diff --git a/avm/res/insights/webtest/main.json b/avm/res/insights/webtest/main.json index fbf790faf9a..b5ece61cce9 100644 --- a/avm/res/insights/webtest/main.json +++ b/avm/res/insights/webtest/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "279019710662992731" + "version": "0.26.170.59819", + "templateHash": "9763185230579436305" }, "name": "Web Tests", "description": "This module deploys a Web Test.", From 2e753f7df26cd8269721b01250b926ac26376ce3 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Fri, 3 May 2024 01:06:36 +0200 Subject: [PATCH 06/52] fix: Temporarily disabled OpenAI test (#1826) ## Description - Removed identity warning - Disabled the deployed as described above with an impossible condition - Added a big disclaimer to the test's description - Added a post-deployment tests which's only purpose it is to also add a warning to the workflow output ![image](https://github.com/Azure/bicep-registry-modules/assets/5365358/e27f5fa9-54f6-4327-ace8-1905ab400bf3) ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.cognitive-services.account](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml/badge.svg?branch=users%2Falsehr%2FcognitiveServicesDisableTest)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml) | ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting changes) - [x] 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. - [ ] 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 --- avm/res/cognitive-services/account/README.md | 8 ++++++- avm/res/cognitive-services/account/main.bicep | 2 +- avm/res/cognitive-services/account/main.json | 6 ++--- .../e2e/ai-model-deployment/main.test.bicep | 11 +++++++-- .../e2e/ai-model-deployment/warning.tests.ps1 | 24 +++++++++++++++++++ 5 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 avm/res/cognitive-services/account/tests/e2e/ai-model-deployment/warning.tests.ps1 diff --git a/avm/res/cognitive-services/account/README.md b/avm/res/cognitive-services/account/README.md index 820802cdb82..e5804e0da1e 100644 --- a/avm/res/cognitive-services/account/README.md +++ b/avm/res/cognitive-services/account/README.md @@ -41,7 +41,13 @@ The following section provides usage examples for the module, which were used to ### Example 1: _Using `deployments` in parameter set_ -This instance deploys the module with the AI model deployment feature. +This instance deploys the module with the AI model deployment feature.' + +Note, this test is temporarily disabled as it needs to be enabled on the subscription. +As we don't want other contributions from being blocked by this, we disabled the test for now / rely on a manual execution outside the CI environemnt +You can find more information here: https://learn.microsoft.com/en-us/legal/cognitive-services/openai/limited-access +And register here: https://aka.ms/oai/access +
diff --git a/avm/res/cognitive-services/account/main.bicep b/avm/res/cognitive-services/account/main.bicep index 293821f9b8c..07ffb63489e 100644 --- a/avm/res/cognitive-services/account/main.bicep +++ b/avm/res/cognitive-services/account/main.bicep @@ -137,7 +137,7 @@ var formattedUserAssignedIdentities = reduce( var identity = !empty(managedIdentities) ? { type: (managedIdentities.?systemAssigned ?? false) - ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') + ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned, UserAssigned' : 'SystemAssigned') : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : null) userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null } diff --git a/avm/res/cognitive-services/account/main.json b/avm/res/cognitive-services/account/main.json index 7c8c756cb70..7c1ff98ca59 100644 --- a/avm/res/cognitive-services/account/main.json +++ b/avm/res/cognitive-services/account/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "2360701930449304487" + "version": "0.26.170.59819", + "templateHash": "5668118199015896027" }, "name": "Cognitive Services", "description": "This module deploys a Cognitive Service.", @@ -766,7 +766,7 @@ }, "variables": { "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", "builtInRoleNames": { "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", diff --git a/avm/res/cognitive-services/account/tests/e2e/ai-model-deployment/main.test.bicep b/avm/res/cognitive-services/account/tests/e2e/ai-model-deployment/main.test.bicep index 7ee3f5be51b..60d04523d30 100644 --- a/avm/res/cognitive-services/account/tests/e2e/ai-model-deployment/main.test.bicep +++ b/avm/res/cognitive-services/account/tests/e2e/ai-model-deployment/main.test.bicep @@ -1,7 +1,14 @@ targetScope = 'subscription' metadata name = 'Using `deployments` in parameter set' -metadata description = 'This instance deploys the module with the AI model deployment feature.' +metadata description = ''' +This instance deploys the module with the AI model deployment feature.' + +Note, this test is temporarily disabled as it needs to be enabled on the subscription. +As we don't want other contributions from being blocked by this, we disabled the test for now / rely on a manual execution outside the CI environemnt +You can find more information here: https://learn.microsoft.com/en-us/legal/cognitive-services/openai/limited-access +And register here: https://aka.ms/oai/access +''' // ========== // // Parameters // @@ -36,7 +43,7 @@ resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { // ============== // module testDeployment '../../../main.bicep' = [ - for iteration in ['init', 'idem']: { + for iteration in ['init', 'idem']: if (true == false) { scope: resourceGroup name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}-ai' params: { diff --git a/avm/res/cognitive-services/account/tests/e2e/ai-model-deployment/warning.tests.ps1 b/avm/res/cognitive-services/account/tests/e2e/ai-model-deployment/warning.tests.ps1 new file mode 100644 index 00000000000..21deb1f6a31 --- /dev/null +++ b/avm/res/cognitive-services/account/tests/e2e/ai-model-deployment/warning.tests.ps1 @@ -0,0 +1,24 @@ +###################################### +## Additional post-deployment tests ## +###################################### +## +## You can add any custom post-deployment validation tests you want here, or add them spread accross multiple test files in the test case folder. +## +########################### + +param ( + [Parameter(Mandatory = $false)] + [hashtable] $TestInputData = @{} +) + +Describe 'Warning' { + + It 'Disabled test' { + + Write-Output @{ + Warning = "Note, the OpenAI-Deployments test is temporarily disabled as it needs to be enabled on the subscription.
As we don't want other contributions from being blocked by this, we disabled the test for now / rely on a manual execution outside the CI environemnt. For more information please review the [offical docs](https://learn.microsoft.com/en-us/legal/cognitive-services/openai/limited-access) and or register [here](https://aka.ms/oai/access" + + } + } +} + From 697ea31031da9fd4dc24b1f15e4ec9dbad80d9ee Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Fri, 3 May 2024 04:59:38 +0200 Subject: [PATCH 07/52] fix: WebApp - Updated to latest PE schema (#1794) ## Description - Updated to latest PE schema - Addressed warnings Fixes #1793 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.web.site](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.web.site.yml/badge.svg?branch=users%2Falsehr%2F1793_PEUpdate&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.web.site.yml) | ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting changes) - [ ] Azure Verified Module updates: - [x] 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. - [ ] 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 --- avm/res/web/site/README.md | 18 ++++- .../main.bicep | 15 ++-- .../main.json | 4 +- .../web/site/config--appsettings/main.json | 4 +- .../web/site/config--authsettingsv2/main.json | 4 +- .../relay/main.json | 4 +- avm/res/web/site/main.bicep | 17 +++-- avm/res/web/site/main.json | 72 +++++++++++++------ avm/res/web/site/slot/README.md | 18 ++++- .../main.bicep | 17 ++--- .../main.json | 4 +- .../site/slot/config--appsettings/main.json | 4 +- .../slot/config--authsettingsv2/main.json | 4 +- .../relay/main.json | 4 +- avm/res/web/site/slot/main.bicep | 19 +++-- avm/res/web/site/slot/main.json | 55 ++++++++------ 16 files changed, 178 insertions(+), 85 deletions(-) diff --git a/avm/res/web/site/README.md b/avm/res/web/site/README.md index fd8403c4f38..21971f56f98 100644 --- a/avm/res/web/site/README.md +++ b/avm/res/web/site/README.md @@ -2125,6 +2125,8 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | +| [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | | [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/resource groups in this deployment. | @@ -2320,6 +2322,20 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.resourceGroupName` + +Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. + +- Required: No +- Type: string + ### Parameter: `privateEndpoints.roleAssignments` Array of role assignments to create. @@ -2654,7 +2670,7 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm/res/network/private-endpoint:0.4.0` | Remote reference | +| `br/public:avm/res/network/private-endpoint:0.4.1` | Remote reference | ## Notes diff --git a/avm/res/web/site/basic-publishing-credentials-policy/main.bicep b/avm/res/web/site/basic-publishing-credentials-policy/main.bicep index de0e237cc3b..f09d81edf7b 100644 --- a/avm/res/web/site/basic-publishing-credentials-policy/main.bicep +++ b/avm/res/web/site/basic-publishing-credentials-policy/main.bicep @@ -2,17 +2,17 @@ metadata name = 'Web Site Basic Publishing Credentials Policies' metadata description = 'This module deploys a Web Site Basic Publishing Credentials Policy.' metadata owner = 'Azure/module-maintainers' -@sys.description('Required. The name of the resource.') +@description('Required. The name of the resource.') @allowed([ 'scm' 'ftp' ]) param name string -@sys.description('Optional. Set to true to enable or false to disable a publishing method.') +@description('Optional. Set to true to enable or false to disable a publishing method.') param allow bool = true -@sys.description('Conditional. The name of the parent web site. Required if the template is used in a standalone deployment.') +@description('Conditional. The name of the parent web site. Required if the template is used in a standalone deployment.') param webAppName string @description('Optional. Location for all Resources.') @@ -23,6 +23,7 @@ resource webApp 'Microsoft.Web/sites@2022-09-01' existing = { } resource basicPublishingCredentialsPolicy 'Microsoft.Web/sites/basicPublishingCredentialsPolicies@2022-09-01' = { + #disable-next-line BCP225 // False-positive. Value is required. name: name location: location parent: webApp @@ -31,14 +32,14 @@ resource basicPublishingCredentialsPolicy 'Microsoft.Web/sites/basicPublishingCr } } -@sys.description('The name of the basic publishing credential policy.') +@description('The name of the basic publishing credential policy.') output name string = basicPublishingCredentialsPolicy.name -@sys.description('The resource ID of the basic publishing credential policy.') +@description('The resource ID of the basic publishing credential policy.') output resourceId string = basicPublishingCredentialsPolicy.id -@sys.description('The name of the resource group the basic publishing credential policy was deployed into.') +@description('The name of the resource group the basic publishing credential policy was deployed into.') output resourceGroupName string = resourceGroup().name -@sys.description('The location the resource was deployed into.') +@description('The location the resource was deployed into.') output location string = basicPublishingCredentialsPolicy.location diff --git a/avm/res/web/site/basic-publishing-credentials-policy/main.json b/avm/res/web/site/basic-publishing-credentials-policy/main.json index cc6e4e5abb7..d66be056076 100644 --- a/avm/res/web/site/basic-publishing-credentials-policy/main.json +++ b/avm/res/web/site/basic-publishing-credentials-policy/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "12379291046700283915" + "version": "0.26.170.59819", + "templateHash": "1590652329081458395" }, "name": "Web Site Basic Publishing Credentials Policies", "description": "This module deploys a Web Site Basic Publishing Credentials Policy.", diff --git a/avm/res/web/site/config--appsettings/main.json b/avm/res/web/site/config--appsettings/main.json index aa1a357e497..60bd2b692ed 100644 --- a/avm/res/web/site/config--appsettings/main.json +++ b/avm/res/web/site/config--appsettings/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "18064037455551234601" + "version": "0.26.170.59819", + "templateHash": "12051629915105082529" }, "name": "Site App Settings", "description": "This module deploys a Site App Setting.", diff --git a/avm/res/web/site/config--authsettingsv2/main.json b/avm/res/web/site/config--authsettingsv2/main.json index 4a56803f1a4..0c5c3fd8f34 100644 --- a/avm/res/web/site/config--authsettingsv2/main.json +++ b/avm/res/web/site/config--authsettingsv2/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "9660352953607316036" + "version": "0.26.170.59819", + "templateHash": "14303407385986258247" }, "name": "Site Auth Settings V2 Config", "description": "This module deploys a Site Auth Settings V2 Configuration.", diff --git a/avm/res/web/site/hybrid-connection-namespace/relay/main.json b/avm/res/web/site/hybrid-connection-namespace/relay/main.json index 9b76669f1b5..149129143b0 100644 --- a/avm/res/web/site/hybrid-connection-namespace/relay/main.json +++ b/avm/res/web/site/hybrid-connection-namespace/relay/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "12607693486765150465" + "version": "0.26.170.59819", + "templateHash": "15287918657229788223" }, "name": "Web/Function Apps Hybrid Connection Relay", "description": "This module deploys a Site Hybrid Connection Namespace Relay.", diff --git a/avm/res/web/site/main.bicep b/avm/res/web/site/main.bicep index 9c2aefa0e44..1d2c0cc3c02 100644 --- a/avm/res/web/site/main.bicep +++ b/avm/res/web/site/main.bicep @@ -168,7 +168,7 @@ var formattedUserAssignedIdentities = reduce( var identity = !empty(managedIdentities) ? { type: (managedIdentities.?systemAssigned ?? false) - ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') + ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned, UserAssigned' : 'SystemAssigned') : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : 'None') userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null } @@ -418,12 +418,13 @@ resource app_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01 } ] -module app_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.4.0' = [ +module app_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.4.1' = [ for (privateEndpoint, index) in (privateEndpoints ?? []): { - name: '${uniqueString(deployment().name, location)}-App-PrivateEndpoint-${index}' + name: '${uniqueString(deployment().name, location)}-app-PrivateEndpoint-${index}' + scope: resourceGroup(privateEndpoint.?resourceGroupName ?? '') params: { name: privateEndpoint.?name ?? 'pep-${last(split(app.id, '/'))}-${privateEndpoint.?service ?? 'sites'}-${index}' - privateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections != true + privateLinkServiceConnections: privateEndpoint.?isManualConnection != true ? [ { name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(app.id, '/'))}-${privateEndpoint.?service ?? 'sites'}-${index}' @@ -436,7 +437,7 @@ module app_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.4.0' = } ] : null - manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections == true + manualPrivateLinkServiceConnections: privateEndpoint.?isManualConnection == true ? [ { name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(app.id, '/'))}-${privateEndpoint.?service ?? 'sites'}-${index}' @@ -549,6 +550,9 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? + @description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? @@ -612,6 +616,9 @@ type privateEndpointType = { @description('Optional. Enable/Disable usage telemetry for module.') enableTelemetry: bool? + + @description('Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.') + resourceGroupName: string? }[]? type diagnosticSettingType = { diff --git a/avm/res/web/site/main.json b/avm/res/web/site/main.json index 607d3adbb57..65d7ddc02c5 100644 --- a/avm/res/web/site/main.json +++ b/avm/res/web/site/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.26.170.59819", - "templateHash": "5830272725104890600" + "templateHash": "3119256984353816365" }, "name": "Web/Function Apps", "description": "This module deploys a Web or Function App.", @@ -146,6 +146,13 @@ "description": "Optional. The location to deploy the private endpoint to." } }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, "service": { "type": "string", "nullable": true, @@ -305,6 +312,13 @@ "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } + }, + "resourceGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource." + } } } }, @@ -747,7 +761,7 @@ }, "variables": { "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", "builtInRoleNames": { "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", @@ -1301,7 +1315,7 @@ "_generator": { "name": "bicep", "version": "0.26.170.59819", - "templateHash": "5665258089530156840" + "templateHash": "497999704181455009" }, "name": "Web/Function App Deployment Slots", "description": "This module deploys a Web or Function App Deployment Slot.", @@ -1441,6 +1455,13 @@ "description": "Optional. The location to deploy the private endpoint to." } }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, "service": { "type": "string", "nullable": true, @@ -1600,6 +1621,13 @@ "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } + }, + "resourceGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource." + } } } }, @@ -2035,7 +2063,7 @@ }, "variables": { "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", "builtInRoleNames": { "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", @@ -2708,7 +2736,8 @@ }, "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-Slot-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[format('{0}-slot-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "resourceGroup": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupName'), '')]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -2716,10 +2745,10 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}-{3}', last(split(resourceId('Microsoft.Web/sites', parameters('appName')), '/')), parameters('name'), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), format('sites-{0}', parameters('name'))), copyIndex()))]" + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Web/sites', parameters('appName')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), format('sites-{0}', parameters('name'))), copyIndex()))]" }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Web/sites', parameters('appName')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), format('sites-{0}', parameters('name'))), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Web/sites', parameters('appName')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), format('sites-{0}', parameters('name')))))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Web/sites', parameters('appName')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), format('sites-{0}', parameters('name'))), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Web/sites', parameters('appName')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), format('sites-{0}', parameters('name')))), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Web/sites', parameters('appName')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), format('sites-{0}', parameters('name'))), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Web/sites', parameters('appName')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), format('sites-{0}', parameters('name')))))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Web/sites', parameters('appName')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), format('sites-{0}', parameters('name'))), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Web/sites', parameters('appName')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), format('sites-{0}', parameters('name')))), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", "subnetResourceId": { "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, @@ -2764,8 +2793,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "2592884001616184297" + "version": "0.25.53.49325", + "templateHash": "4120048060064073955" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", @@ -3130,7 +3159,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -3235,8 +3264,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "9321937464667207030" + "version": "0.25.53.49325", + "templateHash": "11244630631275470040" }, "name": "Private Endpoint Private DNS Zone Groups", "description": "This module deploys a Private Endpoint Private DNS Zone Group.", @@ -3637,7 +3666,8 @@ }, "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-App-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[format('{0}-app-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "resourceGroup": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupName'), '')]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -3647,8 +3677,8 @@ "name": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Web/sites', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'sites'), copyIndex()))]" }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Web/sites', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'sites'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Web/sites', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'sites')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Web/sites', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'sites'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Web/sites', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'sites')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Web/sites', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'sites'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Web/sites', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'sites')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Web/sites', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'sites'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Web/sites', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'sites')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", "subnetResourceId": { "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, @@ -3693,8 +3723,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "2592884001616184297" + "version": "0.25.53.49325", + "templateHash": "4120048060064073955" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", @@ -4059,7 +4089,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -4164,8 +4194,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "9321937464667207030" + "version": "0.25.53.49325", + "templateHash": "11244630631275470040" }, "name": "Private Endpoint Private DNS Zone Groups", "description": "This module deploys a Private Endpoint Private DNS Zone Group.", diff --git a/avm/res/web/site/slot/README.md b/avm/res/web/site/slot/README.md index d6bd88486f8..35595b34399 100644 --- a/avm/res/web/site/slot/README.md +++ b/avm/res/web/site/slot/README.md @@ -517,6 +517,8 @@ Configuration details for private endpoints. | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | +| [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | | [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/resource groups in this deployment. | @@ -712,6 +714,20 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.resourceGroupName` + +Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. + +- Required: No +- Type: string + ### Parameter: `privateEndpoints.roleAssignments` Array of role assignments to create. @@ -1034,7 +1050,7 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm/res/network/private-endpoint:0.4.0` | Remote reference | +| `br/public:avm/res/network/private-endpoint:0.4.1` | Remote reference | ## Notes diff --git a/avm/res/web/site/slot/basic-publishing-credentials-policy/main.bicep b/avm/res/web/site/slot/basic-publishing-credentials-policy/main.bicep index fc239412ccb..327b4566cd4 100644 --- a/avm/res/web/site/slot/basic-publishing-credentials-policy/main.bicep +++ b/avm/res/web/site/slot/basic-publishing-credentials-policy/main.bicep @@ -2,20 +2,20 @@ metadata name = 'Web Site Slot Basic Publishing Credentials Policies' metadata description = 'This module deploys a Web Site Slot Basic Publishing Credentials Policy.' metadata owner = 'Azure/module-maintainers' -@sys.description('Required. The name of the resource.') +@description('Required. The name of the resource.') @allowed([ 'scm' 'ftp' ]) param name string -@sys.description('Optional. Set to true to enable or false to disable a publishing method.') +@description('Optional. Set to true to enable or false to disable a publishing method.') param allow bool = true -@sys.description('Conditional. The name of the parent web site. Required if the template is used in a standalone deployment.') +@description('Conditional. The name of the parent web site. Required if the template is used in a standalone deployment.') param appName string -@sys.description('Conditional. The name of the parent web site slot. Required if the template is used in a standalone deployment.') +@description('Conditional. The name of the parent web site slot. Required if the template is used in a standalone deployment.') param slotName string @description('Optional. Location for all Resources.') @@ -30,6 +30,7 @@ resource app 'Microsoft.Web/sites@2022-09-01' existing = { } resource basicPublishingCredentialsPolicy 'Microsoft.Web/sites/slots/basicPublishingCredentialsPolicies@2022-09-01' = { + #disable-next-line BCP225 // False-positive. Value is required. name: name location: location parent: app::slot @@ -38,14 +39,14 @@ resource basicPublishingCredentialsPolicy 'Microsoft.Web/sites/slots/basicPublis } } -@sys.description('The name of the basic publishing credential policy.') +@description('The name of the basic publishing credential policy.') output name string = basicPublishingCredentialsPolicy.name -@sys.description('The resource ID of the basic publishing credential policy.') +@description('The resource ID of the basic publishing credential policy.') output resourceId string = basicPublishingCredentialsPolicy.id -@sys.description('The name of the resource group the basic publishing credential policy was deployed into.') +@description('The name of the resource group the basic publishing credential policy was deployed into.') output resourceGroupName string = resourceGroup().name -@sys.description('The location the resource was deployed into.') +@description('The location the resource was deployed into.') output location string = basicPublishingCredentialsPolicy.location diff --git a/avm/res/web/site/slot/basic-publishing-credentials-policy/main.json b/avm/res/web/site/slot/basic-publishing-credentials-policy/main.json index 5edba81498e..a3a6ec2201f 100644 --- a/avm/res/web/site/slot/basic-publishing-credentials-policy/main.json +++ b/avm/res/web/site/slot/basic-publishing-credentials-policy/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "2236066853450471067" + "version": "0.26.170.59819", + "templateHash": "4923254671011353973" }, "name": "Web Site Slot Basic Publishing Credentials Policies", "description": "This module deploys a Web Site Slot Basic Publishing Credentials Policy.", diff --git a/avm/res/web/site/slot/config--appsettings/main.json b/avm/res/web/site/slot/config--appsettings/main.json index 6f64bbb3466..0ae972101e9 100644 --- a/avm/res/web/site/slot/config--appsettings/main.json +++ b/avm/res/web/site/slot/config--appsettings/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "12764984503745572183" + "version": "0.26.170.59819", + "templateHash": "16550727222833899283" }, "name": "Site Slot App Settings", "description": "This module deploys a Site Slot App Setting.", diff --git a/avm/res/web/site/slot/config--authsettingsv2/main.json b/avm/res/web/site/slot/config--authsettingsv2/main.json index e066ea03ace..7853d2be24b 100644 --- a/avm/res/web/site/slot/config--authsettingsv2/main.json +++ b/avm/res/web/site/slot/config--authsettingsv2/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "1333776366661137381" + "version": "0.26.170.59819", + "templateHash": "512112730780239094" }, "name": "Site Slot Auth Settings V2 Config", "description": "This module deploys a Site Auth Settings V2 Configuration.", diff --git a/avm/res/web/site/slot/hybrid-connection-namespace/relay/main.json b/avm/res/web/site/slot/hybrid-connection-namespace/relay/main.json index 34a8005abb5..a1149dd2048 100644 --- a/avm/res/web/site/slot/hybrid-connection-namespace/relay/main.json +++ b/avm/res/web/site/slot/hybrid-connection-namespace/relay/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "1058820827217282473" + "version": "0.26.170.59819", + "templateHash": "15033433727480709023" }, "name": "Web/Function Apps Slot Hybrid Connection Relay", "description": "This module deploys a Site Slot Hybrid Connection Namespace Relay.", diff --git a/avm/res/web/site/slot/main.bicep b/avm/res/web/site/slot/main.bicep index f5aa6cf5f10..5e580d7c148 100644 --- a/avm/res/web/site/slot/main.bicep +++ b/avm/res/web/site/slot/main.bicep @@ -160,7 +160,7 @@ var formattedUserAssignedIdentities = reduce( var identity = !empty(managedIdentities) ? { type: (managedIdentities.?systemAssigned ?? false) - ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') + ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned, UserAssigned' : 'SystemAssigned') : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : null) userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null } @@ -344,12 +344,13 @@ resource slot_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-0 } ] -module slot_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.4.0' = [ +module slot_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.4.1' = [ for (privateEndpoint, index) in (privateEndpoints ?? []): { - name: '${uniqueString(deployment().name, location)}-Slot-PrivateEndpoint-${index}' + name: '${uniqueString(deployment().name, location)}-slot-PrivateEndpoint-${index}' + scope: resourceGroup(privateEndpoint.?resourceGroupName ?? '') params: { - name: privateEndpoint.?name ?? 'pep-${last(split(app.id, '/'))}-${name}-${privateEndpoint.?service ?? 'sites-${slot.name}'}-${index}' - privateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections != true + name: privateEndpoint.?name ?? 'pep-${last(split(app.id, '/'))}-${privateEndpoint.?service ?? 'sites-${slot.name}'}-${index}' + privateLinkServiceConnections: privateEndpoint.?isManualConnection != true ? [ { name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(app.id, '/'))}-${privateEndpoint.?service ?? 'sites-${slot.name}'}-${index}' @@ -362,7 +363,7 @@ module slot_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.4.0' } ] : null - manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections == true + manualPrivateLinkServiceConnections: privateEndpoint.?isManualConnection == true ? [ { name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(app.id, '/'))}-${privateEndpoint.?service ?? 'sites-${slot.name}'}-${index}' @@ -461,6 +462,9 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? + @description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? @@ -524,6 +528,9 @@ type privateEndpointType = { @description('Optional. Enable/Disable usage telemetry for module.') enableTelemetry: bool? + + @description('Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.') + resourceGroupName: string? }[]? type diagnosticSettingType = { diff --git a/avm/res/web/site/slot/main.json b/avm/res/web/site/slot/main.json index ca03c4ee64a..fbc2ce7afe2 100644 --- a/avm/res/web/site/slot/main.json +++ b/avm/res/web/site/slot/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "7436278786647572492" + "version": "0.26.170.59819", + "templateHash": "497999704181455009" }, "name": "Web/Function App Deployment Slots", "description": "This module deploys a Web or Function App Deployment Slot.", @@ -146,6 +146,13 @@ "description": "Optional. The location to deploy the private endpoint to." } }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, "service": { "type": "string", "nullable": true, @@ -305,6 +312,13 @@ "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } + }, + "resourceGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource." + } } } }, @@ -740,7 +754,7 @@ }, "variables": { "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", "builtInRoleNames": { "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", @@ -913,8 +927,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "12764984503745572183" + "version": "0.26.170.59819", + "templateHash": "16550727222833899283" }, "name": "Site Slot App Settings", "description": "This module deploys a Site Slot App Setting.", @@ -1083,8 +1097,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "1333776366661137381" + "version": "0.26.170.59819", + "templateHash": "512112730780239094" }, "name": "Site Slot Auth Settings V2 Config", "description": "This module deploys a Site Auth Settings V2 Configuration.", @@ -1199,8 +1213,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "2236066853450471067" + "version": "0.26.170.59819", + "templateHash": "4923254671011353973" }, "name": "Web Site Slot Basic Publishing Credentials Policies", "description": "This module deploys a Web Site Slot Basic Publishing Credentials Policy.", @@ -1325,8 +1339,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "1058820827217282473" + "version": "0.26.170.59819", + "templateHash": "15033433727480709023" }, "name": "Web/Function Apps Slot Hybrid Connection Relay", "description": "This module deploys a Site Slot Hybrid Connection Namespace Relay.", @@ -1413,7 +1427,8 @@ }, "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-Slot-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[format('{0}-slot-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "resourceGroup": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupName'), '')]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -1421,10 +1436,10 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}-{3}', last(split(resourceId('Microsoft.Web/sites', parameters('appName')), '/')), parameters('name'), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), format('sites-{0}', parameters('name'))), copyIndex()))]" + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Web/sites', parameters('appName')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), format('sites-{0}', parameters('name'))), copyIndex()))]" }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Web/sites', parameters('appName')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), format('sites-{0}', parameters('name'))), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Web/sites', parameters('appName')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), format('sites-{0}', parameters('name')))))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Web/sites', parameters('appName')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), format('sites-{0}', parameters('name'))), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Web/sites', parameters('appName')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), format('sites-{0}', parameters('name')))), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Web/sites', parameters('appName')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), format('sites-{0}', parameters('name'))), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Web/sites', parameters('appName')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), format('sites-{0}', parameters('name')))))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Web/sites', parameters('appName')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), format('sites-{0}', parameters('name'))), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Web/sites', parameters('appName')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), format('sites-{0}', parameters('name')))), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", "subnetResourceId": { "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, @@ -1469,8 +1484,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "2592884001616184297" + "version": "0.25.53.49325", + "templateHash": "4120048060064073955" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", @@ -1835,7 +1850,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -1940,8 +1955,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "9321937464667207030" + "version": "0.25.53.49325", + "templateHash": "11244630631275470040" }, "name": "Private Endpoint Private DNS Zone Groups", "description": "This module deploys a Private Endpoint Private DNS Zone Group.", From 0bd86c285f4d8ce9887e3a2947efb730f3118c62 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Fri, 3 May 2024 11:16:00 +0200 Subject: [PATCH 08/52] feat: Added custom location overwrite (#1721) ## Description - Added custom location overwrite - This is important if you want to rerun / test the same resource deployment more than once (e.g. because you disabled the removal the first time around) and don't want the location rotation to complicate the effort ![image](https://github.com/Azure/bicep-registry-modules/assets/5365358/92be6ccc-e85d-40c3-a7fc-827760be26e0) ![image](https://github.com/Azure/bicep-registry-modules/assets/5365358/1a5c7b28-fffa-4d7d-8ec6-344917def61c) ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.key-vault.vault](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml/badge.svg?branch=users%2Falsehr%2FoverwriteDefaultLocation&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml) | ![image](https://github.com/Azure/bicep-registry-modules/assets/5365358/cd7b541f-7317-49b7-b0be-bd28fac327f3) ## Type of Change - [x] Update to CI Environment or utlities (Non-module effecting 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. - [ ] 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 --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- .../avm-validateModuleDeployment/action.yml | 17 +++++++++++++---- .../avm.ptn.authorization.policy-assignment.yml | 4 ++++ .../avm.ptn.authorization.role-assignment.yml | 4 ++++ .../avm.ptn.policy-insights.remediation.yml | 4 ++++ .../avm.ptn.security.security-center.yml | 4 ++++ .../workflows/avm.res.aad.domain-service.yml | 4 ++++ .../avm.res.analysis-services.server.yml | 4 ++++ .../avm.res.api-management.service.yml | 4 ++++ ...es.app-configuration.configuration-store.yml | 4 ++++ .github/workflows/avm.res.app.container-app.yml | 4 ++++ .../avm.res.app.managed-environment.yml | 4 ++++ .../avm.res.automation.automation-account.yml | 4 ++++ .../workflows/avm.res.batch.batch-account.yml | 4 ++++ .github/workflows/avm.res.cache.redis.yml | 4 ++++ .github/workflows/avm.res.cdn.profile.yml | 4 ++++ .../avm.res.cognitive-services.account.yml | 4 ++++ .../avm.res.compute.availability-set.yml | 4 ++++ .../avm.res.compute.disk-encryption-set.yml | 4 ++++ .github/workflows/avm.res.compute.disk.yml | 4 ++++ .github/workflows/avm.res.compute.gallery.yml | 4 ++++ .github/workflows/avm.res.compute.image.yml | 4 ++++ ...vm.res.compute.proximity-placement-group.yml | 4 ++++ .../avm.res.compute.ssh-public-key.yml | 4 ++++ ...vm.res.compute.virtual-machine-scale-set.yml | 4 ++++ .../avm.res.compute.virtual-machine.yml | 4 ++++ .../workflows/avm.res.consumption.budget.yml | 4 ++++ ...m.res.container-instance.container-group.yml | 4 ++++ .../avm.res.container-registry.registry.yml | 4 ++++ ...vm.res.container-service.managed-cluster.yml | 4 ++++ .../workflows/avm.res.data-factory.factory.yml | 4 ++++ .../avm.res.data-protection.backup-vault.yml | 4 ++++ .../avm.res.databricks.access-connector.yml | 4 ++++ .../workflows/avm.res.databricks.workspace.yml | 4 ++++ .../avm.res.db-for-my-sql.flexible-server.yml | 4 ++++ ...m.res.db-for-postgre-sql.flexible-server.yml | 4 ++++ ...desktop-virtualization.application-group.yml | 4 ++++ ...avm.res.desktop-virtualization.host-pool.yml | 4 ++++ ....res.desktop-virtualization.scaling-plan.yml | 4 ++++ ...avm.res.desktop-virtualization.workspace.yml | 4 ++++ .github/workflows/avm.res.dev-test-lab.lab.yml | 5 ++++- ...res.digital-twins.digital-twins-instance.yml | 4 ++++ .../avm.res.document-db.database-account.yml | 4 ++++ .github/workflows/avm.res.event-grid.domain.yml | 4 ++++ .../workflows/avm.res.event-grid.namespace.yml | 4 ++++ .../avm.res.event-grid.system-topic.yml | 4 ++++ .github/workflows/avm.res.event-grid.topic.yml | 4 ++++ .../workflows/avm.res.event-hub.namespace.yml | 4 ++++ .../workflows/avm.res.health-bot.health-bot.yml | 4 ++++ .../avm.res.healthcare-apis.workspace.yml | 4 ++++ .../workflows/avm.res.insights.action-group.yml | 4 ++++ .../avm.res.insights.activity-log-alert.yml | 4 ++++ .../workflows/avm.res.insights.component.yml | 4 ++++ ...vm.res.insights.data-collection-endpoint.yml | 4 ++++ .../avm.res.insights.data-collection-rule.yml | 4 ++++ .../avm.res.insights.diagnostic-setting.yml | 4 ++++ .../workflows/avm.res.insights.metric-alert.yml | 4 ++++ .../avm.res.insights.private-link-scope.yml | 4 ++++ .../avm.res.insights.scheduled-query-rule.yml | 4 ++++ .github/workflows/avm.res.insights.webtest.yml | 4 ++++ .github/workflows/avm.res.key-vault.vault.yml | 4 ++++ ...m.res.kubernetes-configuration.extension.yml | 4 ++++ ...ernetes-configuration.flux-configuration.yml | 4 ++++ .../avm.res.load-test-service.load-test.yml | 4 ++++ .github/workflows/avm.res.logic.workflow.yml | 4 ++++ ....res.machine-learning-services.workspace.yml | 4 ++++ ...es.maintenance.maintenance-configuration.yml | 4 ++++ ....managed-identity.user-assigned-identity.yml | 4 ++++ ...managed-services.registration-definition.yml | 4 ++++ .../avm.res.management.management-group.yml | 4 ++++ .../avm.res.net-app.net-app-account.yml | 4 ++++ ...-gateway-web-application-firewall-policy.yml | 4 ++++ .../avm.res.network.application-gateway.yml | 4 ++++ ...m.res.network.application-security-group.yml | 4 ++++ .../avm.res.network.azure-firewall.yml | 4 ++++ .../workflows/avm.res.network.bastion-host.yml | 4 ++++ .../workflows/avm.res.network.connection.yml | 4 ++++ .../avm.res.network.ddos-protection-plan.yml | 4 ++++ .../avm.res.network.dns-forwarding-ruleset.yml | 4 ++++ .../workflows/avm.res.network.dns-resolver.yml | 4 ++++ .github/workflows/avm.res.network.dns-zone.yml | 4 ++++ .../avm.res.network.express-route-circuit.yml | 4 ++++ .../avm.res.network.express-route-gateway.yml | 4 ++++ .../avm.res.network.firewall-policy.yml | 4 ++++ ...ont-door-web-application-firewall-policy.yml | 4 ++++ .../workflows/avm.res.network.front-door.yml | 4 ++++ .github/workflows/avm.res.network.ip-group.yml | 4 ++++ .../workflows/avm.res.network.load-balancer.yml | 4 ++++ .../avm.res.network.local-network-gateway.yml | 4 ++++ .../workflows/avm.res.network.nat-gateway.yml | 4 ++++ .../avm.res.network.network-interface.yml | 4 ++++ .../avm.res.network.network-manager.yml | 5 ++++- .../avm.res.network.network-security-group.yml | 4 ++++ .../avm.res.network.network-watcher.yml | 5 ++++- .../avm.res.network.private-dns-zone.yml | 4 ++++ .../avm.res.network.private-endpoint.yml | 4 ++++ .../avm.res.network.private-link-service.yml | 4 ++++ .../avm.res.network.public-ip-address.yml | 4 ++++ .../avm.res.network.public-ip-prefix.yml | 4 ++++ .../workflows/avm.res.network.route-table.yml | 4 ++++ .../avm.res.network.service-endpoint-policy.yml | 4 ++++ .../avm.res.network.trafficmanagerprofile.yml | 4 ++++ .../workflows/avm.res.network.virtual-hub.yml | 4 ++++ .../avm.res.network.virtual-network-gateway.yml | 4 ++++ .../avm.res.network.virtual-network.yml | 4 ++++ .../workflows/avm.res.network.virtual-wan.yml | 5 ++++- .../workflows/avm.res.network.vpn-gateway.yml | 4 ++++ .github/workflows/avm.res.network.vpn-site.yml | 4 ++++ .../avm.res.operational-insights.workspace.yml | 4 ++++ .../avm.res.operations-management.solution.yml | 4 ++++ .../avm.res.power-bi-dedicated.capacity.yml | 4 ++++ .github/workflows/avm.res.purview.account.yml | 4 ++++ .../avm.res.recovery-services.vault.yml | 4 ++++ .github/workflows/avm.res.relay.namespace.yml | 4 ++++ .../workflows/avm.res.resource-graph.query.yml | 4 ++++ .../avm.res.resources.deployment-script.yml | 4 ++++ .../avm.res.resources.resource-group.yml | 4 ++++ .../workflows/avm.res.search.search-service.yml | 4 ++++ .../workflows/avm.res.service-bus.namespace.yml | 4 ++++ .../avm.res.service-fabric.cluster.yml | 4 ++++ .../avm.res.signal-r-service.signal-r.yml | 4 ++++ .../avm.res.signal-r-service.web-pub-sub.yml | 4 ++++ .github/workflows/avm.res.sql.instance-pool.yml | 4 ++++ .../workflows/avm.res.sql.managed-instance.yml | 4 ++++ .github/workflows/avm.res.sql.server.yml | 4 ++++ .../avm.res.storage.storage-account.yml | 4 ++++ .../avm.res.synapse.private-link-hub.yml | 4 ++++ .github/workflows/avm.res.synapse.workspace.yml | 4 ++++ ...es.virtual-machine-images.image-template.yml | 4 ++++ .github/workflows/avm.res.web.connection.yml | 4 ++++ .../avm.res.web.hosting-environment.yml | 5 ++++- .github/workflows/avm.res.web.serverfarm.yml | 4 ++++ .github/workflows/avm.res.web.site.yml | 4 ++++ .github/workflows/avm.res.web.static-site.yml | 4 ++++ .github/workflows/avm.template.module.yml | 1 + ...on.ps1 => Get-AvailableResourceLocation.ps1} | 5 ++--- 135 files changed, 544 insertions(+), 12 deletions(-) rename avm/utilities/pipelines/e2eValidation/regionSelector/{Get-AzAvailableResourceLocation.ps1 => Get-AvailableResourceLocation.ps1} (96%) diff --git a/.github/actions/templates/avm-validateModuleDeployment/action.yml b/.github/actions/templates/avm-validateModuleDeployment/action.yml index 84dde50f325..e9c2ed3d878 100644 --- a/.github/actions/templates/avm-validateModuleDeployment/action.yml +++ b/.github/actions/templates/avm-validateModuleDeployment/action.yml @@ -14,13 +14,14 @@ ## |======================================================================================================================================================================================| ## | Parameter | Required | Default | Description | Example | ## |----------------------------|----------|---------|-------------------------------------------------------|----------------------------------------------------------------------------| -## | modulePath | true | '' | The path to the module file directory | 'modules/api-management/service/main.bicep' -## | templateFilePath | true | '' | The path to the template file to use for deployment | 'modules/api-management/service/tests/e2e/maix/main.test.bicep' | +## | modulePath | true | '' | The path to the module file directory | 'modules/api-management/service/main.bicep' | +## | templateFilePath | true | '' | The path to the template file to use for deployment | 'modules/api-management/service/tests/e2e/maix/main.test.bicep' | ## | deploymentMetadataLocation | true | '' | The location to store the deployment metadata | 'WestEurope' | ## | subscriptionId | false | '' | The subscriptionId to deploy to | '1a97b80a-4dda-4f50-ab53-349e29344654' | ## | managementGroupId | false | '' | The managementGroupId to deploy to | '1a97b80a-4dda-4f50-ab53-349e29344654' | ## | customTokens | false | '' | Additional token pairs in json format. | '{"tokenName":"tokenValue"}' | ## | removeDeployment | false | 'true' | Set "true" to set module up for removal | 'true' | +## | customLocation | false | | Custom location overwrite, if needed | 'WestEurope' | ## |======================================================================================================================================================================================| ## ######################################################### @@ -51,6 +52,9 @@ inputs: description: 'Set "true" to set module up for removal' default: "true" required: false + customLocation: + description: "Custom location overwrite, if needed" + required: false runs: using: "composite" @@ -73,7 +77,7 @@ runs: Write-Output '::group::Get Recommended Regions' # Load used functions - . (Join-Path $env:GITHUB_WORKSPACE 'avm' 'utilities' 'pipelines' 'e2eValidation' 'regionSelector' 'Get-AzAvailableResourceLocation.ps1') + . (Join-Path $env:GITHUB_WORKSPACE 'avm' 'utilities' 'pipelines' 'e2eValidation' 'regionSelector' 'Get-AvailableResourceLocation.ps1') # Set function input parameters $functionInput = @{ @@ -84,7 +88,12 @@ runs: Write-Verbose "Invoke function with" -Verbose Write-Verbose ($functionInput | ConvertTo-Json | Out-String) -Verbose - $resourceLocation = Get-AzAvailableResourceLocation @functionInput -Verbose + if([String]::IsNullOrEmpty('${{ inputs.customLocation }}')) { + $resourceLocation = Get-AvailableResourceLocation @functionInput -Verbose + } else { + $resourceLocation = '${{ inputs.customLocation }}' + Write-Verbose 'Using specified location [${{ inputs.customLocation }}]' -Verbose + } Write-Verbose ('{0}-{1}' -f 'resourceLocation', $resourceLocation) -Verbose Write-Output ('{0}={1}' -f 'resourceLocation', $resourceLocation) >> $env:GITHUB_OUTPUT diff --git a/.github/workflows/avm.ptn.authorization.policy-assignment.yml b/.github/workflows/avm.ptn.authorization.policy-assignment.yml index 89b9f28b0f1..9f4c3c0b284 100644 --- a/.github/workflows/avm.ptn.authorization.policy-assignment.yml +++ b/.github/workflows/avm.ptn.authorization.policy-assignment.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.ptn.authorization.role-assignment.yml b/.github/workflows/avm.ptn.authorization.role-assignment.yml index c9ad8281520..9ca50b1d044 100644 --- a/.github/workflows/avm.ptn.authorization.role-assignment.yml +++ b/.github/workflows/avm.ptn.authorization.role-assignment.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.ptn.policy-insights.remediation.yml b/.github/workflows/avm.ptn.policy-insights.remediation.yml index eecddf314cb..91d2e8e4c5e 100644 --- a/.github/workflows/avm.ptn.policy-insights.remediation.yml +++ b/.github/workflows/avm.ptn.policy-insights.remediation.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.ptn.security.security-center.yml b/.github/workflows/avm.ptn.security.security-center.yml index 3052d3e4bf1..cf261de239a 100644 --- a/.github/workflows/avm.ptn.security.security-center.yml +++ b/.github/workflows/avm.ptn.security.security-center.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.aad.domain-service.yml b/.github/workflows/avm.res.aad.domain-service.yml index b6c0a5883fd..e98c043f0e0 100644 --- a/.github/workflows/avm.res.aad.domain-service.yml +++ b/.github/workflows/avm.res.aad.domain-service.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.analysis-services.server.yml b/.github/workflows/avm.res.analysis-services.server.yml index f0423cebc18..1e96f00472e 100644 --- a/.github/workflows/avm.res.analysis-services.server.yml +++ b/.github/workflows/avm.res.analysis-services.server.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.api-management.service.yml b/.github/workflows/avm.res.api-management.service.yml index e50143e5eb6..3108be5b519 100644 --- a/.github/workflows/avm.res.api-management.service.yml +++ b/.github/workflows/avm.res.api-management.service.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.app-configuration.configuration-store.yml b/.github/workflows/avm.res.app-configuration.configuration-store.yml index 64007151e56..0463f85411f 100644 --- a/.github/workflows/avm.res.app-configuration.configuration-store.yml +++ b/.github/workflows/avm.res.app-configuration.configuration-store.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.app.container-app.yml b/.github/workflows/avm.res.app.container-app.yml index eda9086f29f..7cccd1a641f 100644 --- a/.github/workflows/avm.res.app.container-app.yml +++ b/.github/workflows/avm.res.app.container-app.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.app.managed-environment.yml b/.github/workflows/avm.res.app.managed-environment.yml index 9870549e1b4..d2351fcff67 100644 --- a/.github/workflows/avm.res.app.managed-environment.yml +++ b/.github/workflows/avm.res.app.managed-environment.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.automation.automation-account.yml b/.github/workflows/avm.res.automation.automation-account.yml index a1d821360d3..af3f5129796 100644 --- a/.github/workflows/avm.res.automation.automation-account.yml +++ b/.github/workflows/avm.res.automation.automation-account.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.batch.batch-account.yml b/.github/workflows/avm.res.batch.batch-account.yml index 9a6a729a159..b9b66adb189 100644 --- a/.github/workflows/avm.res.batch.batch-account.yml +++ b/.github/workflows/avm.res.batch.batch-account.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.cache.redis.yml b/.github/workflows/avm.res.cache.redis.yml index ac43a0e789a..503e28b98ff 100644 --- a/.github/workflows/avm.res.cache.redis.yml +++ b/.github/workflows/avm.res.cache.redis.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.cdn.profile.yml b/.github/workflows/avm.res.cdn.profile.yml index 59cc7b8ee8e..6a8b29b8895 100644 --- a/.github/workflows/avm.res.cdn.profile.yml +++ b/.github/workflows/avm.res.cdn.profile.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.cognitive-services.account.yml b/.github/workflows/avm.res.cognitive-services.account.yml index bf98e748fdb..eeef979d0f9 100644 --- a/.github/workflows/avm.res.cognitive-services.account.yml +++ b/.github/workflows/avm.res.cognitive-services.account.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.compute.availability-set.yml b/.github/workflows/avm.res.compute.availability-set.yml index 9d8262d723c..8a2436c8e49 100644 --- a/.github/workflows/avm.res.compute.availability-set.yml +++ b/.github/workflows/avm.res.compute.availability-set.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.compute.disk-encryption-set.yml b/.github/workflows/avm.res.compute.disk-encryption-set.yml index d100ca82d4c..546ae42703c 100644 --- a/.github/workflows/avm.res.compute.disk-encryption-set.yml +++ b/.github/workflows/avm.res.compute.disk-encryption-set.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.compute.disk.yml b/.github/workflows/avm.res.compute.disk.yml index 532b8d33953..696d3988b00 100644 --- a/.github/workflows/avm.res.compute.disk.yml +++ b/.github/workflows/avm.res.compute.disk.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.compute.gallery.yml b/.github/workflows/avm.res.compute.gallery.yml index ecd2971eacd..1e276eb8bfc 100644 --- a/.github/workflows/avm.res.compute.gallery.yml +++ b/.github/workflows/avm.res.compute.gallery.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.compute.image.yml b/.github/workflows/avm.res.compute.image.yml index 34d2ddbf841..e924643b800 100644 --- a/.github/workflows/avm.res.compute.image.yml +++ b/.github/workflows/avm.res.compute.image.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.compute.proximity-placement-group.yml b/.github/workflows/avm.res.compute.proximity-placement-group.yml index 203bcda2f6c..af48c165c1a 100644 --- a/.github/workflows/avm.res.compute.proximity-placement-group.yml +++ b/.github/workflows/avm.res.compute.proximity-placement-group.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.compute.ssh-public-key.yml b/.github/workflows/avm.res.compute.ssh-public-key.yml index f6009ff23f3..79b1157f629 100644 --- a/.github/workflows/avm.res.compute.ssh-public-key.yml +++ b/.github/workflows/avm.res.compute.ssh-public-key.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.compute.virtual-machine-scale-set.yml b/.github/workflows/avm.res.compute.virtual-machine-scale-set.yml index 6684d6ac6f8..72d92d5a4cb 100644 --- a/.github/workflows/avm.res.compute.virtual-machine-scale-set.yml +++ b/.github/workflows/avm.res.compute.virtual-machine-scale-set.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.compute.virtual-machine.yml b/.github/workflows/avm.res.compute.virtual-machine.yml index ea05134a0c0..45e66007b2f 100644 --- a/.github/workflows/avm.res.compute.virtual-machine.yml +++ b/.github/workflows/avm.res.compute.virtual-machine.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.consumption.budget.yml b/.github/workflows/avm.res.consumption.budget.yml index 90b490e86b7..1472af059c9 100644 --- a/.github/workflows/avm.res.consumption.budget.yml +++ b/.github/workflows/avm.res.consumption.budget.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.container-instance.container-group.yml b/.github/workflows/avm.res.container-instance.container-group.yml index 9782de00fa4..fe04e5be9c6 100644 --- a/.github/workflows/avm.res.container-instance.container-group.yml +++ b/.github/workflows/avm.res.container-instance.container-group.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.container-registry.registry.yml b/.github/workflows/avm.res.container-registry.registry.yml index 33375897320..d75e15cbc96 100644 --- a/.github/workflows/avm.res.container-registry.registry.yml +++ b/.github/workflows/avm.res.container-registry.registry.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.container-service.managed-cluster.yml b/.github/workflows/avm.res.container-service.managed-cluster.yml index 09fe56615ac..69df988a960 100644 --- a/.github/workflows/avm.res.container-service.managed-cluster.yml +++ b/.github/workflows/avm.res.container-service.managed-cluster.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.data-factory.factory.yml b/.github/workflows/avm.res.data-factory.factory.yml index 85f84e0b076..4ba1391d765 100644 --- a/.github/workflows/avm.res.data-factory.factory.yml +++ b/.github/workflows/avm.res.data-factory.factory.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.data-protection.backup-vault.yml b/.github/workflows/avm.res.data-protection.backup-vault.yml index a7bb6a820b7..532ab8ceb29 100644 --- a/.github/workflows/avm.res.data-protection.backup-vault.yml +++ b/.github/workflows/avm.res.data-protection.backup-vault.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.databricks.access-connector.yml b/.github/workflows/avm.res.databricks.access-connector.yml index 148b0f3b476..37e0affa14c 100644 --- a/.github/workflows/avm.res.databricks.access-connector.yml +++ b/.github/workflows/avm.res.databricks.access-connector.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.databricks.workspace.yml b/.github/workflows/avm.res.databricks.workspace.yml index c77a174cc50..363a057cc0c 100644 --- a/.github/workflows/avm.res.databricks.workspace.yml +++ b/.github/workflows/avm.res.databricks.workspace.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.db-for-my-sql.flexible-server.yml b/.github/workflows/avm.res.db-for-my-sql.flexible-server.yml index e3db3a22827..0e87dc75f09 100644 --- a/.github/workflows/avm.res.db-for-my-sql.flexible-server.yml +++ b/.github/workflows/avm.res.db-for-my-sql.flexible-server.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.db-for-postgre-sql.flexible-server.yml b/.github/workflows/avm.res.db-for-postgre-sql.flexible-server.yml index 1f1cc20472f..a3c2d330b39 100644 --- a/.github/workflows/avm.res.db-for-postgre-sql.flexible-server.yml +++ b/.github/workflows/avm.res.db-for-postgre-sql.flexible-server.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.desktop-virtualization.application-group.yml b/.github/workflows/avm.res.desktop-virtualization.application-group.yml index cfaf4c73d1b..1a44934c463 100644 --- a/.github/workflows/avm.res.desktop-virtualization.application-group.yml +++ b/.github/workflows/avm.res.desktop-virtualization.application-group.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.desktop-virtualization.host-pool.yml b/.github/workflows/avm.res.desktop-virtualization.host-pool.yml index acd977b9fc5..32bf95419e1 100644 --- a/.github/workflows/avm.res.desktop-virtualization.host-pool.yml +++ b/.github/workflows/avm.res.desktop-virtualization.host-pool.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.desktop-virtualization.scaling-plan.yml b/.github/workflows/avm.res.desktop-virtualization.scaling-plan.yml index 354e66c840e..fa90aa158aa 100644 --- a/.github/workflows/avm.res.desktop-virtualization.scaling-plan.yml +++ b/.github/workflows/avm.res.desktop-virtualization.scaling-plan.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.desktop-virtualization.workspace.yml b/.github/workflows/avm.res.desktop-virtualization.workspace.yml index a9751917306..187250410a9 100644 --- a/.github/workflows/avm.res.desktop-virtualization.workspace.yml +++ b/.github/workflows/avm.res.desktop-virtualization.workspace.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.dev-test-lab.lab.yml b/.github/workflows/avm.res.dev-test-lab.lab.yml index f21b83d851f..279249ea823 100644 --- a/.github/workflows/avm.res.dev-test-lab.lab.yml +++ b/.github/workflows/avm.res.dev-test-lab.lab.yml @@ -20,7 +20,10 @@ on: description: "Remove deployed module" required: false default: true - + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.digital-twins.digital-twins-instance.yml b/.github/workflows/avm.res.digital-twins.digital-twins-instance.yml index fc9e6fb5da1..5a35addd220 100644 --- a/.github/workflows/avm.res.digital-twins.digital-twins-instance.yml +++ b/.github/workflows/avm.res.digital-twins.digital-twins-instance.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.document-db.database-account.yml b/.github/workflows/avm.res.document-db.database-account.yml index 0256cf706ba..a50ef58296b 100644 --- a/.github/workflows/avm.res.document-db.database-account.yml +++ b/.github/workflows/avm.res.document-db.database-account.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.event-grid.domain.yml b/.github/workflows/avm.res.event-grid.domain.yml index 9381b46be37..69e41ab2137 100644 --- a/.github/workflows/avm.res.event-grid.domain.yml +++ b/.github/workflows/avm.res.event-grid.domain.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.event-grid.namespace.yml b/.github/workflows/avm.res.event-grid.namespace.yml index 918be160e47..016af52fa56 100644 --- a/.github/workflows/avm.res.event-grid.namespace.yml +++ b/.github/workflows/avm.res.event-grid.namespace.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.event-grid.system-topic.yml b/.github/workflows/avm.res.event-grid.system-topic.yml index 91a39b07025..84a57808172 100644 --- a/.github/workflows/avm.res.event-grid.system-topic.yml +++ b/.github/workflows/avm.res.event-grid.system-topic.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.event-grid.topic.yml b/.github/workflows/avm.res.event-grid.topic.yml index c18831793cc..54a4a8b3f6e 100644 --- a/.github/workflows/avm.res.event-grid.topic.yml +++ b/.github/workflows/avm.res.event-grid.topic.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.event-hub.namespace.yml b/.github/workflows/avm.res.event-hub.namespace.yml index fdb60c6967e..bf62295498a 100644 --- a/.github/workflows/avm.res.event-hub.namespace.yml +++ b/.github/workflows/avm.res.event-hub.namespace.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.health-bot.health-bot.yml b/.github/workflows/avm.res.health-bot.health-bot.yml index 28168746577..ca78da1dd6b 100644 --- a/.github/workflows/avm.res.health-bot.health-bot.yml +++ b/.github/workflows/avm.res.health-bot.health-bot.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.healthcare-apis.workspace.yml b/.github/workflows/avm.res.healthcare-apis.workspace.yml index 1bbb96d64bb..6e10efdc87c 100644 --- a/.github/workflows/avm.res.healthcare-apis.workspace.yml +++ b/.github/workflows/avm.res.healthcare-apis.workspace.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.insights.action-group.yml b/.github/workflows/avm.res.insights.action-group.yml index e1ab58c33d3..ce0f46d29a9 100644 --- a/.github/workflows/avm.res.insights.action-group.yml +++ b/.github/workflows/avm.res.insights.action-group.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.insights.activity-log-alert.yml b/.github/workflows/avm.res.insights.activity-log-alert.yml index 56909df4978..589c3de4355 100644 --- a/.github/workflows/avm.res.insights.activity-log-alert.yml +++ b/.github/workflows/avm.res.insights.activity-log-alert.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.insights.component.yml b/.github/workflows/avm.res.insights.component.yml index 9a050de1b31..c514b20d447 100644 --- a/.github/workflows/avm.res.insights.component.yml +++ b/.github/workflows/avm.res.insights.component.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.insights.data-collection-endpoint.yml b/.github/workflows/avm.res.insights.data-collection-endpoint.yml index 4378fd0524c..af327a3620f 100644 --- a/.github/workflows/avm.res.insights.data-collection-endpoint.yml +++ b/.github/workflows/avm.res.insights.data-collection-endpoint.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.insights.data-collection-rule.yml b/.github/workflows/avm.res.insights.data-collection-rule.yml index 38f40faa0f6..079a74431b6 100644 --- a/.github/workflows/avm.res.insights.data-collection-rule.yml +++ b/.github/workflows/avm.res.insights.data-collection-rule.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.insights.diagnostic-setting.yml b/.github/workflows/avm.res.insights.diagnostic-setting.yml index 795331cb396..4d92a2b3c36 100644 --- a/.github/workflows/avm.res.insights.diagnostic-setting.yml +++ b/.github/workflows/avm.res.insights.diagnostic-setting.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.insights.metric-alert.yml b/.github/workflows/avm.res.insights.metric-alert.yml index 9257fd9da0c..909e71d901f 100644 --- a/.github/workflows/avm.res.insights.metric-alert.yml +++ b/.github/workflows/avm.res.insights.metric-alert.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.insights.private-link-scope.yml b/.github/workflows/avm.res.insights.private-link-scope.yml index cef950e2d17..ba6ebbc4da5 100644 --- a/.github/workflows/avm.res.insights.private-link-scope.yml +++ b/.github/workflows/avm.res.insights.private-link-scope.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.insights.scheduled-query-rule.yml b/.github/workflows/avm.res.insights.scheduled-query-rule.yml index cc8498a9e20..7752b8d8284 100644 --- a/.github/workflows/avm.res.insights.scheduled-query-rule.yml +++ b/.github/workflows/avm.res.insights.scheduled-query-rule.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.insights.webtest.yml b/.github/workflows/avm.res.insights.webtest.yml index 56170b2b41b..41d83bd0a8d 100644 --- a/.github/workflows/avm.res.insights.webtest.yml +++ b/.github/workflows/avm.res.insights.webtest.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.key-vault.vault.yml b/.github/workflows/avm.res.key-vault.vault.yml index 5968981b0a9..e5e36c4f18f 100644 --- a/.github/workflows/avm.res.key-vault.vault.yml +++ b/.github/workflows/avm.res.key-vault.vault.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.kubernetes-configuration.extension.yml b/.github/workflows/avm.res.kubernetes-configuration.extension.yml index a64e3ec6ae8..c5173cdeffa 100644 --- a/.github/workflows/avm.res.kubernetes-configuration.extension.yml +++ b/.github/workflows/avm.res.kubernetes-configuration.extension.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.kubernetes-configuration.flux-configuration.yml b/.github/workflows/avm.res.kubernetes-configuration.flux-configuration.yml index c2b6639e50b..265783bdf9b 100644 --- a/.github/workflows/avm.res.kubernetes-configuration.flux-configuration.yml +++ b/.github/workflows/avm.res.kubernetes-configuration.flux-configuration.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.load-test-service.load-test.yml b/.github/workflows/avm.res.load-test-service.load-test.yml index 255a2abdcad..dd4ca538022 100644 --- a/.github/workflows/avm.res.load-test-service.load-test.yml +++ b/.github/workflows/avm.res.load-test-service.load-test.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.logic.workflow.yml b/.github/workflows/avm.res.logic.workflow.yml index 4e26779ac43..46c01e28e2c 100644 --- a/.github/workflows/avm.res.logic.workflow.yml +++ b/.github/workflows/avm.res.logic.workflow.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.machine-learning-services.workspace.yml b/.github/workflows/avm.res.machine-learning-services.workspace.yml index 0870695a7b0..640c8556792 100644 --- a/.github/workflows/avm.res.machine-learning-services.workspace.yml +++ b/.github/workflows/avm.res.machine-learning-services.workspace.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.maintenance.maintenance-configuration.yml b/.github/workflows/avm.res.maintenance.maintenance-configuration.yml index 557b54b8230..4ec3807ca71 100644 --- a/.github/workflows/avm.res.maintenance.maintenance-configuration.yml +++ b/.github/workflows/avm.res.maintenance.maintenance-configuration.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.managed-identity.user-assigned-identity.yml b/.github/workflows/avm.res.managed-identity.user-assigned-identity.yml index 091029721eb..32bd11123a3 100644 --- a/.github/workflows/avm.res.managed-identity.user-assigned-identity.yml +++ b/.github/workflows/avm.res.managed-identity.user-assigned-identity.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.managed-services.registration-definition.yml b/.github/workflows/avm.res.managed-services.registration-definition.yml index 71332194d1e..6445bd9ac55 100644 --- a/.github/workflows/avm.res.managed-services.registration-definition.yml +++ b/.github/workflows/avm.res.managed-services.registration-definition.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.management.management-group.yml b/.github/workflows/avm.res.management.management-group.yml index 2cba65a51f6..fed43544c26 100644 --- a/.github/workflows/avm.res.management.management-group.yml +++ b/.github/workflows/avm.res.management.management-group.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.net-app.net-app-account.yml b/.github/workflows/avm.res.net-app.net-app-account.yml index 072606e52d7..efeb3c22e7a 100644 --- a/.github/workflows/avm.res.net-app.net-app-account.yml +++ b/.github/workflows/avm.res.net-app.net-app-account.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.application-gateway-web-application-firewall-policy.yml b/.github/workflows/avm.res.network.application-gateway-web-application-firewall-policy.yml index 3ada19eb967..2dbc3221f36 100644 --- a/.github/workflows/avm.res.network.application-gateway-web-application-firewall-policy.yml +++ b/.github/workflows/avm.res.network.application-gateway-web-application-firewall-policy.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.application-gateway.yml b/.github/workflows/avm.res.network.application-gateway.yml index c2c4c9f4645..e280f4d4dd2 100644 --- a/.github/workflows/avm.res.network.application-gateway.yml +++ b/.github/workflows/avm.res.network.application-gateway.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.application-security-group.yml b/.github/workflows/avm.res.network.application-security-group.yml index dd6a8ea1971..5c2e8cd503e 100644 --- a/.github/workflows/avm.res.network.application-security-group.yml +++ b/.github/workflows/avm.res.network.application-security-group.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.azure-firewall.yml b/.github/workflows/avm.res.network.azure-firewall.yml index e17568a3aa2..2046301eaad 100644 --- a/.github/workflows/avm.res.network.azure-firewall.yml +++ b/.github/workflows/avm.res.network.azure-firewall.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.bastion-host.yml b/.github/workflows/avm.res.network.bastion-host.yml index 2200b41740e..b1907a24718 100644 --- a/.github/workflows/avm.res.network.bastion-host.yml +++ b/.github/workflows/avm.res.network.bastion-host.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.connection.yml b/.github/workflows/avm.res.network.connection.yml index 66808c8311d..ac83b293a1a 100644 --- a/.github/workflows/avm.res.network.connection.yml +++ b/.github/workflows/avm.res.network.connection.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.ddos-protection-plan.yml b/.github/workflows/avm.res.network.ddos-protection-plan.yml index a496035ec70..6d848dbadf6 100644 --- a/.github/workflows/avm.res.network.ddos-protection-plan.yml +++ b/.github/workflows/avm.res.network.ddos-protection-plan.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.dns-forwarding-ruleset.yml b/.github/workflows/avm.res.network.dns-forwarding-ruleset.yml index 09fd3b93bb6..9fa39400714 100644 --- a/.github/workflows/avm.res.network.dns-forwarding-ruleset.yml +++ b/.github/workflows/avm.res.network.dns-forwarding-ruleset.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.dns-resolver.yml b/.github/workflows/avm.res.network.dns-resolver.yml index 8ade3fca082..3cb787510d6 100644 --- a/.github/workflows/avm.res.network.dns-resolver.yml +++ b/.github/workflows/avm.res.network.dns-resolver.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.dns-zone.yml b/.github/workflows/avm.res.network.dns-zone.yml index 30a7251dd12..1e07cff6b89 100644 --- a/.github/workflows/avm.res.network.dns-zone.yml +++ b/.github/workflows/avm.res.network.dns-zone.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.express-route-circuit.yml b/.github/workflows/avm.res.network.express-route-circuit.yml index c0284316a4e..f5b64f71bbb 100644 --- a/.github/workflows/avm.res.network.express-route-circuit.yml +++ b/.github/workflows/avm.res.network.express-route-circuit.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.express-route-gateway.yml b/.github/workflows/avm.res.network.express-route-gateway.yml index cd309a876c2..e5ac188c8fe 100644 --- a/.github/workflows/avm.res.network.express-route-gateway.yml +++ b/.github/workflows/avm.res.network.express-route-gateway.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.firewall-policy.yml b/.github/workflows/avm.res.network.firewall-policy.yml index f9afa2c9145..f219a26d375 100644 --- a/.github/workflows/avm.res.network.firewall-policy.yml +++ b/.github/workflows/avm.res.network.firewall-policy.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.front-door-web-application-firewall-policy.yml b/.github/workflows/avm.res.network.front-door-web-application-firewall-policy.yml index b0cf5b7adf5..0588a346c1e 100644 --- a/.github/workflows/avm.res.network.front-door-web-application-firewall-policy.yml +++ b/.github/workflows/avm.res.network.front-door-web-application-firewall-policy.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.front-door.yml b/.github/workflows/avm.res.network.front-door.yml index aeebe4b8e03..82c5a0c2da8 100644 --- a/.github/workflows/avm.res.network.front-door.yml +++ b/.github/workflows/avm.res.network.front-door.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.ip-group.yml b/.github/workflows/avm.res.network.ip-group.yml index beae160b06c..6b45ce90214 100644 --- a/.github/workflows/avm.res.network.ip-group.yml +++ b/.github/workflows/avm.res.network.ip-group.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.load-balancer.yml b/.github/workflows/avm.res.network.load-balancer.yml index 82d767037a2..e92d462ce1b 100644 --- a/.github/workflows/avm.res.network.load-balancer.yml +++ b/.github/workflows/avm.res.network.load-balancer.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.local-network-gateway.yml b/.github/workflows/avm.res.network.local-network-gateway.yml index 4bd6d37c068..3207ac68cdf 100644 --- a/.github/workflows/avm.res.network.local-network-gateway.yml +++ b/.github/workflows/avm.res.network.local-network-gateway.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.nat-gateway.yml b/.github/workflows/avm.res.network.nat-gateway.yml index 34dd4c8ff9b..8c62d7529a6 100644 --- a/.github/workflows/avm.res.network.nat-gateway.yml +++ b/.github/workflows/avm.res.network.nat-gateway.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.network-interface.yml b/.github/workflows/avm.res.network.network-interface.yml index 9e7fd880ddd..c1f1481d54b 100644 --- a/.github/workflows/avm.res.network.network-interface.yml +++ b/.github/workflows/avm.res.network.network-interface.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.network-manager.yml b/.github/workflows/avm.res.network.network-manager.yml index de51d0761f7..df7080fe481 100644 --- a/.github/workflows/avm.res.network.network-manager.yml +++ b/.github/workflows/avm.res.network.network-manager.yml @@ -20,7 +20,10 @@ on: description: "Remove deployed module" required: false default: true - + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.network-security-group.yml b/.github/workflows/avm.res.network.network-security-group.yml index daa4e72f0e6..3532677245a 100644 --- a/.github/workflows/avm.res.network.network-security-group.yml +++ b/.github/workflows/avm.res.network.network-security-group.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.network-watcher.yml b/.github/workflows/avm.res.network.network-watcher.yml index 823b4baf3e3..ddbd5d8a191 100644 --- a/.github/workflows/avm.res.network.network-watcher.yml +++ b/.github/workflows/avm.res.network.network-watcher.yml @@ -20,7 +20,10 @@ on: description: "Remove deployed module" required: false default: true - + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.private-dns-zone.yml b/.github/workflows/avm.res.network.private-dns-zone.yml index 5a4e8317d99..452cf857d2a 100644 --- a/.github/workflows/avm.res.network.private-dns-zone.yml +++ b/.github/workflows/avm.res.network.private-dns-zone.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.private-endpoint.yml b/.github/workflows/avm.res.network.private-endpoint.yml index 5d23ab8081a..03fb4f97571 100644 --- a/.github/workflows/avm.res.network.private-endpoint.yml +++ b/.github/workflows/avm.res.network.private-endpoint.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.private-link-service.yml b/.github/workflows/avm.res.network.private-link-service.yml index c07fda9761e..51b571e5f73 100644 --- a/.github/workflows/avm.res.network.private-link-service.yml +++ b/.github/workflows/avm.res.network.private-link-service.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.public-ip-address.yml b/.github/workflows/avm.res.network.public-ip-address.yml index db38984755d..703938c44b6 100644 --- a/.github/workflows/avm.res.network.public-ip-address.yml +++ b/.github/workflows/avm.res.network.public-ip-address.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.public-ip-prefix.yml b/.github/workflows/avm.res.network.public-ip-prefix.yml index efe48d6ba03..9f5d34f4f2a 100644 --- a/.github/workflows/avm.res.network.public-ip-prefix.yml +++ b/.github/workflows/avm.res.network.public-ip-prefix.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.route-table.yml b/.github/workflows/avm.res.network.route-table.yml index 8dd1c6e2dd1..dc8afc1f651 100644 --- a/.github/workflows/avm.res.network.route-table.yml +++ b/.github/workflows/avm.res.network.route-table.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.service-endpoint-policy.yml b/.github/workflows/avm.res.network.service-endpoint-policy.yml index 80e26edeac0..1af7a2a717d 100644 --- a/.github/workflows/avm.res.network.service-endpoint-policy.yml +++ b/.github/workflows/avm.res.network.service-endpoint-policy.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.trafficmanagerprofile.yml b/.github/workflows/avm.res.network.trafficmanagerprofile.yml index fe5f3c42162..1bd4e2a4e93 100644 --- a/.github/workflows/avm.res.network.trafficmanagerprofile.yml +++ b/.github/workflows/avm.res.network.trafficmanagerprofile.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.virtual-hub.yml b/.github/workflows/avm.res.network.virtual-hub.yml index 07eb5900cc5..44326a6420f 100644 --- a/.github/workflows/avm.res.network.virtual-hub.yml +++ b/.github/workflows/avm.res.network.virtual-hub.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.virtual-network-gateway.yml b/.github/workflows/avm.res.network.virtual-network-gateway.yml index f3603f6a93b..e8bb321b02e 100644 --- a/.github/workflows/avm.res.network.virtual-network-gateway.yml +++ b/.github/workflows/avm.res.network.virtual-network-gateway.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.virtual-network.yml b/.github/workflows/avm.res.network.virtual-network.yml index 19dcc10683f..57e8ba620e6 100644 --- a/.github/workflows/avm.res.network.virtual-network.yml +++ b/.github/workflows/avm.res.network.virtual-network.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.virtual-wan.yml b/.github/workflows/avm.res.network.virtual-wan.yml index 2e0cb52e58f..879d2af07bd 100644 --- a/.github/workflows/avm.res.network.virtual-wan.yml +++ b/.github/workflows/avm.res.network.virtual-wan.yml @@ -20,7 +20,10 @@ on: description: "Remove deployed module" required: false default: true - + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.vpn-gateway.yml b/.github/workflows/avm.res.network.vpn-gateway.yml index cad31de2f07..3f09789e570 100644 --- a/.github/workflows/avm.res.network.vpn-gateway.yml +++ b/.github/workflows/avm.res.network.vpn-gateway.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.network.vpn-site.yml b/.github/workflows/avm.res.network.vpn-site.yml index 9bd6329f4ba..fb43b3ba057 100644 --- a/.github/workflows/avm.res.network.vpn-site.yml +++ b/.github/workflows/avm.res.network.vpn-site.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.operational-insights.workspace.yml b/.github/workflows/avm.res.operational-insights.workspace.yml index 58e95538aea..45afd8e76fc 100644 --- a/.github/workflows/avm.res.operational-insights.workspace.yml +++ b/.github/workflows/avm.res.operational-insights.workspace.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.operations-management.solution.yml b/.github/workflows/avm.res.operations-management.solution.yml index d91fa4e81df..e7d0341c7fc 100644 --- a/.github/workflows/avm.res.operations-management.solution.yml +++ b/.github/workflows/avm.res.operations-management.solution.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.power-bi-dedicated.capacity.yml b/.github/workflows/avm.res.power-bi-dedicated.capacity.yml index 318a6ac32e7..ab480c7d9f9 100644 --- a/.github/workflows/avm.res.power-bi-dedicated.capacity.yml +++ b/.github/workflows/avm.res.power-bi-dedicated.capacity.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.purview.account.yml b/.github/workflows/avm.res.purview.account.yml index a32032f4cc9..2b3c88ed76a 100644 --- a/.github/workflows/avm.res.purview.account.yml +++ b/.github/workflows/avm.res.purview.account.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.recovery-services.vault.yml b/.github/workflows/avm.res.recovery-services.vault.yml index 9d5a1dc1ff2..08ee36a2249 100644 --- a/.github/workflows/avm.res.recovery-services.vault.yml +++ b/.github/workflows/avm.res.recovery-services.vault.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.relay.namespace.yml b/.github/workflows/avm.res.relay.namespace.yml index 52e8a21ebfe..83e0627d83c 100644 --- a/.github/workflows/avm.res.relay.namespace.yml +++ b/.github/workflows/avm.res.relay.namespace.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.resource-graph.query.yml b/.github/workflows/avm.res.resource-graph.query.yml index cf6dbea5541..5066241fde3 100644 --- a/.github/workflows/avm.res.resource-graph.query.yml +++ b/.github/workflows/avm.res.resource-graph.query.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.resources.deployment-script.yml b/.github/workflows/avm.res.resources.deployment-script.yml index 83fe844bf57..9f690b11203 100644 --- a/.github/workflows/avm.res.resources.deployment-script.yml +++ b/.github/workflows/avm.res.resources.deployment-script.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.resources.resource-group.yml b/.github/workflows/avm.res.resources.resource-group.yml index 1029a715326..7efbefa09f6 100644 --- a/.github/workflows/avm.res.resources.resource-group.yml +++ b/.github/workflows/avm.res.resources.resource-group.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.search.search-service.yml b/.github/workflows/avm.res.search.search-service.yml index bc1cee5a317..d61eadc6f9f 100644 --- a/.github/workflows/avm.res.search.search-service.yml +++ b/.github/workflows/avm.res.search.search-service.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.service-bus.namespace.yml b/.github/workflows/avm.res.service-bus.namespace.yml index cc9f1d73e6c..88318c8e27e 100644 --- a/.github/workflows/avm.res.service-bus.namespace.yml +++ b/.github/workflows/avm.res.service-bus.namespace.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.service-fabric.cluster.yml b/.github/workflows/avm.res.service-fabric.cluster.yml index 2e2c93206cb..c1ca69f2fb1 100644 --- a/.github/workflows/avm.res.service-fabric.cluster.yml +++ b/.github/workflows/avm.res.service-fabric.cluster.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.signal-r-service.signal-r.yml b/.github/workflows/avm.res.signal-r-service.signal-r.yml index 45832831812..dcace6a7c51 100644 --- a/.github/workflows/avm.res.signal-r-service.signal-r.yml +++ b/.github/workflows/avm.res.signal-r-service.signal-r.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.signal-r-service.web-pub-sub.yml b/.github/workflows/avm.res.signal-r-service.web-pub-sub.yml index 63bfe1a0ae5..63e950f713f 100644 --- a/.github/workflows/avm.res.signal-r-service.web-pub-sub.yml +++ b/.github/workflows/avm.res.signal-r-service.web-pub-sub.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.sql.instance-pool.yml b/.github/workflows/avm.res.sql.instance-pool.yml index 659c39b82a4..068c67372d2 100644 --- a/.github/workflows/avm.res.sql.instance-pool.yml +++ b/.github/workflows/avm.res.sql.instance-pool.yml @@ -21,6 +21,10 @@ on: # We had to set this to false because the SQL Instance Pool takes more than 24 hours to get deleted required: false default: false + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.sql.managed-instance.yml b/.github/workflows/avm.res.sql.managed-instance.yml index 3e9ebac6f28..8f2be513b84 100644 --- a/.github/workflows/avm.res.sql.managed-instance.yml +++ b/.github/workflows/avm.res.sql.managed-instance.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.sql.server.yml b/.github/workflows/avm.res.sql.server.yml index 318c70f382f..3d4492d8615 100644 --- a/.github/workflows/avm.res.sql.server.yml +++ b/.github/workflows/avm.res.sql.server.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.storage.storage-account.yml b/.github/workflows/avm.res.storage.storage-account.yml index 5463a26207a..7083867ec3b 100644 --- a/.github/workflows/avm.res.storage.storage-account.yml +++ b/.github/workflows/avm.res.storage.storage-account.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.synapse.private-link-hub.yml b/.github/workflows/avm.res.synapse.private-link-hub.yml index 78d7f360825..3fd652f3ceb 100644 --- a/.github/workflows/avm.res.synapse.private-link-hub.yml +++ b/.github/workflows/avm.res.synapse.private-link-hub.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.synapse.workspace.yml b/.github/workflows/avm.res.synapse.workspace.yml index 37dd6ce412d..5a36b42e544 100644 --- a/.github/workflows/avm.res.synapse.workspace.yml +++ b/.github/workflows/avm.res.synapse.workspace.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.virtual-machine-images.image-template.yml b/.github/workflows/avm.res.virtual-machine-images.image-template.yml index 649b950f18c..1577e940c22 100644 --- a/.github/workflows/avm.res.virtual-machine-images.image-template.yml +++ b/.github/workflows/avm.res.virtual-machine-images.image-template.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.web.connection.yml b/.github/workflows/avm.res.web.connection.yml index c3b8b69c55e..05b0cb2663f 100644 --- a/.github/workflows/avm.res.web.connection.yml +++ b/.github/workflows/avm.res.web.connection.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.web.hosting-environment.yml b/.github/workflows/avm.res.web.hosting-environment.yml index 76c245192be..93e53f15167 100644 --- a/.github/workflows/avm.res.web.hosting-environment.yml +++ b/.github/workflows/avm.res.web.hosting-environment.yml @@ -20,7 +20,10 @@ on: description: "Remove deployed module" required: false default: true - + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.web.serverfarm.yml b/.github/workflows/avm.res.web.serverfarm.yml index 49e6a91d0e1..7e464d42563 100644 --- a/.github/workflows/avm.res.web.serverfarm.yml +++ b/.github/workflows/avm.res.web.serverfarm.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.web.site.yml b/.github/workflows/avm.res.web.site.yml index b0742ae7721..27620ec5773 100644 --- a/.github/workflows/avm.res.web.site.yml +++ b/.github/workflows/avm.res.web.site.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.res.web.static-site.yml b/.github/workflows/avm.res.web.static-site.yml index 111370620f5..eb6fecbd352 100644 --- a/.github/workflows/avm.res.web.static-site.yml +++ b/.github/workflows/avm.res.web.static-site.yml @@ -20,6 +20,10 @@ on: description: "Remove deployed module" required: false default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false push: branches: - main diff --git a/.github/workflows/avm.template.module.yml b/.github/workflows/avm.template.module.yml index 70eeb5ea5bf..fe8ef021509 100644 --- a/.github/workflows/avm.template.module.yml +++ b/.github/workflows/avm.template.module.yml @@ -129,6 +129,7 @@ jobs: subscriptionId: "${{ secrets.ARM_SUBSCRIPTION_ID }}" managementGroupId: "${{ secrets.ARM_MGMTGROUP_ID }}" removeDeployment: "${{ fromJson(inputs.workflowInput).removeDeployment }}" + customLocation: "${{ fromJson(inputs.workflowInput).customLocation }}" env: AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} diff --git a/avm/utilities/pipelines/e2eValidation/regionSelector/Get-AzAvailableResourceLocation.ps1 b/avm/utilities/pipelines/e2eValidation/regionSelector/Get-AvailableResourceLocation.ps1 similarity index 96% rename from avm/utilities/pipelines/e2eValidation/regionSelector/Get-AzAvailableResourceLocation.ps1 rename to avm/utilities/pipelines/e2eValidation/regionSelector/Get-AvailableResourceLocation.ps1 index fea03eb471e..1ec7dc12c32 100644 --- a/avm/utilities/pipelines/e2eValidation/regionSelector/Get-AzAvailableResourceLocation.ps1 +++ b/avm/utilities/pipelines/e2eValidation/regionSelector/Get-AvailableResourceLocation.ps1 @@ -21,12 +21,12 @@ Optional. The root path of the repository. Required. The location of the resource group where the global resources will be deployed. .EXAMPLE -Get-AzAvailableResourceLocation -ModuleRoot ".\avm\res\resources\resource-group" -repoRoot .\ +Get-AvailableResourceLocation -ModuleRoot ".\avm\res\resources\resource-group" -repoRoot .\ Get the recommended paired regions available for the service. #> -function Get-AzAvailableResourceLocation { +function Get-AvailableResourceLocation { param ( [Parameter(Mandatory = $false)] @@ -58,7 +58,6 @@ function Get-AzAvailableResourceLocation { 'switzerlandnorth', 'uaenorth', 'westeurope', - 'westus2', 'westus2' ) ) From a5c9af8e4ee3a35accf8ae8f3a725fe7b0a2a9af Mon Sep 17 00:00:00 2001 From: Zach Trocinski <30884663+oZakari@users.noreply.github.com> Date: Fri, 3 May 2024 04:20:07 -0500 Subject: [PATCH 09/52] fix: Update publishing job to only trigger if git repo is assocaited to the upstream repo (#1830) ## Description Experiencing the publishing job getting triggered when using the main branch in forks. Adding an additional condition to the job to only trigger if the workflow is being run within the upstream repository. https://docs.github.com/en/actions/learn-github-actions/contexts#github-context ## Pipeline Reference Pipeline run with context set to my fork https://github.com/oZakari/bicep-registry-modules/actions/runs/8930012279 Pipeline with context set to Azure org https://github.com/oZakari/bicep-registry-modules/actions/runs/8930022963 ## Type of Change - [x] Update to CI Environment or utlities (Non-module effecting 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. - [ ] 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 - [ ] 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 --- .github/workflows/avm.template.module.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/avm.template.module.yml b/.github/workflows/avm.template.module.yml index fe8ef021509..efb117c5f68 100644 --- a/.github/workflows/avm.template.module.yml +++ b/.github/workflows/avm.template.module.yml @@ -141,6 +141,7 @@ jobs: runs-on: ubuntu-latest # Note: Below always() required in condition due to psrule jobs being skipped for ptn modules not having defaults or waf-aligned folders if: github.ref == 'refs/heads/main' && + github.repository == 'Azure/bicep-registry-modules' && always() && needs.job_module_static_validation.result == 'success' && needs.job_module_deploy_validation.result == 'success' From f1b281eb9aa0d40d80a323ec97abc994ab48102b Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Fri, 3 May 2024 11:52:03 +0200 Subject: [PATCH 10/52] fix: Added additional case handling to logic that pulls workflow inputs (#1833) ## Description Added additional case handling to logic that pulls workflow inputs to account for non-required parameters without defaults This did already work for workflow-dispatch but not merge to main ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.security.security-center](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.security.security-center.yml/badge.svg?branch=users%2Falsehr%2FcustomLocalFollowUp)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.security.security-center.yml) | ## Type of Change - [x] Update to CI Environment or utlities (Non-module effecting 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. - [ ] 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 --- .../actions/templates/avm-getWorkflowInput/action.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/actions/templates/avm-getWorkflowInput/action.yml b/.github/actions/templates/avm-getWorkflowInput/action.yml index b78c1eb7f9b..8c686805d96 100644 --- a/.github/actions/templates/avm-getWorkflowInput/action.yml +++ b/.github/actions/templates/avm-getWorkflowInput/action.yml @@ -66,6 +66,11 @@ runs: # Output values to be accessed by next jobs $workflowInput = @{} foreach($parameterName in $parameters.Keys) { + if([String]::IsNullOrEmpty($parameters[$parameterName])) { + Write-Verbose "Skipping parameter [$parameterName] as it has no explicit or default value" -Verbose + continue + } + Write-Verbose ('Passing output [{0}] with value [{1}]' -f $parameterName, $parameters[$parameterName]) -Verbose $workflowInput[$parameterName] = $parameters[$parameterName] } @@ -88,6 +93,12 @@ runs: # Output values to be accessed by next jobs $workflowInput = @{} foreach($parameterName in $workflowParameters.Keys) { + + if([String]::IsNullOrEmpty($workflowParameters[$parameterName])) { + Write-Verbose "Skipping parameter [$parameterName] as it has no explicit or default value" -Verbose + continue + } + Write-Verbose ('Passing output [{0}] with value [{1}]' -f $parameterName, $workflowParameters[$parameterName]) -Verbose $workflowInput[$parameterName] = $workflowParameters[$parameterName].toString() } From bf2f123d27f06134ebec7de65e8cdb75ac13bf58 Mon Sep 17 00:00:00 2001 From: Christoph Vollmann Date: Fri, 3 May 2024 12:13:49 +0200 Subject: [PATCH 11/52] fix: Allow empty parameters in subnet `avm/res/network/virtual-network` (#1772) ## Description You cannot provide the following parameters in your subnet parameter, if they are empty: - networkSecurityGroup - natGateway - routeTable As soon as they are set, they have to have a correct resource id. This PR implements additional checks for given, but empty, parameters. I also added a new subnet definition in the `max` test to check for the correct behaviour. Fixes #1681 Closes #1681 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.network.virtual-network](https://github.com/cloudchristoph/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network.yml/badge.svg?branch=1681_vnet_subnet_conditional_params)](https://github.com/cloudchristoph/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module effecting changes) - [x] Azure Verified Module updates: - [x] Bugfix containing backwards compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [x] 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. - [ ] 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`. - [x] 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 --- avm/res/network/virtual-network/README.md | 14 ++++++++++++ avm/res/network/virtual-network/main.bicep | 6 ++--- avm/res/network/virtual-network/main.json | 22 +++++++++---------- .../tests/e2e/max/main.test.bicep | 9 +++++++- 4 files changed, 36 insertions(+), 15 deletions(-) diff --git a/avm/res/network/virtual-network/README.md b/avm/res/network/virtual-network/README.md index 87cb1ddedc3..2618d0811fd 100644 --- a/avm/res/network/virtual-network/README.md +++ b/avm/res/network/virtual-network/README.md @@ -188,6 +188,13 @@ module virtualNetwork 'br/public:avm/res/network/virtual-network:' = { privateEndpointNetworkPolicies: 'Disabled' privateLinkServiceNetworkPolicies: 'Enabled' } + { + addressPrefix: '' + name: 'az-subnet-x-004' + natGatewayResourceId: '' + networkSecurityGroupResourceId: '' + routeTableResourceId: '' + } { addressPrefix: '' name: 'AzureBastionSubnet' @@ -319,6 +326,13 @@ module virtualNetwork 'br/public:avm/res/network/virtual-network:' = { "privateEndpointNetworkPolicies": "Disabled", "privateLinkServiceNetworkPolicies": "Enabled" }, + { + "addressPrefix": "", + "name": "az-subnet-x-004", + "natGatewayResourceId": "", + "networkSecurityGroupResourceId": "", + "routeTableResourceId": "" + }, { "addressPrefix": "", "name": "AzureBastionSubnet", diff --git a/avm/res/network/virtual-network/main.bicep b/avm/res/network/virtual-network/main.bicep index e1d6854e1c1..2d272099bc7 100644 --- a/avm/res/network/virtual-network/main.bicep +++ b/avm/res/network/virtual-network/main.bicep @@ -130,12 +130,12 @@ resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { : [] delegations: contains(subnet, 'delegations') ? subnet.delegations : [] ipAllocations: contains(subnet, 'ipAllocations') ? subnet.ipAllocations : [] - natGateway: contains(subnet, 'natGatewayResourceId') + natGateway: contains(subnet, 'natGatewayResourceId') && !empty(subnet.natGatewayResourceId) ? { id: subnet.natGatewayResourceId } : null - networkSecurityGroup: contains(subnet, 'networkSecurityGroupResourceId') + networkSecurityGroup: contains(subnet, 'networkSecurityGroupResourceId') && !empty(subnet.networkSecurityGroupResourceId) ? { id: subnet.networkSecurityGroupResourceId } @@ -146,7 +146,7 @@ resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { privateLinkServiceNetworkPolicies: contains(subnet, 'privateLinkServiceNetworkPolicies') ? subnet.privateLinkServiceNetworkPolicies : null - routeTable: contains(subnet, 'routeTableResourceId') + routeTable: contains(subnet, 'routeTableResourceId') && !empty(subnet.routeTableResourceId) ? { id: subnet.routeTableResourceId } diff --git a/avm/res/network/virtual-network/main.json b/avm/res/network/virtual-network/main.json index 8e3664e6619..e6058d75335 100644 --- a/avm/res/network/virtual-network/main.json +++ b/avm/res/network/virtual-network/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "11377673418536997302" + "version": "0.26.170.59819", + "templateHash": "15351421638054038409" }, "name": "Virtual Networks", "description": "This module deploys a Virtual Network (vNet).", @@ -382,11 +382,11 @@ "applicationGatewayIPConfigurations": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'applicationGatewayIPConfigurations'), parameters('subnets')[copyIndex('subnets')].applicationGatewayIPConfigurations, createArray())]", "delegations": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'delegations'), parameters('subnets')[copyIndex('subnets')].delegations, createArray())]", "ipAllocations": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'ipAllocations'), parameters('subnets')[copyIndex('subnets')].ipAllocations, createArray())]", - "natGateway": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'natGatewayResourceId'), createObject('id', parameters('subnets')[copyIndex('subnets')].natGatewayResourceId), null())]", - "networkSecurityGroup": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'networkSecurityGroupResourceId'), createObject('id', parameters('subnets')[copyIndex('subnets')].networkSecurityGroupResourceId), null())]", + "natGateway": "[if(and(contains(parameters('subnets')[copyIndex('subnets')], 'natGatewayResourceId'), not(empty(parameters('subnets')[copyIndex('subnets')].natGatewayResourceId))), createObject('id', parameters('subnets')[copyIndex('subnets')].natGatewayResourceId), null())]", + "networkSecurityGroup": "[if(and(contains(parameters('subnets')[copyIndex('subnets')], 'networkSecurityGroupResourceId'), not(empty(parameters('subnets')[copyIndex('subnets')].networkSecurityGroupResourceId))), createObject('id', parameters('subnets')[copyIndex('subnets')].networkSecurityGroupResourceId), null())]", "privateEndpointNetworkPolicies": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'privateEndpointNetworkPolicies'), parameters('subnets')[copyIndex('subnets')].privateEndpointNetworkPolicies, null())]", "privateLinkServiceNetworkPolicies": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'privateLinkServiceNetworkPolicies'), parameters('subnets')[copyIndex('subnets')].privateLinkServiceNetworkPolicies, null())]", - "routeTable": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'routeTableResourceId'), createObject('id', parameters('subnets')[copyIndex('subnets')].routeTableResourceId), null())]", + "routeTable": "[if(and(contains(parameters('subnets')[copyIndex('subnets')], 'routeTableResourceId'), not(empty(parameters('subnets')[copyIndex('subnets')].routeTableResourceId))), createObject('id', parameters('subnets')[copyIndex('subnets')].routeTableResourceId), null())]", "serviceEndpoints": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'serviceEndpoints'), parameters('subnets')[copyIndex('subnets')].serviceEndpoints, createArray())]", "serviceEndpointPolicies": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'serviceEndpointPolicies'), parameters('subnets')[copyIndex('subnets')].serviceEndpointPolicies, createArray())]" } @@ -523,8 +523,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "11309828149329550402" + "version": "0.26.170.59819", + "templateHash": "17306638026226376877" }, "name": "Virtual Network Subnets", "description": "This module deploys a Virtual Network Subnet.", @@ -849,8 +849,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "2926837656927862519" + "version": "0.26.170.59819", + "templateHash": "17624189975510507274" }, "name": "Virtual Network Peerings", "description": "This module deploys a Virtual Network Peering.", @@ -994,8 +994,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "2926837656927862519" + "version": "0.26.170.59819", + "templateHash": "17624189975510507274" }, "name": "Virtual Network Peerings", "description": "This module deploys a Virtual Network Peering.", diff --git a/avm/res/network/virtual-network/tests/e2e/max/main.test.bicep b/avm/res/network/virtual-network/tests/e2e/max/main.test.bicep index 0eff43a79da..6111d452f34 100644 --- a/avm/res/network/virtual-network/tests/e2e/max/main.test.bicep +++ b/avm/res/network/virtual-network/tests/e2e/max/main.test.bicep @@ -151,11 +151,18 @@ module testDeployment '../../../main.bicep' = [ } { addressPrefix: cidrSubnet(addressPrefix, 24, 4) + name: '${namePrefix}-az-subnet-x-004' + networkSecurityGroupResourceId: '' + natGatewayResourceId: '' + routeTableResourceId: '' + } + { + addressPrefix: cidrSubnet(addressPrefix, 24, 5) name: 'AzureBastionSubnet' networkSecurityGroupResourceId: nestedDependencies.outputs.networkSecurityGroupBastionResourceId } { - addressPrefix: cidrSubnet(addressPrefix, 24, 5) + addressPrefix: cidrSubnet(addressPrefix, 24, 6) name: 'AzureFirewallSubnet' } ] From c888ed8b1787d9bc6c82a0698eb4213ed6b51c52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20H=C3=A9zser?= Date: Fri, 3 May 2024 18:02:02 +0200 Subject: [PATCH 12/52] adds imageResourceIds as output - `avm/res/compute/gallery` (#1818) ## Description The resource ids of deployed images are available as output parameter. Fixes #1798 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.compute.gallery](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.compute.gallery.yml/badge.svg)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.compute.gallery.yml) | ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [x] 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`. - [x] 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 --- avm/res/compute/gallery/README.md | 1 + avm/res/compute/gallery/application/main.json | 4 ++-- avm/res/compute/gallery/image/main.json | 4 ++-- avm/res/compute/gallery/main.bicep | 5 +++++ avm/res/compute/gallery/main.json | 22 ++++++++++++++----- avm/res/compute/gallery/version.json | 2 +- 6 files changed, 27 insertions(+), 11 deletions(-) diff --git a/avm/res/compute/gallery/README.md b/avm/res/compute/gallery/README.md index 081835b82b3..cf8e00455a3 100644 --- a/avm/res/compute/gallery/README.md +++ b/avm/res/compute/gallery/README.md @@ -684,6 +684,7 @@ Tags for all resources. | Output | Type | Description | | :-- | :-- | :-- | +| `imageResourceIds` | array | The resource ids of the deployed images. | | `location` | string | The location the resource was deployed into. | | `name` | string | The name of the deployed image gallery. | | `resourceGroupName` | string | The resource group of the deployed image gallery. | diff --git a/avm/res/compute/gallery/application/main.json b/avm/res/compute/gallery/application/main.json index 9c8df87f87a..91e65e1bb15 100644 --- a/avm/res/compute/gallery/application/main.json +++ b/avm/res/compute/gallery/application/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "3817884050778525461" + "version": "0.26.170.59819", + "templateHash": "9175012718933553578" }, "name": "Compute Galleries Applications", "description": "This module deploys an Azure Compute Gallery Application.", diff --git a/avm/res/compute/gallery/image/main.json b/avm/res/compute/gallery/image/main.json index 6ff4eedb7d7..11f350a32c3 100644 --- a/avm/res/compute/gallery/image/main.json +++ b/avm/res/compute/gallery/image/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "15034895982698413313" + "version": "0.26.170.59819", + "templateHash": "7059991596058545894" }, "name": "Compute Galleries Image Definitions", "description": "This module deploys an Azure Compute Gallery Image Definition.", diff --git a/avm/res/compute/gallery/main.bicep b/avm/res/compute/gallery/main.bicep index 58b61a145bb..28634714724 100644 --- a/avm/res/compute/gallery/main.bicep +++ b/avm/res/compute/gallery/main.bicep @@ -183,6 +183,11 @@ output name string = gallery.name @sys.description('The location the resource was deployed into.') output location string = gallery.location +@sys.description('The resource ids of the deployed images.') +output imageResourceIds array = [ + for index in range(0, length(images ?? [])): galleries_images[index].outputs.resourceId +] + // =============== // // Definitions // // =============== // diff --git a/avm/res/compute/gallery/main.json b/avm/res/compute/gallery/main.json index c2863f574ca..1a3c273c2fd 100644 --- a/avm/res/compute/gallery/main.json +++ b/avm/res/compute/gallery/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "5329218260776835511" + "version": "0.26.170.59819", + "templateHash": "4586802822078326566" }, "name": "Azure Compute Galleries", "description": "This module deploys an Azure Compute Gallery (formerly known as Shared Image Gallery).", @@ -319,8 +319,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "3817884050778525461" + "version": "0.26.170.59819", + "templateHash": "9175012718933553578" }, "name": "Compute Galleries Applications", "description": "This module deploys an Azure Compute Gallery Application.", @@ -676,8 +676,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "15034895982698413313" + "version": "0.26.170.59819", + "templateHash": "7059991596058545894" }, "name": "Compute Galleries Image Definitions", "description": "This module deploys an Azure Compute Gallery Image Definition.", @@ -1111,6 +1111,16 @@ "description": "The location the resource was deployed into." }, "value": "[reference('gallery', '2022-03-03', 'full').location]" + }, + "imageResourceIds": { + "type": "array", + "metadata": { + "description": "The resource ids of the deployed images." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('images'), createArray()))))]", + "input": "[reference(format('galleries_images[{0}]', range(0, length(coalesce(parameters('images'), createArray())))[copyIndex()])).outputs.resourceId.value]" + } } } } \ No newline at end of file diff --git a/avm/res/compute/gallery/version.json b/avm/res/compute/gallery/version.json index 76049e1c4ad..13669e66018 100644 --- a/avm/res/compute/gallery/version.json +++ b/avm/res/compute/gallery/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.3", + "version": "0.4", "pathFilters": [ "./main.json" ] From 5d3810da7a35f3105ca74c80a00f13cb13338148 Mon Sep 17 00:00:00 2001 From: emichellecarter Date: Fri, 3 May 2024 11:06:05 -0500 Subject: [PATCH 13/52] docs: Removing orphaned module file - `avm/res/insights/scheduled-query-rule` (#1821) ## Description ## Pipeline Reference [![avm.res.insights.scheduled-query-rule](https://github.com/emichellecarter/bicep-registry-modules/actions/workflows/avm.res.insights.scheduled-query-rule.yml/badge.svg)](https://github.com/emichellecarter/bicep-registry-modules/actions/workflows/avm.res.insights.scheduled-query-rule.yml) ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting 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. - [ ] 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`. - [X] 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. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings Co-authored-by: Michelle Carter --- avm/res/insights/scheduled-query-rule/ORPHANED.md | 4 ---- avm/res/insights/scheduled-query-rule/README.md | 5 ----- avm/res/insights/scheduled-query-rule/main.json | 4 ++-- 3 files changed, 2 insertions(+), 11 deletions(-) delete mode 100644 avm/res/insights/scheduled-query-rule/ORPHANED.md diff --git a/avm/res/insights/scheduled-query-rule/ORPHANED.md b/avm/res/insights/scheduled-query-rule/ORPHANED.md deleted file mode 100644 index ef8fa911d2b..00000000000 --- a/avm/res/insights/scheduled-query-rule/ORPHANED.md +++ /dev/null @@ -1,4 +0,0 @@ -⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️ - -- Only security and bug fixes are being handled by the AVM core team at present. -- If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)! \ No newline at end of file diff --git a/avm/res/insights/scheduled-query-rule/README.md b/avm/res/insights/scheduled-query-rule/README.md index f23d8999a05..4d4f1f1904c 100644 --- a/avm/res/insights/scheduled-query-rule/README.md +++ b/avm/res/insights/scheduled-query-rule/README.md @@ -1,10 +1,5 @@ # Scheduled Query Rules `[Microsoft.Insights/scheduledQueryRules]` -> ⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️ -> -> - Only security and bug fixes are being handled by the AVM core team at present. -> - If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)! - This module deploys a Scheduled Query Rule. ## Navigation diff --git a/avm/res/insights/scheduled-query-rule/main.json b/avm/res/insights/scheduled-query-rule/main.json index 3f5f174495a..c8dad9e133c 100644 --- a/avm/res/insights/scheduled-query-rule/main.json +++ b/avm/res/insights/scheduled-query-rule/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "11130634754232789940" + "version": "0.26.170.59819", + "templateHash": "15037142199357270998" }, "name": "Scheduled Query Rules", "description": "This module deploys a Scheduled Query Rule.", From 0c30c69ac64fdbe094f3bf7b22fb327e1efcda23 Mon Sep 17 00:00:00 2001 From: elisa anzelmo Date: Fri, 3 May 2024 18:58:08 +0200 Subject: [PATCH 14/52] fix: not supported Powershell and Python versions on Automation Runbook type (#1834) ## Description - updated runbook API version t 2023-11-01 to support all the following runbook types: 'Graph' 'GraphPowerShell' 'GraphPowerShellWorkflow' 'PowerShell' 'PowerShell72' 'PowerShellWorkflow' 'Python2' 'Python3' 'Script' (required) - updated useridentity and keyservices to be compliant with new bicep requirements - updated PSRule excemption file for default checks Closes #1757 Closes #1743 Closes #1445 ## Pipeline Reference | Pipeline | | -------- | [![avm.res.automation.automation-account](https://github.com/elanzel/bicep-registry-modules/actions/workflows/avm.res.automation.automation-account.yml/badge.svg?branch=automationaccount)](https://github.com/elanzel/bicep-registry-modules/actions/workflows/avm.res.automation.automation-account.yml) | | ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [X] 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. - [ ] 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 --------- Co-authored-by: Alexander Sehr --- .../automation/automation-account/README.md | 2 +- .../automation-account/job-schedule/main.json | 4 +- .../automation/automation-account/main.bicep | 8 ++-- .../automation/automation-account/main.json | 46 ++++++++++--------- .../automation-account/module/main.json | 4 +- .../automation-account/runbook/README.md | 6 ++- .../automation-account/runbook/main.bicep | 6 ++- .../automation-account/runbook/main.json | 14 ++++-- .../automation-account/schedule/main.json | 4 +- .../software-update-configuration/main.json | 4 +- .../automation-account/variable/main.json | 4 +- .../psrule/.ps-rule/min-suppress.Rule.yaml | 2 + 12 files changed, 61 insertions(+), 43 deletions(-) diff --git a/avm/res/automation/automation-account/README.md b/avm/res/automation/automation-account/README.md index 26fd342e223..f6f4457d6b8 100644 --- a/avm/res/automation/automation-account/README.md +++ b/avm/res/automation/automation-account/README.md @@ -20,7 +20,7 @@ This module deploys an Azure Automation Account. | `Microsoft.Automation/automationAccounts` | [2022-08-08](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automation/2022-08-08/automationAccounts) | | `Microsoft.Automation/automationAccounts/jobSchedules` | [2022-08-08](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automation/2022-08-08/automationAccounts/jobSchedules) | | `Microsoft.Automation/automationAccounts/modules` | [2022-08-08](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automation/2022-08-08/automationAccounts/modules) | -| `Microsoft.Automation/automationAccounts/runbooks` | [2022-08-08](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automation/2022-08-08/automationAccounts/runbooks) | +| `Microsoft.Automation/automationAccounts/runbooks` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automation/2023-11-01/automationAccounts/runbooks) | | `Microsoft.Automation/automationAccounts/schedules` | [2022-08-08](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automation/2022-08-08/automationAccounts/schedules) | | `Microsoft.Automation/automationAccounts/softwareUpdateConfigurations` | [2019-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automation/2019-06-01/automationAccounts/softwareUpdateConfigurations) | | `Microsoft.Automation/automationAccounts/variables` | [2022-08-08](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automation/2022-08-08/automationAccounts/variables) | diff --git a/avm/res/automation/automation-account/job-schedule/main.json b/avm/res/automation/automation-account/job-schedule/main.json index 1d7dbb1dfec..713d17c9ace 100644 --- a/avm/res/automation/automation-account/job-schedule/main.json +++ b/avm/res/automation/automation-account/job-schedule/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "3709450248827326388" + "version": "0.26.170.59819", + "templateHash": "1753602189799388874" }, "name": "Automation Account Job Schedules", "description": "This module deploys an Azure Automation Account Job Schedule.", diff --git a/avm/res/automation/automation-account/main.bicep b/avm/res/automation/automation-account/main.bicep index 3f579884c47..d4bf94c7e92 100644 --- a/avm/res/automation/automation-account/main.bicep +++ b/avm/res/automation/automation-account/main.bicep @@ -83,8 +83,8 @@ var formattedUserAssignedIdentities = reduce( var identity = !empty(managedIdentities) ? { type: (managedIdentities.?systemAssigned ?? false) - ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') - : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : null) + ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned, UserAssigned' : 'SystemAssigned') + : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : 'None') userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null } : null @@ -172,7 +172,7 @@ resource automationAccount 'Microsoft.Automation/automationAccounts@2022-08-08' } encryption: !empty(customerManagedKey) ? { - keySource: 'Microsoft.KeyVault' + keySource: 'Microsoft.Keyvault' identity: !empty(customerManagedKey.?userAssignedIdentityResourceId) ? { userAssignedIdentity: cMKUserAssignedIdentity.id @@ -180,7 +180,7 @@ resource automationAccount 'Microsoft.Automation/automationAccounts@2022-08-08' : null keyVaultProperties: { keyName: customerManagedKey!.keyName - keyVaultUri: cMKKeyVault.properties.vaultUri + keyvaultUri: cMKKeyVault.properties.vaultUri keyVersion: !empty(customerManagedKey.?keyVersion ?? '') ? customerManagedKey!.keyVersion : last(split(cMKKeyVault::cMKKey.properties.keyUriWithVersion, '/')) diff --git a/avm/res/automation/automation-account/main.json b/avm/res/automation/automation-account/main.json index ef54d7a09b3..2f891a354c7 100644 --- a/avm/res/automation/automation-account/main.json +++ b/avm/res/automation/automation-account/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "16001446000186457588" + "version": "0.26.170.59819", + "templateHash": "9883583040461189210" }, "name": "Automation Accounts", "description": "This module deploys an Azure Automation Account.", @@ -629,7 +629,7 @@ }, "variables": { "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", "builtInRoleNames": { "Automation Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f353d9bd-d4a6-484e-a77a-8050b599b867')]", "Automation Job Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4fe576fe-1146-4730-92eb-48519fa6bf9f')]", @@ -704,7 +704,7 @@ "sku": { "name": "[parameters('skuName')]" }, - "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keySource', 'Microsoft.KeyVault', 'identity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), createObject('userAssignedIdentity', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/')))), null()), 'keyVaultProperties', createObject('keyName', parameters('customerManagedKey').keyName, 'keyVaultUri', reference('cMKKeyVault').vaultUri, 'keyVersion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), parameters('customerManagedKey').keyVersion, last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/'))))), null())]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keySource', 'Microsoft.Keyvault', 'identity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), createObject('userAssignedIdentity', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/')))), null()), 'keyVaultProperties', createObject('keyName', parameters('customerManagedKey').keyName, 'keyvaultUri', reference('cMKKeyVault').vaultUri, 'keyVersion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), parameters('customerManagedKey').keyVersion, last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/'))))), null())]", "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), if(equals(parameters('publicNetworkAccess'), 'Disabled'), false(), true()), if(not(empty(parameters('privateEndpoints'))), false(), null()))]", "disableLocalAuth": "[parameters('disableLocalAuth')]" }, @@ -830,8 +830,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "8037849223912660600" + "version": "0.26.170.59819", + "templateHash": "17695610509863036784" }, "name": "Automation Account Modules", "description": "This module deploys an Azure Automation Account Module.", @@ -972,8 +972,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "10057879847143996563" + "version": "0.26.170.59819", + "templateHash": "138940659217362139" }, "name": "Automation Account Schedules", "description": "This module deploys an Azure Automation Account Schedule.", @@ -1151,8 +1151,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "14714097202201612277" + "version": "0.26.170.59819", + "templateHash": "6946565957724859459" }, "name": "Automation Account Runbooks", "description": "This module deploys an Azure Automation Account Runbook.", @@ -1178,7 +1178,11 @@ "GraphPowerShell", "GraphPowerShellWorkflow", "PowerShell", - "PowerShellWorkflow" + "PowerShell72", + "PowerShellWorkflow", + "Python2", + "Python3", + "Script" ], "metadata": { "description": "Required. The type of the runbook." @@ -1268,7 +1272,7 @@ }, "runbook": { "type": "Microsoft.Automation/automationAccounts/runbooks", - "apiVersion": "2022-08-08", + "apiVersion": "2023-11-01", "name": "[format('{0}/{1}', parameters('automationAccountName'), parameters('name'))]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", @@ -1310,7 +1314,7 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('runbook', '2022-08-08', 'full').location]" + "value": "[reference('runbook', '2023-11-01', 'full').location]" } } } @@ -1351,8 +1355,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "3709450248827326388" + "version": "0.26.170.59819", + "templateHash": "1753602189799388874" }, "name": "Automation Account Job Schedules", "description": "This module deploys an Azure Automation Account Job Schedule.", @@ -1479,8 +1483,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "1065450815403209329" + "version": "0.26.170.59819", + "templateHash": "12833257216729067514" }, "name": "Automation Account Variables", "description": "This module deploys an Azure Automation Account Variable.", @@ -1594,8 +1598,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "7204307644126778192" + "version": "0.26.170.59819", + "templateHash": "11747347606522833060" }, "name": "Log Analytics Workspace Linked Services", "description": "This module deploys a Log Analytics Workspace Linked Service.", @@ -1913,8 +1917,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "7586828544795723203" + "version": "0.26.170.59819", + "templateHash": "14866221548688198425" }, "name": "Automation Account Software Update Configurations", "description": "This module deploys an Azure Automation Account Software Update Configuration.", diff --git a/avm/res/automation/automation-account/module/main.json b/avm/res/automation/automation-account/module/main.json index 546c8505d54..f8cbfa3d7a3 100644 --- a/avm/res/automation/automation-account/module/main.json +++ b/avm/res/automation/automation-account/module/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "8037849223912660600" + "version": "0.26.170.59819", + "templateHash": "17695610509863036784" }, "name": "Automation Account Modules", "description": "This module deploys an Azure Automation Account Module.", diff --git a/avm/res/automation/automation-account/runbook/README.md b/avm/res/automation/automation-account/runbook/README.md index b10d9c903bd..933591a6135 100644 --- a/avm/res/automation/automation-account/runbook/README.md +++ b/avm/res/automation/automation-account/runbook/README.md @@ -14,7 +14,7 @@ This module deploys an Azure Automation Account Runbook. | Resource Type | API Version | | :-- | :-- | -| `Microsoft.Automation/automationAccounts/runbooks` | [2022-08-08](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automation/2022-08-08/automationAccounts/runbooks) | +| `Microsoft.Automation/automationAccounts/runbooks` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automation/2023-11-01/automationAccounts/runbooks) | ## Parameters @@ -69,7 +69,11 @@ The type of the runbook. 'GraphPowerShell' 'GraphPowerShellWorkflow' 'PowerShell' + 'PowerShell72' 'PowerShellWorkflow' + 'Python2' + 'Python3' + 'Script' ] ``` diff --git a/avm/res/automation/automation-account/runbook/main.bicep b/avm/res/automation/automation-account/runbook/main.bicep index 4f41bf68ca6..e45047c60ad 100644 --- a/avm/res/automation/automation-account/runbook/main.bicep +++ b/avm/res/automation/automation-account/runbook/main.bicep @@ -13,7 +13,11 @@ param automationAccountName string 'GraphPowerShell' 'GraphPowerShellWorkflow' 'PowerShell' + 'PowerShell72' 'PowerShellWorkflow' + 'Python2' + 'Python3' + 'Script' ]) @sys.description('Required. The type of the runbook.') param type string @@ -74,7 +78,7 @@ var publishContentLink = empty(uri) version: !empty(version) ? version : null } -resource runbook 'Microsoft.Automation/automationAccounts/runbooks@2022-08-08' = { +resource runbook 'Microsoft.Automation/automationAccounts/runbooks@2023-11-01' = { name: name parent: automationAccount location: location diff --git a/avm/res/automation/automation-account/runbook/main.json b/avm/res/automation/automation-account/runbook/main.json index 4f23a696b62..327797d3538 100644 --- a/avm/res/automation/automation-account/runbook/main.json +++ b/avm/res/automation/automation-account/runbook/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "14714097202201612277" + "version": "0.26.170.59819", + "templateHash": "6946565957724859459" }, "name": "Automation Account Runbooks", "description": "This module deploys an Azure Automation Account Runbook.", @@ -32,7 +32,11 @@ "GraphPowerShell", "GraphPowerShellWorkflow", "PowerShell", - "PowerShellWorkflow" + "PowerShell72", + "PowerShellWorkflow", + "Python2", + "Python3", + "Script" ], "metadata": { "description": "Required. The type of the runbook." @@ -122,7 +126,7 @@ }, "runbook": { "type": "Microsoft.Automation/automationAccounts/runbooks", - "apiVersion": "2022-08-08", + "apiVersion": "2023-11-01", "name": "[format('{0}/{1}', parameters('automationAccountName'), parameters('name'))]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", @@ -164,7 +168,7 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('runbook', '2022-08-08', 'full').location]" + "value": "[reference('runbook', '2023-11-01', 'full').location]" } } } \ No newline at end of file diff --git a/avm/res/automation/automation-account/schedule/main.json b/avm/res/automation/automation-account/schedule/main.json index 4a8ef6d8704..35ada70ebbb 100644 --- a/avm/res/automation/automation-account/schedule/main.json +++ b/avm/res/automation/automation-account/schedule/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "10057879847143996563" + "version": "0.26.170.59819", + "templateHash": "138940659217362139" }, "name": "Automation Account Schedules", "description": "This module deploys an Azure Automation Account Schedule.", diff --git a/avm/res/automation/automation-account/software-update-configuration/main.json b/avm/res/automation/automation-account/software-update-configuration/main.json index 62ca53d37e8..f8d5f292354 100644 --- a/avm/res/automation/automation-account/software-update-configuration/main.json +++ b/avm/res/automation/automation-account/software-update-configuration/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "7586828544795723203" + "version": "0.26.170.59819", + "templateHash": "14866221548688198425" }, "name": "Automation Account Software Update Configurations", "description": "This module deploys an Azure Automation Account Software Update Configuration.", diff --git a/avm/res/automation/automation-account/variable/main.json b/avm/res/automation/automation-account/variable/main.json index a7d20d69f28..0bb8e16cda4 100644 --- a/avm/res/automation/automation-account/variable/main.json +++ b/avm/res/automation/automation-account/variable/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "1065450815403209329" + "version": "0.26.170.59819", + "templateHash": "12833257216729067514" }, "name": "Automation Account Variables", "description": "This module deploys an Azure Automation Account Variable.", diff --git a/avm/utilities/pipelines/staticValidation/psrule/.ps-rule/min-suppress.Rule.yaml b/avm/utilities/pipelines/staticValidation/psrule/.ps-rule/min-suppress.Rule.yaml index b15a2d0b3e3..3a57dca0603 100644 --- a/avm/utilities/pipelines/staticValidation/psrule/.ps-rule/min-suppress.Rule.yaml +++ b/avm/utilities/pipelines/staticValidation/psrule/.ps-rule/min-suppress.Rule.yaml @@ -15,6 +15,8 @@ spec: - Azure.Cognitive.ManagedIdentity # Automation specific - Azure.Automation.ManagedIdentity + - Azure.Automation.AuditLogs # Diagnostic Settings cannot be set by default, but require user input + - Azure.Automation.PlatformLogs # Diagnostic Settings cannot be set by default, but require user input # Key Vault specific - Azure.KeyVault.Logs - Azure.KeyVault.Firewall From 4e222b937a38d52ef80aa1c3774d09bf36b4a95d Mon Sep 17 00:00:00 2001 From: Rainer Halanek <61878316+rahalan@users.noreply.github.com> Date: Fri, 3 May 2024 18:59:51 +0200 Subject: [PATCH 15/52] feat: Update VMSS to default to flexible orchestration mode - `avm/res/compute/virtual-machine-scale-set` (#1819) - updated to newest API version - orchestration mode is now selectable - VMSS now defaults to flexible orchestration mode - additional parameters to rolling update policy added - Tests updated Successful run: [![avm.res.compute.virtual-machine-scale-set](https://github.com/rahalan/bicep-registry-modules/actions/workflows/avm.res.compute.virtual-machine-scale-set.yml/badge.svg?branch=users%2Frahalan%2FUpdateVMSS)](https://github.com/rahalan/bicep-registry-modules/actions/workflows/avm.res.compute.virtual-machine-scale-set.yml) --- .../virtual-machine-scale-set/README.md | 104 ++++++++++++++++-- .../extension/README.md | 2 +- .../extension/main.bicep | 4 +- .../extension/main.json | 4 +- .../virtual-machine-scale-set/main.bicep | 47 ++++++-- .../virtual-machine-scale-set/main.json | 94 +++++++++++----- .../tests/e2e/linux.defaults/main.test.bicep | 3 + .../tests/e2e/linux.max/main.test.bicep | 5 +- .../tests/e2e/linux.ssecmk/main.test.bicep | 3 + .../e2e/windows.defaults/main.test.bicep | 3 + .../tests/e2e/windows.max/main.test.bicep | 5 +- .../e2e/windows.waf-aligned/main.test.bicep | 5 +- .../virtual-machine-scale-set/version.json | 2 +- 13 files changed, 226 insertions(+), 55 deletions(-) diff --git a/avm/res/compute/virtual-machine-scale-set/README.md b/avm/res/compute/virtual-machine-scale-set/README.md index 96b8ddefeb9..bf45b23c523 100644 --- a/avm/res/compute/virtual-machine-scale-set/README.md +++ b/avm/res/compute/virtual-machine-scale-set/README.md @@ -17,8 +17,8 @@ This module deploys a Virtual Machine Scale Set. | :-- | :-- | | `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | | `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | -| `Microsoft.Compute/virtualMachineScaleSets` | [2022-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2022-11-01/virtualMachineScaleSets) | -| `Microsoft.Compute/virtualMachineScaleSets/extensions` | [2022-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2022-11-01/virtualMachineScaleSets/extensions) | +| `Microsoft.Compute/virtualMachineScaleSets` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2023-09-01/virtualMachineScaleSets) | +| `Microsoft.Compute/virtualMachineScaleSets/extensions` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2023-09-01/virtualMachineScaleSets/extensions) | | `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | ## Usage examples @@ -76,6 +76,9 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s { name: 'ipconfig1' properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsslinmin' + } subnet: { id: '' } @@ -151,6 +154,9 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s { "name": "ipconfig1", "properties": { + "publicIPAddressConfiguration": { + "name": "pip-cvmsslinmin" + }, "subnet": { "id": "" } @@ -286,7 +292,7 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s name: 'myCustomLockName' } managedIdentities: { - systemAssigned: true + systemAssigned: false userAssignedResourceIds: [ '' ] @@ -297,6 +303,9 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s { name: 'ipconfig1' properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsslinmax' + } subnet: { id: '' } @@ -481,7 +490,7 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s }, "managedIdentities": { "value": { - "systemAssigned": true, + "systemAssigned": false, "userAssignedResourceIds": [ "" ] @@ -494,6 +503,9 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s { "name": "ipconfig1", "properties": { + "publicIPAddressConfiguration": { + "name": "pip-cvmsslinmax" + }, "subnet": { "id": "" } @@ -609,6 +621,9 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s { name: 'ipconfig1' properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsslcmk' + } subnet: { id: '' } @@ -707,6 +722,9 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s { "name": "ipconfig1", "properties": { + "publicIPAddressConfiguration": { + "name": "pip-cvmsslcmk" + }, "subnet": { "id": "" } @@ -772,6 +790,9 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s { name: 'ipconfig1' properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsswinmin' + } subnet: { id: '' } @@ -841,6 +862,9 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s { "name": "ipconfig1", "properties": { + "publicIPAddressConfiguration": { + "name": "pip-cvmsswinmin" + }, "subnet": { "id": "" } @@ -967,7 +991,7 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s name: 'myCustomLockName' } managedIdentities: { - systemAssigned: true + systemAssigned: false userAssignedResourceIds: [ '' ] @@ -978,6 +1002,9 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s { name: 'ipconfig1' properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsswinmax' + } subnet: { id: '' } @@ -1152,7 +1179,7 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s }, "managedIdentities": { "value": { - "systemAssigned": true, + "systemAssigned": false, "userAssignedResourceIds": [ "" ] @@ -1165,6 +1192,9 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s { "name": "ipconfig1", "properties": { + "publicIPAddressConfiguration": { + "name": "pip-cvmsswinmax" + }, "subnet": { "id": "" } @@ -1315,7 +1345,7 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s } location: '' managedIdentities: { - systemAssigned: true + systemAssigned: false userAssignedResourceIds: [ '' ] @@ -1326,6 +1356,9 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s { name: 'ipconfig1' properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsswinwaf' + } subnet: { id: '' } @@ -1487,7 +1520,7 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s }, "managedIdentities": { "value": { - "systemAssigned": true, + "systemAssigned": false, "userAssignedResourceIds": [ "" ] @@ -1500,6 +1533,9 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s { "name": "ipconfig1", "properties": { + "publicIPAddressConfiguration": { + "name": "pip-cvmsswinwaf" + }, "subnet": { "id": "" } @@ -1569,6 +1605,7 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s | [`doNotRunExtensionsOnOverprovisionedVMs`](#parameter-donotrunextensionsonoverprovisionedvms) | bool | When Overprovision is enabled, extensions are launched only on the requested number of VMs which are finally kept. This property will hence ensure that the extensions do not run on the extra overprovisioned VMs. | | [`enableAutomaticOSUpgrade`](#parameter-enableautomaticosupgrade) | bool | Indicates whether OS upgrades should automatically be applied to scale set instances in a rolling fashion when a newer version of the OS image becomes available. Default value is false. If this is set to true for Windows based scale sets, enableAutomaticUpdates is automatically set to false and cannot be set to true. | | [`enableAutomaticUpdates`](#parameter-enableautomaticupdates) | bool | Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning. | +| [`enableCrossZoneUpgrade`](#parameter-enablecrosszoneupgrade) | bool | Allow VMSS to ignore AZ boundaries when constructing upgrade batches. Take into consideration the Update Domain and maxBatchInstancePercent to determine the batch size. | | [`enableEvictionPolicy`](#parameter-enableevictionpolicy) | bool | Specifies the eviction policy for the low priority virtual machine. Will result in 'Deallocate' eviction policy. | | [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | | [`encryptionAtHost`](#parameter-encryptionathost) | bool | This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your virtual machine scale sets. | @@ -1588,16 +1625,20 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s | [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | | [`maxBatchInstancePercent`](#parameter-maxbatchinstancepercent) | int | The maximum percent of total virtual machine instances that will be upgraded simultaneously by the rolling upgrade in one batch. As this is a maximum, unhealthy instances in previous or future batches can cause the percentage of instances in a batch to decrease to ensure higher reliability. | | [`maxPriceForLowPriorityVm`](#parameter-maxpriceforlowpriorityvm) | string | Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars. | +| [`maxSurge`](#parameter-maxsurge) | bool | Create new virtual machines to upgrade the scale set, rather than updating the existing virtual machines. Existing virtual machines will be deleted once the new virtual machines are created for each batch. | | [`maxUnhealthyInstancePercent`](#parameter-maxunhealthyinstancepercent) | int | The maximum percentage of the total virtual machine instances in the scale set that can be simultaneously unhealthy, either as a result of being upgraded, or by being found in an unhealthy state by the virtual machine health checks before the rolling upgrade aborts. This constraint will be checked prior to starting any batch. | | [`maxUnhealthyUpgradedInstancePercent`](#parameter-maxunhealthyupgradedinstancepercent) | int | The maximum percentage of the total virtual machine instances in the scale set that can be simultaneously unhealthy, either as a result of being upgraded, or by being found in an unhealthy state by the virtual machine health checks before the rolling upgrade aborts. This constraint will be checked prior to starting any batch. | | [`monitoringWorkspaceId`](#parameter-monitoringworkspaceid) | string | Resource ID of the monitoring log analytics workspace. | +| [`orchestrationMode`](#parameter-orchestrationmode) | string | Specifies the orchestration mode for the virtual machine scale set. | | [`overprovision`](#parameter-overprovision) | bool | Specifies whether the Virtual Machine Scale Set should be overprovisioned. | | [`pauseTimeBetweenBatches`](#parameter-pausetimebetweenbatches) | string | The wait time between completing the update for all virtual machines in one batch and starting the next batch. The time duration should be specified in ISO 8601 format. | | [`plan`](#parameter-plan) | object | Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use. | +| [`prioritizeUnhealthyInstances`](#parameter-prioritizeunhealthyinstances) | bool | Upgrade all unhealthy instances in a scale set before any healthy instances. | | [`provisionVMAgent`](#parameter-provisionvmagent) | bool | Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later. | | [`proximityPlacementGroupResourceId`](#parameter-proximityplacementgroupresourceid) | string | Resource ID of a proximity placement group. | | [`publicKeys`](#parameter-publickeys) | array | The list of SSH public keys used to authenticate with linux based VMs. | | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`rollbackFailedInstancesOnPolicyBreach`](#parameter-rollbackfailedinstancesonpolicybreach) | bool | Rollback failed instances to previous model if the Rolling Upgrade policy is violated. | | [`sasTokenValidityLength`](#parameter-sastokenvaliditylength) | string | SAS token validity length to use to download files from storage accounts. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours. | | [`scaleInPolicy`](#parameter-scaleinpolicy) | object | Specifies the scale-in policy that decides which virtual machines are chosen for removal when a Virtual Machine Scale Set is scaled-in. | | [`scaleSetFaultDomain`](#parameter-scalesetfaultdomain) | int | Fault Domain count for each placement group. | @@ -1900,6 +1941,14 @@ Indicates whether Automatic Updates is enabled for the Windows virtual machine. - Type: bool - Default: `True` +### Parameter: `enableCrossZoneUpgrade` + +Allow VMSS to ignore AZ boundaries when constructing upgrade batches. Take into consideration the Update Domain and maxBatchInstancePercent to determine the batch size. + +- Required: No +- Type: bool +- Default: `False` + ### Parameter: `enableEvictionPolicy` Specifies the eviction policy for the low priority virtual machine. Will result in 'Deallocate' eviction policy. @@ -2149,6 +2198,14 @@ Specifies the maximum price you are willing to pay for a low priority VM/VMSS. T - Type: string - Default: `''` +### Parameter: `maxSurge` + +Create new virtual machines to upgrade the scale set, rather than updating the existing virtual machines. Existing virtual machines will be deleted once the new virtual machines are created for each batch. + +- Required: No +- Type: bool +- Default: `False` + ### Parameter: `maxUnhealthyInstancePercent` The maximum percentage of the total virtual machine instances in the scale set that can be simultaneously unhealthy, either as a result of being upgraded, or by being found in an unhealthy state by the virtual machine health checks before the rolling upgrade aborts. This constraint will be checked prior to starting any batch. @@ -2173,6 +2230,21 @@ Resource ID of the monitoring log analytics workspace. - Type: string - Default: `''` +### Parameter: `orchestrationMode` + +Specifies the orchestration mode for the virtual machine scale set. + +- Required: No +- Type: string +- Default: `'Flexible'` +- Allowed: + ```Bicep + [ + 'Flexible' + 'Uniform' + ] + ``` + ### Parameter: `overprovision` Specifies whether the Virtual Machine Scale Set should be overprovisioned. @@ -2197,6 +2269,14 @@ Specifies information about the marketplace image used to create the virtual mac - Type: object - Default: `{}` +### Parameter: `prioritizeUnhealthyInstances` + +Upgrade all unhealthy instances in a scale set before any healthy instances. + +- Required: No +- Type: bool +- Default: `False` + ### Parameter: `provisionVMAgent` Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later. @@ -2310,6 +2390,14 @@ The principal type of the assigned principal ID. ] ``` +### Parameter: `rollbackFailedInstancesOnPolicyBreach` + +Rollback failed instances to previous model if the Rolling Upgrade policy is violated. + +- Required: No +- Type: bool +- Default: `False` + ### Parameter: `sasTokenValidityLength` SAS token validity length to use to download files from storage accounts. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours. diff --git a/avm/res/compute/virtual-machine-scale-set/extension/README.md b/avm/res/compute/virtual-machine-scale-set/extension/README.md index 11e4e8c5add..f8b36bff7fd 100644 --- a/avm/res/compute/virtual-machine-scale-set/extension/README.md +++ b/avm/res/compute/virtual-machine-scale-set/extension/README.md @@ -14,7 +14,7 @@ This module deploys a Virtual Machine Scale Set Extension. | Resource Type | API Version | | :-- | :-- | -| `Microsoft.Compute/virtualMachineScaleSets/extensions` | [2022-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2022-11-01/virtualMachineScaleSets/extensions) | +| `Microsoft.Compute/virtualMachineScaleSets/extensions` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2023-09-01/virtualMachineScaleSets/extensions) | ## Parameters diff --git a/avm/res/compute/virtual-machine-scale-set/extension/main.bicep b/avm/res/compute/virtual-machine-scale-set/extension/main.bicep index 5f5074d008b..c876201e516 100644 --- a/avm/res/compute/virtual-machine-scale-set/extension/main.bicep +++ b/avm/res/compute/virtual-machine-scale-set/extension/main.bicep @@ -36,11 +36,11 @@ param supressFailures bool = false @description('Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available.') param enableAutomaticUpgrade bool -resource virtualMachineScaleSet 'Microsoft.Compute/virtualMachineScaleSets@2022-11-01' existing = { +resource virtualMachineScaleSet 'Microsoft.Compute/virtualMachineScaleSets@2023-09-01' existing = { name: virtualMachineScaleSetName } -resource extension 'Microsoft.Compute/virtualMachineScaleSets/extensions@2022-11-01' = { +resource extension 'Microsoft.Compute/virtualMachineScaleSets/extensions@2023-09-01' = { name: name parent: virtualMachineScaleSet properties: { diff --git a/avm/res/compute/virtual-machine-scale-set/extension/main.json b/avm/res/compute/virtual-machine-scale-set/extension/main.json index 936509ea012..6edd526b76e 100644 --- a/avm/res/compute/virtual-machine-scale-set/extension/main.json +++ b/avm/res/compute/virtual-machine-scale-set/extension/main.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "8948100547542268397" + "templateHash": "1737879623418595926" }, "name": "Virtual Machine Scale Set Extensions", "description": "This module deploys a Virtual Machine Scale Set Extension.", @@ -86,7 +86,7 @@ "resources": [ { "type": "Microsoft.Compute/virtualMachineScaleSets/extensions", - "apiVersion": "2022-11-01", + "apiVersion": "2023-09-01", "name": "[format('{0}/{1}', parameters('virtualMachineScaleSetName'), parameters('name'))]", "properties": { "publisher": "[parameters('publisher')]", diff --git a/avm/res/compute/virtual-machine-scale-set/main.bicep b/avm/res/compute/virtual-machine-scale-set/main.bicep index 0d4fc210a6f..1a446e1aff3 100644 --- a/avm/res/compute/virtual-machine-scale-set/main.bicep +++ b/avm/res/compute/virtual-machine-scale-set/main.bicep @@ -148,6 +148,18 @@ param lock lockType ]) param upgradePolicyMode string = 'Manual' +@description('Optional. Allow VMSS to ignore AZ boundaries when constructing upgrade batches. Take into consideration the Update Domain and maxBatchInstancePercent to determine the batch size.') +param enableCrossZoneUpgrade bool = false + +@description('Optional. Create new virtual machines to upgrade the scale set, rather than updating the existing virtual machines. Existing virtual machines will be deleted once the new virtual machines are created for each batch.') +param maxSurge bool = false + +@description('Optional. Upgrade all unhealthy instances in a scale set before any healthy instances.') +param prioritizeUnhealthyInstances bool = false + +@description('Optional. Rollback failed instances to previous model if the Rolling Upgrade policy is violated.') +param rollbackFailedInstancesOnPolicyBreach bool = false + @description('Optional. The maximum percent of total virtual machine instances that will be upgraded simultaneously by the rolling upgrade in one batch. As this is a maximum, unhealthy instances in previous or future batches can cause the percentage of instances in a batch to decrease to ensure higher reliability.') param maxBatchInstancePercent int = 20 @@ -177,6 +189,13 @@ param gracePeriod string = 'PT30M' @maxLength(15) param vmNamePrefix string = 'vmssvm' +@description('Optional. Specifies the orchestration mode for the virtual machine scale set.') +@allowed([ + 'Flexible' + 'Uniform' +]) +param orchestrationMode string = 'Flexible' + @description('Optional. Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later.') param provisionVMAgent bool = true @@ -393,13 +412,14 @@ resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = } } -resource vmss 'Microsoft.Compute/virtualMachineScaleSets@2022-11-01' = { +resource vmss 'Microsoft.Compute/virtualMachineScaleSets@2023-09-01' = { name: name location: location tags: tags identity: identity zones: availabilityZones properties: { + orchestrationMode: orchestrationMode proximityPlacementGroup: !empty(proximityPlacementGroupResourceId) ? { id: proximityPlacementGroupResourceId @@ -407,12 +427,18 @@ resource vmss 'Microsoft.Compute/virtualMachineScaleSets@2022-11-01' = { : null upgradePolicy: { mode: upgradePolicyMode - rollingUpgradePolicy: { - maxBatchInstancePercent: maxBatchInstancePercent - maxUnhealthyInstancePercent: maxUnhealthyInstancePercent - maxUnhealthyUpgradedInstancePercent: maxUnhealthyUpgradedInstancePercent - pauseTimeBetweenBatches: pauseTimeBetweenBatches - } + rollingUpgradePolicy: upgradePolicyMode == 'Rolling' + ? { + enableCrossZoneUpgrade: enableCrossZoneUpgrade + maxBatchInstancePercent: maxBatchInstancePercent + maxSurge: maxSurge + maxUnhealthyInstancePercent: maxUnhealthyInstancePercent + maxUnhealthyUpgradedInstancePercent: maxUnhealthyUpgradedInstancePercent + pauseTimeBetweenBatches: pauseTimeBetweenBatches + prioritizeUnhealthyInstances: prioritizeUnhealthyInstances + rollbackFailedInstancesOnPolicyBreach: rollbackFailedInstancesOnPolicyBreach + } + : null automaticOSUpgradePolicy: { enableAutomaticOSUpgrade: enableAutomaticOSUpgrade disableAutomaticRollback: disableAutomaticRollback @@ -483,6 +509,7 @@ resource vmss 'Microsoft.Compute/virtualMachineScaleSets@2022-11-01' = { ] } networkProfile: { + networkApiVersion: (orchestrationMode == 'Flexible') ? '2020-11-01' : null networkInterfaceConfigurations: [ for (nicConfiguration, index) in nicConfigurations: { name: '${name}${nicConfiguration.nicSuffix}configuration-${index}' @@ -519,8 +546,10 @@ resource vmss 'Microsoft.Compute/virtualMachineScaleSets@2022-11-01' = { : null scheduledEventsProfile: scheduledEventsProfile } - overprovision: overprovision - doNotRunExtensionsOnOverprovisionedVMs: doNotRunExtensionsOnOverprovisionedVMs + overprovision: (orchestrationMode == 'Uniform') ? overprovision : null + doNotRunExtensionsOnOverprovisionedVMs: (orchestrationMode == 'Uniform') + ? doNotRunExtensionsOnOverprovisionedVMs + : null zoneBalance: zoneBalance == 'true' ? zoneBalance : null platformFaultDomainCount: scaleSetFaultDomain singlePlacementGroup: singlePlacementGroup diff --git a/avm/res/compute/virtual-machine-scale-set/main.json b/avm/res/compute/virtual-machine-scale-set/main.json index 518c5e8df85..c1ce67cf033 100644 --- a/avm/res/compute/virtual-machine-scale-set/main.json +++ b/avm/res/compute/virtual-machine-scale-set/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "15325819648954627762" + "templateHash": "9133361224761516270" }, "name": "Virtual Machine Scale Sets", "description": "This module deploys a Virtual Machine Scale Set.", @@ -500,6 +500,34 @@ "description": "Optional. Specifies the mode of an upgrade to virtual machines in the scale set.' Manual - You control the application of updates to virtual machines in the scale set. You do this by using the manualUpgrade action. ; Automatic - All virtual machines in the scale set are automatically updated at the same time. - Automatic, Manual, Rolling." } }, + "enableCrossZoneUpgrade": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Allow VMSS to ignore AZ boundaries when constructing upgrade batches. Take into consideration the Update Domain and maxBatchInstancePercent to determine the batch size." + } + }, + "maxSurge": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Create new virtual machines to upgrade the scale set, rather than updating the existing virtual machines. Existing virtual machines will be deleted once the new virtual machines are created for each batch." + } + }, + "prioritizeUnhealthyInstances": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Upgrade all unhealthy instances in a scale set before any healthy instances." + } + }, + "rollbackFailedInstancesOnPolicyBreach": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Rollback failed instances to previous model if the Rolling Upgrade policy is violated." + } + }, "maxBatchInstancePercent": { "type": "int", "defaultValue": 20, @@ -565,6 +593,17 @@ "description": "Optional. Specifies the computer name prefix for all of the virtual machines in the scale set." } }, + "orchestrationMode": { + "type": "string", + "defaultValue": "Flexible", + "allowedValues": [ + "Flexible", + "Uniform" + ], + "metadata": { + "description": "Optional. Specifies the orchestration mode for the virtual machine scale set." + } + }, "provisionVMAgent": { "type": "bool", "defaultValue": true, @@ -815,22 +854,18 @@ }, "vmss": { "type": "Microsoft.Compute/virtualMachineScaleSets", - "apiVersion": "2022-11-01", + "apiVersion": "2023-09-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", "identity": "[variables('identity')]", "zones": "[parameters('availabilityZones')]", "properties": { + "orchestrationMode": "[parameters('orchestrationMode')]", "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]", "upgradePolicy": { "mode": "[parameters('upgradePolicyMode')]", - "rollingUpgradePolicy": { - "maxBatchInstancePercent": "[parameters('maxBatchInstancePercent')]", - "maxUnhealthyInstancePercent": "[parameters('maxUnhealthyInstancePercent')]", - "maxUnhealthyUpgradedInstancePercent": "[parameters('maxUnhealthyUpgradedInstancePercent')]", - "pauseTimeBetweenBatches": "[parameters('pauseTimeBetweenBatches')]" - }, + "rollingUpgradePolicy": "[if(equals(parameters('upgradePolicyMode'), 'Rolling'), createObject('enableCrossZoneUpgrade', parameters('enableCrossZoneUpgrade'), 'maxBatchInstancePercent', parameters('maxBatchInstancePercent'), 'maxSurge', parameters('maxSurge'), 'maxUnhealthyInstancePercent', parameters('maxUnhealthyInstancePercent'), 'maxUnhealthyUpgradedInstancePercent', parameters('maxUnhealthyUpgradedInstancePercent'), 'pauseTimeBetweenBatches', parameters('pauseTimeBetweenBatches'), 'prioritizeUnhealthyInstances', parameters('prioritizeUnhealthyInstances'), 'rollbackFailedInstancesOnPolicyBreach', parameters('rollbackFailedInstancesOnPolicyBreach')), null())]", "automaticOSUpgradePolicy": { "enableAutomaticOSUpgrade": "[parameters('enableAutomaticOSUpgrade')]", "disableAutomaticRollback": "[parameters('disableAutomaticRollback')]" @@ -906,7 +941,8 @@ } } } - ] + ], + "networkApiVersion": "[if(equals(parameters('orchestrationMode'), 'Flexible'), '2020-11-01', null())]" }, "diagnosticsProfile": { "bootDiagnostics": { @@ -920,8 +956,8 @@ "billingProfile": "[if(and(not(empty(parameters('vmPriority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', parameters('maxPriceForLowPriorityVm')), null())]", "scheduledEventsProfile": "[parameters('scheduledEventsProfile')]" }, - "overprovision": "[parameters('overprovision')]", - "doNotRunExtensionsOnOverprovisionedVMs": "[parameters('doNotRunExtensionsOnOverprovisionedVMs')]", + "overprovision": "[if(equals(parameters('orchestrationMode'), 'Uniform'), parameters('overprovision'), null())]", + "doNotRunExtensionsOnOverprovisionedVMs": "[if(equals(parameters('orchestrationMode'), 'Uniform'), parameters('doNotRunExtensionsOnOverprovisionedVMs'), null())]", "zoneBalance": "[if(equals(parameters('zoneBalance'), 'true'), parameters('zoneBalance'), null())]", "platformFaultDomainCount": "[parameters('scaleSetFaultDomain')]", "singlePlacementGroup": "[parameters('singlePlacementGroup')]", @@ -1055,7 +1091,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "8948100547542268397" + "templateHash": "1737879623418595926" }, "name": "Virtual Machine Scale Set Extensions", "description": "This module deploys a Virtual Machine Scale Set Extension.", @@ -1136,7 +1172,7 @@ "resources": [ { "type": "Microsoft.Compute/virtualMachineScaleSets/extensions", - "apiVersion": "2022-11-01", + "apiVersion": "2023-09-01", "name": "[format('{0}/{1}', parameters('virtualMachineScaleSetName'), parameters('name'))]", "properties": { "publisher": "[parameters('publisher')]", @@ -1217,7 +1253,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "8948100547542268397" + "templateHash": "1737879623418595926" }, "name": "Virtual Machine Scale Set Extensions", "description": "This module deploys a Virtual Machine Scale Set Extension.", @@ -1298,7 +1334,7 @@ "resources": [ { "type": "Microsoft.Compute/virtualMachineScaleSets/extensions", - "apiVersion": "2022-11-01", + "apiVersion": "2023-09-01", "name": "[format('{0}/{1}', parameters('virtualMachineScaleSetName'), parameters('name'))]", "properties": { "publisher": "[parameters('publisher')]", @@ -1386,7 +1422,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "8948100547542268397" + "templateHash": "1737879623418595926" }, "name": "Virtual Machine Scale Set Extensions", "description": "This module deploys a Virtual Machine Scale Set Extension.", @@ -1467,7 +1503,7 @@ "resources": [ { "type": "Microsoft.Compute/virtualMachineScaleSets/extensions", - "apiVersion": "2022-11-01", + "apiVersion": "2023-09-01", "name": "[format('{0}/{1}', parameters('virtualMachineScaleSetName'), parameters('name'))]", "properties": { "publisher": "[parameters('publisher')]", @@ -1545,7 +1581,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "8948100547542268397" + "templateHash": "1737879623418595926" }, "name": "Virtual Machine Scale Set Extensions", "description": "This module deploys a Virtual Machine Scale Set Extension.", @@ -1626,7 +1662,7 @@ "resources": [ { "type": "Microsoft.Compute/virtualMachineScaleSets/extensions", - "apiVersion": "2022-11-01", + "apiVersion": "2023-09-01", "name": "[format('{0}/{1}', parameters('virtualMachineScaleSetName'), parameters('name'))]", "properties": { "publisher": "[parameters('publisher')]", @@ -1703,7 +1739,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "8948100547542268397" + "templateHash": "1737879623418595926" }, "name": "Virtual Machine Scale Set Extensions", "description": "This module deploys a Virtual Machine Scale Set Extension.", @@ -1784,7 +1820,7 @@ "resources": [ { "type": "Microsoft.Compute/virtualMachineScaleSets/extensions", - "apiVersion": "2022-11-01", + "apiVersion": "2023-09-01", "name": "[format('{0}/{1}', parameters('virtualMachineScaleSetName'), parameters('name'))]", "properties": { "publisher": "[parameters('publisher')]", @@ -1865,7 +1901,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "8948100547542268397" + "templateHash": "1737879623418595926" }, "name": "Virtual Machine Scale Set Extensions", "description": "This module deploys a Virtual Machine Scale Set Extension.", @@ -1946,7 +1982,7 @@ "resources": [ { "type": "Microsoft.Compute/virtualMachineScaleSets/extensions", - "apiVersion": "2022-11-01", + "apiVersion": "2023-09-01", "name": "[format('{0}/{1}', parameters('virtualMachineScaleSetName'), parameters('name'))]", "properties": { "publisher": "[parameters('publisher')]", @@ -2033,7 +2069,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "8948100547542268397" + "templateHash": "1737879623418595926" }, "name": "Virtual Machine Scale Set Extensions", "description": "This module deploys a Virtual Machine Scale Set Extension.", @@ -2114,7 +2150,7 @@ "resources": [ { "type": "Microsoft.Compute/virtualMachineScaleSets/extensions", - "apiVersion": "2022-11-01", + "apiVersion": "2023-09-01", "name": "[format('{0}/{1}', parameters('virtualMachineScaleSetName'), parameters('name'))]", "properties": { "publisher": "[parameters('publisher')]", @@ -2195,7 +2231,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "8948100547542268397" + "templateHash": "1737879623418595926" }, "name": "Virtual Machine Scale Set Extensions", "description": "This module deploys a Virtual Machine Scale Set Extension.", @@ -2276,7 +2312,7 @@ "resources": [ { "type": "Microsoft.Compute/virtualMachineScaleSets/extensions", - "apiVersion": "2022-11-01", + "apiVersion": "2023-09-01", "name": "[format('{0}/{1}', parameters('virtualMachineScaleSetName'), parameters('name'))]", "properties": { "publisher": "[parameters('publisher')]", @@ -2349,14 +2385,14 @@ "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[coalesce(tryGet(tryGet(reference('vmss', '2022-11-01', 'full'), 'identity'), 'principalId'), '')]" + "value": "[coalesce(tryGet(tryGet(reference('vmss', '2023-09-01', 'full'), 'identity'), 'principalId'), '')]" }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('vmss', '2022-11-01', 'full').location]" + "value": "[reference('vmss', '2023-09-01', 'full').location]" } } } \ No newline at end of file diff --git a/avm/res/compute/virtual-machine-scale-set/tests/e2e/linux.defaults/main.test.bicep b/avm/res/compute/virtual-machine-scale-set/tests/e2e/linux.defaults/main.test.bicep index f2bda654171..c762304bb7a 100644 --- a/avm/res/compute/virtual-machine-scale-set/tests/e2e/linux.defaults/main.test.bicep +++ b/avm/res/compute/virtual-machine-scale-set/tests/e2e/linux.defaults/main.test.bicep @@ -81,6 +81,9 @@ module testDeployment '../../../main.bicep' = [ subnet: { id: nestedDependencies.outputs.subnetResourceId } + publicIPAddressConfiguration: { + name: '${namePrefix}-pip-${serviceShort}' + } } } ] diff --git a/avm/res/compute/virtual-machine-scale-set/tests/e2e/linux.max/main.test.bicep b/avm/res/compute/virtual-machine-scale-set/tests/e2e/linux.max/main.test.bicep index 1794bd05719..75ece5bcafc 100644 --- a/avm/res/compute/virtual-machine-scale-set/tests/e2e/linux.max/main.test.bicep +++ b/avm/res/compute/virtual-machine-scale-set/tests/e2e/linux.max/main.test.bicep @@ -173,6 +173,9 @@ module testDeployment '../../../main.bicep' = [ subnet: { id: nestedDependencies.outputs.subnetResourceId } + publicIPAddressConfiguration: { + name: '${namePrefix}-pip-${serviceShort}' + } } } ] @@ -195,7 +198,7 @@ module testDeployment '../../../main.bicep' = [ scaleSetFaultDomain: 1 skuCapacity: 1 managedIdentities: { - systemAssigned: true + systemAssigned: false userAssignedResourceIds: [ nestedDependencies.outputs.managedIdentityResourceId ] diff --git a/avm/res/compute/virtual-machine-scale-set/tests/e2e/linux.ssecmk/main.test.bicep b/avm/res/compute/virtual-machine-scale-set/tests/e2e/linux.ssecmk/main.test.bicep index 035f41d15f9..01239114376 100644 --- a/avm/res/compute/virtual-machine-scale-set/tests/e2e/linux.ssecmk/main.test.bicep +++ b/avm/res/compute/virtual-machine-scale-set/tests/e2e/linux.ssecmk/main.test.bicep @@ -79,6 +79,9 @@ module testDeployment '../../../main.bicep' = [ subnet: { id: nestedDependencies.outputs.subnetResourceId } + publicIPAddressConfiguration: { + name: '${namePrefix}-pip-${serviceShort}' + } } } ] diff --git a/avm/res/compute/virtual-machine-scale-set/tests/e2e/windows.defaults/main.test.bicep b/avm/res/compute/virtual-machine-scale-set/tests/e2e/windows.defaults/main.test.bicep index 085ffb5828f..7ece80db050 100644 --- a/avm/res/compute/virtual-machine-scale-set/tests/e2e/windows.defaults/main.test.bicep +++ b/avm/res/compute/virtual-machine-scale-set/tests/e2e/windows.defaults/main.test.bicep @@ -82,6 +82,9 @@ module testDeployment '../../../main.bicep' = [ subnet: { id: nestedDependencies.outputs.subnetResourceId } + publicIPAddressConfiguration: { + name: '${namePrefix}-pip-${serviceShort}' + } } } ] diff --git a/avm/res/compute/virtual-machine-scale-set/tests/e2e/windows.max/main.test.bicep b/avm/res/compute/virtual-machine-scale-set/tests/e2e/windows.max/main.test.bicep index ecc12d03d8c..ae46d40a0cb 100644 --- a/avm/res/compute/virtual-machine-scale-set/tests/e2e/windows.max/main.test.bicep +++ b/avm/res/compute/virtual-machine-scale-set/tests/e2e/windows.max/main.test.bicep @@ -174,6 +174,9 @@ module testDeployment '../../../main.bicep' = [ subnet: { id: nestedDependencies.outputs.subnetResourceId } + publicIPAddressConfiguration: { + name: '${namePrefix}-pip-${serviceShort}' + } } } ] @@ -189,7 +192,7 @@ module testDeployment '../../../main.bicep' = [ ] skuCapacity: 1 managedIdentities: { - systemAssigned: true + systemAssigned: false userAssignedResourceIds: [ nestedDependencies.outputs.managedIdentityResourceId ] diff --git a/avm/res/compute/virtual-machine-scale-set/tests/e2e/windows.waf-aligned/main.test.bicep b/avm/res/compute/virtual-machine-scale-set/tests/e2e/windows.waf-aligned/main.test.bicep index 761f393356f..03744395301 100644 --- a/avm/res/compute/virtual-machine-scale-set/tests/e2e/windows.waf-aligned/main.test.bicep +++ b/avm/res/compute/virtual-machine-scale-set/tests/e2e/windows.waf-aligned/main.test.bicep @@ -170,6 +170,9 @@ module testDeployment '../../../main.bicep' = [ subnet: { id: nestedDependencies.outputs.subnetResourceId } + publicIPAddressConfiguration: { + name: '${namePrefix}-pip-${serviceShort}' + } } } ] @@ -178,7 +181,7 @@ module testDeployment '../../../main.bicep' = [ ] skuCapacity: 1 managedIdentities: { - systemAssigned: true + systemAssigned: false userAssignedResourceIds: [ nestedDependencies.outputs.managedIdentityResourceId ] diff --git a/avm/res/compute/virtual-machine-scale-set/version.json b/avm/res/compute/virtual-machine-scale-set/version.json index 83083db6945..1c035df49f2 100644 --- a/avm/res/compute/virtual-machine-scale-set/version.json +++ b/avm/res/compute/virtual-machine-scale-set/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.1", + "version": "0.2", "pathFilters": [ "./main.json" ] From 734b6d1434876e9c96e780797c5db3eb040a3a05 Mon Sep 17 00:00:00 2001 From: rodney-almeida <64196999+rodney-almeida@users.noreply.github.com> Date: Mon, 6 May 2024 08:53:48 +0100 Subject: [PATCH 16/52] fix: Set subnet batch size decorator (#1771) ## Description Rerunning the vnet module with multiple subnets over an existing vnet resource can at times cause a 'another operation is in progress' error. For this reason the batchSize decorator has been added for the subsequent subnet child module call to minimise this error. ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.network.virtual-network](https://github.com/rodney-almeida/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network.yml/badge.svg?branch=rodney-almeida%2F1519)](https://github.com/rodney-almeida/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network.yml) | ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting changes) - [x] Azure Verified Module updates: - [x] Bugfix containing backwards compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [x] 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. - [ ] 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`. - [x] 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 --------- Co-authored-by: Rodney Almeida Co-authored-by: ChrisSidebotham-MSFT <48600046+ChrisSidebotham@users.noreply.github.com> --- avm/res/network/virtual-network/main.bicep | 1 + avm/res/network/virtual-network/main.json | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/avm/res/network/virtual-network/main.bicep b/avm/res/network/virtual-network/main.bicep index 2d272099bc7..28c1db21ae2 100644 --- a/avm/res/network/virtual-network/main.bicep +++ b/avm/res/network/virtual-network/main.bicep @@ -167,6 +167,7 @@ resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { // You can safely remove the below child module (virtualNetwork_subnets) in your consumption of the module (virtualNetworks) to reduce the template size and duplication. //NOTE End : ------------------------------------ +@batchSize(1) module virtualNetwork_subnets 'subnet/main.bicep' = [ for (subnet, index) in subnets: { name: '${uniqueString(deployment().name, location)}-subnet-${index}' diff --git a/avm/res/network/virtual-network/main.json b/avm/res/network/virtual-network/main.json index e6058d75335..900b04583db 100644 --- a/avm/res/network/virtual-network/main.json +++ b/avm/res/network/virtual-network/main.json @@ -483,7 +483,9 @@ "virtualNetwork_subnets": { "copy": { "name": "virtualNetwork_subnets", - "count": "[length(parameters('subnets'))]" + "count": "[length(parameters('subnets'))]", + "mode": "serial", + "batchSize": 1 }, "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", From a787ece619e0d0ef3114eb9b6588402b6592e335 Mon Sep 17 00:00:00 2001 From: Christoph Vollmann Date: Mon, 6 May 2024 13:12:13 +0200 Subject: [PATCH 17/52] fix: CDN Profile - Parameter name for originGroups - `avm/res/cdn/profile` (#1742) ## Description Parameter `originGroup` had a typo (was named: `origionGroups`). Fixed module and tests and bumped version from 0.1 to 0.2 because the change is not backwards compatible. Fixes #1739 Closes #1739 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.cdn.profile](https://github.com/cloudchristoph/bicep-registry-modules/actions/workflows/avm.res.cdn.profile.yml/badge.svg?branch=1739_fix_cdn_parameter_origingroups)](https://github.com/cloudchristoph/bicep-registry-modules/actions/workflows/avm.res.cdn.profile.yml) | ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [x] 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. - [ ] 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`. - [x] 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 Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- avm/res/cdn/profile/README.md | 16 ++--- avm/res/cdn/profile/main.bicep | 6 +- avm/res/cdn/profile/main.json | 62 +++++++++---------- .../cdn/profile/tests/e2e/afd/main.test.bicep | 2 +- avm/res/cdn/profile/version.json | 4 +- 5 files changed, 45 insertions(+), 45 deletions(-) diff --git a/avm/res/cdn/profile/README.md b/avm/res/cdn/profile/README.md index 826e2450fee..e201ef9e08a 100644 --- a/avm/res/cdn/profile/README.md +++ b/avm/res/cdn/profile/README.md @@ -84,8 +84,7 @@ module profile 'br/public:avm/res/cdn/profile:' = { } ] location: 'global' - originResponseTimeoutSeconds: 60 - origionGroups: [ + originGroups: [ { loadBalancingSettings: { additionalLatencyInMilliseconds: 50 @@ -101,6 +100,7 @@ module profile 'br/public:avm/res/cdn/profile:' = { ] } ] + originResponseTimeoutSeconds: 60 ruleSets: [ { name: 'deptestcdnpafdruleset' @@ -179,10 +179,7 @@ module profile 'br/public:avm/res/cdn/profile:' = { "location": { "value": "global" }, - "originResponseTimeoutSeconds": { - "value": 60 - }, - "origionGroups": { + "originGroups": { "value": [ { "loadBalancingSettings": { @@ -200,6 +197,9 @@ module profile 'br/public:avm/res/cdn/profile:' = { } ] }, + "originResponseTimeoutSeconds": { + "value": 60 + }, "ruleSets": { "value": [ { @@ -580,7 +580,7 @@ module profile 'br/public:avm/res/cdn/profile:' = { | Parameter | Type | Description | | :-- | :-- | :-- | -| [`origionGroups`](#parameter-origiongroups) | array | Array of origin group objects. Required if the afdEndpoints is specified. | +| [`originGroups`](#parameter-origingroups) | array | Array of origin group objects. Required if the afdEndpoints is specified. | **Optional parameters** @@ -631,7 +631,7 @@ The pricing tier (defines a CDN provider, feature list and rate) of the CDN prof ] ``` -### Parameter: `origionGroups` +### Parameter: `originGroups` Array of origin group objects. Required if the afdEndpoints is specified. diff --git a/avm/res/cdn/profile/main.bicep b/avm/res/cdn/profile/main.bicep index 27d05ae8c14..90ae0b7a5c6 100644 --- a/avm/res/cdn/profile/main.bicep +++ b/avm/res/cdn/profile/main.bicep @@ -42,7 +42,7 @@ param secrets array = [] param customDomains array = [] @description('Conditional. Array of origin group objects. Required if the afdEndpoints is specified.') -param origionGroups array = [] +param originGroups array = [] @description('Optional. Array of rule set objects.') param ruleSets array = [] @@ -202,8 +202,8 @@ module profile_customDomains 'customdomain/main.bicep' = [ ] module profile_originGroups 'origingroup/main.bicep' = [ - for (origingroup, index) in origionGroups: { - name: '${uniqueString(deployment().name)}-Profile-OrigionGroup-${index}' + for (origingroup, index) in originGroups: { + name: '${uniqueString(deployment().name)}-Profile-OriginGroup-${index}' params: { name: origingroup.name profileName: profile.name diff --git a/avm/res/cdn/profile/main.json b/avm/res/cdn/profile/main.json index c0f0f30a682..5577657e810 100644 --- a/avm/res/cdn/profile/main.json +++ b/avm/res/cdn/profile/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "9474385640753599051" + "version": "0.26.170.59819", + "templateHash": "2222991004022934698" }, "name": "CDN Profiles", "description": "This module deploys a CDN Profile.", @@ -175,7 +175,7 @@ "description": "Optional. Array of custom domain objects." } }, - "origionGroups": { + "originGroups": { "type": "array", "defaultValue": [], "metadata": { @@ -337,8 +337,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "5516612458443504281" + "version": "0.26.170.59819", + "templateHash": "2906172435071993445" }, "name": "CDN Profiles Endpoints", "description": "This module deploys a CDN Profile Endpoint.", @@ -457,8 +457,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "11112660703037023992" + "version": "0.26.170.59819", + "templateHash": "3665403791951260301" }, "name": "CDN Profiles Endpoints Origins", "description": "This module deploys a CDN Profile Endpoint Origin.", @@ -703,8 +703,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "7298174434641608123" + "version": "0.26.170.59819", + "templateHash": "364931243138434002" }, "name": "CDN Profiles Secret", "description": "This module deploys a CDN Profile Secret.", @@ -852,8 +852,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "15657388199001378642" + "version": "0.26.170.59819", + "templateHash": "15721665305636481516" }, "name": "CDN Profiles Custom Domains", "description": "This module deploys a CDN Profile Custom Domains.", @@ -979,11 +979,11 @@ "profile_originGroups": { "copy": { "name": "profile_originGroups", - "count": "[length(parameters('origionGroups'))]" + "count": "[length(parameters('originGroups'))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-Profile-OrigionGroup-{1}', uniqueString(deployment().name), copyIndex())]", + "name": "[format('{0}-Profile-OriginGroup-{1}', uniqueString(deployment().name), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -991,25 +991,25 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[parameters('origionGroups')[copyIndex()].name]" + "value": "[parameters('originGroups')[copyIndex()].name]" }, "profileName": { "value": "[parameters('name')]" }, "loadBalancingSettings": { - "value": "[parameters('origionGroups')[copyIndex()].loadBalancingSettings]" + "value": "[parameters('originGroups')[copyIndex()].loadBalancingSettings]" }, "healthProbeSettings": { - "value": "[tryGet(parameters('origionGroups')[copyIndex()], 'healthProbeSettings')]" + "value": "[tryGet(parameters('originGroups')[copyIndex()], 'healthProbeSettings')]" }, "sessionAffinityState": { - "value": "[tryGet(parameters('origionGroups')[copyIndex()], 'sessionAffinityState')]" + "value": "[tryGet(parameters('originGroups')[copyIndex()], 'sessionAffinityState')]" }, "trafficRestorationTimeToHealedOrNewEndpointsInMinutes": { - "value": "[tryGet(parameters('origionGroups')[copyIndex()], 'trafficRestorationTimeToHealedOrNewEndpointsInMinutes')]" + "value": "[tryGet(parameters('originGroups')[copyIndex()], 'trafficRestorationTimeToHealedOrNewEndpointsInMinutes')]" }, "origins": { - "value": "[parameters('origionGroups')[copyIndex()].origins]" + "value": "[parameters('originGroups')[copyIndex()].origins]" } }, "template": { @@ -1019,8 +1019,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "8706007645911322422" + "version": "0.26.170.59819", + "templateHash": "12438540618132459307" }, "name": "CDN Profiles Origin Group", "description": "This module deploys a CDN Profile Origin Group.", @@ -1156,8 +1156,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "16657064743499074369" + "version": "0.26.170.59819", + "templateHash": "8566106020570825253" }, "name": "CDN Profiles Origin", "description": "This module deploys a CDN Profile Origin.", @@ -1382,8 +1382,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "1809010747275335698" + "version": "0.26.170.59819", + "templateHash": "5891069247146856543" }, "name": "CDN Profiles Rule Sets", "description": "This module deploys a CDN Profile rule set.", @@ -1468,8 +1468,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "8195283154733773558" + "version": "0.26.170.59819", + "templateHash": "4690708071413750601" }, "name": "CDN Profiles Rules", "description": "This module deploys a CDN Profile rule.", @@ -1656,8 +1656,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "8869132357079269087" + "version": "0.26.170.59819", + "templateHash": "3255198433705940781" }, "name": "CDN Profiles AFD Endpoints", "description": "This module deploys a CDN Profile AFD Endpoint.", @@ -1807,8 +1807,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "8525791914559803218" + "version": "0.26.170.59819", + "templateHash": "12469321322924109409" }, "name": "CDN Profiles AFD Endpoint Route", "description": "This module deploys a CDN Profile AFD Endpoint route.", diff --git a/avm/res/cdn/profile/tests/e2e/afd/main.test.bicep b/avm/res/cdn/profile/tests/e2e/afd/main.test.bicep index b559a41236f..66f834fa199 100644 --- a/avm/res/cdn/profile/tests/e2e/afd/main.test.bicep +++ b/avm/res/cdn/profile/tests/e2e/afd/main.test.bicep @@ -52,7 +52,7 @@ module testDeployment '../../../main.bicep' = [ certificateType: 'ManagedCertificate' } ] - origionGroups: [ + originGroups: [ { name: 'dep-${namePrefix}-test-${serviceShort}-origin-group' loadBalancingSettings: { diff --git a/avm/res/cdn/profile/version.json b/avm/res/cdn/profile/version.json index 83083db6945..9481fea58ee 100644 --- a/avm/res/cdn/profile/version.json +++ b/avm/res/cdn/profile/version.json @@ -1,7 +1,7 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.1", + "version": "0.2", "pathFilters": [ "./main.json" ] -} \ No newline at end of file +} From 72e59827b6f817f611dbb9fafea1762bb19eda47 Mon Sep 17 00:00:00 2001 From: Richard Hooper Date: Mon, 6 May 2024 12:23:58 +0100 Subject: [PATCH 18/52] feat: added option to enable image cleaner to container service aks. - `avm/res/container-service/managed-cluster` (#1697) ## Description This gives you user the option to enable image cleaner on an AKS cluster ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.container-service.managed-cluster](https://github.com/PixelRobots/bicep-registry-modules/actions/workflows/avm.res.container-service.managed-cluster.yml/badge.svg?branch=feat-rh-image-clean)](https://github.com/PixelRobots/bicep-registry-modules/actions/workflows/avm.res.container-service.managed-cluster.yml) | ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting changes) - [X] 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. - [ ] 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 --------- Signed-off-by: PixelRobots <22979170+PixelRobots@users.noreply.github.com> Co-authored-by: Ilhaan Rasheed Co-authored-by: Alexander Sehr --- .../managed-cluster/README.md | 18 +++++++++++++++++ .../managed-cluster/main.bicep | 13 ++++++++++++ .../managed-cluster/main.json | 20 +++++++++++++++++-- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/avm/res/container-service/managed-cluster/README.md b/avm/res/container-service/managed-cluster/README.md index 18b51cc75bb..2c6fc4b7623 100644 --- a/avm/res/container-service/managed-cluster/README.md +++ b/avm/res/container-service/managed-cluster/README.md @@ -1494,6 +1494,7 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster: Date: Mon, 6 May 2024 19:32:56 +0200 Subject: [PATCH 19/52] feat: Bing is not available - `avm/res/cognitive-services/account` (#1807) Bing is not available under Cognitive Services: `Get-AzCognitiveServicesAccountSku | select -ExpandProperty Kind -Unique | sort ` returns: AIServices AnomalyDetector CognitiveServices ComputerVision ContentModerator ContentSafety ConversationalLanguageUnderstanding CustomVision.Prediction CustomVision.Training Face FormRecognizer HealthInsights ImmersiveReader Internal.AllInOne LanguageAuthoring LUIS.Authoring MetricsAdvisor Personalizer QnAMaker.v2 SpeechServices TextAnalytics TextTranslation ## Description ## Pipeline Reference | Pipeline | | -------- | | | ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting 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. - [ ] 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 - [ ] I'm sure there are no other open Pull Requests for the same update/change - [ ] I have run `Set-AVMModule` locally to generate the supporting module files. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/res/cognitive-services/account/main.bicep | 5 ----- 1 file changed, 5 deletions(-) diff --git a/avm/res/cognitive-services/account/main.bicep b/avm/res/cognitive-services/account/main.bicep index 07ffb63489e..cefa63b906b 100644 --- a/avm/res/cognitive-services/account/main.bicep +++ b/avm/res/cognitive-services/account/main.bicep @@ -9,11 +9,6 @@ param name string @allowed([ 'AIServices' 'AnomalyDetector' - 'Bing.Autosuggest.v7' - 'Bing.CustomSearch' - 'Bing.EntitySearch' - 'Bing.Search.v7' - 'Bing.SpellCheck.v7' 'CognitiveServices' 'ComputerVision' 'ContentModerator' From 395bb1c83930bcdb764425fcf4480e7ff5c6a85c Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Mon, 6 May 2024 20:20:56 +0200 Subject: [PATCH 20/52] fix: Fixed typo in 'Publish from tag' workflow (#1853) ## Description - Fixed typo in 'Publish from tag' workflow. The workflow was referencing the wrong task to get the tag name. ## Type of Change - [x] Update to CI Environment or utlities (Non-module effecting 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. - [ ] 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 --- .github/workflows/platform.publish-tag.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/platform.publish-tag.yml b/.github/workflows/platform.publish-tag.yml index 1bde3c49502..cf5c8d2f38c 100644 --- a/.github/workflows/platform.publish-tag.yml +++ b/.github/workflows/platform.publish-tag.yml @@ -87,7 +87,7 @@ jobs: $functionInput = @{ Version = "${{ steps.publish_tag.outputs.version }}" PublishedModuleName = "${{ steps.publish_tag.outputs.publishedModuleName }}" - GitTagName = "${{ steps.publish_step.outputs.gitTagName }}" + GitTagName = "${{ steps.publish_tag.outputs.gitTagName }}" } From 33e60b2cb93ec3e8940082ce69f600dcadb06bd8 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Tue, 7 May 2024 00:27:36 +0200 Subject: [PATCH 21/52] feat: Removed enforcement of UDT schemas for pattern modules (#1832) ## Description Skipping UDT tests for Pattern modules Closes #1749 Example Resource (note the UDT schema tests) ![image](https://github.com/Azure/bicep-registry-modules/assets/5365358/62e914f8-0692-48af-8273-ff193538e03e) Example Pattern (note the lack of UDT schema tests) ![image](https://github.com/Azure/bicep-registry-modules/assets/5365358/190a0562-14d4-4209-8604-37d6dff76a35) ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.security.security-center](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.security.security-center.yml/badge.svg?branch=users%2Falsehr%2F1749_skipRoleTypePtn&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.security.security-center.yml) | | [![avm.res.aad.domain-service](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.aad.domain-service.yml/badge.svg?branch=users%2Falsehr%2F1749_skipRoleTypePtn&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.aad.domain-service.yml) | ## Type of Change - [x] Update to CI Environment or utlities (Non-module effecting 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. - [ ] 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 --- .../pipelines/staticValidation/compliance/module.tests.ps1 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index 938ec4556d4..e2df8ed6560 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -626,6 +626,11 @@ Describe 'Module tests' -Tag 'Module' { $udtSpecificTestCases = [System.Collections.ArrayList] @() # Specific UDT test cases for singular UDTs (e.g. tags) foreach ($moduleFolderPath in $moduleFolderPaths) { + if ($moduleFolderPath -match '[\/|\\]avm[\/|\\]ptn[\/|\\]') { + # Skip UDT interface tests for ptn modules + continue + } + $resourceTypeIdentifier = ($moduleFolderPath -split '[\/|\\]{1}avm[\/|\\]{1}(res|ptn)[\/|\\]{1}')[2] -replace '\\', '/' # 'avm/res|ptn//' would return '/' $templateFilePath = Join-Path $moduleFolderPath 'main.bicep' $templateFileContent = $builtTestFileMap[$templateFilePath] From b7b70a6ef9f8d0dda6540d41c947e6ead779693d Mon Sep 17 00:00:00 2001 From: Ilhaan Rasheed Date: Mon, 6 May 2024 15:40:01 -0700 Subject: [PATCH 22/52] fix: Update files after Set-AVMModule run - `avm/res/cognitive-services/account` (#1854) ## Description Updating ARM and readme files for cognitive services bicep module after https://github.com/Azure/bicep-registry-modules/pull/1807 was merged without running Set-AVMModule. ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.cognitive-services.account](https://github.com/ilhaan/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml/badge.svg?branch=cogservices-setavm-fix)](https://github.com/ilhaan/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml) | ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting changes) - [ ] Azure Verified Module updates: - [x] 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. - [ ] 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`. - [x] 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 Co-authored-by: Javier Cevallos --- avm/res/cognitive-services/account/README.md | 5 ----- avm/res/cognitive-services/account/main.json | 9 ++------- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/avm/res/cognitive-services/account/README.md b/avm/res/cognitive-services/account/README.md index e5804e0da1e..334da0443c6 100644 --- a/avm/res/cognitive-services/account/README.md +++ b/avm/res/cognitive-services/account/README.md @@ -944,11 +944,6 @@ Kind of the Cognitive Services. Use 'Get-AzCognitiveServicesAccountSku' to deter [ 'AIServices' 'AnomalyDetector' - 'Bing.Autosuggest.v7' - 'Bing.CustomSearch' - 'Bing.EntitySearch' - 'Bing.Search.v7' - 'Bing.SpellCheck.v7' 'CognitiveServices' 'ComputerVision' 'ContentModerator' diff --git a/avm/res/cognitive-services/account/main.json b/avm/res/cognitive-services/account/main.json index 7c1ff98ca59..8b8cbfdf282 100644 --- a/avm/res/cognitive-services/account/main.json +++ b/avm/res/cognitive-services/account/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "5668118199015896027" + "version": "0.26.54.24096", + "templateHash": "16646471610876147779" }, "name": "Cognitive Services", "description": "This module deploys a Cognitive Service.", @@ -560,11 +560,6 @@ "allowedValues": [ "AIServices", "AnomalyDetector", - "Bing.Autosuggest.v7", - "Bing.CustomSearch", - "Bing.EntitySearch", - "Bing.Search.v7", - "Bing.SpellCheck.v7", "CognitiveServices", "ComputerVision", "ContentModerator", From 3ec663b0ca118a49577cb498e86e18aab4cf3c5e Mon Sep 17 00:00:00 2001 From: Erika Gressi <56914614+eriqua@users.noreply.github.com> Date: Tue, 7 May 2024 07:51:25 +0200 Subject: [PATCH 23/52] fix: network watcher missing v2 formatting (#1855) ## Description Reformatting bicep template and test files to v2 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.network.network-watcher](https://github.com/eriqua/bicep-registry-modules/actions/workflows/avm.res.network.network-watcher.yml/badge.svg?branch=fix%2Fnw-v2-format)](https://github.com/eriqua/bicep-registry-modules/actions/workflows/avm.res.network.network-watcher.yml) | ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting changes) - [x] Azure Verified Module updates: - [x] 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. - [ ] 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 --- .../connection-monitor/main.bicep | 1 - .../connection-monitor/main.json | 4 +- .../network-watcher/flow-log/main.json | 4 +- avm/res/network/network-watcher/main.json | 12 +- .../tests/e2e/defaults/main.test.bicep | 16 +- .../tests/e2e/max/main.test.bicep | 193 +++++++++--------- .../tests/e2e/waf-aligned/main.test.bicep | 156 +++++++------- 7 files changed, 197 insertions(+), 189 deletions(-) diff --git a/avm/res/network/network-watcher/connection-monitor/main.bicep b/avm/res/network/network-watcher/connection-monitor/main.bicep index 0823dabe667..436ac52f4f9 100644 --- a/avm/res/network/network-watcher/connection-monitor/main.bicep +++ b/avm/res/network/network-watcher/connection-monitor/main.bicep @@ -26,7 +26,6 @@ param testGroups array = [] @description('Optional. Specify the Log Analytics Workspace Resource ID.') param workspaceResourceId string = '' - resource networkWatcher 'Microsoft.Network/networkWatchers@2023-04-01' existing = { name: networkWatcherName } diff --git a/avm/res/network/network-watcher/connection-monitor/main.json b/avm/res/network/network-watcher/connection-monitor/main.json index 6c3fd5c843b..3d9fe1be89f 100644 --- a/avm/res/network/network-watcher/connection-monitor/main.json +++ b/avm/res/network/network-watcher/connection-monitor/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "13403868700445795620" + "version": "0.26.170.59819", + "templateHash": "14911705346376844157" }, "name": "Network Watchers Connection Monitors", "description": "This module deploys a Network Watcher Connection Monitor.", diff --git a/avm/res/network/network-watcher/flow-log/main.json b/avm/res/network/network-watcher/flow-log/main.json index 13384804687..3727d61a852 100644 --- a/avm/res/network/network-watcher/flow-log/main.json +++ b/avm/res/network/network-watcher/flow-log/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "7721211688474892554" + "version": "0.26.170.59819", + "templateHash": "3648590963487326602" }, "name": "NSG Flow Logs", "description": "This module controls the Network Security Group Flow Logs and analytics settings.\n**Note: this module must be run on the Resource Group where Network Watcher is deployed**", diff --git a/avm/res/network/network-watcher/main.json b/avm/res/network/network-watcher/main.json index 1a74c3d9f4a..70dbb91a454 100644 --- a/avm/res/network/network-watcher/main.json +++ b/avm/res/network/network-watcher/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "4063023963915633324" + "version": "0.26.170.59819", + "templateHash": "9453655433534463092" }, "name": "Network Watchers", "description": "This module deploys a Network Watcher.", @@ -272,8 +272,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "13403868700445795620" + "version": "0.26.170.59819", + "templateHash": "14911705346376844157" }, "name": "Network Watchers Connection Monitors", "description": "This module deploys a Network Watcher Connection Monitor.", @@ -434,8 +434,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "7721211688474892554" + "version": "0.26.170.59819", + "templateHash": "3648590963487326602" }, "name": "NSG Flow Logs", "description": "This module controls the Network Security Group Flow Logs and analytics settings.\n**Note: this module must be run on the Resource Group where Network Watcher is deployed**", diff --git a/avm/res/network/network-watcher/tests/e2e/defaults/main.test.bicep b/avm/res/network/network-watcher/tests/e2e/defaults/main.test.bicep index 9fcca025ef5..9493a14f811 100644 --- a/avm/res/network/network-watcher/tests/e2e/defaults/main.test.bicep +++ b/avm/res/network/network-watcher/tests/e2e/defaults/main.test.bicep @@ -41,11 +41,13 @@ resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { // ============== // @batchSize(1) -module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { - scope: resourceGroup - name: '${uniqueString(deployment().name, tempLocation)}-test-${serviceShort}-${iteration}' - params: { - // Note: This value is not required and only set to enable testing - location: tempLocation +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, tempLocation)}-test-${serviceShort}-${iteration}' + params: { + // Note: This value is not required and only set to enable testing + location: tempLocation + } } -}] +] diff --git a/avm/res/network/network-watcher/tests/e2e/max/main.test.bicep b/avm/res/network/network-watcher/tests/e2e/max/main.test.bicep index 4386fe3d6ef..7cbe596947c 100644 --- a/avm/res/network/network-watcher/tests/e2e/max/main.test.bicep +++ b/avm/res/network/network-watcher/tests/e2e/max/main.test.bicep @@ -71,102 +71,107 @@ module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/t // Test Execution // // ============== // @batchSize(1) -module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { - scope: resourceGroup - name: '${uniqueString(deployment().name, tempLocation)}-test-${serviceShort}-${iteration}' - params: { - name: 'NetworkWatcher_${tempLocation}' - location: tempLocation - connectionMonitors: [ - { - name: '${namePrefix}-${serviceShort}-cm-001' - endpoints: [ - { - name: '${namePrefix}-subnet-001(${resourceGroup.name})' - resourceId: nestedDependencies.outputs.virtualMachineResourceId - type: 'AzureVM' - } - { - address: 'www.bing.com' - name: 'Bing' - type: 'ExternalAddress' - } - ] - testConfigurations: [ - { - httpConfiguration: { - method: 'Get' - port: 80 - preferHTTPS: false - requestHeaders: [] - validStatusCodeRanges: [ - '200' - ] +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, tempLocation)}-test-${serviceShort}-${iteration}' + params: { + name: 'NetworkWatcher_${tempLocation}' + location: tempLocation + connectionMonitors: [ + { + name: '${namePrefix}-${serviceShort}-cm-001' + endpoints: [ + { + name: '${namePrefix}-subnet-001(${resourceGroup.name})' + resourceId: nestedDependencies.outputs.virtualMachineResourceId + type: 'AzureVM' } - name: 'HTTP Bing Test' - protocol: 'Http' - successThreshold: { - checksFailedPercent: 5 - roundTripTimeMs: 100 + { + address: 'www.bing.com' + name: 'Bing' + type: 'ExternalAddress' } - testFrequencySec: 30 - } - ] - testGroups: [ - { - destinations: [ - 'Bing' - ] - disable: false - name: 'test-http-Bing' - sources: [ - '${namePrefix}-subnet-001(${resourceGroup.name})' - ] - testConfigurations: [ - 'HTTP Bing Test' - ] - } - ] - workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId - } - ] - flowLogs: [ - { - enabled: false - storageId: diagnosticDependencies.outputs.storageAccountResourceId - targetResourceId: nestedDependencies.outputs.firstNetworkSecurityGroupResourceId - } - { - formatVersion: 1 - name: '${namePrefix}-${serviceShort}-fl-001' - retentionInDays: 8 - storageId: diagnosticDependencies.outputs.storageAccountResourceId - targetResourceId: nestedDependencies.outputs.secondNetworkSecurityGroupResourceId - trafficAnalyticsInterval: 10 - workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId - } - ] - roleAssignments: [ - { - roleDefinitionIdOrName: 'Owner' - principalId: nestedDependencies.outputs.managedIdentityPrincipalId - principalType: 'ServicePrincipal' - } - { - roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' - principalId: nestedDependencies.outputs.managedIdentityPrincipalId - principalType: 'ServicePrincipal' - } - { - roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') - principalId: nestedDependencies.outputs.managedIdentityPrincipalId - principalType: 'ServicePrincipal' + ] + testConfigurations: [ + { + httpConfiguration: { + method: 'Get' + port: 80 + preferHTTPS: false + requestHeaders: [] + validStatusCodeRanges: [ + '200' + ] + } + name: 'HTTP Bing Test' + protocol: 'Http' + successThreshold: { + checksFailedPercent: 5 + roundTripTimeMs: 100 + } + testFrequencySec: 30 + } + ] + testGroups: [ + { + destinations: [ + 'Bing' + ] + disable: false + name: 'test-http-Bing' + sources: [ + '${namePrefix}-subnet-001(${resourceGroup.name})' + ] + testConfigurations: [ + 'HTTP Bing Test' + ] + } + ] + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + flowLogs: [ + { + enabled: false + storageId: diagnosticDependencies.outputs.storageAccountResourceId + targetResourceId: nestedDependencies.outputs.firstNetworkSecurityGroupResourceId + } + { + formatVersion: 1 + name: '${namePrefix}-${serviceShort}-fl-001' + retentionInDays: 8 + storageId: diagnosticDependencies.outputs.storageAccountResourceId + targetResourceId: nestedDependencies.outputs.secondNetworkSecurityGroupResourceId + trafficAnalyticsInterval: 10 + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' } - ] - tags: { - 'hidden-title': 'This is visible in the resource name' - Environment: 'Non-Prod' - Role: 'DeploymentValidation' } } -}] +] diff --git a/avm/res/network/network-watcher/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/network-watcher/tests/e2e/waf-aligned/main.test.bicep index 32fc7388400..bcc85b93c7d 100644 --- a/avm/res/network/network-watcher/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/network/network-watcher/tests/e2e/waf-aligned/main.test.bicep @@ -72,85 +72,87 @@ module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/t // ============== // @batchSize(1) -module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { - scope: resourceGroup - name: '${uniqueString(deployment().name, tempLocation)}-test-${serviceShort}-${iteration}' - params: { - name: 'NetworkWatcher_${tempLocation}' - location: tempLocation - connectionMonitors: [ - { - name: '${namePrefix}-${serviceShort}-cm-001' - endpoints: [ - { - name: '${namePrefix}-subnet-001(${resourceGroup.name})' - resourceId: nestedDependencies.outputs.virtualMachineResourceId - type: 'AzureVM' - } - { - address: 'www.bing.com' - name: 'Bing' - type: 'ExternalAddress' - } - ] - testConfigurations: [ - { - httpConfiguration: { - method: 'Get' - port: 80 - preferHTTPS: false - requestHeaders: [] - validStatusCodeRanges: [ - '200' - ] +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, tempLocation)}-test-${serviceShort}-${iteration}' + params: { + name: 'NetworkWatcher_${tempLocation}' + location: tempLocation + connectionMonitors: [ + { + name: '${namePrefix}-${serviceShort}-cm-001' + endpoints: [ + { + name: '${namePrefix}-subnet-001(${resourceGroup.name})' + resourceId: nestedDependencies.outputs.virtualMachineResourceId + type: 'AzureVM' } - name: 'HTTP Bing Test' - protocol: 'Http' - successThreshold: { - checksFailedPercent: 5 - roundTripTimeMs: 100 + { + address: 'www.bing.com' + name: 'Bing' + type: 'ExternalAddress' } - testFrequencySec: 30 - } - ] - testGroups: [ - { - destinations: [ - 'Bing' - ] - disable: false - name: 'test-http-Bing' - sources: [ - '${namePrefix}-subnet-001(${resourceGroup.name})' - ] - testConfigurations: [ - 'HTTP Bing Test' - ] - } - ] - workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId - } - ] - flowLogs: [ - { - enabled: false - storageId: diagnosticDependencies.outputs.storageAccountResourceId - targetResourceId: nestedDependencies.outputs.firstNetworkSecurityGroupResourceId - } - { - formatVersion: 1 - name: '${namePrefix}-${serviceShort}-fl-001' - retentionInDays: 8 - storageId: diagnosticDependencies.outputs.storageAccountResourceId - targetResourceId: nestedDependencies.outputs.secondNetworkSecurityGroupResourceId - trafficAnalyticsInterval: 10 - workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + ] + testConfigurations: [ + { + httpConfiguration: { + method: 'Get' + port: 80 + preferHTTPS: false + requestHeaders: [] + validStatusCodeRanges: [ + '200' + ] + } + name: 'HTTP Bing Test' + protocol: 'Http' + successThreshold: { + checksFailedPercent: 5 + roundTripTimeMs: 100 + } + testFrequencySec: 30 + } + ] + testGroups: [ + { + destinations: [ + 'Bing' + ] + disable: false + name: 'test-http-Bing' + sources: [ + '${namePrefix}-subnet-001(${resourceGroup.name})' + ] + testConfigurations: [ + 'HTTP Bing Test' + ] + } + ] + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + flowLogs: [ + { + enabled: false + storageId: diagnosticDependencies.outputs.storageAccountResourceId + targetResourceId: nestedDependencies.outputs.firstNetworkSecurityGroupResourceId + } + { + formatVersion: 1 + name: '${namePrefix}-${serviceShort}-fl-001' + retentionInDays: 8 + storageId: diagnosticDependencies.outputs.storageAccountResourceId + targetResourceId: nestedDependencies.outputs.secondNetworkSecurityGroupResourceId + trafficAnalyticsInterval: 10 + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' } - ] - tags: { - 'hidden-title': 'This is visible in the resource name' - Environment: 'Non-Prod' - Role: 'DeploymentValidation' } } -}] +] From 3c77b46c3ce434f7883c84eeb0012903977c0cbf Mon Sep 17 00:00:00 2001 From: Erika Gressi <56914614+eriqua@users.noreply.github.com> Date: Tue, 7 May 2024 07:52:18 +0200 Subject: [PATCH 24/52] fix: app managed environment missing v2 formatting (#1856) ## Description Reformatting app managed environment to v2 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.app.managed-environment](https://github.com/eriqua/bicep-registry-modules/actions/workflows/avm.res.app.managed-environment.yml/badge.svg?branch=fix%2Fappme-v2-format)](https://github.com/eriqua/bicep-registry-modules/actions/workflows/avm.res.app.managed-environment.yml) | ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting changes) - [x] Azure Verified Module updates: - [x] 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. - [ ] 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 --- avm/res/app/managed-environment/main.json | 4 +- .../tests/e2e/defaults/dependencies.bicep | 1 - .../tests/e2e/defaults/main.test.bicep | 50 ++++----- .../tests/e2e/max/dependencies.bicep | 1 - .../tests/e2e/max/main.test.bicep | 101 +++++++++--------- .../tests/e2e/waf-aligned/dependencies.bicep | 1 - .../tests/e2e/waf-aligned/main.test.bicep | 99 +++++++++-------- 7 files changed, 133 insertions(+), 124 deletions(-) diff --git a/avm/res/app/managed-environment/main.json b/avm/res/app/managed-environment/main.json index 005a9294d16..13537daa444 100644 --- a/avm/res/app/managed-environment/main.json +++ b/avm/res/app/managed-environment/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "1208664329573960589" + "version": "0.26.170.59819", + "templateHash": "17801833041272323788" }, "name": "App ManagedEnvironments", "description": "This module deploys an App Managed Environment (also known as a Container App Environment).", diff --git a/avm/res/app/managed-environment/tests/e2e/defaults/dependencies.bicep b/avm/res/app/managed-environment/tests/e2e/defaults/dependencies.bicep index c4ea8327c4f..88839d3b586 100644 --- a/avm/res/app/managed-environment/tests/e2e/defaults/dependencies.bicep +++ b/avm/res/app/managed-environment/tests/e2e/defaults/dependencies.bicep @@ -49,7 +49,6 @@ resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { } ] } - } @description('The resource ID of the created Virtual Network Subnet.') diff --git a/avm/res/app/managed-environment/tests/e2e/defaults/main.test.bicep b/avm/res/app/managed-environment/tests/e2e/defaults/main.test.bicep index 2e2152ec1af..754f5fcfd9a 100644 --- a/avm/res/app/managed-environment/tests/e2e/defaults/main.test.bicep +++ b/avm/res/app/managed-environment/tests/e2e/defaults/main.test.bicep @@ -45,29 +45,31 @@ module nestedDependencies 'dependencies.bicep' = { // ============== // @batchSize(1) -module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { - scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' - params: { - name: '${namePrefix}${serviceShort}001' - logAnalyticsWorkspaceResourceId: nestedDependencies.outputs.logAnalyticsWorkspaceResourceId - location: resourceLocation - workloadProfiles: [ - { - workloadProfileType: 'D4' - name: 'CAW01' - minimumCount: 0 - maximumCount: 3 - } +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + logAnalyticsWorkspaceResourceId: nestedDependencies.outputs.logAnalyticsWorkspaceResourceId + location: resourceLocation + workloadProfiles: [ + { + workloadProfileType: 'D4' + name: 'CAW01' + minimumCount: 0 + maximumCount: 3 + } + ] + internal: true + dockerBridgeCidr: '172.16.0.1/28' + platformReservedCidr: '172.17.17.0/24' + platformReservedDnsIP: '172.17.17.17' + infrastructureSubnetId: nestedDependencies.outputs.subnetResourceId + infrastructureResourceGroupName: 'me-${resourceGroupName}' + } + dependsOn: [ + nestedDependencies ] - internal: true - dockerBridgeCidr: '172.16.0.1/28' - platformReservedCidr: '172.17.17.0/24' - platformReservedDnsIP: '172.17.17.17' - infrastructureSubnetId: nestedDependencies.outputs.subnetResourceId - infrastructureResourceGroupName: 'me-${resourceGroupName}' } - dependsOn: [ - nestedDependencies - ] -}] +] diff --git a/avm/res/app/managed-environment/tests/e2e/max/dependencies.bicep b/avm/res/app/managed-environment/tests/e2e/max/dependencies.bicep index 1bf3d4e873a..ca9894d9dd4 100644 --- a/avm/res/app/managed-environment/tests/e2e/max/dependencies.bicep +++ b/avm/res/app/managed-environment/tests/e2e/max/dependencies.bicep @@ -52,7 +52,6 @@ resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { } ] } - } resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { diff --git a/avm/res/app/managed-environment/tests/e2e/max/main.test.bicep b/avm/res/app/managed-environment/tests/e2e/max/main.test.bicep index d296e436c9d..c48a95ec30d 100644 --- a/avm/res/app/managed-environment/tests/e2e/max/main.test.bicep +++ b/avm/res/app/managed-environment/tests/e2e/max/main.test.bicep @@ -46,55 +46,60 @@ module nestedDependencies 'dependencies.bicep' = { // ============== // @batchSize(1) -module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { - scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' - params: { - name: '${namePrefix}${serviceShort}001' - logAnalyticsWorkspaceResourceId: nestedDependencies.outputs.logAnalyticsWorkspaceResourceId - location: resourceLocation - workloadProfiles: [ - { - workloadProfileType: 'D4' - name: 'CAW01' - minimumCount: 0 - maximumCount: 3 - } - ] - internal: true - dockerBridgeCidr: '172.16.0.1/28' - platformReservedCidr: '172.17.17.0/24' - platformReservedDnsIP: '172.17.17.17' - infrastructureSubnetId: nestedDependencies.outputs.subnetResourceId - infrastructureResourceGroupName: 'me-${resourceGroupName}' - roleAssignments: [ - { - roleDefinitionIdOrName: 'Owner' - principalId: nestedDependencies.outputs.managedIdentityPrincipalId - principalType: 'ServicePrincipal' - } - { - roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' - principalId: nestedDependencies.outputs.managedIdentityPrincipalId - principalType: 'ServicePrincipal' +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + logAnalyticsWorkspaceResourceId: nestedDependencies.outputs.logAnalyticsWorkspaceResourceId + location: resourceLocation + workloadProfiles: [ + { + workloadProfileType: 'D4' + name: 'CAW01' + minimumCount: 0 + maximumCount: 3 + } + ] + internal: true + dockerBridgeCidr: '172.16.0.1/28' + platformReservedCidr: '172.17.17.0/24' + platformReservedDnsIP: '172.17.17.17' + infrastructureSubnetId: nestedDependencies.outputs.subnetResourceId + infrastructureResourceGroupName: 'me-${resourceGroupName}' + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' } - { - roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') - principalId: nestedDependencies.outputs.managedIdentityPrincipalId - principalType: 'ServicePrincipal' + tags: { + 'hidden-title': 'This is visible in the resource name' + Env: 'test' } - ] - - lock: { - kind: 'CanNotDelete' - name: 'myCustomLockName' - } - tags: { - 'hidden-title': 'This is visible in the resource name' - Env: 'test' } + dependsOn: [ + nestedDependencies + ] } - dependsOn: [ - nestedDependencies - ] -}] +] diff --git a/avm/res/app/managed-environment/tests/e2e/waf-aligned/dependencies.bicep b/avm/res/app/managed-environment/tests/e2e/waf-aligned/dependencies.bicep index 1bf3d4e873a..ca9894d9dd4 100644 --- a/avm/res/app/managed-environment/tests/e2e/waf-aligned/dependencies.bicep +++ b/avm/res/app/managed-environment/tests/e2e/waf-aligned/dependencies.bicep @@ -52,7 +52,6 @@ resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { } ] } - } resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { diff --git a/avm/res/app/managed-environment/tests/e2e/waf-aligned/main.test.bicep b/avm/res/app/managed-environment/tests/e2e/waf-aligned/main.test.bicep index 99134894ff8..5239a21e0f4 100644 --- a/avm/res/app/managed-environment/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/app/managed-environment/tests/e2e/waf-aligned/main.test.bicep @@ -46,54 +46,59 @@ module nestedDependencies 'dependencies.bicep' = { // ============== // @batchSize(1) -module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { - scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' - params: { - name: '${namePrefix}${serviceShort}001' - logAnalyticsWorkspaceResourceId: nestedDependencies.outputs.logAnalyticsWorkspaceResourceId - location: resourceLocation - workloadProfiles: [ - { - workloadProfileType: 'D4' - name: 'CAW01' - minimumCount: 0 - maximumCount: 3 - } - ] - internal: true - dockerBridgeCidr: '172.16.0.1/28' - platformReservedCidr: '172.17.17.0/24' - platformReservedDnsIP: '172.17.17.17' - infrastructureSubnetId: nestedDependencies.outputs.subnetResourceId - infrastructureResourceGroupName: 'me-${resourceGroupName}' - roleAssignments: [ - { - roleDefinitionIdOrName: 'Owner' - principalId: nestedDependencies.outputs.managedIdentityPrincipalId - principalType: 'ServicePrincipal' +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + logAnalyticsWorkspaceResourceId: nestedDependencies.outputs.logAnalyticsWorkspaceResourceId + location: resourceLocation + workloadProfiles: [ + { + workloadProfileType: 'D4' + name: 'CAW01' + minimumCount: 0 + maximumCount: 3 + } + ] + internal: true + dockerBridgeCidr: '172.16.0.1/28' + platformReservedCidr: '172.17.17.0/24' + platformReservedDnsIP: '172.17.17.17' + infrastructureSubnetId: nestedDependencies.outputs.subnetResourceId + infrastructureResourceGroupName: 'me-${resourceGroupName}' + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' } - { - roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' - principalId: nestedDependencies.outputs.managedIdentityPrincipalId - principalType: 'ServicePrincipal' + tags: { + 'hidden-title': 'This is visible in the resource name' + Env: 'test' } - { - roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') - principalId: nestedDependencies.outputs.managedIdentityPrincipalId - principalType: 'ServicePrincipal' - } - ] - lock: { - kind: 'CanNotDelete' - name: 'myCustomLockName' - } - tags: { - 'hidden-title': 'This is visible in the resource name' - Env: 'test' } + dependsOn: [ + nestedDependencies + ] } - dependsOn: [ - nestedDependencies - ] -}] +] From e3505a6b3c38faaae99bf5517b3eaea1f062ccba Mon Sep 17 00:00:00 2001 From: Rainer Halanek <61878316+rahalan@users.noreply.github.com> Date: Tue, 7 May 2024 11:38:09 +0200 Subject: [PATCH 25/52] feat: add requested features to VM module - `avm/res/compute/virtual-machine` (#1835) Fixes/Solves: - #1760 - #1779 - #1775 successful run (only NVidia fails because of MCAPS policy): [![avm.res.compute.virtual-machine](https://github.com/rahalan/bicep-registry-modules/actions/workflows/avm.res.compute.virtual-machine.yml/badge.svg?branch=users%2Frahalan%2FUpdateVM)](https://github.com/rahalan/bicep-registry-modules/actions/workflows/avm.res.compute.virtual-machine.yml) --------- Co-authored-by: Alexander Sehr --- avm/res/compute/virtual-machine/README.md | 136 ++++++++++++++++++ avm/res/compute/virtual-machine/main.bicep | 22 ++- avm/res/compute/virtual-machine/main.json | 111 ++++++++++---- .../modules/nic-configuration.bicep | 3 + .../tests/e2e/windows.vmss/dependencies.bicep | 101 +++++++++++++ .../tests/e2e/windows.vmss/main.test.bicep | 93 ++++++++++++ 6 files changed, 435 insertions(+), 31 deletions(-) create mode 100644 avm/res/compute/virtual-machine/tests/e2e/windows.vmss/dependencies.bicep create mode 100644 avm/res/compute/virtual-machine/tests/e2e/windows.vmss/main.test.bicep diff --git a/avm/res/compute/virtual-machine/README.md b/avm/res/compute/virtual-machine/README.md index 3db8d2fc603..066f7e0fc88 100644 --- a/avm/res/compute/virtual-machine/README.md +++ b/avm/res/compute/virtual-machine/README.md @@ -46,6 +46,7 @@ The following section provides usage examples for the module, which were used to - [Using large parameter set for Windows](#example-8-using-large-parameter-set-for-windows) - [Deploy a VM with nVidia graphic card](#example-9-deploy-a-vm-with-nvidia-graphic-card) - [Using disk encryption set for the VM.](#example-10-using-disk-encryption-set-for-the-vm) +- [Adding the VM to a VMSS.](#example-11-adding-the-vm-to-a-vmss) ### Example 1: _Using automanage for the VM._ @@ -2947,6 +2948,132 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

+### Example 11: _Adding the VM to a VMSS._ + +This instance deploys the module with the minimum set of required parameters and adds it to a VMSS. + + +

+ +via Bicep module + +```bicep +module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { + name: 'virtualMachineDeployment' + params: { + // Required parameters + adminUsername: 'localAdminUser' + imageReference: { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + name: 'cvmwinvmss' + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } + ] + osDisk: { + caching: 'ReadWrite' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Windows' + vmSize: 'Standard_DS2_v2' + zone: 0 + // Non-required parameters + adminPassword: '' + location: '' + virtualMachineScaleSetResourceId: '' + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "adminUsername": { + "value": "localAdminUser" + }, + "imageReference": { + "value": { + "offer": "WindowsServer", + "publisher": "MicrosoftWindowsServer", + "sku": "2022-datacenter-azure-edition", + "version": "latest" + } + }, + "name": { + "value": "cvmwinvmss" + }, + "nicConfigurations": { + "value": [ + { + "ipConfigurations": [ + { + "name": "ipconfig01", + "subnetResourceId": "" + } + ], + "nicSuffix": "-nic-01" + } + ] + }, + "osDisk": { + "value": { + "caching": "ReadWrite", + "diskSizeGB": 128, + "managedDisk": { + "storageAccountType": "Premium_LRS" + } + } + }, + "osType": { + "value": "Windows" + }, + "vmSize": { + "value": "Standard_DS2_v2" + }, + "zone": { + "value": 0 + }, + // Non-required parameters + "adminPassword": { + "value": "" + }, + "location": { + "value": "" + }, + "virtualMachineScaleSetResourceId": { + "value": "" + } + } +} +``` + +
+

+ ## Parameters @@ -3026,6 +3153,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`timeZone`](#parameter-timezone) | string | Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`. | | [`ultraSSDEnabled`](#parameter-ultrassdenabled) | bool | The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled. | +| [`virtualMachineScaleSetResourceId`](#parameter-virtualmachinescalesetresourceid) | string | Resource ID of a virtual machine scale set, where the VM should be added. | | [`vTpmEnabled`](#parameter-vtpmenabled) | bool | Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings. | | [`winRM`](#parameter-winrm) | array | Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell. - WinRMConfiguration object. | @@ -4057,6 +4185,14 @@ The flag that enables or disables a capability to have one or more managed data - Type: bool - Default: `False` +### Parameter: `virtualMachineScaleSetResourceId` + +Resource ID of a virtual machine scale set, where the VM should be added. + +- Required: No +- Type: string +- Default: `''` + ### Parameter: `vTpmEnabled` Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings. diff --git a/avm/res/compute/virtual-machine/main.bicep b/avm/res/compute/virtual-machine/main.bicep index e90df427a64..c9687a20b86 100644 --- a/avm/res/compute/virtual-machine/main.bicep +++ b/avm/res/compute/virtual-machine/main.bicep @@ -97,6 +97,9 @@ param bootDiagnosticStorageAccountUri string = '.blob.${environment().suffixes.s @description('Optional. Resource ID of a proximity placement group.') param proximityPlacementGroupResourceId string = '' +@description('Optional. Resource ID of a virtual machine scale set, where the VM should be added.') +param virtualMachineScaleSetResourceId string = '' + @description('Optional. Resource ID of an availability set. Cannot be used in combination with availability zone nor scale set.') param availabilitySetResourceId string = '' @@ -567,6 +570,11 @@ resource vm 'Microsoft.Compute/virtualMachines@2023-09-01' = { id: proximityPlacementGroupResourceId } : null + virtualMachineScaleSet: !empty(virtualMachineScaleSetResourceId) + ? { + id: virtualMachineScaleSetResourceId + } + : null priority: priority evictionPolicy: enableEvictionPolicy ? 'Deallocate' : null #disable-next-line BCP036 @@ -649,6 +657,7 @@ module vm_aadJoinExtension 'extension/main.bicep' = ? extensionAadJoinConfig.enableAutomaticUpgrade : false settings: contains(extensionAadJoinConfig, 'settings') ? extensionAadJoinConfig.settings : {} + supressFailures: extensionAadJoinConfig.?supressFailures ?? false tags: extensionAadJoinConfig.?tags ?? tags } } @@ -672,6 +681,7 @@ module vm_domainJoinExtension 'extension/main.bicep' = ? extensionDomainJoinConfig.enableAutomaticUpgrade : false settings: extensionDomainJoinConfig.settings + supressFailures: extensionDomainJoinConfig.?supressFailures ?? false tags: extensionDomainJoinConfig.?tags ?? tags protectedSettings: { Password: extensionDomainJoinPassword @@ -701,6 +711,7 @@ module vm_microsoftAntiMalwareExtension 'extension/main.bicep' = ? extensionAntiMalwareConfig.enableAutomaticUpgrade : false settings: extensionAntiMalwareConfig.settings + supressFailures: extensionAntiMalwareConfig.?supressFailures ?? false tags: extensionAntiMalwareConfig.?tags ?? tags } dependsOn: [ @@ -750,6 +761,7 @@ module vm_azureMonitorAgentExtension 'extension/main.bicep' = : '' GCS_AUTO_CONFIG: osType == 'Linux' ? true : null } + supressFailures: extensionMonitoringAgentConfig.?supressFailures ?? false tags: extensionMonitoringAgentConfig.?tags ?? tags protectedSettings: { workspaceKey: !empty(extensionMonitoringAgentConfig.?monitoringWorkspaceId ?? '') @@ -785,6 +797,7 @@ module vm_dependencyAgentExtension 'extension/main.bicep' = ? extensionDependencyAgentConfig.enableAMA : true } + supressFailures: extensionDependencyAgentConfig.?supressFailures ?? false tags: extensionDependencyAgentConfig.?tags ?? tags } dependsOn: [ @@ -810,6 +823,7 @@ module vm_networkWatcherAgentExtension 'extension/main.bicep' = enableAutomaticUpgrade: contains(extensionNetworkWatcherAgentConfig, 'enableAutomaticUpgrade') ? extensionNetworkWatcherAgentConfig.enableAutomaticUpgrade : false + supressFailures: extensionNetworkWatcherAgentConfig.?supressFailures ?? false tags: extensionNetworkWatcherAgentConfig.?tags ?? tags } dependsOn: [ @@ -836,6 +850,7 @@ module vm_desiredStateConfigurationExtension 'extension/main.bicep' = ? extensionDSCConfig.enableAutomaticUpgrade : false settings: contains(extensionDSCConfig, 'settings') ? extensionDSCConfig.settings : {} + supressFailures: extensionDSCConfig.?supressFailures ?? false tags: extensionDSCConfig.?tags ?? tags protectedSettings: contains(extensionDSCConfig, 'protectedSettings') ? extensionDSCConfig.protectedSettings : {} } @@ -869,6 +884,7 @@ module vm_customScriptExtension 'extension/main.bicep' = : fileData.uri ] } + supressFailures: extensionCustomScriptConfig.?supressFailures ?? false tags: extensionCustomScriptConfig.?tags ?? tags protectedSettings: extensionCustomScriptProtectedSetting } @@ -898,7 +914,8 @@ module vm_azureDiskEncryptionExtension 'extension/main.bicep' = forceUpdateTag: contains(extensionAzureDiskEncryptionConfig, 'forceUpdateTag') ? extensionAzureDiskEncryptionConfig.forceUpdateTag : '1.0' - settings: extensionAzureDiskEncryptionConfig.settings + settings: extensionAzureDiskEncryptionConfig.?settings ?? {} + supressFailures: extensionAzureDiskEncryptionConfig.?supressFailures ?? false tags: extensionAzureDiskEncryptionConfig.?tags ?? tags } dependsOn: [ @@ -924,6 +941,7 @@ module vm_nvidiaGpuDriverWindowsExtension 'extension/main.bicep' = enableAutomaticUpgrade: contains(extensionNvidiaGpuDriverWindows, 'enableAutomaticUpgrade') ? extensionNvidiaGpuDriverWindows.enableAutomaticUpgrade : false + supressFailures: extensionNvidiaGpuDriverWindows.?supressFailures ?? false tags: extensionNvidiaGpuDriverWindows.?tags ?? tags } dependsOn: [ @@ -957,6 +975,7 @@ module vm_hostPoolRegistrationExtension 'extension/main.bicep' = registrationInfoToken: extensionHostPoolRegistration.registrationInfoToken aadJoin: true } + supressFailures: extensionHostPoolRegistration.?supressFailures ?? false } tags: extensionHostPoolRegistration.?tags ?? tags } @@ -989,6 +1008,7 @@ module vm_azureGuestConfigurationExtension 'extension/main.bicep' = settings: contains(extensionGuestConfigurationExtension, 'settings') ? extensionGuestConfigurationExtension.settings : {} + supressFailures: extensionGuestConfigurationExtension.?supressFailures ?? false protectedSettings: extensionGuestConfigurationExtensionProtectedSettings tags: extensionGuestConfigurationExtension.?tags ?? tags } diff --git a/avm/res/compute/virtual-machine/main.json b/avm/res/compute/virtual-machine/main.json index f3c54b5b252..7a231c9d835 100644 --- a/avm/res/compute/virtual-machine/main.json +++ b/avm/res/compute/virtual-machine/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "8697354479542896000" + "templateHash": "16790973878425743878" }, "name": "Virtual Machines", "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs.", @@ -502,6 +502,13 @@ "description": "Optional. Resource ID of a proximity placement group." } }, + "virtualMachineScaleSetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of a virtual machine scale set, where the VM should be added." + } + }, "availabilitySetResourceId": { "type": "string", "defaultValue": "", @@ -1017,6 +1024,7 @@ }, "availabilitySet": "[if(not(empty(parameters('availabilitySetResourceId'))), createObject('id', parameters('availabilitySetResourceId')), null())]", "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]", + "virtualMachineScaleSet": "[if(not(empty(parameters('virtualMachineScaleSetResourceId'))), createObject('id', parameters('virtualMachineScaleSetResourceId')), null())]", "priority": "[parameters('priority')]", "evictionPolicy": "[if(parameters('enableEvictionPolicy'), 'Deallocate', null())]", "billingProfile": "[if(and(not(empty(parameters('priority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', json(parameters('maxPriceForLowPriorityVm'))), null())]", @@ -1172,7 +1180,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "1849400803354837318" + "templateHash": "15955967529014054327" } }, "definitions": { @@ -1483,6 +1491,15 @@ "lock": { "value": "[parameters('lock')]" }, + "idleTimeoutInMinutes": { + "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'idleTimeoutInMinutes')]" + }, + "ddosSettings": { + "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'ddosSettings')]" + }, + "dnsSettings": { + "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'dnsSettings')]" + }, "publicIPAddressVersion": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAddressVersion'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPAddressVersion), createObject('value', 'IPv4'))]", "publicIPAllocationMethod": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAllocationMethod'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPAllocationMethod), createObject('value', 'Static'))]", "publicIpPrefixResourceId": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPPrefixResourceId'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPPrefixResourceId), createObject('value', ''))]", @@ -2701,6 +2718,9 @@ "autoUpgradeMinorVersion": "[if(contains(parameters('extensionAadJoinConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionAadJoinConfig').autoUpgradeMinorVersion), createObject('value', true()))]", "enableAutomaticUpgrade": "[if(contains(parameters('extensionAadJoinConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionAadJoinConfig').enableAutomaticUpgrade), createObject('value', false()))]", "settings": "[if(contains(parameters('extensionAadJoinConfig'), 'settings'), createObject('value', parameters('extensionAadJoinConfig').settings), createObject('value', createObject()))]", + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'supressFailures'), false())]" + }, "tags": { "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'tags'), parameters('tags'))]" } @@ -2712,8 +2732,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "8063436714999902780" + "version": "0.26.54.24096", + "templateHash": "16251967456691023698" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -2902,6 +2922,9 @@ "settings": { "value": "[parameters('extensionDomainJoinConfig').settings]" }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'supressFailures'), false())]" + }, "tags": { "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'tags'), parameters('tags'))]" }, @@ -2918,8 +2941,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "8063436714999902780" + "version": "0.26.54.24096", + "templateHash": "16251967456691023698" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -3109,6 +3132,9 @@ "settings": { "value": "[parameters('extensionAntiMalwareConfig').settings]" }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'supressFailures'), false())]" + }, "tags": { "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'tags'), parameters('tags'))]" } @@ -3120,8 +3146,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "8063436714999902780" + "version": "0.26.54.24096", + "templateHash": "16251967456691023698" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -3318,6 +3344,9 @@ "GCS_AUTO_CONFIG": "[if(equals(parameters('osType'), 'Linux'), true(), null())]" } }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'supressFailures'), false())]" + }, "tags": { "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'tags'), parameters('tags'))]" }, @@ -3334,8 +3363,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "8063436714999902780" + "version": "0.26.54.24096", + "templateHash": "16251967456691023698" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -3526,6 +3555,9 @@ "enableAMA": "[if(contains(parameters('extensionDependencyAgentConfig'), 'enableAMA'), parameters('extensionDependencyAgentConfig').enableAMA, true())]" } }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'supressFailures'), false())]" + }, "tags": { "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'tags'), parameters('tags'))]" } @@ -3537,8 +3569,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "8063436714999902780" + "version": "0.26.54.24096", + "templateHash": "16251967456691023698" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -3723,6 +3755,9 @@ "typeHandlerVersion": "[if(contains(parameters('extensionNetworkWatcherAgentConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionNetworkWatcherAgentConfig').typeHandlerVersion), createObject('value', '1.4'))]", "autoUpgradeMinorVersion": "[if(contains(parameters('extensionNetworkWatcherAgentConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionNetworkWatcherAgentConfig').autoUpgradeMinorVersion), createObject('value', true()))]", "enableAutomaticUpgrade": "[if(contains(parameters('extensionNetworkWatcherAgentConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionNetworkWatcherAgentConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'supressFailures'), false())]" + }, "tags": { "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'tags'), parameters('tags'))]" } @@ -3734,8 +3769,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "8063436714999902780" + "version": "0.26.54.24096", + "templateHash": "16251967456691023698" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -3923,6 +3958,9 @@ "autoUpgradeMinorVersion": "[if(contains(parameters('extensionDSCConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionDSCConfig').autoUpgradeMinorVersion), createObject('value', true()))]", "enableAutomaticUpgrade": "[if(contains(parameters('extensionDSCConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionDSCConfig').enableAutomaticUpgrade), createObject('value', false()))]", "settings": "[if(contains(parameters('extensionDSCConfig'), 'settings'), createObject('value', parameters('extensionDSCConfig').settings), createObject('value', createObject()))]", + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'supressFailures'), false())]" + }, "tags": { "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'tags'), parameters('tags'))]" }, @@ -3935,8 +3973,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "8063436714999902780" + "version": "0.26.54.24096", + "templateHash": "16251967456691023698" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -4130,6 +4168,9 @@ ] } }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'supressFailures'), false())]" + }, "tags": { "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'tags'), parameters('tags'))]" }, @@ -4144,8 +4185,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "8063436714999902780" + "version": "0.26.54.24096", + "templateHash": "16251967456691023698" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -4332,7 +4373,10 @@ "enableAutomaticUpgrade": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').enableAutomaticUpgrade), createObject('value', false()))]", "forceUpdateTag": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'forceUpdateTag'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').forceUpdateTag), createObject('value', '1.0'))]", "settings": { - "value": "[parameters('extensionAzureDiskEncryptionConfig').settings]" + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'supressFailures'), false())]" }, "tags": { "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'tags'), parameters('tags'))]" @@ -4345,8 +4389,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "8063436714999902780" + "version": "0.26.54.24096", + "templateHash": "16251967456691023698" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -4533,6 +4577,9 @@ "typeHandlerVersion": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'typeHandlerVersion'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').typeHandlerVersion), createObject('value', '1.4'))]", "autoUpgradeMinorVersion": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').autoUpgradeMinorVersion), createObject('value', true()))]", "enableAutomaticUpgrade": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').enableAutomaticUpgrade), createObject('value', false()))]", + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'supressFailures'), false())]" + }, "tags": { "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'tags'), parameters('tags'))]" } @@ -4544,8 +4591,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "8063436714999902780" + "version": "0.26.54.24096", + "templateHash": "16251967456691023698" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -4740,7 +4787,8 @@ "hostPoolName": "[parameters('extensionHostPoolRegistration').hostPoolName]", "registrationInfoToken": "[parameters('extensionHostPoolRegistration').registrationInfoToken]", "aadJoin": true - } + }, + "supressFailures": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'supressFailures'), false())]" } }, "tags": { @@ -4754,8 +4802,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "8063436714999902780" + "version": "0.26.54.24096", + "templateHash": "16251967456691023698" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -4940,6 +4988,9 @@ "enableAutomaticUpgrade": "[if(contains(parameters('extensionGuestConfigurationExtension'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionGuestConfigurationExtension').enableAutomaticUpgrade), createObject('value', true()))]", "forceUpdateTag": "[if(contains(parameters('extensionGuestConfigurationExtension'), 'forceUpdateTag'), createObject('value', parameters('extensionGuestConfigurationExtension').forceUpdateTag), createObject('value', '1.0'))]", "settings": "[if(contains(parameters('extensionGuestConfigurationExtension'), 'settings'), createObject('value', parameters('extensionGuestConfigurationExtension').settings), createObject('value', createObject()))]", + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'supressFailures'), false())]" + }, "protectedSettings": { "value": "[parameters('extensionGuestConfigurationExtensionProtectedSettings')]" }, @@ -4954,8 +5005,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "8063436714999902780" + "version": "0.26.54.24096", + "templateHash": "16251967456691023698" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -5153,8 +5204,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "2393851439891433510" + "version": "0.26.54.24096", + "templateHash": "5385249890312845255" }, "name": "Recovery Service Vaults Protection Container Protected Item", "description": "This module deploys a Recovery Services Vault Protection Container Protected Item.", diff --git a/avm/res/compute/virtual-machine/modules/nic-configuration.bicep b/avm/res/compute/virtual-machine/modules/nic-configuration.bicep index 6720238a342..8cf385877db 100644 --- a/avm/res/compute/virtual-machine/modules/nic-configuration.bicep +++ b/avm/res/compute/virtual-machine/modules/nic-configuration.bicep @@ -35,6 +35,9 @@ module networkInterface_publicIPAddresses 'br/public:avm/res/network/public-ip-a diagnosticSettings: ipConfiguration.?diagnosticSettings location: location lock: lock + idleTimeoutInMinutes: ipConfiguration.pipConfiguration.?idleTimeoutInMinutes + ddosSettings: ipConfiguration.pipConfiguration.?ddosSettings + dnsSettings: ipConfiguration.pipConfiguration.?dnsSettings publicIPAddressVersion: contains(ipConfiguration.pipConfiguration, 'publicIPAddressVersion') ? ipConfiguration.pipConfiguration.publicIPAddressVersion : 'IPv4' diff --git a/avm/res/compute/virtual-machine/tests/e2e/windows.vmss/dependencies.bicep b/avm/res/compute/virtual-machine/tests/e2e/windows.vmss/dependencies.bicep new file mode 100644 index 00000000000..6c8fcca3f38 --- /dev/null +++ b/avm/res/compute/virtual-machine/tests/e2e/windows.vmss/dependencies.bicep @@ -0,0 +1,101 @@ +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Virtual Machine Scale Set to create.') +param vmssName string + +@description('Required. The name of the public IP address for the Virtual Machine Scale Set to create.') +param pipName string + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource vmss 'Microsoft.Compute/virtualMachineScaleSets@2023-09-01' = { + name: vmssName + location: location + sku: { + name: 'Standard_B12ms' + } + properties: { + orchestrationMode: 'Flexible' + platformFaultDomainCount: 1 + virtualMachineProfile: { + osProfile: { + adminUsername: 'localAdminUser' + adminPassword: password + computerNamePrefix: 'vmssvm' + } + storageProfile: { + osDisk: { + createOption: 'fromImage' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + osType: 'Windows' + } + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + } + networkProfile: { + networkApiVersion: '2020-11-01' + networkInterfaceConfigurations: [ + { + name: 'nicconfig1' + properties: { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + subnet: { + id: virtualNetwork.properties.subnets[0].id + } + publicIPAddressConfiguration: { + name: pipName + } + } + } + ] + } + } + ] + } + } + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Virtual Machine Scale Set.') +output vmssResourceId string = vmss.id diff --git a/avm/res/compute/virtual-machine/tests/e2e/windows.vmss/main.test.bicep b/avm/res/compute/virtual-machine/tests/e2e/windows.vmss/main.test.bicep new file mode 100644 index 00000000000..55485d9edea --- /dev/null +++ b/avm/res/compute/virtual-machine/tests/e2e/windows.vmss/main.test.bicep @@ -0,0 +1,93 @@ +targetScope = 'subscription' + +metadata name = 'Adding the VM to a VMSS.' +metadata description = 'This instance deploys the module with the minimum set of required parameters and adds it to a VMSS.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cvmwinvmss' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + vmssName: 'dep-${namePrefix}-vmss-${serviceShort}' + pipName: 'dep-${namePrefix}-pip-${serviceShort}' + password: password + } +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}' + adminUsername: 'localAdminUser' + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + zone: 0 + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + } + ] + nicSuffix: '-nic-01' + } + ] + osDisk: { + diskSizeGB: 128 + caching: 'ReadWrite' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Windows' + vmSize: 'Standard_DS2_v2' + adminPassword: password + virtualMachineScaleSetResourceId: nestedDependencies.outputs.vmssResourceId + } + } +] From fa3bf6d344965945fcd35cc18dcfec2ca97d8481 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Tue, 7 May 2024 19:34:02 +0200 Subject: [PATCH 26/52] fix: Added missing context switching to deployment target resolution (#1871) ## Description Added missing context switching to deployment target resolution This is important if e.g. resources are deployed into a new subscription which, by default, cannot be the context at the time the pipeline starts runnning. Important to LZ-Accelerator. ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.key-vault.vault](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml/badge.svg?branch=users%2Falsehr%2FdeploymentNameResolutino&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml) | ## Type of Change - [x] Update to CI Environment or utlities (Non-module effecting 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. - [ ] 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 --- .../Get-DeploymentTargetResourceList.ps1 | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Get-DeploymentTargetResourceList.ps1 b/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Get-DeploymentTargetResourceList.ps1 index 42f521b9ce0..5e87380e797 100644 --- a/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Get-DeploymentTargetResourceList.ps1 +++ b/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Get-DeploymentTargetResourceList.ps1 @@ -58,6 +58,7 @@ function Get-DeploymentTargetResourceListInner { ) $resultSet = [System.Collections.ArrayList]@() + $currentContext = Get-AzContext ############################################## # Get all deployment children based on scope # @@ -65,24 +66,24 @@ function Get-DeploymentTargetResourceListInner { switch ($Scope) { 'resourcegroup' { if (Get-AzResourceGroup -Name $resourceGroupName -ErrorAction 'SilentlyContinue') { - [array]$deploymentTargets = (Get-AzResourceGroupDeploymentOperation -DeploymentName $name -ResourceGroupName $resourceGroupName).TargetResource | Where-Object { $_ -ne $null } + [array]$deploymentTargets = (Get-AzResourceGroupDeploymentOperation -DeploymentName $name -ResourceGroupName $resourceGroupName).TargetResource | Where-Object { $_ -ne $null } | Select-Object -Unique } else { # In case the resource group itself was already deleted, there is no need to try and fetch deployments from it # In case we already have any such resources in the list, we should remove them - [array]$resultSet = $resultSet | Where-Object { $_ -notmatch "/resourceGroups/$resourceGroupName/" } + [array]$resultSet = $resultSet | Where-Object { $_ -notmatch "\/resourceGroups\/$resourceGroupName\/" } } break } 'subscription' { - [array]$deploymentTargets = (Get-AzDeploymentOperation -DeploymentName $name).TargetResource | Where-Object { $_ -ne $null } + [array]$deploymentTargets = (Get-AzDeploymentOperation -DeploymentName $name).TargetResource | Where-Object { $_ -ne $null } | Select-Object -Unique break } 'managementgroup' { - [array]$deploymentTargets = (Get-AzManagementGroupDeploymentOperation -DeploymentName $name -ManagementGroupId $ManagementGroupId).TargetResource | Where-Object { $_ -ne $null } + [array]$deploymentTargets = (Get-AzManagementGroupDeploymentOperation -DeploymentName $name -ManagementGroupId $ManagementGroupId).TargetResource | Where-Object { $_ -ne $null } | Select-Object -Unique break } 'tenant' { - [array]$deploymentTargets = (Get-AzTenantDeploymentOperation -DeploymentName $name).TargetResource | Where-Object { $_ -ne $null } + [array]$deploymentTargets = (Get-AzTenantDeploymentOperation -DeploymentName $name).TargetResource | Where-Object { $_ -ne $null } | Select-Object -Unique break } } @@ -90,7 +91,7 @@ function Get-DeploymentTargetResourceListInner { ########################### # Manage nested resources # ########################### - foreach ($deployment in ($deploymentTargets | Where-Object { $_ -notmatch '/deployments/' } )) { + foreach ($deployment in ($deploymentTargets | Where-Object { $_ -notmatch '\/deployments\/' } )) { Write-Verbose ('Found deployed resource [{0}]' -f $deployment) [array]$resultSet += $deployment } @@ -98,17 +99,29 @@ function Get-DeploymentTargetResourceListInner { ############################# # Manage nested deployments # ############################# - foreach ($deployment in ($deploymentTargets | Where-Object { $_ -match '/deployments/' } )) { + foreach ($deployment in ($deploymentTargets | Where-Object { $_ -match '\/deployments\/' } )) { $name = Split-Path $deployment -Leaf if ($deployment -match '/resourceGroups/') { # Resource Group Level Child Deployments # ########################################## + if ($deployment -match '^\/subscriptions\/([0-9a-zA-Z-]+?)\/') { + $subscriptionId = $Matches[1] + if ($currentContext.Subscription.Id -ne $subscriptionId) { + $null = Set-AzContext -Subscription $subscriptionId + } + } Write-Verbose ('Found [resource group] deployment [{0}]' -f $deployment) $resourceGroupName = $deployment.split('/resourceGroups/')[1].Split('/')[0] [array]$resultSet += Get-DeploymentTargetResourceListInner -Name $name -Scope 'resourcegroup' -ResourceGroupName $ResourceGroupName } elseif ($deployment -match '/subscriptions/') { # Subscription Level Child Deployments # ######################################## + if ($deployment -match '^\/subscriptions\/([0-9a-zA-Z-]+?)\/') { + $subscriptionId = $Matches[1] + if ($currentContext.Subscription.Id -ne $subscriptionId) { + $null = Set-AzContext -Subscription $subscriptionId + } + } Write-Verbose ('Found [subscription] deployment [{0}]' -f $deployment) [array]$resultSet += Get-DeploymentTargetResourceListInner -Name $name -Scope 'subscription' } elseif ($deployment -match '/managementgroups/') { @@ -124,7 +137,7 @@ function Get-DeploymentTargetResourceListInner { } } - return $resultSet + return $resultSet | Select-Object -Unique } #endregion From 47b4880e834075ab2f3fd5a98ff09503f27b2aab Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Wed, 8 May 2024 12:59:27 +0200 Subject: [PATCH 27/52] feat: Implemented logic to make `resourceLocation` optional in CI (#1883) ## Description - Implemented logic to make `resourceLocation` optional in CI - Remove all `resourceLocation` parameters where optional (because it was enforced) - Aligned `enforcedLocation` name ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.compute.virtual-machine](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.virtual-machine.yml/badge.svg?branch=users%2Falsehr%2FoptionalLocation&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.virtual-machine.yml) | | [![avm.res.document-db.database-account](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.document-db.database-account.yml/badge.svg?branch=users%2Falsehr%2FoptionalLocation&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.document-db.database-account.yml) | | [![avm.res.network.network-watcher](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.network-watcher.yml/badge.svg?branch=users%2Falsehr%2FoptionalLocation&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.network-watcher.yml) | | [![avm.res.sql.instance-pool](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.sql.instance-pool.yml/badge.svg?branch=users%2Falsehr%2FoptionalLocation&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.sql.instance-pool.yml) | | [![avm.res.web.serverfarm](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.web.serverfarm.yml/badge.svg?branch=users%2Falsehr%2FoptionalLocation&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.web.serverfarm.yml) (unrelated) | ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting 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. - [ ] 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 - [ ] I'm sure there are no other open Pull Requests for the same update/change - [ ] I have run `Set-AVMModule` locally to generate the supporting module files. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings --- .../avm-validateModuleDeployment/action.yml | 12 +++++++-- avm/res/compute/virtual-machine/README.md | 2 +- .../tests/e2e/windows.nvidia/main.test.bicep | 15 +++++------ .../tests/e2e/analytical/main.test.bicep | 4 +-- .../e2e/boundedConsistency/main.test.bicep | 4 +-- .../tests/e2e/defaults/main.test.bicep | 4 +-- .../tests/e2e/gremlindb/main.test.bicep | 4 +-- .../tests/e2e/kvSecrets/main.test.bicep | 4 +-- .../tests/e2e/managedIdentity/main.test.bicep | 4 +-- .../tests/e2e/mongodb/main.test.bicep | 4 +-- .../tests/e2e/multiRegion/main.test.bicep | 4 +-- .../tests/e2e/plain/main.test.bicep | 4 +-- .../publicRestrictedAccess/main.test.bicep | 4 +-- .../tests/e2e/sqldb/main.test.bicep | 4 +-- .../tests/e2e/waf-aligned/main.test.bicep | 4 +-- .../tests/e2e/defaults/main.test.bicep | 17 +++++------- .../tests/e2e/max/main.test.bicep | 27 +++++++++---------- .../tests/e2e/waf-aligned/main.test.bicep | 27 +++++++++---------- .../tests/e2e/defaults/main.test.bicep | 20 ++++++-------- .../tests/e2e/waf-aligned/main.test.bicep | 20 ++++++-------- .../tests/e2e/defaults/main.test.bicep | 11 +++----- .../serverfarm/tests/e2e/max/main.test.bicep | 19 ++++++------- .../tests/e2e/waf-aligned/main.test.bicep | 15 +++++------ 23 files changed, 94 insertions(+), 139 deletions(-) diff --git a/.github/actions/templates/avm-validateModuleDeployment/action.yml b/.github/actions/templates/avm-validateModuleDeployment/action.yml index e9c2ed3d878..b6e1145f7d9 100644 --- a/.github/actions/templates/avm-validateModuleDeployment/action.yml +++ b/.github/actions/templates/avm-validateModuleDeployment/action.yml @@ -205,7 +205,11 @@ runs: SubscriptionId = $subscriptionId ManagementGroupId = $managementGroupId RepoRoot = $env:GITHUB_WORKSPACE - AdditionalParameters = @{ + AdditionalParameters = @{} + } + + if($moduleTemplatePossibleParameters -contains 'resourceLocation') { + $functionInput.AdditionalParameters += @{ resourceLocation = '${{ steps.get-resource-location.outputs.resourceLocation }}' } } @@ -257,7 +261,11 @@ runs: ManagementGroupId = $managementGroupId DoNotThrow = $true RepoRoot = $env:GITHUB_WORKSPACE - AdditionalParameters = @{ + AdditionalParameters = @{} + } + + if($moduleTemplatePossibleParameters -contains 'resourceLocation') { + $functionInput.AdditionalParameters += @{ resourceLocation = '${{ steps.get-resource-location.outputs.resourceLocation }}' } } diff --git a/avm/res/compute/virtual-machine/README.md b/avm/res/compute/virtual-machine/README.md index 066f7e0fc88..28d05dbcb0a 100644 --- a/avm/res/compute/virtual-machine/README.md +++ b/avm/res/compute/virtual-machine/README.md @@ -25,7 +25,7 @@ This module deploys a Virtual Machine with one or multiple NICs and optionally o | `Microsoft.GuestConfiguration/guestConfigurationAssignments` | [2020-06-25](https://learn.microsoft.com/en-us/azure/templates/Microsoft.GuestConfiguration/2020-06-25/guestConfigurationAssignments) | | `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | | `Microsoft.Network/networkInterfaces` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/networkInterfaces) | -| `Microsoft.Network/publicIPAddresses` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/publicIPAddresses) | +| `Microsoft.Network/publicIPAddresses` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-09-01/publicIPAddresses) | | `Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems` | [2023-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.RecoveryServices/2023-01-01/vaults/backupFabrics/protectionContainers/protectedItems) | ## Usage examples diff --git a/avm/res/compute/virtual-machine/tests/e2e/windows.nvidia/main.test.bicep b/avm/res/compute/virtual-machine/tests/e2e/windows.nvidia/main.test.bicep index 271127387ba..035c2446eda 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/windows.nvidia/main.test.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/windows.nvidia/main.test.bicep @@ -11,9 +11,6 @@ metadata description = 'This instance deploys the module for a VM with dedicated @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = 'eastus' - @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') param serviceShort string = 'cvmwinnv' @@ -25,7 +22,7 @@ param password string = newGuid() param namePrefix string = '#_namePrefix_#' #disable-next-line no-hardcoded-location // Due to quotas and capacity challenges, this region must be used in the AVM testing subscription -var tempLocation = 'eastus' +var enforcedLocation = 'eastus' // ============ // // Dependencies // @@ -35,14 +32,14 @@ var tempLocation = 'eastus' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, tempLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { - location: tempLocation + location: enforcedLocation virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' } } @@ -54,9 +51,9 @@ module nestedDependencies 'dependencies.bicep' = { module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, tempLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { - location: tempLocation + location: enforcedLocation name: '${namePrefix}${serviceShort}' adminUsername: 'localAdminUser' imageReference: { diff --git a/avm/res/document-db/database-account/tests/e2e/analytical/main.test.bicep b/avm/res/document-db/database-account/tests/e2e/analytical/main.test.bicep index 2ea410a71cc..d8084ee5ad0 100644 --- a/avm/res/document-db/database-account/tests/e2e/analytical/main.test.bicep +++ b/avm/res/document-db/database-account/tests/e2e/analytical/main.test.bicep @@ -11,9 +11,6 @@ metadata description = 'This instance deploys the module with analytical storage @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-documentdb.databaseaccounts-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location - @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') param serviceShort string = 'dddaanl' @@ -21,6 +18,7 @@ param serviceShort string = 'dddaanl' param namePrefix string = '#_namePrefix_#' // Pipeline is selecting random regions which dont support all cosmos features and have constraints when creating new cosmos +#disable-next-line no-hardcoded-location var enforcedLocation = 'eastasia' // ============== // diff --git a/avm/res/document-db/database-account/tests/e2e/boundedConsistency/main.test.bicep b/avm/res/document-db/database-account/tests/e2e/boundedConsistency/main.test.bicep index 3d27d57753d..ed724f3b13c 100644 --- a/avm/res/document-db/database-account/tests/e2e/boundedConsistency/main.test.bicep +++ b/avm/res/document-db/database-account/tests/e2e/boundedConsistency/main.test.bicep @@ -11,9 +11,6 @@ metadata description = 'This instance deploys the module specifying a default co @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-documentdb.databaseaccounts-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location - @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') param serviceShort string = 'dddabco' @@ -21,6 +18,7 @@ param serviceShort string = 'dddabco' param namePrefix string = '#_namePrefix_#' // Pipeline is selecting random regions which dont support all cosmos features and have constraints when creating new cosmos +#disable-next-line no-hardcoded-location var enforcedLocation = 'eastasia' // ============== // diff --git a/avm/res/document-db/database-account/tests/e2e/defaults/main.test.bicep b/avm/res/document-db/database-account/tests/e2e/defaults/main.test.bicep index 0b1d63d088d..3a1fc5b7f01 100644 --- a/avm/res/document-db/database-account/tests/e2e/defaults/main.test.bicep +++ b/avm/res/document-db/database-account/tests/e2e/defaults/main.test.bicep @@ -11,9 +11,6 @@ metadata description = 'This instance deploys the module with the minimum set of @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-documentdb.databaseaccounts-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location - @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') param serviceShort string = 'dddamin' @@ -21,6 +18,7 @@ param serviceShort string = 'dddamin' param namePrefix string = '#_namePrefix_#' // Pipeline is selecting random regions which dont support all cosmos features and have constraints when creating new cosmos +#disable-next-line no-hardcoded-location var enforcedLocation = 'eastasia' // ============ // diff --git a/avm/res/document-db/database-account/tests/e2e/gremlindb/main.test.bicep b/avm/res/document-db/database-account/tests/e2e/gremlindb/main.test.bicep index 27e2388ffdf..4b9652bdd67 100644 --- a/avm/res/document-db/database-account/tests/e2e/gremlindb/main.test.bicep +++ b/avm/res/document-db/database-account/tests/e2e/gremlindb/main.test.bicep @@ -11,9 +11,6 @@ metadata description = 'This instance deploys the module with a Gremlin Database @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-documentdb.databaseaccounts-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location - @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') param serviceShort string = 'dddagrm' @@ -21,6 +18,7 @@ param serviceShort string = 'dddagrm' param namePrefix string = '#_namePrefix_#' // Pipeline is selecting random regions which dont support all cosmos features and have constraints when creating new cosmos +#disable-next-line no-hardcoded-location var enforcedLocation = 'eastasia' // ============ // diff --git a/avm/res/document-db/database-account/tests/e2e/kvSecrets/main.test.bicep b/avm/res/document-db/database-account/tests/e2e/kvSecrets/main.test.bicep index 1fcfbe4d43c..aa68b074b51 100644 --- a/avm/res/document-db/database-account/tests/e2e/kvSecrets/main.test.bicep +++ b/avm/res/document-db/database-account/tests/e2e/kvSecrets/main.test.bicep @@ -11,9 +11,6 @@ metadata description = 'This instance deploys the module saving all its secrets @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-documentdb.databaseaccounts-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location - @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') param serviceShort string = 'dddaskvs' @@ -21,6 +18,7 @@ param serviceShort string = 'dddaskvs' param namePrefix string = '#_namePrefix_#' // Pipeline is selecting random regions which dont support all cosmos features and have constraints when creating new cosmos +#disable-next-line no-hardcoded-location var enforcedLocation = 'eastasia' // ============== // diff --git a/avm/res/document-db/database-account/tests/e2e/managedIdentity/main.test.bicep b/avm/res/document-db/database-account/tests/e2e/managedIdentity/main.test.bicep index dfe9571383a..70e0dbae60c 100644 --- a/avm/res/document-db/database-account/tests/e2e/managedIdentity/main.test.bicep +++ b/avm/res/document-db/database-account/tests/e2e/managedIdentity/main.test.bicep @@ -11,9 +11,6 @@ metadata description = 'This instance deploys the module with an system and user @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-documentdb.databaseaccounts-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location - @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') param serviceShort string = 'dddaumi' @@ -21,6 +18,7 @@ param serviceShort string = 'dddaumi' param namePrefix string = '#_namePrefix_#' // Pipeline is selecting random regions which dont support all cosmos features and have constraints when creating new cosmos +#disable-next-line no-hardcoded-location var enforcedLocation = 'eastasia' // ============ // diff --git a/avm/res/document-db/database-account/tests/e2e/mongodb/main.test.bicep b/avm/res/document-db/database-account/tests/e2e/mongodb/main.test.bicep index 7755709e240..c2c1f5f676a 100644 --- a/avm/res/document-db/database-account/tests/e2e/mongodb/main.test.bicep +++ b/avm/res/document-db/database-account/tests/e2e/mongodb/main.test.bicep @@ -11,9 +11,6 @@ metadata description = 'This instance deploys the module with a Mongo Database.' @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-documentdb.databaseaccounts-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location - @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') param serviceShort string = 'dddamng' @@ -21,6 +18,7 @@ param serviceShort string = 'dddamng' param namePrefix string = '#_namePrefix_#' // Pipeline is selecting random regions which dont support all cosmos features and have constraints when creating new cosmos +#disable-next-line no-hardcoded-location var enforcedLocation = 'eastasia' // ============ // diff --git a/avm/res/document-db/database-account/tests/e2e/multiRegion/main.test.bicep b/avm/res/document-db/database-account/tests/e2e/multiRegion/main.test.bicep index 988eaf28640..a237081b2ed 100644 --- a/avm/res/document-db/database-account/tests/e2e/multiRegion/main.test.bicep +++ b/avm/res/document-db/database-account/tests/e2e/multiRegion/main.test.bicep @@ -11,9 +11,6 @@ metadata description = 'This instance deploys the module in multiple regions wit @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-documentdb.databaseaccounts-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location - @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') param serviceShort string = 'dddaumr' @@ -21,6 +18,7 @@ param serviceShort string = 'dddaumr' param namePrefix string = '#_namePrefix_#' // Pipeline is selecting random regions which dont support all cosmos features and have constraints when creating new cosmos +#disable-next-line no-hardcoded-location var enforcedLocation = 'eastasia' // ============ // diff --git a/avm/res/document-db/database-account/tests/e2e/plain/main.test.bicep b/avm/res/document-db/database-account/tests/e2e/plain/main.test.bicep index 4ba593a5d0d..1b78ae25986 100644 --- a/avm/res/document-db/database-account/tests/e2e/plain/main.test.bicep +++ b/avm/res/document-db/database-account/tests/e2e/plain/main.test.bicep @@ -11,9 +11,6 @@ metadata description = 'This instance deploys the module without a Database.' @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-documentdb.databaseaccounts-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location - @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') param serviceShort string = 'dddapln' @@ -21,6 +18,7 @@ param serviceShort string = 'dddapln' param namePrefix string = '#_namePrefix_#' // Pipeline is selecting random regions which dont support all cosmos features and have constraints when creating new cosmos +#disable-next-line no-hardcoded-location var enforcedLocation = 'eastasia' // ============== // diff --git a/avm/res/document-db/database-account/tests/e2e/publicRestrictedAccess/main.test.bicep b/avm/res/document-db/database-account/tests/e2e/publicRestrictedAccess/main.test.bicep index 2f6d85f681d..0617252bd1f 100644 --- a/avm/res/document-db/database-account/tests/e2e/publicRestrictedAccess/main.test.bicep +++ b/avm/res/document-db/database-account/tests/e2e/publicRestrictedAccess/main.test.bicep @@ -12,9 +12,6 @@ metadata description = 'This instance deploys the module with public network acc // e.g., for a module 'network/private-endpoint' you could use 'dep-dev-network.privateendpoints-${serviceShort}-rg' param resourceGroupName string = 'dep-${namePrefix}-documentdb.databaseaccounts-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location - @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') // e.g., for a module 'network/private-endpoint' you could use 'npe' as a prefix and then 'waf' as a suffix for the waf-aligned test param serviceShort string = 'dddapres' @@ -23,6 +20,7 @@ param serviceShort string = 'dddapres' param namePrefix string = '#_namePrefix_#' // Pipeline is selecting random regions which dont support all cosmos features and have constraints when creating new cosmos +#disable-next-line no-hardcoded-location var enforcedLocation = 'eastasia' // ============ // diff --git a/avm/res/document-db/database-account/tests/e2e/sqldb/main.test.bicep b/avm/res/document-db/database-account/tests/e2e/sqldb/main.test.bicep index 4185e699348..6662bd82a2d 100644 --- a/avm/res/document-db/database-account/tests/e2e/sqldb/main.test.bicep +++ b/avm/res/document-db/database-account/tests/e2e/sqldb/main.test.bicep @@ -11,9 +11,6 @@ metadata description = 'This instance deploys the module with a SQL Database.' @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-documentdb.databaseaccounts-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location - @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') param serviceShort string = 'dddasql' @@ -21,6 +18,7 @@ param serviceShort string = 'dddasql' param namePrefix string = '#_namePrefix_#' // Pipeline is selecting random regions which dont support all cosmos features and have constraints when creating new cosmos +#disable-next-line no-hardcoded-location var enforcedLocation = 'eastasia' // ============== // diff --git a/avm/res/document-db/database-account/tests/e2e/waf-aligned/main.test.bicep b/avm/res/document-db/database-account/tests/e2e/waf-aligned/main.test.bicep index 6cd7818490b..6d09badaaf4 100644 --- a/avm/res/document-db/database-account/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/document-db/database-account/tests/e2e/waf-aligned/main.test.bicep @@ -12,9 +12,6 @@ metadata description = 'This instance deploys the module in alignment with the b // e.g., for a module 'network/private-endpoint' you could use 'dep-dev-network.privateendpoints-${serviceShort}-rg' param resourceGroupName string = 'dep-${namePrefix}-documentdb.databaseaccounts-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location - @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') // e.g., for a module 'network/private-endpoint' you could use 'npe' as a prefix and then 'waf' as a suffix for the waf-aligned test param serviceShort string = 'dddawaf' @@ -23,6 +20,7 @@ param serviceShort string = 'dddawaf' param namePrefix string = '#_namePrefix_#' // Pipeline is selecting random regions which dont support all cosmos features and have constraints when creating new cosmos +#disable-next-line no-hardcoded-location var enforcedLocation = 'eastasia' // ============ // diff --git a/avm/res/network/network-watcher/tests/e2e/defaults/main.test.bicep b/avm/res/network/network-watcher/tests/e2e/defaults/main.test.bicep index 9493a14f811..0495f289413 100644 --- a/avm/res/network/network-watcher/tests/e2e/defaults/main.test.bicep +++ b/avm/res/network/network-watcher/tests/e2e/defaults/main.test.bicep @@ -11,18 +11,15 @@ metadata description = 'This instance deploys the module with the minimum set of @maxLength(90) param resourceGroupName string = 'NetworkWatcherRG' // Note, this is the default NetworkWatcher resource group. Do not change. -@description('Optional. The location to deploy resources to.') -#disable-next-line no-unused-params // A rotation location cannot be used for this test as NetworkWatcher Resource Groups are created for any test location automatically -param resourceLocation string = deployment().location - -@description('Optional. The static location of the resource group & resources.') // Note, we set the location of the NetworkWatcherRG to avoid conflicts with the already existing NetworkWatcherRG -param tempLocation string = 'uksouth' +// Note, we set the location of the NetworkWatcherRG to avoid conflicts with the already existing NetworkWatcherRG +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') param serviceShort string = 'nnwmin' -#disable-next-line no-unused-params @description('Optional. A token to inject into the name of each resource.') +#disable-next-line no-unused-params param namePrefix string = '#_namePrefix_#' // ============ // @@ -33,7 +30,7 @@ param namePrefix string = '#_namePrefix_#' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: tempLocation + location: enforcedLocation } // ============== // @@ -44,10 +41,10 @@ resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, tempLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { // Note: This value is not required and only set to enable testing - location: tempLocation + location: enforcedLocation } } ] diff --git a/avm/res/network/network-watcher/tests/e2e/max/main.test.bicep b/avm/res/network/network-watcher/tests/e2e/max/main.test.bicep index 7cbe596947c..520f9b79e29 100644 --- a/avm/res/network/network-watcher/tests/e2e/max/main.test.bicep +++ b/avm/res/network/network-watcher/tests/e2e/max/main.test.bicep @@ -11,18 +11,15 @@ metadata description = 'This instance deploys the module with most of its featur @maxLength(90) param resourceGroupName string = 'NetworkWatcherRG' // Note, this is the default NetworkWatcher resource group. Do not change. -@description('Optional. The location to deploy resources to.') -#disable-next-line no-unused-params // A rotation location cannot be used for this test as NetworkWatcher Resource Groups are created for any test location automatically -param resourceLocation string = deployment().location - @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') param serviceShort string = 'nnwmax' @description('Optional. A token to inject into the name of each resource.') param namePrefix string = '#_namePrefix_#' -@description('Optional. The static location of the resource group & resources.') // Note, we set the location of the NetworkWatcherRG to avoid conflicts with the already existing NetworkWatcherRG -param tempLocation string = 'uksouth' +// Note, we set the location of the NetworkWatcherRG to avoid conflicts with the already existing NetworkWatcherRG +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' // ============ // // Dependencies // @@ -32,24 +29,24 @@ param tempLocation string = 'uksouth' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: tempLocation + location: enforcedLocation } resource resourceGroupDependencies 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: 'dep-${namePrefix}-network.networkwatcher-${serviceShort}-rg' - location: tempLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { scope: resourceGroupDependencies - name: '${uniqueString(deployment().name, tempLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' firstNetworkSecurityGroupName: 'dep-${namePrefix}-nsg-1-${serviceShort}' secondNetworkSecurityGroupName: 'dep-${namePrefix}-nsg-2-${serviceShort}' virtualMachineName: 'dep-${namePrefix}-vm-${serviceShort}' virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' - location: tempLocation + location: enforcedLocation } } @@ -57,13 +54,13 @@ module nestedDependencies 'dependencies.bicep' = { // =========== module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { scope: resourceGroupDependencies - name: '${uniqueString(deployment().name, tempLocation)}-diagnosticDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-diagnosticDependencies' params: { storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' - location: tempLocation + location: enforcedLocation } } @@ -74,10 +71,10 @@ module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/t module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, tempLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { - name: 'NetworkWatcher_${tempLocation}' - location: tempLocation + name: 'NetworkWatcher_${enforcedLocation}' + location: enforcedLocation connectionMonitors: [ { name: '${namePrefix}-${serviceShort}-cm-001' diff --git a/avm/res/network/network-watcher/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/network-watcher/tests/e2e/waf-aligned/main.test.bicep index bcc85b93c7d..38eb129189f 100644 --- a/avm/res/network/network-watcher/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/network/network-watcher/tests/e2e/waf-aligned/main.test.bicep @@ -11,18 +11,15 @@ metadata description = 'This instance deploys the module in alignment with the b @maxLength(90) param resourceGroupName string = 'NetworkWatcherRG' // Note, this is the default NetworkWatcher resource group. Do not change. -@description('Optional. The location to deploy resources to.') -#disable-next-line no-unused-params // A rotation location cannot be used for this test as NetworkWatcher Resource Groups are created for any test location automatically -param resourceLocation string = deployment().location - @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') param serviceShort string = 'nnwwaf' @description('Optional. A token to inject into the name of each resource.') param namePrefix string = '#_namePrefix_#' -@description('Optional. The static location of the resource group & resources.') // Note, we set the location of the NetworkWatcherRG to avoid conflicts with the already existing NetworkWatcherRG -param tempLocation string = 'uksouth' +// Note, we set the location of the NetworkWatcherRG to avoid conflicts with the already existing NetworkWatcherRG +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' // ============ // // Dependencies // @@ -32,24 +29,24 @@ param tempLocation string = 'uksouth' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: tempLocation + location: enforcedLocation } resource resourceGroupDependencies 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: 'dep-${namePrefix}-network.networkwatcher-${serviceShort}-rg' - location: tempLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { scope: resourceGroupDependencies - name: '${uniqueString(deployment().name, tempLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' firstNetworkSecurityGroupName: 'dep-${namePrefix}-nsg-1-${serviceShort}' secondNetworkSecurityGroupName: 'dep-${namePrefix}-nsg-2-${serviceShort}' virtualMachineName: 'dep-${namePrefix}-vm-${serviceShort}' virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' - location: tempLocation + location: enforcedLocation } } @@ -57,13 +54,13 @@ module nestedDependencies 'dependencies.bicep' = { // =========== module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { scope: resourceGroupDependencies - name: '${uniqueString(deployment().name, tempLocation)}-diagnosticDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-diagnosticDependencies' params: { storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' - location: tempLocation + location: enforcedLocation } } @@ -75,10 +72,10 @@ module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/t module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, tempLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { - name: 'NetworkWatcher_${tempLocation}' - location: tempLocation + name: 'NetworkWatcher_${enforcedLocation}' + location: enforcedLocation connectionMonitors: [ { name: '${namePrefix}-${serviceShort}-cm-001' diff --git a/avm/res/sql/instance-pool/tests/e2e/defaults/main.test.bicep b/avm/res/sql/instance-pool/tests/e2e/defaults/main.test.bicep index 3e801241ffb..028546766c5 100644 --- a/avm/res/sql/instance-pool/tests/e2e/defaults/main.test.bicep +++ b/avm/res/sql/instance-pool/tests/e2e/defaults/main.test.bicep @@ -11,19 +11,15 @@ metadata description = 'This instance deploys the module with the minimum set of @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-sql.instancepool-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -#disable-next-line no-unused-params // A rotation location cannot be used for this test as the SQL Instance Pool deletion is not possible in the same deployment -param resourceLocation string = deployment().location - @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') -// e.g., for a module 'network/private-endpoint' you could use 'npe' as a prefix and then 'waf' as a suffix for the waf-aligned test param serviceShort string = 'sipmin' @description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') param namePrefix string = '#_namePrefix_#' -@description('Optional. The static location of the resource group & resources.') // Note, we set the location of the SQL Instance Pool to avoid conflicts with the already existing ones -param tempLocation string = 'uksouth' +// Note, we set the location of the NetworkWatcherRG to avoid conflicts with the already existing NetworkWatcherRG +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' // ============ // // Dependencies // @@ -33,12 +29,12 @@ param tempLocation string = 'uksouth' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: tempLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, tempLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' @@ -46,7 +42,7 @@ module nestedDependencies 'dependencies.bicep' = { nsgName: 'dep-${namePrefix}-nsg-${serviceShort}' routeTableName: 'dep-${namePrefix}-rt-${serviceShort}' sqlInstancePoolName: '${namePrefix}${serviceShort}001' - location: tempLocation + location: enforcedLocation } } @@ -56,10 +52,10 @@ module nestedDependencies 'dependencies.bicep' = { module testDeployment '../../../main.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, tempLocation)}-test-${serviceShort}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}' params: { name: nestedDependencies.outputs.sqlInstancePoolName - location: tempLocation + location: enforcedLocation subnetResourceId: nestedDependencies.outputs.subnetId } } diff --git a/avm/res/sql/instance-pool/tests/e2e/waf-aligned/main.test.bicep b/avm/res/sql/instance-pool/tests/e2e/waf-aligned/main.test.bicep index 943e45acec1..ca424f76ef9 100644 --- a/avm/res/sql/instance-pool/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/sql/instance-pool/tests/e2e/waf-aligned/main.test.bicep @@ -11,19 +11,15 @@ metadata description = 'This instance deploys the module in alignment with the b @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-sql.instancepool-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -#disable-next-line no-unused-params // A rotation location cannot be used for this test as the SQL Instance Pool deletion is not possible in the same deployment -param resourceLocation string = deployment().location - @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') -// e.g., for a module 'network/private-endpoint' you could use 'npe' as a prefix and then 'waf' as a suffix for the waf-aligned test param serviceShort string = 'sipwaf' @description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') param namePrefix string = '#_namePrefix_#' -@description('Optional. The static location of the resource group & resources.') // Note, we set the location of the SQL Instance Pool to avoid conflicts with the already existing ones -param tempLocation string = 'northeurope' +// Note, we set the location of the NetworkWatcherRG to avoid conflicts with the already existing NetworkWatcherRG +#disable-next-line no-hardcoded-location +var enforcedLocation = 'northeurope' // ============ // // Dependencies // @@ -33,12 +29,12 @@ param tempLocation string = 'northeurope' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: tempLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, tempLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' @@ -46,7 +42,7 @@ module nestedDependencies 'dependencies.bicep' = { nsgName: 'dep-${namePrefix}-nsg-${serviceShort}' routeTableName: 'dep-${namePrefix}-rt-${serviceShort}' sqlInstancePoolName: '${namePrefix}${serviceShort}001' - location: tempLocation + location: enforcedLocation } } @@ -56,10 +52,10 @@ module nestedDependencies 'dependencies.bicep' = { module testDeployment '../../../main.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, tempLocation)}-test-${serviceShort}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}' params: { name: nestedDependencies.outputs.sqlInstancePoolName - location: tempLocation + location: enforcedLocation skuName: 'GP_Gen8IM' subnetResourceId: nestedDependencies.outputs.subnetId } diff --git a/avm/res/web/serverfarm/tests/e2e/defaults/main.test.bicep b/avm/res/web/serverfarm/tests/e2e/defaults/main.test.bicep index 01837425027..1de03468efe 100644 --- a/avm/res/web/serverfarm/tests/e2e/defaults/main.test.bicep +++ b/avm/res/web/serverfarm/tests/e2e/defaults/main.test.bicep @@ -11,9 +11,6 @@ metadata description = 'This instance deploys the module with a base set of para @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-web.serverfarms-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location - @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') param serviceShort string = 'wsfmin' @@ -21,7 +18,7 @@ param serviceShort string = 'wsfmin' param namePrefix string = '#_namePrefix_#' #disable-next-line no-hardcoded-location // Just a value to avoid ongoing capacity challenges -var tempLocation = 'eastus' +var enforcedLocation = 'eastus' // ============ // // Dependencies // @@ -31,7 +28,7 @@ var tempLocation = 'eastus' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: tempLocation + location: enforcedLocation } // ============== // @@ -42,10 +39,10 @@ resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { name: '${namePrefix}${serviceShort}001' - location: tempLocation + location: enforcedLocation skuName: 'S1' skuCapacity: 2 } diff --git a/avm/res/web/serverfarm/tests/e2e/max/main.test.bicep b/avm/res/web/serverfarm/tests/e2e/max/main.test.bicep index b987bfb1ae3..b5d2046b5f9 100644 --- a/avm/res/web/serverfarm/tests/e2e/max/main.test.bicep +++ b/avm/res/web/serverfarm/tests/e2e/max/main.test.bicep @@ -11,9 +11,6 @@ metadata description = 'This instance deploys the module with most of its featur @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-web.serverfarms-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location - @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') param serviceShort string = 'wsfmax' @@ -21,7 +18,7 @@ param serviceShort string = 'wsfmax' param namePrefix string = '#_namePrefix_#' #disable-next-line no-hardcoded-location // Just a value to avoid ongoing capacity challenges -var tempLocation = 'eastus' +var enforcedLocation = 'eastus' // ============ // // Dependencies // @@ -31,27 +28,27 @@ var tempLocation = 'eastus' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: tempLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' - location: tempLocation + location: enforcedLocation } } module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-diagnosticDependencies' params: { storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' - location: tempLocation + location: enforcedLocation } } @@ -63,10 +60,10 @@ module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/t module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { name: '${namePrefix}${serviceShort}001' - location: tempLocation + location: enforcedLocation skuName: 'S1' skuCapacity: 1 perSiteScaling: true diff --git a/avm/res/web/serverfarm/tests/e2e/waf-aligned/main.test.bicep b/avm/res/web/serverfarm/tests/e2e/waf-aligned/main.test.bicep index 45080f9d3b0..623e3bb6b7b 100644 --- a/avm/res/web/serverfarm/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/web/serverfarm/tests/e2e/waf-aligned/main.test.bicep @@ -11,9 +11,6 @@ metadata description = 'This instance deploys the module in alignment with the b @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-web.serverfarms-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location - @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') param serviceShort string = 'wsfwaf' @@ -21,7 +18,7 @@ param serviceShort string = 'wsfwaf' param namePrefix string = '#_namePrefix_#' #disable-next-line no-hardcoded-location // Just a value to avoid ongoing capacity challenges -var tempLocation = 'eastus' +var enforcedLocation = 'eastus' // ============ // // Dependencies // @@ -31,18 +28,18 @@ var tempLocation = 'eastus' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: tempLocation + location: enforcedLocation } module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-diagnosticDependencies' params: { storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' - location: tempLocation + location: enforcedLocation } } @@ -54,10 +51,10 @@ module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/t module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { name: '${namePrefix}${serviceShort}001' - location: tempLocation + location: enforcedLocation skuName: 'P1v3' skuCapacity: 3 zoneRedundant: true From f86e359eb9038a67b93af31caf7558f658f75761 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Thu, 9 May 2024 10:44:25 +0200 Subject: [PATCH 28/52] feat: Added alias case handling for resource ID resolution in removal logic (#1873) ## Description Added alias case handling for resource ID resolution in removal logic ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.key-vault.vault](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml/badge.svg?branch=users%2Falsehr%2FaliasResolutino&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml) | ## Type of Change - [x] Update to CI Environment or utlities (Non-module effecting 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. - [ ] 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 --- .../helper/Get-ResourceIdsAsFormattedObjectList.ps1 | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Get-ResourceIdsAsFormattedObjectList.ps1 b/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Get-ResourceIdsAsFormattedObjectList.ps1 index 2ac9fbe0ea0..69f83360ebd 100644 --- a/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Get-ResourceIdsAsFormattedObjectList.ps1 +++ b/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Get-ResourceIdsAsFormattedObjectList.ps1 @@ -36,12 +36,18 @@ function Get-ResourceIdsAsFormattedObjectList { switch ($idElements.Count) { { $PSItem -eq 5 } { - if ($idElements[3] -eq 'managementGroups') { + if ($idElements[2] -eq 'Microsoft.Management' -and $idElements[3] -eq 'managementGroups') { # management-group level management group (e.g. '/providers/Microsoft.Management/managementGroups/testMG') $formattedResources += @{ resourceId = $resourceId type = $idElements[2, 3] -join '/' } + } elseif ($idElements[2] -eq 'Microsoft.Subscription' -and $idElements[3] -eq 'aliases') { + # management-group level subscription alias (e.g., '/providers/Microsoft.Subscription/aliases/testSub') + $formattedResources += @{ + resourceId = $resourceId + type = 'Microsoft.Subscription/aliases' + } } else { # subscription level resource group (e.g. '/subscriptions//resourceGroups/myRG') $formattedResources += @{ From 898d1a9ea08bd607bbe2e69accd57fd2c0177f79 Mon Sep 17 00:00:00 2001 From: ChrisSidebotham-MSFT <48600046+ChrisSidebotham@users.noreply.github.com> Date: Thu, 9 May 2024 09:57:15 +0100 Subject: [PATCH 29/52] fix: service bus authorization rules default value fix (#1890) ## Description Closes #1694 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.service-bus.namespace](https://github.com/ChrisSidebotham/bicep-registry-modules/actions/workflows/avm.res.service-bus.namespace.yml/badge.svg?branch=sbus-auth-rule)](https://github.com/ChrisSidebotham/bicep-registry-modules/actions/workflows/avm.res.service-bus.namespace.yml) | ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting changes) - [x] Azure Verified Module updates: - [x] Bugfix containing backwards compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [x] 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. - [ ] 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`. - [x] 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 --- .../namespace/authorization-rule/main.json | 4 +- .../disaster-recovery-config/main.json | 4 +- avm/res/service-bus/namespace/main.json | 53 ++++++++----------- .../migration-configuration/main.json | 4 +- .../namespace/network-rule-set/main.json | 4 +- avm/res/service-bus/namespace/queue/README.md | 16 +----- .../queue/authorization-rule/main.json | 4 +- .../service-bus/namespace/queue/main.bicep | 32 ++++------- avm/res/service-bus/namespace/queue/main.json | 21 ++------ .../topic/authorization-rule/main.json | 4 +- avm/res/service-bus/namespace/topic/main.json | 12 ++--- .../namespace/topic/subscription/main.json | 4 +- avm/res/service-bus/namespace/version.json | 4 +- 13 files changed, 59 insertions(+), 107 deletions(-) diff --git a/avm/res/service-bus/namespace/authorization-rule/main.json b/avm/res/service-bus/namespace/authorization-rule/main.json index a40a89b354c..89c91dc6966 100644 --- a/avm/res/service-bus/namespace/authorization-rule/main.json +++ b/avm/res/service-bus/namespace/authorization-rule/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "15856701624247874001" + "version": "0.26.170.59819", + "templateHash": "8796609182952388149" }, "name": "Service Bus Namespace Authorization Rules", "description": "This module deploys a Service Bus Namespace Authorization Rule.", diff --git a/avm/res/service-bus/namespace/disaster-recovery-config/main.json b/avm/res/service-bus/namespace/disaster-recovery-config/main.json index c2c26068800..7dfe560b5b8 100644 --- a/avm/res/service-bus/namespace/disaster-recovery-config/main.json +++ b/avm/res/service-bus/namespace/disaster-recovery-config/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "3332271240583753856" + "version": "0.26.170.59819", + "templateHash": "2457681488755677620" }, "name": "Service Bus Namespace Disaster Recovery Configs", "description": "This module deploys a Service Bus Namespace Disaster Recovery Config", diff --git a/avm/res/service-bus/namespace/main.json b/avm/res/service-bus/namespace/main.json index 86701b3773c..8baee247360 100644 --- a/avm/res/service-bus/namespace/main.json +++ b/avm/res/service-bus/namespace/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "9228932977984857525" + "version": "0.26.170.59819", + "templateHash": "14015486326288544360" }, "name": "Service Bus Namespaces", "description": "This module deploys a Service Bus Namespace.", @@ -1468,8 +1468,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "15856701624247874001" + "version": "0.26.170.59819", + "templateHash": "8796609182952388149" }, "name": "Service Bus Namespace Authorization Rules", "description": "This module deploys a Service Bus Namespace Authorization Rule.", @@ -1572,8 +1572,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "3332271240583753856" + "version": "0.26.170.59819", + "templateHash": "2457681488755677620" }, "name": "Service Bus Namespace Disaster Recovery Configs", "description": "This module deploys a Service Bus Namespace Disaster Recovery Config", @@ -1677,8 +1677,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "3812335497838251447" + "version": "0.26.170.59819", + "templateHash": "16322713515483912947" }, "name": "Service Bus Namespace Migration Configuration", "description": "This module deploys a Service Bus Namespace Migration Configuration.", @@ -1782,8 +1782,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "7745744247225628529" + "version": "0.26.170.59819", + "templateHash": "12093830653931933232" }, "name": "Service Bus Namespace Network Rule Sets", "description": "This module deploys a ServiceBus Namespace Network Rule Set.", @@ -1982,8 +1982,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "6465956085720113527" + "version": "0.26.170.59819", + "templateHash": "10463460824316688291" }, "name": "Service Bus Namespace Queue", "description": "This module deploys a Service Bus Namespace Queue.", @@ -2224,18 +2224,7 @@ }, "authorizationRules": { "type": "array", - "defaultValue": [ - { - "name": "RootManageSharedAccessKey", - "properties": { - "rights": [ - "Listen", - "Manage", - "Send" - ] - } - } - ], + "defaultValue": [], "metadata": { "description": "Optional. Authorization Rules for the Service Bus Queue." } @@ -2367,8 +2356,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "11000394867797752922" + "version": "0.26.170.59819", + "templateHash": "10634119713895385684" }, "name": "Service Bus Namespace Queue Authorization Rules", "description": "This module deploys a Service Bus Namespace Queue Authorization Rule.", @@ -2548,8 +2537,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "10365585985239248264" + "version": "0.26.170.59819", + "templateHash": "1083080372138021216" }, "name": "Service Bus Namespace Topic", "description": "This module deploys a Service Bus Namespace Topic.", @@ -3031,8 +3020,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "8469884519860433031" + "version": "0.26.170.59819", + "templateHash": "2461421453721833613" }, "name": "Service Bus Namespace Topic Authorization Rules", "description": "This module deploys a Service Bus Namespace Topic Authorization Rule.", @@ -3181,8 +3170,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "14842378053022621119" + "version": "0.26.170.59819", + "templateHash": "14488930902207824569" }, "name": "Service Bus Namespace Topic Subscription", "description": "This module deploys a Service Bus Namespace Topic Subscription.", diff --git a/avm/res/service-bus/namespace/migration-configuration/main.json b/avm/res/service-bus/namespace/migration-configuration/main.json index 15a83a63cce..91d7321088d 100644 --- a/avm/res/service-bus/namespace/migration-configuration/main.json +++ b/avm/res/service-bus/namespace/migration-configuration/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "3812335497838251447" + "version": "0.26.170.59819", + "templateHash": "16322713515483912947" }, "name": "Service Bus Namespace Migration Configuration", "description": "This module deploys a Service Bus Namespace Migration Configuration.", diff --git a/avm/res/service-bus/namespace/network-rule-set/main.json b/avm/res/service-bus/namespace/network-rule-set/main.json index 46f4c8e9ae8..a9b32d39965 100644 --- a/avm/res/service-bus/namespace/network-rule-set/main.json +++ b/avm/res/service-bus/namespace/network-rule-set/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "7745744247225628529" + "version": "0.26.170.59819", + "templateHash": "12093830653931933232" }, "name": "Service Bus Namespace Network Rule Sets", "description": "This module deploys a ServiceBus Namespace Network Rule Set.", diff --git a/avm/res/service-bus/namespace/queue/README.md b/avm/res/service-bus/namespace/queue/README.md index 395c88a36fb..cf3db6cbdf9 100644 --- a/avm/res/service-bus/namespace/queue/README.md +++ b/avm/res/service-bus/namespace/queue/README.md @@ -77,21 +77,7 @@ Authorization Rules for the Service Bus Queue. - Required: No - Type: array -- Default: - ```Bicep - [ - { - name: 'RootManageSharedAccessKey' - properties: { - rights: [ - 'Listen' - 'Manage' - 'Send' - ] - } - } - ] - ``` +- Default: `[]` ### Parameter: `autoDeleteOnIdle` diff --git a/avm/res/service-bus/namespace/queue/authorization-rule/main.json b/avm/res/service-bus/namespace/queue/authorization-rule/main.json index b343e9a4ef3..be761a1b543 100644 --- a/avm/res/service-bus/namespace/queue/authorization-rule/main.json +++ b/avm/res/service-bus/namespace/queue/authorization-rule/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "11000394867797752922" + "version": "0.26.170.59819", + "templateHash": "10634119713895385684" }, "name": "Service Bus Namespace Queue Authorization Rules", "description": "This module deploys a Service Bus Namespace Queue Authorization Rule.", diff --git a/avm/res/service-bus/namespace/queue/main.bicep b/avm/res/service-bus/namespace/queue/main.bicep index 1d924b040c7..3f406d0cbbf 100644 --- a/avm/res/service-bus/namespace/queue/main.bicep +++ b/avm/res/service-bus/namespace/queue/main.bicep @@ -72,18 +72,7 @@ param enablePartitioning bool = false param enableExpress bool = false @description('Optional. Authorization Rules for the Service Bus Queue.') -param authorizationRules array = [ - { - name: 'RootManageSharedAccessKey' - properties: { - rights: [ - 'Listen' - 'Manage' - 'Send' - ] - } - } -] +param authorizationRules array = [] @description('Optional. The lock settings of the service.') param lock lockType @@ -156,17 +145,16 @@ module queue_authorizationRules 'authorization-rule/main.bicep' = [ } ] -resource queue_lock 'Microsoft.Authorization/locks@2020-05-01' = - if (!empty(lock ?? {}) && lock.?kind != 'None') { - name: lock.?name ?? 'lock-${name}' - properties: { - level: lock.?kind ?? '' - notes: lock.?kind == 'CanNotDelete' - ? 'Cannot delete resource or child resources.' - : 'Cannot delete or modify the resource or child resources.' - } - scope: queue +resource queue_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' } + scope: queue +} resource queue_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ for (roleAssignment, index) in (roleAssignments ?? []): { diff --git a/avm/res/service-bus/namespace/queue/main.json b/avm/res/service-bus/namespace/queue/main.json index 16b71c71875..5e2d1c21bd1 100644 --- a/avm/res/service-bus/namespace/queue/main.json +++ b/avm/res/service-bus/namespace/queue/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "6465956085720113527" + "version": "0.26.170.59819", + "templateHash": "10463460824316688291" }, "name": "Service Bus Namespace Queue", "description": "This module deploys a Service Bus Namespace Queue.", @@ -247,18 +247,7 @@ }, "authorizationRules": { "type": "array", - "defaultValue": [ - { - "name": "RootManageSharedAccessKey", - "properties": { - "rights": [ - "Listen", - "Manage", - "Send" - ] - } - } - ], + "defaultValue": [], "metadata": { "description": "Optional. Authorization Rules for the Service Bus Queue." } @@ -390,8 +379,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "11000394867797752922" + "version": "0.26.170.59819", + "templateHash": "10634119713895385684" }, "name": "Service Bus Namespace Queue Authorization Rules", "description": "This module deploys a Service Bus Namespace Queue Authorization Rule.", diff --git a/avm/res/service-bus/namespace/topic/authorization-rule/main.json b/avm/res/service-bus/namespace/topic/authorization-rule/main.json index b2ba6537656..65c0c3ca53f 100644 --- a/avm/res/service-bus/namespace/topic/authorization-rule/main.json +++ b/avm/res/service-bus/namespace/topic/authorization-rule/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "8469884519860433031" + "version": "0.26.170.59819", + "templateHash": "2461421453721833613" }, "name": "Service Bus Namespace Topic Authorization Rules", "description": "This module deploys a Service Bus Namespace Topic Authorization Rule.", diff --git a/avm/res/service-bus/namespace/topic/main.json b/avm/res/service-bus/namespace/topic/main.json index e5db6e691e2..794a226e2fe 100644 --- a/avm/res/service-bus/namespace/topic/main.json +++ b/avm/res/service-bus/namespace/topic/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "10365585985239248264" + "version": "0.26.170.59819", + "templateHash": "1083080372138021216" }, "name": "Service Bus Namespace Topic", "description": "This module deploys a Service Bus Namespace Topic.", @@ -488,8 +488,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "8469884519860433031" + "version": "0.26.170.59819", + "templateHash": "2461421453721833613" }, "name": "Service Bus Namespace Topic Authorization Rules", "description": "This module deploys a Service Bus Namespace Topic Authorization Rule.", @@ -638,8 +638,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "14842378053022621119" + "version": "0.26.170.59819", + "templateHash": "14488930902207824569" }, "name": "Service Bus Namespace Topic Subscription", "description": "This module deploys a Service Bus Namespace Topic Subscription.", diff --git a/avm/res/service-bus/namespace/topic/subscription/main.json b/avm/res/service-bus/namespace/topic/subscription/main.json index 3e87e184d81..608831a29c2 100644 --- a/avm/res/service-bus/namespace/topic/subscription/main.json +++ b/avm/res/service-bus/namespace/topic/subscription/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "14842378053022621119" + "version": "0.26.170.59819", + "templateHash": "14488930902207824569" }, "name": "Service Bus Namespace Topic Subscription", "description": "This module deploys a Service Bus Namespace Topic Subscription.", diff --git a/avm/res/service-bus/namespace/version.json b/avm/res/service-bus/namespace/version.json index 13669e66018..41fc8c654f4 100644 --- a/avm/res/service-bus/namespace/version.json +++ b/avm/res/service-bus/namespace/version.json @@ -1,7 +1,7 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.4", + "version": "0.5", "pathFilters": [ "./main.json" ] -} \ No newline at end of file +} From cf31866b12a7fa62ae6e406118bc66ebf0ecf49b Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Thu, 9 May 2024 16:22:05 +0200 Subject: [PATCH 30/52] feat: Enabled support for `*` properties in UDTs (#1891) ## Description > Note: Required for #1257 Enabled support for `*` properties in UDTs ([ref](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/user-defined-data-types#:~:text=Decorators%20may%20be,10%20characters%20long.)) Used `>Any_other_property<` as a stand-in property name (as `*` seemed a bit unintuitive). We can change it to something else, but the Parameter name must be distinct enough & may not contain whitespaces. Tested for pattern module [Hub Networking](https://github.com/hundredacres/bicep-registry-modules/tree/hubspoke/avm/ptn/network/hub-networking) by @hundredacres Regenerated all docs for testing to ensure everything still works as intended. ## Tests ### Case 1: UDT is object ```bicep @description('Optional. A map of the hub virtual networks to create.') param hubVirtualNetworks hubVirtualNetworkObject type hubVirtualNetworkObject = { @description('Optional. Array of hub virtual networks to create.') *: hubVirtualNetworkType? }? ``` Result ![image](https://github.com/Azure/bicep-registry-modules/assets/5365358/f72a53ea-1e1f-4794-adf6-557e8b71943f) ### Case 2: UDT is array ```bicep @description('Optional. Type test') param testObject testObjectType type testObjectType = { @description('Optional. Array of hub virtual networks to create.') *: hubVirtualNetworkType? }[]? ``` Result ![image](https://github.com/Azure/bicep-registry-modules/assets/5365358/ac5c890d-bc76-448b-b9b8-9c627a2dd09b) ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.key-vault.vault](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml/badge.svg?branch=users%2Falsehr%2FreadmeScriptAstrixSupport&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml) | ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting 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. - [ ] 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 - [ ] I'm sure there are no other open Pull Requests for the same update/change - [ ] I have run `Set-AVMModule` locally to generate the supporting module files. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- avm/res/network/bastion-host/README.md | 2 +- avm/res/network/public-ip-address/README.md | 2 +- avm/res/network/public-ip-prefix/README.md | 2 +- avm/res/resources/deployment-script/README.md | 2 +- .../sharedScripts/Set-ModuleReadMe.ps1 | 37 +++++++++++++------ 5 files changed, 30 insertions(+), 15 deletions(-) diff --git a/avm/res/network/bastion-host/README.md b/avm/res/network/bastion-host/README.md index 098db0b7a9e..c3134f3fbe9 100644 --- a/avm/res/network/bastion-host/README.md +++ b/avm/res/network/bastion-host/README.md @@ -19,7 +19,7 @@ This module deploys a Bastion Host. | `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | | `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | | `Microsoft.Network/bastionHosts` | [2022-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2022-11-01/bastionHosts) | -| `Microsoft.Network/publicIPAddresses` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/publicIPAddresses) | +| `Microsoft.Network/publicIPAddresses` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-09-01/publicIPAddresses) | ## Usage examples diff --git a/avm/res/network/public-ip-address/README.md b/avm/res/network/public-ip-address/README.md index 68b5ff6ceb0..7e00e44faa4 100644 --- a/avm/res/network/public-ip-address/README.md +++ b/avm/res/network/public-ip-address/README.md @@ -18,7 +18,7 @@ This module deploys a Public IP Address. | `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | | `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | | `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | -| `Microsoft.Network/publicIPAddresses` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/publicIPAddresses) | +| `Microsoft.Network/publicIPAddresses` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-09-01/publicIPAddresses) | ## Usage examples diff --git a/avm/res/network/public-ip-prefix/README.md b/avm/res/network/public-ip-prefix/README.md index 9dd7e7ea690..70e67da18f9 100644 --- a/avm/res/network/public-ip-prefix/README.md +++ b/avm/res/network/public-ip-prefix/README.md @@ -17,7 +17,7 @@ This module deploys a Public IP Prefix. | :-- | :-- | | `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | | `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | -| `Microsoft.Network/publicIPPrefixes` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/publicIPPrefixes) | +| `Microsoft.Network/publicIPPrefixes` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-09-01/publicIPPrefixes) | ## Usage examples diff --git a/avm/res/resources/deployment-script/README.md b/avm/res/resources/deployment-script/README.md index 1432d407c55..ca8ccda147d 100644 --- a/avm/res/resources/deployment-script/README.md +++ b/avm/res/resources/deployment-script/README.md @@ -17,7 +17,7 @@ This module deploys Deployment Scripts. | :-- | :-- | | `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | | `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | -| `Microsoft.Resources/deploymentScripts` | [2023-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Resources/deploymentScripts) | +| `Microsoft.Resources/deploymentScripts` | [2023-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Resources/2023-08-01/deploymentScripts) | ## Usage examples diff --git a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 index 0cb4f68bd53..43ee7b2dd72 100644 --- a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 +++ b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 @@ -416,17 +416,32 @@ function Set-DefinitionSection { #recursive call for children if ($definition) { - if ($definition.ContainsKey('items') -and $definition['items'].ContainsKey('properties')) { - $childProperties = $definition['items']['properties'] - $sectionContent = Set-DefinitionSection -TemplateFileContent $TemplateFileContent -Properties $childProperties -ParentName $paramIdentifier -ParentIdentifierLink $paramIdentifierLink -ColumnsInOrder $ColumnsInOrder - - $listSectionContent += $sectionContent - - } elseif ($definition.type -eq 'object' -and $definition['properties']) { - $childProperties = $definition['properties'] - $sectionContent = Set-DefinitionSection -TemplateFileContent $TemplateFileContent -Properties $childProperties -ParentName $paramIdentifier -ParentIdentifierLink $paramIdentifierLink -ColumnsInOrder $ColumnsInOrder - - $listSectionContent += $sectionContent + # 'items' refers to an array + # 'properties' is the default for UDTs, 'additionalProperties' represents a used '*' identifier + if ($definition.Keys -contains 'items' -and ($definition.items.properties.Keys -or $definition.items.additionalProperties.Keys)) { + if ($definition.items.properties.Keys) { + $childProperties = $definition.items.properties + $sectionContent = Set-DefinitionSection -TemplateFileContent $TemplateFileContent -Properties $childProperties -ParentName $paramIdentifier -ParentIdentifierLink $paramIdentifierLink -ColumnsInOrder $ColumnsInOrder + $listSectionContent += $sectionContent + } + if ($definition.items.additionalProperties.Keys) { + $childProperties = $definition.items.additionalProperties + $formattedProperties = @{ '>Any_other_property<' = $childProperties } + $sectionContent = Set-DefinitionSection -TemplateFileContent $TemplateFileContent -Properties $formattedProperties -ParentName $paramIdentifier -ParentIdentifierLink $paramIdentifierLink -ColumnsInOrder $ColumnsInOrder + $listSectionContent += $sectionContent + } + } elseif ($definition.type -eq 'object' -and ($definition.properties.Keys -or $definition.additionalProperties.Keys)) { + if ($definition.properties.Keys) { + $childProperties = $definition.properties + $sectionContent = Set-DefinitionSection -TemplateFileContent $TemplateFileContent -Properties $childProperties -ParentName $paramIdentifier -ParentIdentifierLink $paramIdentifierLink -ColumnsInOrder $ColumnsInOrder + $listSectionContent += $sectionContent + } + if ($definition.additionalProperties.Keys) { + $childProperties = $definition.additionalProperties + $formattedProperties = @{ '>Any_other_property<' = $childProperties } + $sectionContent = Set-DefinitionSection -TemplateFileContent $TemplateFileContent -Properties $formattedProperties -ParentName $paramIdentifier -ParentIdentifierLink $paramIdentifierLink -ColumnsInOrder $ColumnsInOrder + $listSectionContent += $sectionContent + } } } } From dcd987fd8211f5dcd762eccd3c9ef3791e104838 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Fri, 10 May 2024 17:31:58 +0200 Subject: [PATCH 31/52] feat: Added the option to declare a specific resource type to be removed last (#1887) ## Description - Added the option to declare a specific resource type to be removed last - This is required if a resource like a subscription should be removed after everything else is removed. This is done in preparation for the LZ-Accelerator ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.key-vault.vault](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml/badge.svg?branch=users%2Falsehr%2FremoveFinalSequence&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml) | ## Type of Change - [x] Update to CI Environment or utlities (Non-module effecting 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. - [ ] 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 --- .../Initialize-DeploymentRemoval.ps1 | 22 +++++++++++---- .../helper/Get-OrderedResourcesList.ps1 | 28 ++++++++++++++----- .../helper/Remove-Deployment.ps1 | 19 ++++++++++--- 3 files changed, 52 insertions(+), 17 deletions(-) diff --git a/avm/utilities/pipelines/e2eValidation/resourceRemoval/Initialize-DeploymentRemoval.ps1 b/avm/utilities/pipelines/e2eValidation/resourceRemoval/Initialize-DeploymentRemoval.ps1 index 2f8a7b1a011..2ceed9e64b1 100644 --- a/avm/utilities/pipelines/e2eValidation/resourceRemoval/Initialize-DeploymentRemoval.ps1 +++ b/avm/utilities/pipelines/e2eValidation/resourceRemoval/Initialize-DeploymentRemoval.ps1 @@ -70,7 +70,7 @@ function Initialize-DeploymentRemoval { } # The initial sequence is a general order-recommendation - $removalSequence = @( + $RemoveFirstSequence = @( 'Microsoft.Authorization/locks', 'Microsoft.Authorization/roleAssignments', 'Microsoft.Insights/diagnosticSettings', @@ -95,6 +95,10 @@ function Initialize-DeploymentRemoval { 'Microsoft.Resources/resourceGroups' ) + $removeLastSequence = @( + 'Microsoft.Subscription/aliases' + ) + if ($DeploymentNames.Count -gt 0) { Write-Verbose 'Handling resource removal with deployment names' -Verbose foreach ($DeploymentName in $DeploymentNames) { @@ -113,7 +117,12 @@ function Initialize-DeploymentRemoval { # $moduleName = Split-Path (Split-Path (Split-Path $templateFilePath -Parent) -Parent) -LeafBase # switch ($moduleName) { # '' { # For example: 'virtualWans', 'automationAccounts' - # $removalSequence += @( + # $RemoveFirstSequence += @( + # '', # For example: 'Microsoft.Network/vpnSites', 'Microsoft.OperationalInsights/workspaces/linkedServices' + # '', + # '' + # ) + # $RemoveLastSequence += @( # '', # For example: 'Microsoft.Network/vpnSites', 'Microsoft.OperationalInsights/workspaces/linkedServices' # '', # '' @@ -134,10 +143,11 @@ function Initialize-DeploymentRemoval { # Invoke removal $inputObject = @{ - DeploymentNames = $DeploymentNames - ResourceIds = $ResourceIds - TemplateFilePath = $TemplateFilePath - RemovalSequence = $removalSequence + DeploymentNames = $DeploymentNames + ResourceIds = $ResourceIds + TemplateFilePath = $TemplateFilePath + RemoveFirstSequence = $removeFirstSequence + RemoveLastSequence = $removeLastSequence } if (-not [String]::IsNullOrEmpty($TemplateFilePath)) { $inputObject['TemplateFilePath'] = $TemplateFilePath diff --git a/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Get-OrderedResourcesList.ps1 b/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Get-OrderedResourcesList.ps1 index 0c943652674..26ec90a2b3a 100644 --- a/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Get-OrderedResourcesList.ps1 +++ b/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Get-OrderedResourcesList.ps1 @@ -15,11 +15,14 @@ Each item should be in format: type = '...' } -.PARAMETER Order -Optional. The order of resource types to apply for deletion. If order is provided, the list is returned as is +.PARAMETER RemoveFirstSequence +Optional. The order of resource types to remove before all others. If no sequence is provided, the list is returned as is + +.PARAMETER RemoveLastSequence +Optional. The order of resource types to remove after all others. If no sequence is provided, the list is returned as is .EXAMPLE -Get-OrderedResourcesList -ResourcesToOrder @(@{ name = 'myAccount'; resourceId '(..)/Microsoft.Automation/automationAccounts/myAccount'; type = 'Microsoft.Automation/automationAccounts'}) -Order @('Microsoft.Insights/diagnosticSettings','Microsoft.Automation/automationAccounts') +Get-OrderedResourcesList -ResourcesToOrder @(@{ name = 'myAccount'; resourceId '(..)/Microsoft.Automation/automationAccounts/myAccount'; type = 'Microsoft.Automation/automationAccounts'}) -RemoveFirstSequence @('Microsoft.Insights/diagnosticSettings','Microsoft.Automation/automationAccounts') Order the given list of resources which would put the diagnostic settings to the front of the list, then the automation account, then the rest. As only one item exists, the list is returned as is. #> @@ -31,16 +34,27 @@ function Get-OrderedResourcesList { [hashtable[]] $ResourcesToOrder, [Parameter(Mandatory = $false)] - [string[]] $Order = @() + [string[]] $RemoveFirstSequence = @(), + + [Parameter(Mandatory = $false)] + [string[]] $RemoveLastSequence = @() ) - # Going from back to front of the list to stack in the correct order - for ($orderIndex = ($order.Count - 1); $orderIndex -ge 0; $orderIndex--) { - $searchItem = $order[$orderIndex] + # Order resources to remove first. Going from back to front of the list to stack in the correct order + for ($orderIndex = ($RemoveFirstSequence.Count - 1); $orderIndex -ge 0; $orderIndex--) { + $searchItem = $RemoveFirstSequence[$orderIndex] if ($elementsContained = $resourcesToOrder | Where-Object { $_.type -eq $searchItem }) { $resourcesToOrder = @() + $elementsContained + ($resourcesToOrder | Where-Object { $_.type -ne $searchItem }) } } + # Order resources to remove last. Going from front to back of the list to stack in the correct order + for ($orderIndex = 0; $orderIndex -lt $RemoveLastSequence.Count; $orderIndex++) { + $searchItem = $RemoveLastSequence[$orderIndex] + if ($elementsContained = $resourcesToOrder | Where-Object { $_.type -eq $searchItem }) { + $resourcesToOrder = @() + ($resourcesToOrder | Where-Object { $_.type -ne $searchItem }) + $elementsContained + } + } + return $resourcesToOrder } diff --git a/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Remove-Deployment.ps1 b/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Remove-Deployment.ps1 index e15a259a870..fdea2ed2397 100644 --- a/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Remove-Deployment.ps1 +++ b/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Remove-Deployment.ps1 @@ -24,8 +24,11 @@ Optional. The resource Id(s) of the resources to remove. Combined with resources .PARAMETER TemplateFilePath Optional. The path to the template used for the deployment(s). Used to determine the level/scope (e.g. subscription). Required if deploymentName(s) are provided. -.PARAMETER RemovalSequence -Optional. The order of resource types to apply for deletion +.PARAMETER RemoveFirstSequence +Optional. The order of resource types to remove before all others + +.PARAMETER RemoveLastSequence +Optional. The order of resource types to remove after all others .EXAMPLE Remove-Deployment -DeploymentNames @('KeyVault-t1','KeyVault-t2') -TemplateFilePath 'C:/main.json' @@ -52,7 +55,10 @@ function Remove-Deployment { [string] $TemplateFilePath, [Parameter(Mandatory = $false)] - [string[]] $RemovalSequence = @() + [string[]] $RemoveFirstSequence = @(), + + [Parameter(Mandatory = $false)] + [string[]] $RemoveLastSequence = @() ) begin { @@ -152,7 +158,12 @@ function Remove-Deployment { # Order resources # =============== - [array] $resourcesToRemove = Get-OrderedResourcesList -ResourcesToOrder $resourcesToRemove -Order $RemovalSequence + $orderListInputObject = @{ + ResourcesToOrder = $resourcesToRemove + RemoveFirstSequence = $RemoveFirstSequence + RemoveLastSequence = $RemoveLastSequence + } + [array] $resourcesToRemove = Get-OrderedResourcesList @orderListInputObject Write-Verbose ('Total number of deployments after final ordering of resources [{0}]' -f $resourcesToRemove.Count) -Verbose # Remove resources From 9880d414270fefdf6efec87f47dd8b08e99ffd34 Mon Sep 17 00:00:00 2001 From: Ahmad Abdalla <28486158+ahmadabdalla@users.noreply.github.com> Date: Sat, 11 May 2024 20:36:40 +1000 Subject: [PATCH 32/52] feat: Add new parameters for `avm/res/virtual-machine-images/image-template` module (#1849) ## Description Closes #1799 Updated the following: - Move from API version `2022-02-14` to `2023-07-01` to allow usage of the [`optimize`](https://learn.microsoft.com/en-us/azure/virtual-machines/linux/image-builder-json?tabs=bicep%2Cazure-powershell#properties-optimize) feature. - Added support for [`Validate`](https://learn.microsoft.com/en-us/azure/virtual-machines/linux/image-builder-json?tabs=bicep%2Cazure-powershell#properties-validate) and enabled appropriate UDT for it. - Updated description for `vmUserAssignedIdentities`. - Updated version to `0.2`. ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.virtual-machine-images.image-template](https://github.com/ahmadabdalla/bicep-registry-modules/actions/workflows/avm.res.virtual-machine-images.image-template.yml/badge.svg?branch=users%2Fahmad%2F1799_ImageTemplateUpdate)](https://github.com/ahmadabdalla/bicep-registry-modules/actions/workflows/avm.res.virtual-machine-images.image-template.yml) | ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting 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 --- .../image-template/README.md | 188 +++++++++++++++++- .../image-template/main.bicep | 68 ++++++- .../image-template/main.json | 145 +++++++++++++- .../tests/e2e/max/main.test.bicep | 14 ++ .../image-template/version.json | 2 +- 5 files changed, 400 insertions(+), 17 deletions(-) diff --git a/avm/res/virtual-machine-images/image-template/README.md b/avm/res/virtual-machine-images/image-template/README.md index e370d6fdae6..9fa730d3909 100644 --- a/avm/res/virtual-machine-images/image-template/README.md +++ b/avm/res/virtual-machine-images/image-template/README.md @@ -18,7 +18,7 @@ This module deploys a Virtual Machine Image Template that can be consumed by Azu | :-- | :-- | | `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | | `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | -| `Microsoft.VirtualMachineImages/imageTemplates` | [2022-02-14](https://learn.microsoft.com/en-us/azure/templates/Microsoft.VirtualMachineImages/2022-02-14/imageTemplates) | +| `Microsoft.VirtualMachineImages/imageTemplates` | [2023-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.VirtualMachineImages/imageTemplates) | ## Usage examples @@ -208,6 +208,7 @@ module imageTemplate 'br/public:avm/res/virtual-machine-images/image-template:' @@ -328,6 +342,9 @@ module imageTemplate 'br/public:avm/res/virtual-machine-images/image-template:If this field is empty, a resource group with a random name will be created.

If the resource group specified in this field doesn't exist, it will be created with the same name.

If the resource group specified exists, it must be empty and in the same region as the image template.

The resource group created will be deleted during template deletion if this field is empty or the resource group specified doesn't exist,

but if the resource group specified exists the resources created in the resource group will be deleted during template deletion and the resource group itself will remain. | | [`subnetResourceId`](#parameter-subnetresourceid) | string | Resource ID of an already existing subnet, e.g.: /subscriptions//resourceGroups//providers/Microsoft.Network/virtualNetworks//subnets/.

If no value is provided, a new temporary VNET and subnet will be created in the staging resource group and will be deleted along with the remaining temporary resources. | | [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`validationProcess`](#parameter-validationprocess) | object | Configuration options and list of validations to be performed on the resulting image. | | [`vmSize`](#parameter-vmsize) | string | Specifies the size for the VM. | -| [`vmUserAssignedIdentities`](#parameter-vmuserassignedidentities) | array | List of User-Assigned Identities associated to the Build VM for accessing Azure resources such as Key Vaults from your customizer scripts.

Be aware, the user assigned identities specified in the \'managedIdentities\' parameter must have the \'Managed Identity Operator\' role assignment on all the user assigned identities specified in this parameter for Azure Image Builder to be able to associate them to the build VM.

| +| [`vmUserAssignedIdentities`](#parameter-vmuserassignedidentities) | array | List of User-Assigned Identities associated to the Build VM for accessing Azure resources such as Key Vaults from your customizer scripts. Be aware, the user assigned identities specified in the 'managedIdentities' parameter must have the 'Managed Identity Operator' role assignment on all the user assigned identities specified in this parameter for Azure Image Builder to be able to associate them to the build VM. | **Generated parameters** @@ -641,6 +675,20 @@ Specify the name of lock. - Required: No - Type: string +### Parameter: `optimizeVmBoot` + +The optimize property can be enabled while creating a VM image and allows VM optimization to improve image creation time. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + ### Parameter: `osDiskSizeGB` Specifies the size of OS disk. @@ -759,6 +807,140 @@ Tags of the resource. - Required: No - Type: object +### Parameter: `validationProcess` + +Configuration options and list of validations to be performed on the resulting image. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`continueDistributeOnFailure`](#parameter-validationprocesscontinuedistributeonfailure) | bool | If validation fails and this field is set to false, output image(s) will not be distributed. This is the default behavior. If validation fails and this field is set to true, output image(s) will still be distributed. Please use this option with caution as it may result in bad images being distributed for use. In either case (true or false), the end to end image run will be reported as having failed in case of a validation failure. [Note: This field has no effect if validation succeeds.]. | +| [`inVMValidations`](#parameter-validationprocessinvmvalidations) | array | A list of validators that will be performed on the image. Azure Image Builder supports File, PowerShell and Shell validators. | +| [`sourceValidationOnly`](#parameter-validationprocesssourcevalidationonly) | bool | If this field is set to true, the image specified in the 'source' section will directly be validated. No separate build will be run to generate and then validate a customized image. Not supported when performing customizations, validations or distributions on the image. | + +### Parameter: `validationProcess.continueDistributeOnFailure` + +If validation fails and this field is set to false, output image(s) will not be distributed. This is the default behavior. If validation fails and this field is set to true, output image(s) will still be distributed. Please use this option with caution as it may result in bad images being distributed for use. In either case (true or false), the end to end image run will be reported as having failed in case of a validation failure. [Note: This field has no effect if validation succeeds.]. + +- Required: No +- Type: bool + +### Parameter: `validationProcess.inVMValidations` + +A list of validators that will be performed on the image. Azure Image Builder supports File, PowerShell and Shell validators. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`type`](#parameter-validationprocessinvmvalidationstype) | string | The type of validation. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`destination`](#parameter-validationprocessinvmvalidationsdestination) | string | Destination of the file. | +| [`inline`](#parameter-validationprocessinvmvalidationsinline) | array | Array of commands to be run, separated by commas. | +| [`name`](#parameter-validationprocessinvmvalidationsname) | string | Friendly Name to provide context on what this validation step does. | +| [`runAsSystem`](#parameter-validationprocessinvmvalidationsrunassystem) | bool | If specified, the PowerShell script will be run with elevated privileges using the Local System user. Can only be true when the runElevated field above is set to true. | +| [`runElevated`](#parameter-validationprocessinvmvalidationsrunelevated) | bool | If specified, the PowerShell script will be run with elevated privileges. | +| [`scriptUri`](#parameter-validationprocessinvmvalidationsscripturi) | string | URI of the PowerShell script to be run for validation. It can be a github link, Azure Storage URI, etc. | +| [`sha256Checksum`](#parameter-validationprocessinvmvalidationssha256checksum) | string | Value of sha256 checksum of the file, you generate this locally, and then Image Builder will checksum and validate. | +| [`sourceUri`](#parameter-validationprocessinvmvalidationssourceuri) | string | The source URI of the file. | +| [`validExitCodes`](#parameter-validationprocessinvmvalidationsvalidexitcodes) | array | Valid codes that can be returned from the script/inline command, this avoids reported failure of the script/inline command. | + +### Parameter: `validationProcess.inVMValidations.type` + +The type of validation. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'File' + 'PowerShell' + 'Shell' + ] + ``` + +### Parameter: `validationProcess.inVMValidations.destination` + +Destination of the file. + +- Required: No +- Type: string + +### Parameter: `validationProcess.inVMValidations.inline` + +Array of commands to be run, separated by commas. + +- Required: No +- Type: array + +### Parameter: `validationProcess.inVMValidations.name` + +Friendly Name to provide context on what this validation step does. + +- Required: No +- Type: string + +### Parameter: `validationProcess.inVMValidations.runAsSystem` + +If specified, the PowerShell script will be run with elevated privileges using the Local System user. Can only be true when the runElevated field above is set to true. + +- Required: No +- Type: bool + +### Parameter: `validationProcess.inVMValidations.runElevated` + +If specified, the PowerShell script will be run with elevated privileges. + +- Required: No +- Type: bool + +### Parameter: `validationProcess.inVMValidations.scriptUri` + +URI of the PowerShell script to be run for validation. It can be a github link, Azure Storage URI, etc. + +- Required: No +- Type: string + +### Parameter: `validationProcess.inVMValidations.sha256Checksum` + +Value of sha256 checksum of the file, you generate this locally, and then Image Builder will checksum and validate. + +- Required: No +- Type: string + +### Parameter: `validationProcess.inVMValidations.sourceUri` + +The source URI of the file. + +- Required: No +- Type: string + +### Parameter: `validationProcess.inVMValidations.validExitCodes` + +Valid codes that can be returned from the script/inline command, this avoids reported failure of the script/inline command. + +- Required: No +- Type: array + +### Parameter: `validationProcess.sourceValidationOnly` + +If this field is set to true, the image specified in the 'source' section will directly be validated. No separate build will be run to generate and then validate a customized image. Not supported when performing customizations, validations or distributions on the image. + +- Required: No +- Type: bool + ### Parameter: `vmSize` Specifies the size for the VM. @@ -769,7 +951,7 @@ Specifies the size for the VM. ### Parameter: `vmUserAssignedIdentities` -List of User-Assigned Identities associated to the Build VM for accessing Azure resources such as Key Vaults from your customizer scripts.

Be aware, the user assigned identities specified in the \'managedIdentities\' parameter must have the \'Managed Identity Operator\' role assignment on all the user assigned identities specified in this parameter for Azure Image Builder to be able to associate them to the build VM.

+List of User-Assigned Identities associated to the Build VM for accessing Azure resources such as Key Vaults from your customizer scripts. Be aware, the user assigned identities specified in the 'managedIdentities' parameter must have the 'Managed Identity Operator' role assignment on all the user assigned identities specified in this parameter for Azure Image Builder to be able to associate them to the build VM. - Required: No - Type: array diff --git a/avm/res/virtual-machine-images/image-template/main.bicep b/avm/res/virtual-machine-images/image-template/main.bicep index 4c46be1680d..2a61c05386e 100644 --- a/avm/res/virtual-machine-images/image-template/main.bicep +++ b/avm/res/virtual-machine-images/image-template/main.bicep @@ -49,15 +49,22 @@ param roleAssignments roleAssignmentType @description('Required. The distribution targets where the image output needs to go to.') param distributions distributionType[] -@description(''' -Optional. List of User-Assigned Identities associated to the Build VM for accessing Azure resources such as Key Vaults from your customizer scripts. -Be aware, the user assigned identities specified in the \'managedIdentities\' parameter must have the \'Managed Identity Operator\' role assignment on all the user assigned identities specified in this parameter for Azure Image Builder to be able to associate them to the build VM. -''') +@description('Optional. List of User-Assigned Identities associated to the Build VM for accessing Azure resources such as Key Vaults from your customizer scripts. Be aware, the user assigned identities specified in the \'managedIdentities\' parameter must have the \'Managed Identity Operator\' role assignment on all the user assigned identities specified in this parameter for Azure Image Builder to be able to associate them to the build VM.') param vmUserAssignedIdentities array = [] @description('Required. The managed identity definition for this resource.') param managedIdentities managedIdentitiesType +@description('Optional. Configuration options and list of validations to be performed on the resulting image.') +param validationProcess validationProcessType + +@allowed([ + 'Enabled' + 'Disabled' +]) +@description('Optional. The optimize property can be enabled while creating a VM image and allows VM optimization to improve image creation time.') +param optimizeVmBoot string? + var identity = { type: 'UserAssigned' userAssignedIdentities: reduce( @@ -100,7 +107,7 @@ resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = } } -resource imageTemplate 'Microsoft.VirtualMachineImages/imageTemplates@2022-02-14' = { +resource imageTemplate 'Microsoft.VirtualMachineImages/imageTemplates@2023-07-01' = { #disable-next-line use-stable-resource-identifiers // Disabling as ImageTemplates are not idempotent and hence always must have new name name: '${name}-${baseTime}' location: location @@ -164,6 +171,14 @@ resource imageTemplate 'Microsoft.VirtualMachineImages/imageTemplates@2022-02-14 : {}) ) ] + validate: validationProcess + optimize: optimizeVmBoot != null + ? { + vmBoot: { + state: optimizeVmBoot + } + } + : null } } @@ -316,6 +331,47 @@ type managedImageDistributionType = { @description('Required. The resource ID of the managed image. Defaults to a compute image with name \'imageName-baseTime\' in the current resource group.') imageResourceId: string? - @description('Conditional. Name of the managed or unmanaged image that will be created..') + @description('Conditional. Name of the managed or unmanaged image that will be created.') imageName: string } + +type validationProcessType = { + @description('Optional. If validation fails and this field is set to false, output image(s) will not be distributed. This is the default behavior. If validation fails and this field is set to true, output image(s) will still be distributed. Please use this option with caution as it may result in bad images being distributed for use. In either case (true or false), the end to end image run will be reported as having failed in case of a validation failure. [Note: This field has no effect if validation succeeds.].') + continueDistributeOnFailure: bool? + + @description('Optional. A list of validators that will be performed on the image. Azure Image Builder supports File, PowerShell and Shell validators.') + inVMValidations: { + @description('Required. The type of validation.') + type: ('PowerShell' | 'Shell' | 'File') + + @description('Optional. Friendly Name to provide context on what this validation step does.') + name: string? + + @description('Optional. URI of the PowerShell script to be run for validation. It can be a github link, Azure Storage URI, etc.') + scriptUri: string? + + @description('Optional. Array of commands to be run, separated by commas.') + inline: string[]? + + @description('Optional. Valid codes that can be returned from the script/inline command, this avoids reported failure of the script/inline command.') + validExitCodes: int[]? + + @description('Optional. Value of sha256 checksum of the file, you generate this locally, and then Image Builder will checksum and validate.') + sha256Checksum: string? + + @description('Optional. The source URI of the file.') + sourceUri: string? + + @description('Optional. Destination of the file.') + destination: string? + + @description('Optional. If specified, the PowerShell script will be run with elevated privileges using the Local System user. Can only be true when the runElevated field above is set to true.') + runAsSystem: bool? + + @description('Optional. If specified, the PowerShell script will be run with elevated privileges.') + runElevated: bool? + }[]? + + @description('Optional. If this field is set to true, the image specified in the \'source\' section will directly be validated. No separate build will be run to generate and then validate a customized image. Not supported when performing customizations, validations or distributions on the image.') + sourceValidationOnly: bool? +}? diff --git a/avm/res/virtual-machine-images/image-template/main.json b/avm/res/virtual-machine-images/image-template/main.json index e2bef8c3df4..f3894b7f80d 100644 --- a/avm/res/virtual-machine-images/image-template/main.json +++ b/avm/res/virtual-machine-images/image-template/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "4620280027037163005" + "version": "0.26.170.59819", + "templateHash": "16618215702378872010" }, "name": "Virtual Machine Image Templates", "description": "This module deploys a Virtual Machine Image Template that can be consumed by Azure Image Builder (AIB).", @@ -281,10 +281,122 @@ "imageName": { "type": "string", "metadata": { - "description": "Conditional. Name of the managed or unmanaged image that will be created.." + "description": "Conditional. Name of the managed or unmanaged image that will be created." } } } + }, + "validationProcessType": { + "type": "object", + "properties": { + "continueDistributeOnFailure": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If validation fails and this field is set to false, output image(s) will not be distributed. This is the default behavior. If validation fails and this field is set to true, output image(s) will still be distributed. Please use this option with caution as it may result in bad images being distributed for use. In either case (true or false), the end to end image run will be reported as having failed in case of a validation failure. [Note: This field has no effect if validation succeeds.]." + } + }, + "inVMValidations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "File", + "PowerShell", + "Shell" + ], + "metadata": { + "description": "Required. The type of validation." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Friendly Name to provide context on what this validation step does." + } + }, + "scriptUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. URI of the PowerShell script to be run for validation. It can be a github link, Azure Storage URI, etc." + } + }, + "inline": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of commands to be run, separated by commas." + } + }, + "validExitCodes": { + "type": "array", + "items": { + "type": "int" + }, + "nullable": true, + "metadata": { + "description": "Optional. Valid codes that can be returned from the script/inline command, this avoids reported failure of the script/inline command." + } + }, + "sha256Checksum": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Value of sha256 checksum of the file, you generate this locally, and then Image Builder will checksum and validate." + } + }, + "sourceUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source URI of the file." + } + }, + "destination": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Destination of the file." + } + }, + "runAsSystem": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If specified, the PowerShell script will be run with elevated privileges using the Local System user. Can only be true when the runElevated field above is set to true." + } + }, + "runElevated": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If specified, the PowerShell script will be run with elevated privileges." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of validators that will be performed on the image. Azure Image Builder supports File, PowerShell and Shell validators." + } + }, + "sourceValidationOnly": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If this field is set to true, the image specified in the 'source' section will directly be validated. No separate build will be run to generate and then validate a customized image. Not supported when performing customizations, validations or distributions on the image." + } + } + }, + "nullable": true } }, "parameters": { @@ -396,7 +508,7 @@ "type": "array", "defaultValue": [], "metadata": { - "description": "Optional. List of User-Assigned Identities associated to the Build VM for accessing Azure resources such as Key Vaults from your customizer scripts.\nBe aware, the user assigned identities specified in the \\'managedIdentities\\' parameter must have the \\'Managed Identity Operator\\' role assignment on all the user assigned identities specified in this parameter for Azure Image Builder to be able to associate them to the build VM.\n" + "description": "Optional. List of User-Assigned Identities associated to the Build VM for accessing Azure resources such as Key Vaults from your customizer scripts. Be aware, the user assigned identities specified in the 'managedIdentities' parameter must have the 'Managed Identity Operator' role assignment on all the user assigned identities specified in this parameter for Azure Image Builder to be able to associate them to the build VM." } }, "managedIdentities": { @@ -404,6 +516,23 @@ "metadata": { "description": "Required. The managed identity definition for this resource." } + }, + "validationProcess": { + "$ref": "#/definitions/validationProcessType", + "metadata": { + "description": "Optional. Configuration options and list of validations to be performed on the resulting image." + } + }, + "optimizeVmBoot": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The optimize property can be enabled while creating a VM image and allows VM optimization to improve image creation time." + } } }, "variables": { @@ -442,7 +571,7 @@ }, "imageTemplate": { "type": "Microsoft.VirtualMachineImages/imageTemplates", - "apiVersion": "2022-02-14", + "apiVersion": "2023-07-01", "name": "[format('{0}-{1}', parameters('name'), parameters('baseTime'))]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", @@ -464,7 +593,9 @@ }, "source": "[parameters('imageSource')]", "customize": "[parameters('customizationSteps')]", - "stagingResourceGroup": "[parameters('stagingResourceGroup')]" + "stagingResourceGroup": "[parameters('stagingResourceGroup')]", + "validate": "[parameters('validationProcess')]", + "optimize": "[if(not(equals(parameters('optimizeVmBoot'), null())), createObject('vmBoot', createObject('state', parameters('optimizeVmBoot'))), null())]" } }, "imageTemplate_lock": { @@ -545,7 +676,7 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('imageTemplate', '2022-02-14', 'full').location]" + "value": "[reference('imageTemplate', '2023-07-01', 'full').location]" } } } \ No newline at end of file diff --git a/avm/res/virtual-machine-images/image-template/tests/e2e/max/main.test.bicep b/avm/res/virtual-machine-images/image-template/tests/e2e/max/main.test.bicep index 2bd4869dd5d..49eba449c66 100644 --- a/avm/res/virtual-machine-images/image-template/tests/e2e/max/main.test.bicep +++ b/avm/res/virtual-machine-images/image-template/tests/e2e/max/main.test.bicep @@ -81,6 +81,20 @@ module testDeployment '../../../main.bicep' = { ] } ] + validationProcess: { + continueDistributeOnFailure: true + sourceValidationOnly: false + inVMValidations: [ + { + type: 'Shell' + name: 'Validate-Software' + inline: [ + 'echo "Software validation successful."' + ] + } + ] + } + optimizeVmBoot: 'Enabled' imageSource: { type: 'PlatformImage' publisher: 'canonical' diff --git a/avm/res/virtual-machine-images/image-template/version.json b/avm/res/virtual-machine-images/image-template/version.json index 7fa401bdf78..9481fea58ee 100644 --- a/avm/res/virtual-machine-images/image-template/version.json +++ b/avm/res/virtual-machine-images/image-template/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.1", + "version": "0.2", "pathFilters": [ "./main.json" ] From a302384a779c9b32d15ba8378ac902d8df5b5778 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Sat, 11 May 2024 18:43:33 +0200 Subject: [PATCH 33/52] feat: Migrated module App/Jobs from CARML - `avm/res/app/job` (#1823) ## Description Migrated `Microsoft.App/jobs` from CARML & updated to latest specs cc: @MrRoundRobin fyi ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.app.job](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.app.job.yml/badge.svg?branch=users%2Falsehr%2FappJobsModule&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.app.job.yml) | ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting changes) - [x] 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. - [ ] 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 --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- .github/CODEOWNERS | 2 +- .github/ISSUE_TEMPLATE/avm_module_issue.yml | 1 + .github/workflows/avm.res.app.job.yml | 90 ++ avm/res/app/job/ORPHANED.md | 4 + avm/res/app/job/README.md | 812 ++++++++++++++++++ avm/res/app/job/main.bicep | 236 +++++ avm/res/app/job/main.json | 406 +++++++++ .../job/tests/e2e/defaults/dependencies.bicep | 21 + .../job/tests/e2e/defaults/main.test.bicep | 74 ++ .../app/job/tests/e2e/max/dependencies.bicep | 40 + avm/res/app/job/tests/e2e/max/main.test.bicep | 136 +++ .../tests/e2e/waf-aligned/dependencies.bicep | 40 + .../job/tests/e2e/waf-aligned/main.test.bicep | 98 +++ avm/res/app/job/version.json | 7 + 14 files changed, 1966 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/avm.res.app.job.yml create mode 100644 avm/res/app/job/ORPHANED.md create mode 100644 avm/res/app/job/README.md create mode 100644 avm/res/app/job/main.bicep create mode 100644 avm/res/app/job/main.json create mode 100644 avm/res/app/job/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/res/app/job/tests/e2e/defaults/main.test.bicep create mode 100644 avm/res/app/job/tests/e2e/max/dependencies.bicep create mode 100644 avm/res/app/job/tests/e2e/max/main.test.bicep create mode 100644 avm/res/app/job/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/res/app/job/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/res/app/job/version.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a35c3158ea3..893e030b61b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -7,10 +7,10 @@ /avm/ptn/authorization/role-assignment/ @Azure/avm-ptn-authorization-roleassignment-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/ptn/security/security-center/ @Azure/avm-ptn-security-securitycenter-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/aad/domain-service/ @Azure/avm-res-aad-domainservice-module-owners-bicep @Azure/avm-core-team-technical-bicep -#/avm/res/aad/domain-service/ @Azure/avm-res-aad-domainservice-module-owners-bicep /avm/res/analysis-services/server/ @Azure/avm-res-analysisservices-server-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/api-management/service/ @Azure/avm-res-apimanagement-service-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/app/container-app/ @Azure/avm-res-app-containerapp-module-owners-bicep @Azure/avm-core-team-technical-bicep +/avm/res/app/job/ @Azure/avm-res-app-job-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/app/managed-environment/ @Azure/avm-res-app-managedenvironment-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/app-configuration/configuration-store/ @Azure/avm-res-appconfiguration-configurationstore-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/authorization/lock/ @Azure/avm-res-authorization-lock-module-owners-bicep @Azure/avm-core-team-technical-bicep diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index 459c075404c..bd18fad337c 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -51,6 +51,7 @@ body: - "avm/res/api-management/service" - "avm/res/app-configuration/configuration-store" - "avm/res/app/container-app" + - "avm/res/app/job" - "avm/res/app/managed-environment" - "avm/res/automation/automation-account" - "avm/res/batch/batch-account" diff --git a/.github/workflows/avm.res.app.job.yml b/.github/workflows/avm.res.app.job.yml new file mode 100644 index 00000000000..1d91926f99e --- /dev/null +++ b/.github/workflows/avm.res.app.job.yml @@ -0,0 +1,90 @@ +name: "avm.res.app.job" + +on: + schedule: + - cron: "0 12 1/15 * *" # Bi-Weekly Test (on 1st & 15th of month) + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: "Execute static validation" + required: false + default: true + deploymentValidation: + type: boolean + description: "Execute deployment validation" + required: false + default: true + removeDeployment: + type: boolean + description: "Remove deployed module" + required: false + default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.res.app.job.yml" + - "avm/res/app/job/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/res/app/job" + workflowPath: ".github/workflows/avm.res.app.job.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-latest + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get module test file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Run" + permissions: + id-token: write # For OIDC + contents: write # For release tags + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit diff --git a/avm/res/app/job/ORPHANED.md b/avm/res/app/job/ORPHANED.md new file mode 100644 index 00000000000..ef8fa911d2b --- /dev/null +++ b/avm/res/app/job/ORPHANED.md @@ -0,0 +1,4 @@ +⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️ + +- Only security and bug fixes are being handled by the AVM core team at present. +- If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)! \ No newline at end of file diff --git a/avm/res/app/job/README.md b/avm/res/app/job/README.md new file mode 100644 index 00000000000..93e9c6e55a0 --- /dev/null +++ b/avm/res/app/job/README.md @@ -0,0 +1,812 @@ +# Container App Jobs `[Microsoft.App/jobs]` + +> ⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️ +> +> - Only security and bug fixes are being handled by the AVM core team at present. +> - If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)! + +This module deploys a Container App Job. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.App/jobs` | [2023-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.App/2023-05-01/jobs) | +| `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/app/job:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module job 'br/public:avm/res/app/job:' = { + name: 'jobDeployment' + params: { + // Required parameters + containers: [ + { + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: 'simple-hello-world-container' + resources: { + cpu: '' + memory: '0.5Gi' + } + } + ] + environmentResourceId: '' + name: 'ajmin001' + triggerType: 'Manual' + // Non-required parameters + location: '' + manualTriggerConfig: { + parallelism: 1 + replicaCompletionCount: 1 + } + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "containers": { + "value": [ + { + "image": "mcr.microsoft.com/azuredocs/containerapps-helloworld:latest", + "name": "simple-hello-world-container", + "resources": { + "cpu": "", + "memory": "0.5Gi" + } + } + ] + }, + "environmentResourceId": { + "value": "" + }, + "name": { + "value": "ajmin001" + }, + "triggerType": { + "value": "Manual" + }, + // Non-required parameters + "location": { + "value": "" + }, + "manualTriggerConfig": { + "value": { + "parallelism": 1, + "replicaCompletionCount": 1 + } + } + } +} +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module job 'br/public:avm/res/app/job:' = { + name: 'jobDeployment' + params: { + // Required parameters + containers: [ + { + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: 'simple-hello-world-container' + probes: [ + { + httpGet: { + httpHeaders: [ + { + name: 'Custom-Header' + value: 'Awesome' + } + ] + path: '/health' + port: 8080 + } + initialDelaySeconds: 3 + periodSeconds: 3 + type: 'Liveness' + } + ] + resources: { + cpu: '' + memory: '0.5Gi' + } + } + ] + environmentResourceId: '' + name: 'ajmax001' + triggerType: 'Manual' + // Non-required parameters + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] + } + manualTriggerConfig: { + parallelism: 1 + replicaCompletionCount: 1 + } + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + secrets: { + secureList: [ + { + name: 'customtest' + value: '' + } + ] + } + tags: { + Env: 'test' + 'hidden-title': 'This is visible in the resource name' + } + workloadProfileName: '' + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "containers": { + "value": [ + { + "image": "mcr.microsoft.com/azuredocs/containerapps-helloworld:latest", + "name": "simple-hello-world-container", + "probes": [ + { + "httpGet": { + "httpHeaders": [ + { + "name": "Custom-Header", + "value": "Awesome" + } + ], + "path": "/health", + "port": 8080 + }, + "initialDelaySeconds": 3, + "periodSeconds": 3, + "type": "Liveness" + } + ], + "resources": { + "cpu": "", + "memory": "0.5Gi" + } + } + ] + }, + "environmentResourceId": { + "value": "" + }, + "name": { + "value": "ajmax001" + }, + "triggerType": { + "value": "Manual" + }, + // Non-required parameters + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "" + ] + } + }, + "manualTriggerConfig": { + "value": { + "parallelism": 1, + "replicaCompletionCount": 1 + } + }, + "roleAssignments": { + "value": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "secrets": { + "value": { + "secureList": [ + { + "name": "customtest", + "value": "" + } + ] + } + }, + "tags": { + "value": { + "Env": "test", + "hidden-title": "This is visible in the resource name" + } + }, + "workloadProfileName": { + "value": "" + } + } +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module job 'br/public:avm/res/app/job:' = { + name: 'jobDeployment' + params: { + // Required parameters + containers: [ + { + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: 'simple-hello-world-container' + probes: [ + { + httpGet: { + httpHeaders: [ + { + name: 'Custom-Header' + value: 'Awesome' + } + ] + path: '/health' + port: 8080 + } + initialDelaySeconds: 3 + periodSeconds: 3 + type: 'Liveness' + } + ] + resources: { + cpu: '' + memory: '0.5Gi' + } + } + ] + environmentResourceId: '' + name: 'ajwaf001' + triggerType: 'Manual' + // Non-required parameters + location: '' + manualTriggerConfig: { + parallelism: 1 + replicaCompletionCount: 1 + } + tags: { + Env: 'test' + 'hidden-title': 'This is visible in the resource name' + } + workloadProfileName: '' + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "containers": { + "value": [ + { + "image": "mcr.microsoft.com/azuredocs/containerapps-helloworld:latest", + "name": "simple-hello-world-container", + "probes": [ + { + "httpGet": { + "httpHeaders": [ + { + "name": "Custom-Header", + "value": "Awesome" + } + ], + "path": "/health", + "port": 8080 + }, + "initialDelaySeconds": 3, + "periodSeconds": 3, + "type": "Liveness" + } + ], + "resources": { + "cpu": "", + "memory": "0.5Gi" + } + } + ] + }, + "environmentResourceId": { + "value": "" + }, + "name": { + "value": "ajwaf001" + }, + "triggerType": { + "value": "Manual" + }, + // Non-required parameters + "location": { + "value": "" + }, + "manualTriggerConfig": { + "value": { + "parallelism": 1, + "replicaCompletionCount": 1 + } + }, + "tags": { + "value": { + "Env": "test", + "hidden-title": "This is visible in the resource name" + } + }, + "workloadProfileName": { + "value": "" + } + } +} +``` + +
+

+ + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`containers`](#parameter-containers) | array | List of container definitions for the Container App. | +| [`environmentResourceId`](#parameter-environmentresourceid) | string | Resource ID of environment. | +| [`name`](#parameter-name) | string | Name of the Container App. | +| [`triggerType`](#parameter-triggertype) | string | Trigger type of the job. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`eventTriggerConfig`](#parameter-eventtriggerconfig) | object | Required if TriggerType is Event. Configuration of an event driven job. | +| [`initContainersTemplate`](#parameter-initcontainerstemplate) | array | List of specialized containers that run before app containers. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | +| [`manualTriggerConfig`](#parameter-manualtriggerconfig) | object | Required if TriggerType is Manual. Configuration of a manual job. | +| [`registries`](#parameter-registries) | array | Collection of private container registry credentials for containers used by the Container app. | +| [`replicaRetryLimit`](#parameter-replicaretrylimit) | int | The maximum number of times a replica can be retried. | +| [`replicaTimeout`](#parameter-replicatimeout) | int | Maximum number of seconds a replica is allowed to run. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`scheduleTriggerConfig`](#parameter-scheduletriggerconfig) | object | Required if TriggerType is Schedule. Configuration of a schedule based job. | +| [`secrets`](#parameter-secrets) | secureObject | The secrets of the Container App. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`volumes`](#parameter-volumes) | array | List of volume definitions for the Container App. | +| [`workloadProfileName`](#parameter-workloadprofilename) | string | The name of the workload profile to use. | + +### Parameter: `containers` + +List of container definitions for the Container App. + +- Required: Yes +- Type: array + +### Parameter: `environmentResourceId` + +Resource ID of environment. + +- Required: Yes +- Type: string + +### Parameter: `name` + +Name of the Container App. + +- Required: Yes +- Type: string + +### Parameter: `triggerType` + +Trigger type of the job. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Event' + 'Manual' + 'Schedule' + ] + ``` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `eventTriggerConfig` + +Required if TriggerType is Event. Configuration of an event driven job. + +- Required: No +- Type: object + +### Parameter: `initContainersTemplate` + +List of specialized containers that run before app containers. + +- Required: No +- Type: array + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `managedIdentities` + +The managed identity definition for this resource. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`systemAssigned`](#parameter-managedidentitiessystemassigned) | bool | Enables system assigned managed identity on the resource. | +| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. | + +### Parameter: `managedIdentities.systemAssigned` + +Enables system assigned managed identity on the resource. + +- Required: No +- Type: bool + +### Parameter: `managedIdentities.userAssignedResourceIds` + +The resource ID(s) to assign to the resource. + +- Required: No +- Type: array + +### Parameter: `manualTriggerConfig` + +Required if TriggerType is Manual. Configuration of a manual job. + +- Required: No +- Type: object + +### Parameter: `registries` + +Collection of private container registry credentials for containers used by the Container app. + +- Required: No +- Type: array + +### Parameter: `replicaRetryLimit` + +The maximum number of times a replica can be retried. + +- Required: No +- Type: int +- Default: `0` + +### Parameter: `replicaTimeout` + +Maximum number of seconds a replica is allowed to run. + +- Required: No +- Type: int +- Default: `1800` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `scheduleTriggerConfig` + +Required if TriggerType is Schedule. Configuration of a schedule based job. + +- Required: No +- Type: object + +### Parameter: `secrets` + +The secrets of the Container App. + +- Required: No +- Type: secureObject + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `volumes` + +List of volume definitions for the Container App. + +- Required: No +- Type: array + +### Parameter: `workloadProfileName` + +The name of the workload profile to use. + +- Required: No +- Type: string +- Default: `'Consumption'` + + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the Container App Job. | +| `resourceGroupName` | string | The name of the resource group the Container App Job was deployed into. | +| `resourceId` | string | The resource ID of the Container App Job. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | + +## Cross-referenced modules + +_None_ + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/res/app/job/main.bicep b/avm/res/app/job/main.bicep new file mode 100644 index 00000000000..2d9a0f6ba68 --- /dev/null +++ b/avm/res/app/job/main.bicep @@ -0,0 +1,236 @@ +metadata name = 'Container App Jobs' +metadata description = 'This module deploys a Container App Job.' +metadata owner = 'Azure/module-maintainers' + +@description('Required. Name of the Container App.') +param name string + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Required. Resource ID of environment.') +param environmentResourceId string + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Collection of private container registry credentials for containers used by the Container app.') +param registries array? + +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Required. List of container definitions for the Container App.') +param containers array + +@description('Optional. List of specialized containers that run before app containers.') +param initContainersTemplate array? + +@description('Optional. Required if TriggerType is Event. Configuration of an event driven job.') +param eventTriggerConfig object? + +@description('Optional. Required if TriggerType is Schedule. Configuration of a schedule based job.') +param scheduleTriggerConfig object? + +@description('Optional. Required if TriggerType is Manual. Configuration of a manual job.') +param manualTriggerConfig object? + +@description('Optional. The maximum number of times a replica can be retried.') +param replicaRetryLimit int = 0 + +@description('Optional. The name of the workload profile to use.') +param workloadProfileName string = 'Consumption' + +@description('Optional. The secrets of the Container App.') +@secure() +param secrets object? + +@description('Optional. List of volume definitions for the Container App.') +param volumes array? + +@description('Optional. Maximum number of seconds a replica is allowed to run.') +param replicaTimeout int = 1800 + +@allowed([ + 'Event' + 'Manual' + 'Schedule' +]) +@description('Required. Trigger type of the job.') +param triggerType string + +var secretList = secrets.?secureList + +var formattedUserAssignedIdentities = reduce( + map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), + {}, + (cur, next) => union(cur, next) +) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + +var identity = !empty(managedIdentities) + ? { + type: (managedIdentities.?systemAssigned ?? false) + ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') + : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : 'None') + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null + } + : null + +var builtInRoleNames = { + 'ContainerApp Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b' + ) + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator (Preview)': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = if (enableTelemetry) { + name: '46d3xbcp.res.app-job.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource job 'Microsoft.App/jobs@2023-05-01' = { + name: name + tags: tags + location: location + identity: identity + properties: { + environmentId: environmentResourceId + configuration: { + eventTriggerConfig: triggerType == 'Event' ? eventTriggerConfig : null + manualTriggerConfig: triggerType == 'Manual' ? manualTriggerConfig : null + scheduleTriggerConfig: triggerType == 'Schedule' ? scheduleTriggerConfig : null + replicaRetryLimit: replicaRetryLimit + replicaTimeout: replicaTimeout + registries: registries + secrets: secretList + triggerType: triggerType + } + template: { + containers: containers + initContainers: initContainersTemplate + volumes: volumes + } + workloadProfileName: workloadProfileName + } +} + +resource job_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: job +} + +resource automationAccount_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (roleAssignments ?? []): { + name: guid(job.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) + properties: { + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) + ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] + : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: job + } +] +@description('The resource ID of the Container App Job.') +output resourceId string = job.id + +@description('The name of the resource group the Container App Job was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the Container App Job.') +output name string = job.name + +@description('The location the resource was deployed into.') +output location string = job.location + +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string = job.?identity.?principalId ?? '' + +// =============== // +// Definitions // +// =============== // + +type managedIdentitiesType = { + @description('Optional. Enables system assigned managed identity on the resource.') + systemAssigned: bool? + + @description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourceIds: string[]? +}? + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @description('Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/res/app/job/main.json b/avm/res/app/job/main.json new file mode 100644 index 00000000000..6d8ee06c25b --- /dev/null +++ b/avm/res/app/job/main.json @@ -0,0 +1,406 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.27.1.19265", + "templateHash": "11649443218681434280" + }, + "name": "Container App Jobs", + "description": "This module deploys a Container App Job.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "registries": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "containers": { + "type": "array", + "metadata": { + "description": "Required. List of container definitions for the Container App." + } + }, + "initContainersTemplate": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of specialized containers that run before app containers." + } + }, + "eventTriggerConfig": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Required if TriggerType is Event. Configuration of an event driven job." + } + }, + "scheduleTriggerConfig": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Required if TriggerType is Schedule. Configuration of a schedule based job." + } + }, + "manualTriggerConfig": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Required if TriggerType is Manual. Configuration of a manual job." + } + }, + "replicaRetryLimit": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. The maximum number of times a replica can be retried." + } + }, + "workloadProfileName": { + "type": "string", + "defaultValue": "Consumption", + "metadata": { + "description": "Optional. The name of the workload profile to use." + } + }, + "secrets": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "volumes": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of volume definitions for the Container App." + } + }, + "replicaTimeout": { + "type": "int", + "defaultValue": 1800, + "metadata": { + "description": "Optional. Maximum number of seconds a replica is allowed to run." + } + }, + "triggerType": { + "type": "string", + "allowedValues": [ + "Event", + "Manual", + "Schedule" + ], + "metadata": { + "description": "Required. Trigger type of the job." + } + } + }, + "variables": { + "secretList": "[tryGet(parameters('secrets'), 'secureList')]", + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.app-job.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "job": { + "type": "Microsoft.App/jobs", + "apiVersion": "2023-05-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "configuration": { + "eventTriggerConfig": "[if(equals(parameters('triggerType'), 'Event'), parameters('eventTriggerConfig'), null())]", + "manualTriggerConfig": "[if(equals(parameters('triggerType'), 'Manual'), parameters('manualTriggerConfig'), null())]", + "scheduleTriggerConfig": "[if(equals(parameters('triggerType'), 'Schedule'), parameters('scheduleTriggerConfig'), null())]", + "replicaRetryLimit": "[parameters('replicaRetryLimit')]", + "replicaTimeout": "[parameters('replicaTimeout')]", + "registries": "[parameters('registries')]", + "secrets": "[variables('secretList')]", + "triggerType": "[parameters('triggerType')]" + }, + "template": { + "containers": "[parameters('containers')]", + "initContainers": "[parameters('initContainersTemplate')]", + "volumes": "[parameters('volumes')]" + }, + "workloadProfileName": "[parameters('workloadProfileName')]" + } + }, + "job_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.App/jobs/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "job" + ] + }, + "automationAccount_roleAssignments": { + "copy": { + "name": "automationAccount_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.App/jobs/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.App/jobs', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "job" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App Job." + }, + "value": "[resourceId('Microsoft.App/jobs', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App Job was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App Job." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('job', '2023-05-01', 'full').location]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('job', '2023-05-01', 'full'), 'identity'), 'principalId'), '')]" + } + } +} \ No newline at end of file diff --git a/avm/res/app/job/tests/e2e/defaults/dependencies.bicep b/avm/res/app/job/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 00000000000..bb2af3d0f83 --- /dev/null +++ b/avm/res/app/job/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,21 @@ +@description('Required. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Environment to create.') +param managedEnvironmentName string + +resource managedEnvironment 'Microsoft.App/managedEnvironments@2023-05-01' = { + name: managedEnvironmentName + location: location + properties: { + workloadProfiles: [ + { + workloadProfileType: 'Consumption' + name: 'Consumption' + } + ] + } +} + +@description('The resource ID of the created Managed Environment.') +output managedEnvironmentResourceId string = managedEnvironment.id diff --git a/avm/res/app/job/tests/e2e/defaults/main.test.bicep b/avm/res/app/job/tests/e2e/defaults/main.test.bicep new file mode 100644 index 00000000000..546fa7c4c83 --- /dev/null +++ b/avm/res/app/job/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,74 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-app.job-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ajmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// =========== // +// Deployments // +// =========== // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-paramNested' + params: { + location: resourceLocation + managedEnvironmentName: 'dep-${namePrefix}-menv-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + environmentResourceId: nestedDependencies.outputs.managedEnvironmentResourceId + location: resourceLocation + triggerType: 'Manual' + manualTriggerConfig: { + replicaCompletionCount: 1 + parallelism: 1 + } + containers: [ + { + name: 'simple-hello-world-container' + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + resources: { + // workaround as 'float' values are not supported in Bicep, yet the resource providers expects them. Related issue: https://github.com/Azure/bicep/issues/1386 + cpu: json('0.25') + memory: '0.5Gi' + } + } + ] + } + } +] diff --git a/avm/res/app/job/tests/e2e/max/dependencies.bicep b/avm/res/app/job/tests/e2e/max/dependencies.bicep new file mode 100644 index 00000000000..b03d4aca931 --- /dev/null +++ b/avm/res/app/job/tests/e2e/max/dependencies.bicep @@ -0,0 +1,40 @@ +@description('Required. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Environment for Container Apps to create.') +param managedEnvironmentName string + +@description('Required. The name of the managed identity to create.') +param managedIdentityName string + +@description('Required. The name of the workload profile to create.') +param workloadProfileName string + +resource managedEnvironment 'Microsoft.App/managedEnvironments@2023-05-01' = { + name: managedEnvironmentName + location: location + properties: { + workloadProfiles: [ + { + name: workloadProfileName + workloadProfileType: 'D4' + maximumCount: 1 + minimumCount: 1 + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2022-01-31-preview' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created Managed Environment.') +output managedEnvironmentResourceId string = managedEnvironment.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/res/app/job/tests/e2e/max/main.test.bicep b/avm/res/app/job/tests/e2e/max/main.test.bicep new file mode 100644 index 00000000000..18ae51956b3 --- /dev/null +++ b/avm/res/app/job/tests/e2e/max/main.test.bicep @@ -0,0 +1,136 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-app.job-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ajmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// =========== // +// Deployments // +// =========== // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-paramNested' + params: { + location: resourceLocation + managedEnvironmentName: 'dep-${namePrefix}-menv-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + workloadProfileName: serviceShort + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + tags: { + 'hidden-title': 'This is visible in the resource name' + Env: 'test' + } + environmentResourceId: nestedDependencies.outputs.managedEnvironmentResourceId + workloadProfileName: serviceShort + location: resourceLocation + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + secrets: { + secureList: [ + { + name: 'customtest' + value: guid(deployment().name) + } + ] + } + triggerType: 'Manual' + manualTriggerConfig: { + replicaCompletionCount: 1 + parallelism: 1 + } + containers: [ + { + name: 'simple-hello-world-container' + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + resources: { + // workaround as 'float' values are not supported in Bicep, yet the resource providers expects them. Related issue: https://github.com/Azure/bicep/issues/1386 + cpu: json('0.25') + memory: '0.5Gi' + } + probes: [ + { + type: 'Liveness' + httpGet: { + path: '/health' + port: 8080 + httpHeaders: [ + { + name: 'Custom-Header' + value: 'Awesome' + } + ] + } + initialDelaySeconds: 3 + periodSeconds: 3 + } + ] + } + ] + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + } + } +] diff --git a/avm/res/app/job/tests/e2e/waf-aligned/dependencies.bicep b/avm/res/app/job/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 00000000000..b03d4aca931 --- /dev/null +++ b/avm/res/app/job/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,40 @@ +@description('Required. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Environment for Container Apps to create.') +param managedEnvironmentName string + +@description('Required. The name of the managed identity to create.') +param managedIdentityName string + +@description('Required. The name of the workload profile to create.') +param workloadProfileName string + +resource managedEnvironment 'Microsoft.App/managedEnvironments@2023-05-01' = { + name: managedEnvironmentName + location: location + properties: { + workloadProfiles: [ + { + name: workloadProfileName + workloadProfileType: 'D4' + maximumCount: 1 + minimumCount: 1 + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2022-01-31-preview' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created Managed Environment.') +output managedEnvironmentResourceId string = managedEnvironment.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/res/app/job/tests/e2e/waf-aligned/main.test.bicep b/avm/res/app/job/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 00000000000..93b2d344ab1 --- /dev/null +++ b/avm/res/app/job/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,98 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-app.job-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ajwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// =========== // +// Deployments // +// =========== // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-paramNested' + params: { + location: resourceLocation + managedEnvironmentName: 'dep-${namePrefix}-menv-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + workloadProfileName: serviceShort + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + tags: { + 'hidden-title': 'This is visible in the resource name' + Env: 'test' + } + environmentResourceId: nestedDependencies.outputs.managedEnvironmentResourceId + workloadProfileName: serviceShort + location: resourceLocation + triggerType: 'Manual' + manualTriggerConfig: { + replicaCompletionCount: 1 + parallelism: 1 + } + containers: [ + { + name: 'simple-hello-world-container' + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + resources: { + // workaround as 'float' values are not supported in Bicep, yet the resource providers expects them. Related issue: https://github.com/Azure/bicep/issues/1386 + cpu: json('0.25') + memory: '0.5Gi' + } + probes: [ + { + type: 'Liveness' + httpGet: { + path: '/health' + port: 8080 + httpHeaders: [ + { + name: 'Custom-Header' + value: 'Awesome' + } + ] + } + initialDelaySeconds: 3 + periodSeconds: 3 + } + ] + } + ] + } + } +] diff --git a/avm/res/app/job/version.json b/avm/res/app/job/version.json new file mode 100644 index 00000000000..7fa401bdf78 --- /dev/null +++ b/avm/res/app/job/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} From 25b69089e72243b2b5e4acb668350c7dbe44444e Mon Sep 17 00:00:00 2001 From: Erika Gressi <56914614+eriqua@users.noreply.github.com> Date: Sun, 12 May 2024 20:59:32 +0200 Subject: [PATCH 34/52] fix: Remove ptn readme (#1916) ## Description Remove ptn readme after the folder has been populated ## Pipeline Reference | Pipeline | | -------- | | | ## Type of Change - [x] Update to CI Environment or utlities (Non-module effecting 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. - [ ] 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 - [ ] I have run `Set-AVMModule` locally to generate the supporting module files. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/ptn/readme.md | 1 - 1 file changed, 1 deletion(-) delete mode 100644 avm/ptn/readme.md diff --git a/avm/ptn/readme.md b/avm/ptn/readme.md deleted file mode 100644 index 933815b8f84..00000000000 --- a/avm/ptn/readme.md +++ /dev/null @@ -1 +0,0 @@ -TODO: Add patterns From f859bf29347200da1c81208ef1db6377cb29da05 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Mon, 13 May 2024 14:44:13 +0200 Subject: [PATCH 35/52] fix: Added case handling for `loadFromFile()` functions that introduce generated variables in ARM JSON files (#1917) ## Description - When using a Bicep function like `loadFileAsBase64()` or `loadFromJson`, the compiled ARM template contains a generated variable with a name like `$fxv#1` or `$fxv#2` - This variable currently fails the Pester test 'Variable names should be camel-cased' - This PR updates the test by - Adding support for the aforementioned deterministic variable name - Updating the test to return the incorrect variables as opposed to just claim that there's at least one incorrect variable ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.key-vault.vault](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml/badge.svg?branch=users%2Falsehr%2FloadFromJson&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml) | | [![avm.res.storage.storage-account](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.storage.storage-account.yml/badge.svg?branch=users%2Falsehr%2FloadFromJson&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.storage.storage-account.yml) (Pester passed) | ## Type of Change - [x] Update to CI Environment or utlities (Non-module effecting 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. - [ ] 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 --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- .../compliance/module.tests.ps1 | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index e2df8ed6560..92e9b154c59 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -810,17 +810,17 @@ Describe 'Module tests' -Tag 'Module' { return } - $CamelCasingFlag = @() - $Variable = $templateFileContent.variables.Keys - - foreach ($Variab in $Variable) { - if ($Variab.substring(0, 1) -cnotmatch '[a-z]' -or $Variab -match '-') { - $CamelCasingFlag += $false - } else { - $CamelCasingFlag += $true + $incorrectVariables = @() + $Variables = $templateFileContent.variables.Keys + + foreach ($variable in $Variables) { + # ^[a-z]+[a-zA-Z]+$ = starts with lower-case letter & may have uppercase letter later + # ^\$fxv#[0-9]+$ = starts with [$fxv#] & ends with a number. This function value is created as a variable when using a Bicep function like loadFileAsBase64() or loadFromJson() + if ($variable -cnotmatch '^[a-z]+[a-zA-Z]+$|^\$fxv#[0-9]+$' -or $variable -match '-') { + $incorrectVariables += $variable } } - $CamelCasingFlag | Should -Not -Contain $false + $incorrectVariables | Should -BeNullOrEmpty } } From 65d14291291b3122d5e83619098f7ee5fd90b8aa Mon Sep 17 00:00:00 2001 From: Kris Baranek Date: Mon, 13 May 2024 20:38:03 +0200 Subject: [PATCH 36/52] feat: New Module `avm/res/communication/email-service` (#1582) ## Description New Module `avm/res/communication/email-service`. Related Module Proposal: https://github.com/Azure/Azure-Verified-Modules/issues/749 ## Adding a new module - [x] A proposal has been submitted and approved. - [ ] I have included "Closes #{module_proposal_issue_number}" in the PR description. - [ ] I have run `brm validate` locally to verify the module files. - [x] I have run deployment tests locally to ensure the module is deployable. ## Pipeline references | Pipeline | | - | | [![avm.res.communication.email-service](https://github.com/krbar/bicep-registry-modules/actions/workflows/avm.res.communication.email-service.yml/badge.svg?branch=users%2Fkrbar%2FemailSvcModule)](https://github.com/krbar/bicep-registry-modules/actions/workflows/avm.res.communication.email-service.yml) | --------- Co-authored-by: Alexander Sehr --- .github/CODEOWNERS | 1 + .github/ISSUE_TEMPLATE/avm_module_issue.yml | 1 + .../avm.res.communication.email-service.yml | 90 +++ avm/res/communication/email-service/README.md | 558 ++++++++++++++ .../email-service/domain/README.md | 255 ++++++ .../email-service/domain/main.bicep | 166 ++++ .../email-service/domain/main.json | 387 ++++++++++ .../domain/sender-username/README.md | 92 +++ .../domain/sender-username/main.bicep | 52 ++ .../domain/sender-username/main.json | 81 ++ .../communication/email-service/main.bicep | 179 +++++ avm/res/communication/email-service/main.json | 725 ++++++++++++++++++ .../tests/e2e/defaults/main.test.bicep | 49 ++ .../tests/e2e/max/dependencies.bicep | 13 + .../tests/e2e/max/main.test.bicep | 133 ++++ .../tests/e2e/waf-aligned/main.test.bicep | 54 ++ .../communication/email-service/version.json | 7 + 17 files changed, 2843 insertions(+) create mode 100644 .github/workflows/avm.res.communication.email-service.yml create mode 100644 avm/res/communication/email-service/README.md create mode 100644 avm/res/communication/email-service/domain/README.md create mode 100644 avm/res/communication/email-service/domain/main.bicep create mode 100644 avm/res/communication/email-service/domain/main.json create mode 100644 avm/res/communication/email-service/domain/sender-username/README.md create mode 100644 avm/res/communication/email-service/domain/sender-username/main.bicep create mode 100644 avm/res/communication/email-service/domain/sender-username/main.json create mode 100644 avm/res/communication/email-service/main.bicep create mode 100644 avm/res/communication/email-service/main.json create mode 100644 avm/res/communication/email-service/tests/e2e/defaults/main.test.bicep create mode 100644 avm/res/communication/email-service/tests/e2e/max/dependencies.bicep create mode 100644 avm/res/communication/email-service/tests/e2e/max/main.test.bicep create mode 100644 avm/res/communication/email-service/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/res/communication/email-service/version.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 893e030b61b..217d9d8f8cc 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -24,6 +24,7 @@ /avm/res/cache/redis/ @Azure/avm-res-cache-redis-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/cdn/profile/ @Azure/avm-res-cdn-profile-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/cognitive-services/account/ @Azure/avm-res-cognitiveservices-account-module-owners-bicep @Azure/avm-core-team-technical-bicep +/avm/res/communication/email-service/ @Azure/avm-res-communication-emailservice-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/compute/availability-set/ @Azure/avm-res-compute-availabilityset-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/compute/disk/ @Azure/avm-res-compute-disk-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/compute/disk-encryption-set/ @Azure/avm-res-compute-diskencryptionset-module-owners-bicep @Azure/avm-core-team-technical-bicep diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index bd18fad337c..9765814bacb 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -58,6 +58,7 @@ body: - "avm/res/cache/redis" - "avm/res/cdn/profile" - "avm/res/cognitive-services/account" + - "avm/res/communication/email-service" - "avm/res/compute/availability-set" - "avm/res/compute/disk" - "avm/res/compute/disk-encryption-set" diff --git a/.github/workflows/avm.res.communication.email-service.yml b/.github/workflows/avm.res.communication.email-service.yml new file mode 100644 index 00000000000..f47e87b1390 --- /dev/null +++ b/.github/workflows/avm.res.communication.email-service.yml @@ -0,0 +1,90 @@ +name: "avm.res.communication.email-service" + +on: + schedule: + - cron: "0 12 1/15 * *" # Bi-Weekly Test (on 1st & 15th of month) + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: "Execute static validation" + required: false + default: true + deploymentValidation: + type: boolean + description: "Execute deployment validation" + required: false + default: true + removeDeployment: + type: boolean + description: "Remove deployed module" + required: false + default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.res.communication.email-service.yml" + - "avm/res/communication/email-service/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/res/communication/email-service" + workflowPath: ".github/workflows/avm.res.communication.email-service.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-latest + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get module test file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Run" + permissions: + id-token: write # For OIDC + contents: write # For release tags + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit diff --git a/avm/res/communication/email-service/README.md b/avm/res/communication/email-service/README.md new file mode 100644 index 00000000000..92df127665b --- /dev/null +++ b/avm/res/communication/email-service/README.md @@ -0,0 +1,558 @@ +# Email Services `[Microsoft.Communication/emailServices]` + +This module deploys an Email Service + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Communication/emailServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Communication/emailServices) | +| `Microsoft.Communication/emailServices/domains` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Communication/emailServices/domains) | +| `Microsoft.Communication/emailServices/domains/senderUsernames` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Communication/emailServices/domains/senderUsernames) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/communication/email-service:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module emailService 'br/public:avm/res/communication/email-service:' = { + name: 'emailServiceDeployment' + params: { + // Required parameters + dataLocation: 'Europe' + name: 'cesmin001' + // Non-required parameters + location: 'global' + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "dataLocation": { + "value": "Europe" + }, + "name": { + "value": "cesmin001" + }, + // Non-required parameters + "location": { + "value": "global" + } + } +} +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module emailService 'br/public:avm/res/communication/email-service:' = { + name: 'emailServiceDeployment' + params: { + // Required parameters + dataLocation: 'United States' + name: 'cesmax001' + // Non-required parameters + domains: [ + { + domainManagement: 'AzureManaged' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + name: 'AzureManagedDomain' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + senderUsernames: [ + { + displayName: 'Do Not Reply' + name: 'donotreply' + userName: 'DoNotReply' + } + { + displayName: 'Customer Service' + name: 'customerservice' + userName: 'CustomerService' + } + ] + tags: { + Role: 'DeploymentValidation' + } + userEngagementTracking: 'Enabled' + } + ] + location: 'global' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "dataLocation": { + "value": "United States" + }, + "name": { + "value": "cesmax001" + }, + // Non-required parameters + "domains": { + "value": [ + { + "domainManagement": "AzureManaged", + "lock": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + }, + "name": "AzureManagedDomain", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "senderUsernames": [ + { + "displayName": "Do Not Reply", + "name": "donotreply", + "userName": "DoNotReply" + }, + { + "displayName": "Customer Service", + "name": "customerservice", + "userName": "CustomerService" + } + ], + "tags": { + "Role": "DeploymentValidation" + }, + "userEngagementTracking": "Enabled" + } + ] + }, + "location": { + "value": "global" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module emailService 'br/public:avm/res/communication/email-service:' = { + name: 'emailServiceDeployment' + params: { + // Required parameters + dataLocation: 'Germany' + name: 'ceswaf001' + // Non-required parameters + location: 'global' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "dataLocation": { + "value": "Germany" + }, + "name": { + "value": "ceswaf001" + }, + // Non-required parameters + "location": { + "value": "global" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dataLocation`](#parameter-datalocation) | string | The location where the communication service stores its data at rest. | +| [`name`](#parameter-name) | string | Name of the email service to create. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`domains`](#parameter-domains) | array | The domains to deploy into this namespace. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Endpoint tags. | + +### Parameter: `dataLocation` + +The location where the communication service stores its data at rest. + +- Required: Yes +- Type: string + +### Parameter: `name` + +Name of the email service to create. + +- Required: Yes +- Type: string + +### Parameter: `domains` + +The domains to deploy into this namespace. + +- Required: No +- Type: array + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `'global'` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Endpoint tags. + +- Required: No +- Type: object + + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `domainNamess` | array | The list of the email domain names. | +| `domainResourceIds` | array | The list of the email domain resource ids. | +| `location` | string | The location the email service was deployed into. | +| `name` | string | The name of the email service. | +| `resourceGroupName` | string | The resource group the email service was deployed into. | +| `resourceId` | string | The resource ID of the email service. | + +## Cross-referenced modules + +_None_ + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/res/communication/email-service/domain/README.md b/avm/res/communication/email-service/domain/README.md new file mode 100644 index 00000000000..47e8dd60c2c --- /dev/null +++ b/avm/res/communication/email-service/domain/README.md @@ -0,0 +1,255 @@ +# Email Services Domains `[Microsoft.Communication/emailServices/domains]` + +This module deploys an Email Service Domain + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Communication/emailServices/domains` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Communication/emailServices/domains) | +| `Microsoft.Communication/emailServices/domains/senderUsernames` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Communication/emailServices/domains/senderUsernames) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the domain to create. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`emailServiceName`](#parameter-emailservicename) | string | The name of the parent email service. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`domainManagement`](#parameter-domainmanagement) | string | Describes how the Domain resource is being managed. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`senderUsernames`](#parameter-senderusernames) | array | The domains to deploy into this namespace. | +| [`tags`](#parameter-tags) | object | Endpoint tags. | +| [`userEngagementTracking`](#parameter-userengagementtracking) | string | Describes whether user engagement tracking is enabled or disabled. | + +### Parameter: `name` + +Name of the domain to create. + +- Required: Yes +- Type: string + +### Parameter: `emailServiceName` + +The name of the parent email service. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `domainManagement` + +Describes how the Domain resource is being managed. + +- Required: No +- Type: string +- Default: `'AzureManaged'` +- Allowed: + ```Bicep + [ + 'AzureManaged' + 'CustomerManaged' + 'CustomerManagedInExchangeOnline' + ] + ``` + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `'global'` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `senderUsernames` + +The domains to deploy into this namespace. + +- Required: No +- Type: array + +### Parameter: `tags` + +Endpoint tags. + +- Required: No +- Type: object + +### Parameter: `userEngagementTracking` + +Describes whether user engagement tracking is enabled or disabled. + +- Required: No +- Type: string +- Default: `'Disabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the domain. | +| `resourceGroupName` | string | The name of the resource group the domain was created in. | +| `resourceId` | string | The resource ID of the domain. | + +## Cross-referenced modules + +_None_ + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/res/communication/email-service/domain/main.bicep b/avm/res/communication/email-service/domain/main.bicep new file mode 100644 index 00000000000..ebb7598e329 --- /dev/null +++ b/avm/res/communication/email-service/domain/main.bicep @@ -0,0 +1,166 @@ +metadata name = 'Email Services Domains' +metadata description = 'This module deploys an Email Service Domain' +metadata owner = 'Azure/module-maintainers' + +@description('Conditional. The name of the parent email service. Required if the template is used in a standalone deployment.') +param emailServiceName string + +@minLength(1) +@maxLength(253) +@description('Required. Name of the domain to create.') +param name string + +@description('Optional. Location for all Resources.') +param location string = 'global' + +@description('Optional. Endpoint tags.') +param tags object? + +@allowed([ + 'AzureManaged' + 'CustomerManaged' + 'CustomerManagedInExchangeOnline' +]) +@description('Optional. Describes how the Domain resource is being managed.') +param domainManagement string = 'AzureManaged' + +@allowed([ + 'Enabled' + 'Disabled' +]) +@description('Optional. Describes whether user engagement tracking is enabled or disabled.') +param userEngagementTracking string = 'Disabled' + +@description('Optional. The domains to deploy into this namespace.') +param senderUsernames array? + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator (Preview)': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +// ============== // +// Resources // +// ============== // + +resource emailService 'Microsoft.Communication/emailServices@2023-04-01' existing = { + name: emailServiceName +} + +resource domain 'Microsoft.Communication/emailServices/domains@2023-04-01' = { + name: name + location: location + tags: tags + parent: emailService + properties: { + domainManagement: domainManagement + userEngagementTracking: userEngagementTracking + } +} + +module domain_senderUsernames 'sender-username/main.bicep' = [ + for (senderUsername, index) in senderUsernames ?? []: { + name: '${uniqueString(deployment().name, location)}-domain-senderusername-${index}' + params: { + emailServiceName: emailService.name + domainName: domain.name + name: senderUsername.name + username: senderUsername.username + displayName: senderUsername.?displayName + } + } +] + +resource domain_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: domain +} + +resource domain_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (roleAssignments ?? []): { + name: guid(domain.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) + properties: { + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) + ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] + : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: domain + } +] + +// ============ // +// Outputs // +// ============ // + +@description('The name of the domain.') +output name string = domain.name + +@description('The resource ID of the domain.') +output resourceId string = domain.id + +@description('The name of the resource group the domain was created in.') +output resourceGroupName string = resourceGroup().name + +// ================ // +// Definitions // +// ================ // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @description('Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/res/communication/email-service/domain/main.json b/avm/res/communication/email-service/domain/main.json new file mode 100644 index 00000000000..bf95f4c8ac3 --- /dev/null +++ b/avm/res/communication/email-service/domain/main.json @@ -0,0 +1,387 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.26.170.59819", + "templateHash": "3536602426579825020" + }, + "name": "Email Services Domains", + "description": "This module deploys an Email Service Domain", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "emailServiceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent email service. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 253, + "metadata": { + "description": "Required. Name of the domain to create." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Endpoint tags." + } + }, + "domainManagement": { + "type": "string", + "defaultValue": "AzureManaged", + "allowedValues": [ + "AzureManaged", + "CustomerManaged", + "CustomerManagedInExchangeOnline" + ], + "metadata": { + "description": "Optional. Describes how the Domain resource is being managed." + } + }, + "userEngagementTracking": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Describes whether user engagement tracking is enabled or disabled." + } + }, + "senderUsernames": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The domains to deploy into this namespace." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "emailService": { + "existing": true, + "type": "Microsoft.Communication/emailServices", + "apiVersion": "2023-04-01", + "name": "[parameters('emailServiceName')]" + }, + "domain": { + "type": "Microsoft.Communication/emailServices/domains", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('emailServiceName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "domainManagement": "[parameters('domainManagement')]", + "userEngagementTracking": "[parameters('userEngagementTracking')]" + }, + "dependsOn": [ + "emailService" + ] + }, + "domain_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Communication/emailServices/{0}/domains/{1}', parameters('emailServiceName'), parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "domain" + ] + }, + "domain_roleAssignments": { + "copy": { + "name": "domain_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Communication/emailServices/{0}/domains/{1}', parameters('emailServiceName'), parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Communication/emailServices/domains', parameters('emailServiceName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "domain" + ] + }, + "domain_senderUsernames": { + "copy": { + "name": "domain_senderUsernames", + "count": "[length(coalesce(parameters('senderUsernames'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-domain-senderusername-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "emailServiceName": { + "value": "[parameters('emailServiceName')]" + }, + "domainName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('senderUsernames'), createArray())[copyIndex()].name]" + }, + "username": { + "value": "[coalesce(parameters('senderUsernames'), createArray())[copyIndex()].username]" + }, + "displayName": { + "value": "[tryGet(coalesce(parameters('senderUsernames'), createArray())[copyIndex()], 'displayName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.26.170.59819", + "templateHash": "11776160114645029549" + }, + "name": "Sender Usernames", + "description": "This module deploys an Sender", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "emailServiceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent email service. Required if the template is used in a standalone deployment." + } + }, + "domainName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent domain. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the sender username resource to create." + } + }, + "username": { + "type": "string", + "metadata": { + "description": "Required. A sender username to be used when sending emails." + } + }, + "displayName": { + "type": "string", + "defaultValue": "[parameters('username')]", + "metadata": { + "description": "Optional. The display name for the senderUsername." + } + } + }, + "resources": [ + { + "type": "Microsoft.Communication/emailServices/domains/senderUsernames", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}/{2}', parameters('emailServiceName'), parameters('domainName'), parameters('name'))]", + "properties": { + "username": "[parameters('username')]", + "displayName": "[parameters('displayName')]" + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the sender username." + }, + "value": "[resourceId('Microsoft.Communication/emailServices/domains/senderUsernames', parameters('emailServiceName'), parameters('domainName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the sender username." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the sender username was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "domain", + "emailService" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the domain." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the domain." + }, + "value": "[resourceId('Microsoft.Communication/emailServices/domains', parameters('emailServiceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the domain was created in." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/res/communication/email-service/domain/sender-username/README.md b/avm/res/communication/email-service/domain/sender-username/README.md new file mode 100644 index 00000000000..4ddec4e68bd --- /dev/null +++ b/avm/res/communication/email-service/domain/sender-username/README.md @@ -0,0 +1,92 @@ +# Sender Usernames `[Microsoft.Communication/emailServices/domains/senderUsernames]` + +This module deploys an Sender + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Communication/emailServices/domains/senderUsernames` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Communication/emailServices/domains/senderUsernames) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the sender username resource to create. | +| [`username`](#parameter-username) | string | A sender username to be used when sending emails. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`domainName`](#parameter-domainname) | string | The name of the parent domain. Required if the template is used in a standalone deployment. | +| [`emailServiceName`](#parameter-emailservicename) | string | The name of the parent email service. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`displayName`](#parameter-displayname) | string | The display name for the senderUsername. | + +### Parameter: `name` + +Name of the sender username resource to create. + +- Required: Yes +- Type: string + +### Parameter: `username` + +A sender username to be used when sending emails. + +- Required: Yes +- Type: string + +### Parameter: `domainName` + +The name of the parent domain. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `emailServiceName` + +The name of the parent email service. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `displayName` + +The display name for the senderUsername. + +- Required: No +- Type: string +- Default: `[parameters('username')]` + + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the sender username. | +| `resourceGroupName` | string | The name of the resource group the sender username was created in. | +| `resourceId` | string | The resource ID of the sender username. | + +## Cross-referenced modules + +_None_ + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/res/communication/email-service/domain/sender-username/main.bicep b/avm/res/communication/email-service/domain/sender-username/main.bicep new file mode 100644 index 00000000000..37c9c82562b --- /dev/null +++ b/avm/res/communication/email-service/domain/sender-username/main.bicep @@ -0,0 +1,52 @@ +metadata name = 'Sender Usernames' +metadata description = 'This module deploys an Sender' +metadata owner = 'Azure/module-maintainers' + +@description('Conditional. The name of the parent email service. Required if the template is used in a standalone deployment.') +param emailServiceName string + +@description('Conditional. The name of the parent domain. Required if the template is used in a standalone deployment.') +param domainName string + +@description('Required. Name of the sender username resource to create.') +param name string + +@description('Required. A sender username to be used when sending emails.') +param username string + +@description('Optional. The display name for the senderUsername.') +param displayName string = username + +// ============== // +// Resources // +// ============== // + +resource emailService 'Microsoft.Communication/emailServices@2023-04-01' existing = { + name: emailServiceName + + resource domain 'domains@2023-04-01' existing = { + name: domainName + } +} + +resource senderUsername 'Microsoft.Communication/emailServices/domains/senderUsernames@2023-04-01' = { + name: name + parent: emailService::domain + properties: { + username: username + displayName: displayName + } +} + +// ============ // +// Outputs // +// ============ // + +@description('The resource ID of the sender username.') +output resourceId string = senderUsername.id + +@description('The name of the sender username.') +output name string = senderUsername.name + +@description('The name of the resource group the sender username was created in.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/res/communication/email-service/domain/sender-username/main.json b/avm/res/communication/email-service/domain/sender-username/main.json new file mode 100644 index 00000000000..48abd0ade62 --- /dev/null +++ b/avm/res/communication/email-service/domain/sender-username/main.json @@ -0,0 +1,81 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.26.170.59819", + "templateHash": "11776160114645029549" + }, + "name": "Sender Usernames", + "description": "This module deploys an Sender", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "emailServiceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent email service. Required if the template is used in a standalone deployment." + } + }, + "domainName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent domain. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the sender username resource to create." + } + }, + "username": { + "type": "string", + "metadata": { + "description": "Required. A sender username to be used when sending emails." + } + }, + "displayName": { + "type": "string", + "defaultValue": "[parameters('username')]", + "metadata": { + "description": "Optional. The display name for the senderUsername." + } + } + }, + "resources": [ + { + "type": "Microsoft.Communication/emailServices/domains/senderUsernames", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}/{2}', parameters('emailServiceName'), parameters('domainName'), parameters('name'))]", + "properties": { + "username": "[parameters('username')]", + "displayName": "[parameters('displayName')]" + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the sender username." + }, + "value": "[resourceId('Microsoft.Communication/emailServices/domains/senderUsernames', parameters('emailServiceName'), parameters('domainName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the sender username." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the sender username was created in." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/res/communication/email-service/main.bicep b/avm/res/communication/email-service/main.bicep new file mode 100644 index 00000000000..15492649fd2 --- /dev/null +++ b/avm/res/communication/email-service/main.bicep @@ -0,0 +1,179 @@ +metadata name = 'Email Services' +metadata description = 'This module deploys an Email Service' +metadata owner = 'Azure/module-maintainers' + +@minLength(1) +@maxLength(63) +@description('Required. Name of the email service to create.') +param name string + +@description('Optional. Location for all Resources.') +param location string = 'global' + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Endpoint tags.') +param tags object? + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Required. The location where the communication service stores its data at rest.') +param dataLocation string + +@description('Optional. The domains to deploy into this namespace.') +param domains array? + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator (Preview)': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +// ============== // +// Resources // +// ============== // + +resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = if (enableTelemetry) { + name: '46d3xbcp.res.communication-emailservice.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource email 'Microsoft.Communication/emailServices@2023-04-01' = { + name: name + location: location + tags: tags + properties: { + dataLocation: dataLocation + } +} + +module email_domains 'domain/main.bicep' = [ + for (domain, index) in (domains ?? []): { + name: '${uniqueString(deployment().name, location)}-email-domain-${index}' + params: { + emailServiceName: email.name + name: domain.name + location: location + domainManagement: domain.?domainManagement + userEngagementTracking: domain.?userEngagementTracking + senderUsernames: domain.?senderUsernames + roleAssignments: domain.?roleAssignments + lock: domain.?lock ?? lock + tags: domain.?tags ?? tags + } + } +] + +resource email_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: email +} + +resource email_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (roleAssignments ?? []): { + name: guid(email.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) + properties: { + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) + ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] + : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: email + } +] + +// ============ // +// Outputs // +// ============ // + +@description('The name of the email service.') +output name string = email.name + +@description('The resource ID of the email service.') +output resourceId string = email.id + +@description('The resource group the email service was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The location the email service was deployed into.') +output location string = email.location + +@description('The list of the email domain resource ids.') +output domainResourceIds array = [for (domain, index) in (domains ?? []): email_domains[index].outputs.resourceId] + +@description('The list of the email domain names.') +output domainNamess array = [for (domain, index) in (domains ?? []): email_domains[index].outputs.name] + +// ================ // +// Definitions // +// ================ // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @description('Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/res/communication/email-service/main.json b/avm/res/communication/email-service/main.json new file mode 100644 index 00000000000..815b3a746ad --- /dev/null +++ b/avm/res/communication/email-service/main.json @@ -0,0 +1,725 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.26.170.59819", + "templateHash": "17252916584930209182" + }, + "name": "Email Services", + "description": "This module deploys an Email Service", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 63, + "metadata": { + "description": "Required. Name of the email service to create." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Endpoint tags." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "dataLocation": { + "type": "string", + "metadata": { + "description": "Required. The location where the communication service stores its data at rest." + } + }, + "domains": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The domains to deploy into this namespace." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.communication-emailservice.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "email": { + "type": "Microsoft.Communication/emailServices", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "dataLocation": "[parameters('dataLocation')]" + } + }, + "email_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Communication/emailServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "email" + ] + }, + "email_roleAssignments": { + "copy": { + "name": "email_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Communication/emailServices/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Communication/emailServices', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "email" + ] + }, + "email_domains": { + "copy": { + "name": "email_domains", + "count": "[length(coalesce(parameters('domains'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-email-domain-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "emailServiceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('domains'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[parameters('location')]" + }, + "domainManagement": { + "value": "[tryGet(coalesce(parameters('domains'), createArray())[copyIndex()], 'domainManagement')]" + }, + "userEngagementTracking": { + "value": "[tryGet(coalesce(parameters('domains'), createArray())[copyIndex()], 'userEngagementTracking')]" + }, + "senderUsernames": { + "value": "[tryGet(coalesce(parameters('domains'), createArray())[copyIndex()], 'senderUsernames')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('domains'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('domains'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('domains'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.26.170.59819", + "templateHash": "3536602426579825020" + }, + "name": "Email Services Domains", + "description": "This module deploys an Email Service Domain", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "emailServiceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent email service. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 253, + "metadata": { + "description": "Required. Name of the domain to create." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Endpoint tags." + } + }, + "domainManagement": { + "type": "string", + "defaultValue": "AzureManaged", + "allowedValues": [ + "AzureManaged", + "CustomerManaged", + "CustomerManagedInExchangeOnline" + ], + "metadata": { + "description": "Optional. Describes how the Domain resource is being managed." + } + }, + "userEngagementTracking": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Describes whether user engagement tracking is enabled or disabled." + } + }, + "senderUsernames": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The domains to deploy into this namespace." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "emailService": { + "existing": true, + "type": "Microsoft.Communication/emailServices", + "apiVersion": "2023-04-01", + "name": "[parameters('emailServiceName')]" + }, + "domain": { + "type": "Microsoft.Communication/emailServices/domains", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('emailServiceName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "domainManagement": "[parameters('domainManagement')]", + "userEngagementTracking": "[parameters('userEngagementTracking')]" + }, + "dependsOn": [ + "emailService" + ] + }, + "domain_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Communication/emailServices/{0}/domains/{1}', parameters('emailServiceName'), parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "domain" + ] + }, + "domain_roleAssignments": { + "copy": { + "name": "domain_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Communication/emailServices/{0}/domains/{1}', parameters('emailServiceName'), parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Communication/emailServices/domains', parameters('emailServiceName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "domain" + ] + }, + "domain_senderUsernames": { + "copy": { + "name": "domain_senderUsernames", + "count": "[length(coalesce(parameters('senderUsernames'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-domain-senderusername-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "emailServiceName": { + "value": "[parameters('emailServiceName')]" + }, + "domainName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('senderUsernames'), createArray())[copyIndex()].name]" + }, + "username": { + "value": "[coalesce(parameters('senderUsernames'), createArray())[copyIndex()].username]" + }, + "displayName": { + "value": "[tryGet(coalesce(parameters('senderUsernames'), createArray())[copyIndex()], 'displayName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.26.170.59819", + "templateHash": "11776160114645029549" + }, + "name": "Sender Usernames", + "description": "This module deploys an Sender", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "emailServiceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent email service. Required if the template is used in a standalone deployment." + } + }, + "domainName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent domain. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the sender username resource to create." + } + }, + "username": { + "type": "string", + "metadata": { + "description": "Required. A sender username to be used when sending emails." + } + }, + "displayName": { + "type": "string", + "defaultValue": "[parameters('username')]", + "metadata": { + "description": "Optional. The display name for the senderUsername." + } + } + }, + "resources": [ + { + "type": "Microsoft.Communication/emailServices/domains/senderUsernames", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}/{2}', parameters('emailServiceName'), parameters('domainName'), parameters('name'))]", + "properties": { + "username": "[parameters('username')]", + "displayName": "[parameters('displayName')]" + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the sender username." + }, + "value": "[resourceId('Microsoft.Communication/emailServices/domains/senderUsernames', parameters('emailServiceName'), parameters('domainName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the sender username." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the sender username was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "domain", + "emailService" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the domain." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the domain." + }, + "value": "[resourceId('Microsoft.Communication/emailServices/domains', parameters('emailServiceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the domain was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "email" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the email service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the email service." + }, + "value": "[resourceId('Microsoft.Communication/emailServices', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the email service was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the email service was deployed into." + }, + "value": "[reference('email', '2023-04-01', 'full').location]" + }, + "domainResourceIds": { + "type": "array", + "metadata": { + "description": "The list of the email domain resource ids." + }, + "copy": { + "count": "[length(coalesce(parameters('domains'), createArray()))]", + "input": "[reference(format('email_domains[{0}]', copyIndex())).outputs.resourceId.value]" + } + }, + "domainNamess": { + "type": "array", + "metadata": { + "description": "The list of the email domain names." + }, + "copy": { + "count": "[length(coalesce(parameters('domains'), createArray()))]", + "input": "[reference(format('email_domains[{0}]', copyIndex())).outputs.name.value]" + } + } + } +} \ No newline at end of file diff --git a/avm/res/communication/email-service/tests/e2e/defaults/main.test.bicep b/avm/res/communication/email-service/tests/e2e/defaults/main.test.bicep new file mode 100644 index 00000000000..52182833301 --- /dev/null +++ b/avm/res/communication/email-service/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,49 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-communication.emailservice-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cesmin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: 'global' + dataLocation: 'Europe' + } + } +] diff --git a/avm/res/communication/email-service/tests/e2e/max/dependencies.bicep b/avm/res/communication/email-service/tests/e2e/max/dependencies.bicep new file mode 100644 index 00000000000..d3677704327 --- /dev/null +++ b/avm/res/communication/email-service/tests/e2e/max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/res/communication/email-service/tests/e2e/max/main.test.bicep b/avm/res/communication/email-service/tests/e2e/max/main.test.bicep new file mode 100644 index 00000000000..b0b7e59d7f7 --- /dev/null +++ b/avm/res/communication/email-service/tests/e2e/max/main.test.bicep @@ -0,0 +1,133 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-communication.emailservice-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cesmax' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: 'global' + dataLocation: 'United States' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + domains: [ + { + name: 'AzureManagedDomain' + tags: { + Role: 'DeploymentValidation' + } + domainManagement: 'AzureManaged' + userEngagementTracking: 'Enabled' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + senderUsernames: [ + { + name: 'donotreply' + userName: 'DoNotReply' + displayName: 'Do Not Reply' + } + { + name: 'customerservice' + userName: 'CustomerService' + displayName: 'Customer Service' + } + ] + } + ] + } + } +] diff --git a/avm/res/communication/email-service/tests/e2e/waf-aligned/main.test.bicep b/avm/res/communication/email-service/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 00000000000..0b064f161f3 --- /dev/null +++ b/avm/res/communication/email-service/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,54 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-communication.emailservice-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ceswaf' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: 'global' + dataLocation: 'Germany' + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/res/communication/email-service/version.json b/avm/res/communication/email-service/version.json new file mode 100644 index 00000000000..8def869edeb --- /dev/null +++ b/avm/res/communication/email-service/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} From d0204550c1837d3adecbcdd61845ea68ef138729 Mon Sep 17 00:00:00 2001 From: Kris Baranek Date: Tue, 14 May 2024 08:58:02 +0200 Subject: [PATCH 37/52] feat: New Module `avm/res/communication/communication-service` (#1605) ## Description New Module `avm/res/communication/communication-service`. Related Module Proposal: https://github.com/Azure/Azure-Verified-Modules/issues/748 ## Adding a new module - [x] A proposal has been submitted and approved. - [ ] I have included "Closes #{module_proposal_issue_number}" in the PR description. - [ ] I have run `brm validate` locally to verify the module files. - [x] I have run deployment tests locally to ensure the module is deployable. ## Pipeline references | Pipeline | | - | | [![avm.res.communication.communication-service](https://github.com/krbar/bicep-registry-modules/actions/workflows/avm.res.communication.communication-service.yml/badge.svg?branch=users%2Fkrbar%2FcommSvcModule)](https://github.com/krbar/bicep-registry-modules/actions/workflows/avm.res.communication.communication-service.yml) | --- .github/CODEOWNERS | 1 + .github/ISSUE_TEMPLATE/avm_module_issue.yml | 1 + ...es.communication.communication-service.yml | 90 +++ .../communication-service/README.md | 714 ++++++++++++++++++ .../communication-service/main.bicep | 263 +++++++ .../communication-service/main.json | 481 ++++++++++++ .../tests/e2e/defaults/main.test.bicep | 49 ++ .../tests/e2e/max/dependencies.bicep | 38 + .../tests/e2e/max/main.test.bicep | 125 +++ .../tests/e2e/waf-aligned/main.test.bicep | 74 ++ .../communication-service/version.json | 7 + 11 files changed, 1843 insertions(+) create mode 100644 .github/workflows/avm.res.communication.communication-service.yml create mode 100644 avm/res/communication/communication-service/README.md create mode 100644 avm/res/communication/communication-service/main.bicep create mode 100644 avm/res/communication/communication-service/main.json create mode 100644 avm/res/communication/communication-service/tests/e2e/defaults/main.test.bicep create mode 100644 avm/res/communication/communication-service/tests/e2e/max/dependencies.bicep create mode 100644 avm/res/communication/communication-service/tests/e2e/max/main.test.bicep create mode 100644 avm/res/communication/communication-service/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/res/communication/communication-service/version.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 217d9d8f8cc..730d31af409 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -24,6 +24,7 @@ /avm/res/cache/redis/ @Azure/avm-res-cache-redis-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/cdn/profile/ @Azure/avm-res-cdn-profile-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/cognitive-services/account/ @Azure/avm-res-cognitiveservices-account-module-owners-bicep @Azure/avm-core-team-technical-bicep +/avm/res/communication/communication-service/ @Azure/avm-res-communication-communicationservice-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/communication/email-service/ @Azure/avm-res-communication-emailservice-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/compute/availability-set/ @Azure/avm-res-compute-availabilityset-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/compute/disk/ @Azure/avm-res-compute-disk-module-owners-bicep @Azure/avm-core-team-technical-bicep diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index 9765814bacb..43e4d477db4 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -58,6 +58,7 @@ body: - "avm/res/cache/redis" - "avm/res/cdn/profile" - "avm/res/cognitive-services/account" + - "avm/res/communication/communication-service" - "avm/res/communication/email-service" - "avm/res/compute/availability-set" - "avm/res/compute/disk" diff --git a/.github/workflows/avm.res.communication.communication-service.yml b/.github/workflows/avm.res.communication.communication-service.yml new file mode 100644 index 00000000000..0679579e9ab --- /dev/null +++ b/.github/workflows/avm.res.communication.communication-service.yml @@ -0,0 +1,90 @@ +name: "avm.res.communication.communication-service" + +on: + schedule: + - cron: "0 12 1/15 * *" # Bi-Weekly Test (on 1st & 15th of month) + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: "Execute static validation" + required: false + default: true + deploymentValidation: + type: boolean + description: "Execute deployment validation" + required: false + default: true + removeDeployment: + type: boolean + description: "Remove deployed module" + required: false + default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.res.communication.communication-service.yml" + - "avm/res/communication/communication-service/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/res/communication/communication-service" + workflowPath: ".github/workflows/avm.res.communication.communication-service.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-latest + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get module test file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Run" + permissions: + id-token: write # For OIDC + contents: write # For release tags + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit diff --git a/avm/res/communication/communication-service/README.md b/avm/res/communication/communication-service/README.md new file mode 100644 index 00000000000..5370ac81fb5 --- /dev/null +++ b/avm/res/communication/communication-service/README.md @@ -0,0 +1,714 @@ +# Communication Services `[Microsoft.Communication/communicationServices]` + +This module deploys a Communication Service + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Communication/communicationServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Communication/communicationServices) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/communication/communication-service:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module communicationService 'br/public:avm/res/communication/communication-service:' = { + name: 'communicationServiceDeployment' + params: { + // Required parameters + dataLocation: 'Germany' + name: 'ccsmin001' + // Non-required parameters + location: 'global' + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "dataLocation": { + "value": "Germany" + }, + "name": { + "value": "ccsmin001" + }, + // Non-required parameters + "location": { + "value": "global" + } + } +} +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module communicationService 'br/public:avm/res/communication/communication-service:' = { + name: 'communicationServiceDeployment' + params: { + // Required parameters + dataLocation: 'Germany' + name: 'ccsmax001' + // Non-required parameters + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + linkedDomains: [ + '' + ] + location: 'global' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + managedIdentities: { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] + } + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "dataLocation": { + "value": "Germany" + }, + "name": { + "value": "ccsmax001" + }, + // Non-required parameters + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "linkedDomains": { + "value": [ + "" + ] + }, + "location": { + "value": "global" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "managedIdentities": { + "value": { + "systemAssigned": false, + "userAssignedResourceIds": [ + "" + ] + } + }, + "roleAssignments": { + "value": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module communicationService 'br/public:avm/res/communication/communication-service:' = { + name: 'communicationServiceDeployment' + params: { + // Required parameters + dataLocation: 'Germany' + name: 'ccswaf001' + // Non-required parameters + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + location: 'global' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "dataLocation": { + "value": "Germany" + }, + "name": { + "value": "ccswaf001" + }, + // Non-required parameters + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "location": { + "value": "global" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dataLocation`](#parameter-datalocation) | string | The location where the communication service stores its data at rest. | +| [`name`](#parameter-name) | string | Name of the communication service to create. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`linkedDomains`](#parameter-linkeddomains) | array | List of email Domain resource Ids. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Resource tags. | + +### Parameter: `dataLocation` + +The location where the communication service stores its data at rest. + +- Required: Yes +- Type: string + +### Parameter: `name` + +Name of the communication service to create. + +- Required: Yes +- Type: string + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | string | Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-diagnosticsettingsmetriccategoriesenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string + +### Parameter: `diagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.name` + +The name of diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `linkedDomains` + +List of email Domain resource Ids. + +- Required: No +- Type: array + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `'global'` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `managedIdentities` + +The managed identity definition for this resource. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`systemAssigned`](#parameter-managedidentitiessystemassigned) | bool | Enables system assigned managed identity on the resource. | +| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. | + +### Parameter: `managedIdentities.systemAssigned` + +Enables system assigned managed identity on the resource. + +- Required: No +- Type: bool + +### Parameter: `managedIdentities.userAssignedResourceIds` + +The resource ID(s) to assign to the resource. + +- Required: No +- Type: array + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Resource tags. + +- Required: No +- Type: object + + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the communication service was deployed into. | +| `name` | string | The name of the communication service. | +| `resourceGroupName` | string | The resource group the communication service was deployed into. | +| `resourceId` | string | The resource ID of the communication service. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | + +## Cross-referenced modules + +_None_ + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/res/communication/communication-service/main.bicep b/avm/res/communication/communication-service/main.bicep new file mode 100644 index 00000000000..dbfe4343a98 --- /dev/null +++ b/avm/res/communication/communication-service/main.bicep @@ -0,0 +1,263 @@ +metadata name = 'Communication Services' +metadata description = 'This module deploys a Communication Service' +metadata owner = 'Azure/module-maintainers' + +@minLength(1) +@maxLength(63) +@description('Required. Name of the communication service to create.') +param name string + +@description('Optional. Location for all Resources.') +param location string = 'global' + +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType + +@description('Optional. Resource tags.') +param tags object? + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Required. The location where the communication service stores its data at rest.') +param dataLocation string + +@description('Optional. List of email Domain resource Ids.') +param linkedDomains string[]? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var formattedUserAssignedIdentities = reduce( + map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), + {}, + (cur, next) => union(cur, next) +) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + +var identity = !empty(managedIdentities) + ? { + type: (managedIdentities.?systemAssigned ?? false) + ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') + : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : 'None') + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null + } + : null + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +// ============== // +// Resources // +// ============== // + +resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = if (enableTelemetry) { + name: '46d3xbcp.res.communication-communicationservice.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource communicationService 'Microsoft.Communication/communicationServices@2023-04-01' = { + name: name + location: location + identity: identity + tags: tags + properties: { + dataLocation: dataLocation + linkedDomains: linkedDomains + } +} + +resource communicationService_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: communicationService +} + +resource communicationService_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: communicationService + } +] + +resource communicationService_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (roleAssignments ?? []): { + name: guid(communicationService.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) + properties: { + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) + ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] + : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: communicationService + } +] + +// ============ // +// Outputs // +// ============ // + +@description('The name of the communication service.') +output name string = communicationService.name + +@description('The resource ID of the communication service.') +output resourceId string = communicationService.id + +@description('The resource group the communication service was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The location the communication service was deployed into.') +output location string = communicationService.location + +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string = communicationService.?identity.?principalId ?? '' + +// ================ // +// Definitions // +// ================ // + +type managedIdentitiesType = { + @description('Optional. Enables system assigned managed identity on the resource.') + systemAssigned: bool? + + @description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourceIds: string[]? +}? + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @description('Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type diagnosticSettingType = { + @description('Optional. The name of diagnostic setting.') + name: string? + + @description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection.') + logCategoriesAndGroups: { + @description('Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here.') + category: string? + + @description('Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs.') + categoryGroup: string? + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection.') + metricCategories: { + @description('Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics.') + category: string + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.') + logAnalyticsDestinationType: ('Dedicated' | 'AzureDiagnostics')? + + @description('Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + workspaceResourceId: string? + + @description('Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + storageAccountResourceId: string? + + @description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.') + eventHubAuthorizationRuleResourceId: string? + + @description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + eventHubName: string? + + @description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') + marketplacePartnerResourceId: string? +}[]? diff --git a/avm/res/communication/communication-service/main.json b/avm/res/communication/communication-service/main.json new file mode 100644 index 00000000000..85b0cbf040f --- /dev/null +++ b/avm/res/communication/communication-service/main.json @@ -0,0 +1,481 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.26.170.59819", + "templateHash": "12398183463909693728" + }, + "name": "Communication Services", + "description": "This module deploys a Communication Service", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 63, + "metadata": { + "description": "Required. Name of the communication service to create." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "dataLocation": { + "type": "string", + "metadata": { + "description": "Required. The location where the communication service stores its data at rest." + } + }, + "linkedDomains": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of email Domain resource Ids." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.communication-communicationservice.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "communicationService": { + "type": "Microsoft.Communication/communicationServices", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "properties": { + "dataLocation": "[parameters('dataLocation')]", + "linkedDomains": "[parameters('linkedDomains')]" + } + }, + "communicationService_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Communication/communicationServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "communicationService" + ] + }, + "communicationService_diagnosticSettings": { + "copy": { + "name": "communicationService_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Communication/communicationServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "communicationService" + ] + }, + "communicationService_roleAssignments": { + "copy": { + "name": "communicationService_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Communication/communicationServices/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Communication/communicationServices', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "communicationService" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the communication service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the communication service." + }, + "value": "[resourceId('Microsoft.Communication/communicationServices', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the communication service was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the communication service was deployed into." + }, + "value": "[reference('communicationService', '2023-04-01', 'full').location]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('communicationService', '2023-04-01', 'full'), 'identity'), 'principalId'), '')]" + } + } +} \ No newline at end of file diff --git a/avm/res/communication/communication-service/tests/e2e/defaults/main.test.bicep b/avm/res/communication/communication-service/tests/e2e/defaults/main.test.bicep new file mode 100644 index 00000000000..f9e33c9d23f --- /dev/null +++ b/avm/res/communication/communication-service/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,49 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-communication-communicationservices-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ccsmin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: 'global' + dataLocation: 'Germany' + } + } +] diff --git a/avm/res/communication/communication-service/tests/e2e/max/dependencies.bicep b/avm/res/communication/communication-service/tests/e2e/max/dependencies.bicep new file mode 100644 index 00000000000..ef29480b6d6 --- /dev/null +++ b/avm/res/communication/communication-service/tests/e2e/max/dependencies.bicep @@ -0,0 +1,38 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Email Service to create.') +param emailServiceName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource emailService 'Microsoft.Communication/emailServices@2023-04-01' = { + name: emailServiceName + location: 'global' + properties: { + dataLocation: 'Germany' + } + + resource domain 'domains@2023-04-01' = { + name: 'AzureManagedDomain' + location: 'global' + properties: { + domainManagement: 'AzureManaged' + } + } +} + +@description('The resource ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created Email Service Domain.') +output emailDomainResourceId string = emailService::domain.id diff --git a/avm/res/communication/communication-service/tests/e2e/max/main.test.bicep b/avm/res/communication/communication-service/tests/e2e/max/main.test.bicep new file mode 100644 index 00000000000..0fbc81cab2c --- /dev/null +++ b/avm/res/communication/communication-service/tests/e2e/max/main.test.bicep @@ -0,0 +1,125 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-communication-communicationservices-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ccsmax' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + emailServiceName: 'dep-${namePrefix}-email-${serviceShort}' + location: resourceLocation + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: 'global' + dataLocation: 'Germany' + linkedDomains: [ + nestedDependencies.outputs.emailDomainResourceId + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + managedIdentities: { + systemAssigned: false + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/res/communication/communication-service/tests/e2e/waf-aligned/main.test.bicep b/avm/res/communication/communication-service/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 00000000000..5dd224b6bf1 --- /dev/null +++ b/avm/res/communication/communication-service/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,74 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-communication-communicationservices-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ccswaf' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: 'global' + dataLocation: 'Germany' + diagnosticSettings: [ + { + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/res/communication/communication-service/version.json b/avm/res/communication/communication-service/version.json new file mode 100644 index 00000000000..8def869edeb --- /dev/null +++ b/avm/res/communication/communication-service/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} From b2790c0e96299afbcf4bb0ebe82e61ec901948a8 Mon Sep 17 00:00:00 2001 From: rodney-almeida <64196999+rodney-almeida@users.noreply.github.com> Date: Tue, 14 May 2024 08:50:17 +0100 Subject: [PATCH 38/52] feat: Create\Update User Defined Types with sensitive values to include @secure() decorator. - `avm/res/container-instance/container-group` (#1919) ## Description Update containerType (user defined type) to set environmentVariables.secureValue to be of type secureString. Followed the same logic and created the user defined type for imageRegistryCredentials (imageRegistryCredentialType) as it also has a password attribute. Fixes #1868 Closes #1868 --> ## Pipeline Reference | Pipeline | | -------- | [![avm.res.container-instance.container-group](https://github.com/rodney-almeida/bicep-registry-modules/actions/workflows/avm.res.container-instance.container-group.yml/badge.svg?branch=rodney-almeida-1868)](https://github.com/rodney-almeida/bicep-registry-modules/actions/workflows/avm.res.container-instance.container-group.yml) ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting changes) - [ ] Azure Verified Module updates: - [X] Bugfix containing backwards compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [X] 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. - [ ] 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 --------- Co-authored-by: Rodney Almeida --- .../container-group/README.md | 76 ++++++++++++- .../container-group/main.bicep | 104 ++++++++++-------- .../container-group/main.json | 53 ++++++++- .../tests/e2e/max/main.test.bicep | 11 +- 4 files changed, 189 insertions(+), 55 deletions(-) diff --git a/avm/res/container-instance/container-group/README.md b/avm/res/container-instance/container-group/README.md index c93906a3f9c..983ca8cf49b 100644 --- a/avm/res/container-instance/container-group/README.md +++ b/avm/res/container-instance/container-group/README.md @@ -355,7 +355,16 @@ module containerGroup 'br/public:avm/res/container-instance/container-group: Date: Wed, 15 May 2024 23:53:28 +0200 Subject: [PATCH 39/52] feat: New pattern `avm/ptn/authorization/resource-role-assignment` (#1905) ## Description Adding new pattern `avm/ptn/authorization/resource-role-assignment` https://github.com/Azure/Azure-Verified-Modules/issues/939 Migration of `modules/authorization/resource-scope-role-assignment` Closes #937 ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.authorization.resource-role-assignment](https://github.com/peterbud/bicep-registry-modules/actions/workflows/avm.ptn.authorization.resource-role-assignment.yml/badge.svg?branch=resource-role-assignment)](https://github.com/peterbud/bicep-registry-modules/actions/workflows/avm.ptn.authorization.resource-role-assignment.yml) | ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting 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. - [ ] 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 --- .github/CODEOWNERS | 1 + .github/ISSUE_TEMPLATE/avm_module_issue.yml | 1 + ...authorization.resource-role-assignment.yml | 90 ++++++ .../resource-role-assignment/README.md | 259 ++++++++++++++++++ .../resource-role-assignment/main.bicep | 108 ++++++++ .../resource-role-assignment/main.json | 219 +++++++++++++++ .../modules/generic-role-assignment.json | 56 ++++ .../tests/e2e/all/dependencies.bicep | 28 ++ .../tests/e2e/all/main.test.bicep | 61 +++++ .../tests/e2e/defaults/dependencies.bicep | 28 ++ .../tests/e2e/defaults/main.test.bicep | 59 ++++ .../resource-role-assignment/version.json | 7 + 12 files changed, 917 insertions(+) create mode 100644 .github/workflows/avm.ptn.authorization.resource-role-assignment.yml create mode 100644 avm/ptn/authorization/resource-role-assignment/README.md create mode 100644 avm/ptn/authorization/resource-role-assignment/main.bicep create mode 100644 avm/ptn/authorization/resource-role-assignment/main.json create mode 100644 avm/ptn/authorization/resource-role-assignment/modules/generic-role-assignment.json create mode 100644 avm/ptn/authorization/resource-role-assignment/tests/e2e/all/dependencies.bicep create mode 100644 avm/ptn/authorization/resource-role-assignment/tests/e2e/all/main.test.bicep create mode 100644 avm/ptn/authorization/resource-role-assignment/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/ptn/authorization/resource-role-assignment/tests/e2e/defaults/main.test.bicep create mode 100644 avm/ptn/authorization/resource-role-assignment/version.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 730d31af409..3829d6ef269 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,6 +4,7 @@ /avm/ @Azure/avm-core-team-technical-bicep /avm/utilities/ @Azure/avm-core-team-technical-bicep /avm/ptn/authorization/policy-assignment/ @Azure/avm-ptn-authorization-policyassignment-module-owners-bicep @Azure/avm-core-team-technical-bicep +/avm/ptn/authorization/resource-role-assignment/ @Azure/avm-ptn-authorization-resourceroleassignment-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/ptn/authorization/role-assignment/ @Azure/avm-ptn-authorization-roleassignment-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/ptn/security/security-center/ @Azure/avm-ptn-security-securitycenter-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/aad/domain-service/ @Azure/avm-res-aad-domainservice-module-owners-bicep @Azure/avm-core-team-technical-bicep diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index 43e4d477db4..ab3d0c78670 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -39,6 +39,7 @@ body: options: - "" - "avm/ptn/authorization/policy-assignment" + - "avm/ptn/authorization/resource-role-assignment" - "avm/ptn/authorization/role-assignment" # - "avm/ptn/avd-lza/insights" # - "avm/ptn/avd-lza/management-plane" diff --git a/.github/workflows/avm.ptn.authorization.resource-role-assignment.yml b/.github/workflows/avm.ptn.authorization.resource-role-assignment.yml new file mode 100644 index 00000000000..979d22d8dfa --- /dev/null +++ b/.github/workflows/avm.ptn.authorization.resource-role-assignment.yml @@ -0,0 +1,90 @@ +name: "avm.ptn.authorization.resource-role-assignment" + +on: + schedule: + - cron: "0 12 1/15 * *" # Bi-Weekly Test (on 1st & 15th of month) + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: "Execute static validation" + required: false + default: true + deploymentValidation: + type: boolean + description: "Execute deployment validation" + required: false + default: true + removeDeployment: + type: boolean + description: "Remove deployed module" + required: false + default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.ptn.authorization.resource-role-assignment.yml" + - "avm/ptn/authorization/resource-role-assignment/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/ptn/authorization/resource-role-assignment" + workflowPath: ".github/workflows/avm.ptn.authorization.resource-role-assignment.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-latest + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get module test file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Run" + permissions: + id-token: write # For OIDC + contents: write # For release tags + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit diff --git a/avm/ptn/authorization/resource-role-assignment/README.md b/avm/ptn/authorization/resource-role-assignment/README.md new file mode 100644 index 00000000000..3c440de2259 --- /dev/null +++ b/avm/ptn/authorization/resource-role-assignment/README.md @@ -0,0 +1,259 @@ +# Resource-scoped role assignment `[Microsoft.Authorization/resourceroleassignment]` + +This module deploys a Role Assignment for a specific resource. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/ptn/authorization/resource-role-assignment:`. + +- [Resource Role Assignments](#example-1-resource-role-assignments) +- [Resource Role Assignments](#example-2-resource-role-assignments) + +### Example 1: _Resource Role Assignments_ + +This module deploys a Resource Role Assignment using all parameters. + + +

+ +via Bicep module + +```bicep +module resourceRoleAssignment 'br/public:avm/ptn/authorization/resource-role-assignment:' = { + name: 'resourceRoleAssignmentDeployment' + params: { + // Required parameters + principalId: '' + resourceId: '' + roleDefinitionId: '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' + // Non-required parameters + description: 'Assign Storage Blob Data Reader role to the managed identity on the storage account.' + principalType: 'ServicePrincipal' + roleName: 'Storage Blob Data Reader' + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "principalId": { + "value": "" + }, + "resourceId": { + "value": "" + }, + "roleDefinitionId": { + "value": "2a2b9908-6ea1-4ae2-8e65-a410df84e7d1" + }, + // Non-required parameters + "description": { + "value": "Assign Storage Blob Data Reader role to the managed identity on the storage account." + }, + "principalType": { + "value": "ServicePrincipal" + }, + "roleName": { + "value": "Storage Blob Data Reader" + } + } +} +``` + +
+

+ +### Example 2: _Resource Role Assignments_ + +This module deploys a Resource Role Assignment using minimal parameters. + + +

+ +via Bicep module + +```bicep +module resourceRoleAssignment 'br/public:avm/ptn/authorization/resource-role-assignment:' = { + name: 'resourceRoleAssignmentDeployment' + params: { + // Required parameters + principalId: '' + resourceId: '' + roleDefinitionId: '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' + // Non-required parameters + principalType: 'ServicePrincipal' + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "principalId": { + "value": "" + }, + "resourceId": { + "value": "" + }, + "roleDefinitionId": { + "value": "2a2b9908-6ea1-4ae2-8e65-a410df84e7d1" + }, + // Non-required parameters + "principalType": { + "value": "ServicePrincipal" + } + } +} +``` + +
+

+ + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-principalid) | string | The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity). | +| [`resourceId`](#parameter-resourceid) | string | The scope for the role assignment, fully qualified resourceId. | +| [`roleDefinitionId`](#parameter-roledefinitionid) | string | The role definition ID for the role assignment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-description) | string | The description of role assignment. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`name`](#parameter-name) | string | The unique guid name for the role assignment. | +| [`principalType`](#parameter-principaltype) | string | The principal type of the assigned principal ID. | +| [`roleName`](#parameter-rolename) | string | The name for the role, used for logging. | + +### Parameter: `principalId` + +The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity). + +- Required: Yes +- Type: string + +### Parameter: `resourceId` + +The scope for the role assignment, fully qualified resourceId. + +- Required: Yes +- Type: string + +### Parameter: `roleDefinitionId` + +The role definition ID for the role assignment. + +- Required: Yes +- Type: string + +### Parameter: `description` + +The description of role assignment. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `name` + +The unique guid name for the role assignment. + +- Required: No +- Type: string +- Default: `[guid(parameters('resourceId'), parameters('principalId'), if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId'))))]` + +### Parameter: `principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `roleName` + +The name for the role, used for logging. + +- Required: No +- Type: string +- Default: `''` + + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The GUID of the Role Assignment. | +| `resourceGroupName` | string | The name of the resource group the role assignment was applied at. | +| `resourceId` | string | The resource ID of the Role Assignment. | +| `roleName` | string | The name for the role, used for logging. | + +## Cross-referenced modules + +_None_ + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/ptn/authorization/resource-role-assignment/main.bicep b/avm/ptn/authorization/resource-role-assignment/main.bicep new file mode 100644 index 00000000000..37e0afe82b9 --- /dev/null +++ b/avm/ptn/authorization/resource-role-assignment/main.bicep @@ -0,0 +1,108 @@ +metadata name = 'Resource-scoped role assignment' +metadata description = 'This module deploys a Role Assignment for a specific resource.' +metadata owner = 'Azure/module-maintainers' + +@sys.description('Required. The scope for the role assignment, fully qualified resourceId.') +param resourceId string + +@sys.description('Optional. The unique guid name for the role assignment.') +param name string = guid( + resourceId, + principalId, + contains(roleDefinitionId, '/providers/Microsoft.Authorization/roleDefinitions/') + ? roleDefinitionId + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId) +) + +@sys.description('Required. The role definition ID for the role assignment.') +param roleDefinitionId string + +@sys.description('Optional. The name for the role, used for logging.') +param roleName string = '' + +@sys.description('Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity).') +param principalId string + +@sys.description('Optional. The principal type of the assigned principal ID.') +@allowed([ + 'ServicePrincipal' + 'Group' + 'User' + 'ForeignGroup' + 'Device' + '' +]) +param principalType string = '' + +@sys.description('Optional. The description of role assignment.') +param description string = '' + +@sys.description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// =============== // +// Definitions // +// =============== // + +resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = if (enableTelemetry) { + name: '46d3xbcp.ptn.authorization-resourceroleassignment.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource resourceRoleAssignment 'Microsoft.Resources/deployments@2023-07-01' = { + name: '${guid(resourceId, principalId, roleDefinitionId)}-ResourceRoleAssignment' + properties: { + mode: 'Incremental' + expressionEvaluationOptions: { + scope: 'Outer' + } + template: loadJsonContent('modules/generic-role-assignment.json') + parameters: { + scope: { + value: resourceId + } + name: { + value: name + } + roleDefinitionId: { + value: contains(roleDefinitionId, '/providers/Microsoft.Authorization/roleDefinitions/') + ? roleDefinitionId + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId) + } + principalId: { + value: principalId + } + principalType: { + value: principalType + } + description: { + value: description + } + } + } +} + +@sys.description('The GUID of the Role Assignment.') +output name string = name + +@sys.description('The name for the role, used for logging.') +output roleName string = roleName + +@sys.description('The resource ID of the Role Assignment.') +output resourceId string = resourceRoleAssignment.properties.outputs.roleAssignmentId.value + +@sys.description('The name of the resource group the role assignment was applied at.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/ptn/authorization/resource-role-assignment/main.json b/avm/ptn/authorization/resource-role-assignment/main.json new file mode 100644 index 00000000000..f576453bd93 --- /dev/null +++ b/avm/ptn/authorization/resource-role-assignment/main.json @@ -0,0 +1,219 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.26.170.59819", + "templateHash": "17107961067773605935" + }, + "name": "Resource-scoped role assignment", + "description": "This module deploys a Role Assignment for a specific resource.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The scope for the role assignment, fully qualified resourceId." + } + }, + "name": { + "type": "string", + "defaultValue": "[guid(parameters('resourceId'), parameters('principalId'), if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId'))))]", + "metadata": { + "description": "Optional. The unique guid name for the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition ID for the role assignment." + } + }, + "roleName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name for the role, used for logging." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + } + }, + "principalType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of role assignment." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "$fxv#0": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string" + }, + "name": { + "type": "string" + }, + "roleDefinitionId": { + "type": "string" + }, + "principalId": { + "type": "string" + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[[parameters('scope')]", + "name": "[[parameters('name')]", + "properties": { + "roleDefinitionId": "[[parameters('roleDefinitionId')]", + "principalId": "[[parameters('principalId')]", + "principalType": "[[parameters('principalType')]", + "description": "[[parameters('description')]" + } + } + ], + "outputs": { + "roleAssignmentId": { + "type": "string", + "value": "[[extensionResourceId(parameters('scope'), 'Microsoft.Authorization/roleAssignments', parameters('name'))]" + } + } + } + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.ptn.authorization-resourceroleassignment.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))]", + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "Outer" + }, + "template": "[variables('$fxv#0')]", + "parameters": { + "scope": { + "value": "[parameters('resourceId')]" + }, + "name": { + "value": "[parameters('name')]" + }, + "roleDefinitionId": { + "value": "[if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId')))]" + }, + "principalId": { + "value": "[parameters('principalId')]" + }, + "principalType": { + "value": "[parameters('principalType')]" + }, + "description": { + "value": "[parameters('description')]" + } + } + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The GUID of the Role Assignment." + }, + "value": "[parameters('name')]" + }, + "roleName": { + "type": "string", + "metadata": { + "description": "The name for the role, used for logging." + }, + "value": "[parameters('roleName')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Role Assignment." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))), '2023-07-01').outputs.roleAssignmentId.value]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the role assignment was applied at." + }, + "value": "[resourceGroup().name]" + } + } +} diff --git a/avm/ptn/authorization/resource-role-assignment/modules/generic-role-assignment.json b/avm/ptn/authorization/resource-role-assignment/modules/generic-role-assignment.json new file mode 100644 index 00000000000..2e18bcc9556 --- /dev/null +++ b/avm/ptn/authorization/resource-role-assignment/modules/generic-role-assignment.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string" + }, + "name": { + "type": "string" + }, + "roleDefinitionId": { + "type": "string" + }, + "principalId": { + "type": "string" + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[parameters('scope')]", + "name": "[parameters('name')]", + "properties": { + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "principalId": "[parameters('principalId')]", + "principalType": "[parameters('principalType')]", + "description": "[parameters('description')]" + } + } + ], + "outputs": { + "roleAssignmentId": { + "type": "string", + "value": "[extensionResourceId(parameters('scope'), 'Microsoft.Authorization/roleAssignments', parameters('name'))]" + } + } +} \ No newline at end of file diff --git a/avm/ptn/authorization/resource-role-assignment/tests/e2e/all/dependencies.bicep b/avm/ptn/authorization/resource-role-assignment/tests/e2e/all/dependencies.bicep new file mode 100644 index 00000000000..195c02ed8a5 --- /dev/null +++ b/avm/ptn/authorization/resource-role-assignment/tests/e2e/all/dependencies.bicep @@ -0,0 +1,28 @@ +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: managedIdentityName + location: location +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Storage Account.') +output storageAccountResourceId string = storageAccount.id diff --git a/avm/ptn/authorization/resource-role-assignment/tests/e2e/all/main.test.bicep b/avm/ptn/authorization/resource-role-assignment/tests/e2e/all/main.test.bicep new file mode 100644 index 00000000000..2bc06f024de --- /dev/null +++ b/avm/ptn/authorization/resource-role-assignment/tests/e2e/all/main.test.bicep @@ -0,0 +1,61 @@ +targetScope = 'subscription' +metadata name = 'Resource Role Assignments' +metadata description = 'This module deploys a Resource Role Assignment using all parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-authorization.resourceroleassignment-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'arraall' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2023-07-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + storageAccountName: 'dep${namePrefix}st${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + name: '${guid(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + scope: resourceGroup + params: { + resourceId: nestedDependencies.outputs.storageAccountResourceId + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + roleDefinitionId: '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' + roleName: 'Storage Blob Data Reader' + description: 'Assign Storage Blob Data Reader role to the managed identity on the storage account.' + } + } +] diff --git a/avm/ptn/authorization/resource-role-assignment/tests/e2e/defaults/dependencies.bicep b/avm/ptn/authorization/resource-role-assignment/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 00000000000..ac2fbefc476 --- /dev/null +++ b/avm/ptn/authorization/resource-role-assignment/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,28 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: managedIdentityName + location: location +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Storage Account.') +output storageAccountResourceId string = storageAccount.id diff --git a/avm/ptn/authorization/resource-role-assignment/tests/e2e/defaults/main.test.bicep b/avm/ptn/authorization/resource-role-assignment/tests/e2e/defaults/main.test.bicep new file mode 100644 index 00000000000..252442bc345 --- /dev/null +++ b/avm/ptn/authorization/resource-role-assignment/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,59 @@ +targetScope = 'subscription' +metadata name = 'Resource Role Assignments' +metadata description = 'This module deploys a Resource Role Assignment using minimal parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-authorization.resourceroleassignment-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'arramin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2023-07-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + storageAccountName: 'dep${namePrefix}st${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + name: '${guid(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + scope: resourceGroup + params: { + resourceId: nestedDependencies.outputs.storageAccountResourceId + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + roleDefinitionId: '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' // Storage Blob Data Reader + } + } +] diff --git a/avm/ptn/authorization/resource-role-assignment/version.json b/avm/ptn/authorization/resource-role-assignment/version.json new file mode 100644 index 00000000000..8def869edeb --- /dev/null +++ b/avm/ptn/authorization/resource-role-assignment/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} From dc7914a45c79950231f26b0f704a89fc4c3d3613 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Thu, 16 May 2024 10:15:06 +0200 Subject: [PATCH 40/52] fix: MachineLearningWorkspace - Updated to latest PE schema (#1792) ## Description Updated to latest PE schema Fixes #1791 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.machine-learning-services.workspace](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.machine-learning-services.workspace.yml/badge.svg?branch=users%2Falsehr%2F1791_PEUpdate&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.machine-learning-services.workspace.yml) | ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting changes) - [ ] Azure Verified Module updates: - [x] 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. - [ ] 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 --- .../workspace/README.md | 20 +++++++++++-- .../workspace/main.bicep | 14 +++++++-- .../workspace/main.json | 30 ++++++++++++++----- .../workspace/version.json | 2 +- 4 files changed, 53 insertions(+), 13 deletions(-) diff --git a/avm/res/machine-learning-services/workspace/README.md b/avm/res/machine-learning-services/workspace/README.md index d123fc8d10c..6661c38dead 100644 --- a/avm/res/machine-learning-services/workspace/README.md +++ b/avm/res/machine-learning-services/workspace/README.md @@ -1057,10 +1057,12 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`isManualConnection`](#parameter-privateendpointsismanualconnection) | bool | If Manual Private Link Connection is required. | | [`location`](#parameter-privateendpointslocation) | string | The location to deploy the private endpoint to. | | [`lock`](#parameter-privateendpointslock) | object | Specify the type of lock. | -| [`manualConnectionRequestMessage`](#parameter-privateendpointsmanualconnectionrequestmessage) | string | A message passed to the owner of the remote resource with the manual connection request. Restricted to 140 chars. | +| [`manualConnectionRequestMessage`](#parameter-privateendpointsmanualconnectionrequestmessage) | string | A message passed to the owner of the remote resource with the manual connection request. | | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | +| [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | | [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/resource groups in this deployment. | @@ -1230,7 +1232,7 @@ Specify the name of lock. ### Parameter: `privateEndpoints.manualConnectionRequestMessage` -A message passed to the owner of the remote resource with the manual connection request. Restricted to 140 chars. +A message passed to the owner of the remote resource with the manual connection request. - Required: No - Type: string @@ -1256,6 +1258,20 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.resourceGroupName` + +Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. + +- Required: No +- Type: string + ### Parameter: `privateEndpoints.roleAssignments` Array of role assignments to create. diff --git a/avm/res/machine-learning-services/workspace/main.bicep b/avm/res/machine-learning-services/workspace/main.bicep index ece1f942f0f..035e2f2814e 100644 --- a/avm/res/machine-learning-services/workspace/main.bicep +++ b/avm/res/machine-learning-services/workspace/main.bicep @@ -309,9 +309,10 @@ resource workspace_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@202 module workspace_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.4.1' = [ for (privateEndpoint, index) in (privateEndpoints ?? []): { name: '${uniqueString(deployment().name, location)}-workspace-PrivateEndpoint-${index}' + scope: resourceGroup(privateEndpoint.?resourceGroupName ?? '') params: { name: privateEndpoint.?name ?? 'pep-${last(split(workspace.id, '/'))}-${privateEndpoint.?service ?? 'amlworkspace'}-${index}' - privateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections != true + privateLinkServiceConnections: privateEndpoint.?isManualConnection != true ? [ { name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(workspace.id, '/'))}-${privateEndpoint.?service ?? 'amlworkspace'}-${index}' @@ -324,7 +325,7 @@ module workspace_privateEndpoints 'br/public:avm/res/network/private-endpoint:0. } ] : null - manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections == true + manualPrivateLinkServiceConnections: privateEndpoint.?isManualConnection == true ? [ { name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(workspace.id, '/'))}-${privateEndpoint.?service ?? 'amlworkspace'}-${index}' @@ -447,6 +448,9 @@ type privateEndpointType = { @sys.description('Optional. The location to deploy the private endpoint to.') location: string? + @sys.description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + @sys.description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? @@ -462,7 +466,8 @@ type privateEndpointType = { @sys.description('Optional. If Manual Private Link Connection is required.') isManualConnection: bool? - @sys.description('Optional. A message passed to the owner of the remote resource with the manual connection request. Restricted to 140 chars.') + @sys.description('Optional. A message passed to the owner of the remote resource with the manual connection request.') + @maxLength(140) manualConnectionRequestMessage: string? @sys.description('Optional. Custom DNS configurations.') @@ -509,6 +514,9 @@ type privateEndpointType = { @sys.description('Optional. Enable/Disable usage telemetry for module.') enableTelemetry: bool? + + @sys.description('Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.') + resourceGroupName: string? }[]? type diagnosticSettingType = { diff --git a/avm/res/machine-learning-services/workspace/main.json b/avm/res/machine-learning-services/workspace/main.json index d11a6904f5e..59d6b5bf9b9 100644 --- a/avm/res/machine-learning-services/workspace/main.json +++ b/avm/res/machine-learning-services/workspace/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "16054212084136992012" + "version": "0.26.170.59819", + "templateHash": "3104036699030674643" }, "name": "Machine Learning Services Workspaces", "description": "This module deploys a Machine Learning Services Workspace.", @@ -145,6 +145,13 @@ "description": "Optional. The location to deploy the private endpoint to." } }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, "service": { "type": "string", "nullable": true, @@ -185,8 +192,9 @@ "manualConnectionRequestMessage": { "type": "string", "nullable": true, + "maxLength": 140, "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request. Restricted to 140 chars." + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." } }, "customDnsConfigs": { @@ -303,6 +311,13 @@ "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } + }, + "resourceGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource." + } } } }, @@ -861,8 +876,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "2355820538616279194" + "version": "0.26.170.59819", + "templateHash": "16998034314964845307" }, "name": "Machine Learning Services Workspaces Computes", "description": "This module deploys a Machine Learning Services Workspaces Compute.\n\nAttaching a compute is not idempotent and will fail in case you try to redeploy over an existing compute in AML (see parameter `deployCompute`).", @@ -1080,6 +1095,7 @@ "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", "name": "[format('{0}-workspace-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "resourceGroup": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupName'), '')]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -1089,8 +1105,8 @@ "name": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.MachineLearningServices/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace'), copyIndex()))]" }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.MachineLearningServices/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.MachineLearningServices/workspaces', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.MachineLearningServices/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.MachineLearningServices/workspaces', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.MachineLearningServices/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.MachineLearningServices/workspaces', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.MachineLearningServices/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.MachineLearningServices/workspaces', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", "subnetResourceId": { "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, diff --git a/avm/res/machine-learning-services/workspace/version.json b/avm/res/machine-learning-services/workspace/version.json index 83083db6945..1c035df49f2 100644 --- a/avm/res/machine-learning-services/workspace/version.json +++ b/avm/res/machine-learning-services/workspace/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.1", + "version": "0.2", "pathFilters": [ "./main.json" ] From dee18fe01f941b74b131036386b20a9fa463e58e Mon Sep 17 00:00:00 2001 From: hundredacres Date: Thu, 16 May 2024 01:54:18 -0700 Subject: [PATCH 41/52] fix: Resolve bug with declaring Public IP Prefix use on managementIP (#1939) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Resolved issue when specifying a public IP prefix for the management IP address. Updated to use latest PublicIPAddress AVM module. Updated API version of Microsoft.Network/publicIPAddresses used in tests. Updated formatting of zone param default values. Also added new e2e tests for Public IP Prefix usage. Fixes #1867 Closes #1867 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.network.azure-firewall](https://github.com/hundredacres/bicep-registry-modules/actions/workflows/avm.res.network.azure-firewall.yml/badge.svg?branch=fix%2Fissue%2F1867)](https://github.com/hundredacres/bicep-registry-modules/actions/workflows/avm.res.network.azure-firewall.yml) | ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting changes) - [X] Azure Verified Module updates: - [ ] Bugfix containing backwards compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [X] 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`. - [X] 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 --------- Co-authored-by: Máté Barabás Co-authored-by: Rainer Halanek <61878316+rahalan@users.noreply.github.com> Co-authored-by: JFolberth --- avm/res/network/azure-firewall/README.md | 228 +++++++++++++++-- avm/res/network/azure-firewall/main.bicep | 238 +++++++++--------- avm/res/network/azure-firewall/main.json | 174 ++++++++++--- .../e2e/publicipprefix/dependencies.bicep | 56 +++++ .../tests/e2e/publicipprefix/main.test.bicep | 75 ++++++ avm/res/network/azure-firewall/version.json | 4 +- 6 files changed, 596 insertions(+), 179 deletions(-) create mode 100644 avm/res/network/azure-firewall/tests/e2e/publicipprefix/dependencies.bicep create mode 100644 avm/res/network/azure-firewall/tests/e2e/publicipprefix/main.test.bicep diff --git a/avm/res/network/azure-firewall/README.md b/avm/res/network/azure-firewall/README.md index da0018a179d..e821af3f602 100644 --- a/avm/res/network/azure-firewall/README.md +++ b/avm/res/network/azure-firewall/README.md @@ -19,7 +19,7 @@ This module deploys an Azure Firewall. | `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | | `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | | `Microsoft.Network/azureFirewalls` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/azureFirewalls) | -| `Microsoft.Network/publicIPAddresses` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/publicIPAddresses) | +| `Microsoft.Network/publicIPAddresses` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-09-01/publicIPAddresses) | ## Usage examples @@ -29,15 +29,113 @@ The following section provides usage examples for the module, which were used to >**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/azure-firewall:`. -- [Add-PIP](#example-1-add-pip) -- [Custom-PIP](#example-2-custom-pip) -- [Using only defaults](#example-3-using-only-defaults) -- [Hub-commom](#example-4-hub-commom) -- [Hub-min](#example-5-hub-min) -- [Using large parameter set](#example-6-using-large-parameter-set) -- [WAF-aligned](#example-7-waf-aligned) +- [Issue-1867](#example-1-issue-1867) +- [Add-PIP](#example-2-add-pip) +- [Custom-PIP](#example-3-custom-pip) +- [Using only defaults](#example-4-using-only-defaults) +- [Hub-commom](#example-5-hub-commom) +- [Hub-min](#example-6-hub-min) +- [Using large parameter set](#example-7-using-large-parameter-set) +- [Public-IP-Prefix](#example-8-public-ip-prefix) +- [WAF-aligned](#example-9-waf-aligned) -### Example 1: _Add-PIP_ +### Example 1: _Issue-1867_ + +Validating reported bug 1867 + + +

+ +via Bicep module + +```bicep +module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { + name: 'azureFirewallDeployment' + params: { + // Required parameters + name: 'nafcustom001' + // Non-required parameters + azureSkuTier: 'Basic' + firewallPolicyId: '' + location: '' + managementIPAddressObject: { + managementIPAllocationMethod: 'Static' + managementIPPrefixResourceId: '' + name: 'managementIP01' + skuName: 'Standard' + skuTier: 'Regional' + } + publicIPAddressObject: { + name: 'publicIP01' + publicIPAllocationMethod: 'Static' + publicIPPrefixResourceId: '' + skuName: 'Standard' + skuTier: 'Regional' + } + virtualNetworkResourceId: '' + zones: [] + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nafcustom001" + }, + // Non-required parameters + "azureSkuTier": { + "value": "Basic" + }, + "firewallPolicyId": { + "value": "" + }, + "location": { + "value": "" + }, + "managementIPAddressObject": { + "value": { + "managementIPAllocationMethod": "Static", + "managementIPPrefixResourceId": "", + "name": "managementIP01", + "skuName": "Standard", + "skuTier": "Regional" + } + }, + "publicIPAddressObject": { + "value": { + "name": "publicIP01", + "publicIPAllocationMethod": "Static", + "publicIPPrefixResourceId": "", + "skuName": "Standard", + "skuTier": "Regional" + } + }, + "virtualNetworkResourceId": { + "value": "" + }, + "zones": { + "value": [] + } + } +} +``` + +
+

+ +### Example 2: _Add-PIP_ This instance deploys the module and attaches an existing public IP address. @@ -129,7 +227,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

-### Example 2: _Custom-PIP_ +### Example 3: _Custom-PIP_ This instance deploys the module and will create a public IP address. @@ -239,7 +337,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

-### Example 3: _Using only defaults_ +### Example 4: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -291,7 +389,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

-### Example 4: _Hub-commom_ +### Example 5: _Hub-commom_ This instance deploys the module a vWAN in a typical hub setting. @@ -359,7 +457,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

-### Example 5: _Hub-min_ +### Example 6: _Hub-min_ This instance deploys the module a vWAN minimum hub setting. @@ -423,7 +521,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

-### Example 6: _Using large parameter set_ +### Example 7: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -777,7 +875,99 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

-### Example 7: _WAF-aligned_ +### Example 8: _Public-IP-Prefix_ + +This instance deploys the module and will use a public IP prefix. + + +

+ +via Bicep module + +```bicep +module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { + name: 'azureFirewallDeployment' + params: { + // Required parameters + name: 'nafpip001' + // Non-required parameters + azureSkuTier: 'Basic' + location: '' + managementIPAddressObject: { + managementIPAllocationMethod: 'Static' + managementIPPrefixResourceId: '' + name: 'managementIP01' + skuName: 'Standard' + skuTier: 'Regional' + } + publicIPAddressObject: { + name: 'publicIP01' + publicIPAllocationMethod: 'Static' + publicIPPrefixResourceId: '' + skuName: 'Standard' + skuTier: 'Regional' + } + virtualNetworkResourceId: '' + zones: [] + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nafpip001" + }, + // Non-required parameters + "azureSkuTier": { + "value": "Basic" + }, + "location": { + "value": "" + }, + "managementIPAddressObject": { + "value": { + "managementIPAllocationMethod": "Static", + "managementIPPrefixResourceId": "", + "name": "managementIP01", + "skuName": "Standard", + "skuTier": "Regional" + } + }, + "publicIPAddressObject": { + "value": { + "name": "publicIP01", + "publicIPAllocationMethod": "Static", + "publicIPPrefixResourceId": "", + "skuName": "Standard", + "skuTier": "Regional" + } + }, + "virtualNetworkResourceId": { + "value": "" + }, + "zones": { + "value": [] + } + } +} +``` + +
+

+ +### Example 9: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -2033,9 +2223,9 @@ Zone numbers e.g. 1,2,3. - Default: ```Bicep [ - '1' - '2' - '3' + 1 + 2 + 3 ] ``` @@ -2060,7 +2250,7 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm/res/network/public-ip-address:0.2.1` | Remote reference | +| `br/public:avm/res/network/public-ip-address:0.4.0` | Remote reference | ## Data Collection diff --git a/avm/res/network/azure-firewall/main.bicep b/avm/res/network/azure-firewall/main.bicep index 31765349135..54d4661cf2c 100644 --- a/avm/res/network/azure-firewall/main.bicep +++ b/avm/res/network/azure-firewall/main.bicep @@ -61,9 +61,9 @@ param threatIntelMode string = 'Deny' @description('Optional. Zone numbers e.g. 1,2,3.') param zones array = [ - '1' - '2' - '3' + 1 + 2 + 3 ] @description('Optional. The diagnostic settings of the service.') @@ -143,7 +143,7 @@ var managementIPConfiguration = { id: '${virtualNetworkResourceId}/subnets/AzureFirewallManagementSubnet' // The subnet name must be AzureFirewallManagementSubnet for a 'Basic' SKU tier firewall } }, - (!empty(publicIPResourceID) || !empty(managementIPAddressObject)) + (!empty(managementIPResourceID) || !empty(managementIPAddressObject)) ? { // Use existing Management Public IP, new Management Public IP created in this module, or none if neither publicIPAddress: { @@ -169,138 +169,140 @@ var builtInRoleNames = { ) } -resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = - if (enableTelemetry) { - name: '46d3xbcp.res.network-azurefirewall.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' - properties: { - mode: 'Incremental' - template: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: '1.0.0.0' - resources: [] - outputs: { - telemetry: { - type: 'String' - value: 'For more information, see https://aka.ms/avm/TelemetryInfo' - } +resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-azurefirewall.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' } } } } +} -module publicIPAddress 'br/public:avm/res/network/public-ip-address:0.2.1' = - if (empty(publicIPResourceID) && azureSkuName == 'AZFW_VNet') { - name: '${uniqueString(deployment().name, location)}-Firewall-PIP' - params: { - name: publicIPAddressObject.name - publicIpPrefixResourceId: contains(publicIPAddressObject, 'publicIPPrefixResourceId') - ? (!(empty(publicIPAddressObject.publicIPPrefixResourceId)) - ? publicIPAddressObject.publicIPPrefixResourceId - : '') - : '' - publicIPAllocationMethod: contains(publicIPAddressObject, 'publicIPAllocationMethod') - ? (!(empty(publicIPAddressObject.publicIPAllocationMethod)) - ? publicIPAddressObject.publicIPAllocationMethod - : 'Static') - : 'Static' - skuName: contains(publicIPAddressObject, 'skuName') - ? (!(empty(publicIPAddressObject.skuName)) ? publicIPAddressObject.skuName : 'Standard') - : 'Standard' - skuTier: contains(publicIPAddressObject, 'skuTier') - ? (!(empty(publicIPAddressObject.skuTier)) ? publicIPAddressObject.skuTier : 'Regional') - : 'Regional' - roleAssignments: contains(publicIPAddressObject, 'roleAssignments') - ? (!empty(publicIPAddressObject.roleAssignments) ? publicIPAddressObject.roleAssignments : []) - : [] - diagnosticSettings: publicIPAddressObject.?diagnosticSettings - location: location - lock: lock - tags: publicIPAddressObject.?tags ?? tags - zones: zones - enableTelemetry: publicIPAddressObject.?enableTelemetry ?? enableTelemetry - } +module publicIPAddress 'br/public:avm/res/network/public-ip-address:0.4.0' = if (empty(publicIPResourceID) && azureSkuName == 'AZFW_VNet') { + name: '${uniqueString(deployment().name, location)}-Firewall-PIP' + params: { + name: publicIPAddressObject.name + publicIpPrefixResourceId: contains(publicIPAddressObject, 'publicIPPrefixResourceId') + ? (!(empty(publicIPAddressObject.publicIPPrefixResourceId)) ? publicIPAddressObject.publicIPPrefixResourceId : '') + : '' + publicIPAllocationMethod: contains(publicIPAddressObject, 'publicIPAllocationMethod') + ? (!(empty(publicIPAddressObject.publicIPAllocationMethod)) + ? publicIPAddressObject.publicIPAllocationMethod + : 'Static') + : 'Static' + skuName: contains(publicIPAddressObject, 'skuName') + ? (!(empty(publicIPAddressObject.skuName)) ? publicIPAddressObject.skuName : 'Standard') + : 'Standard' + skuTier: contains(publicIPAddressObject, 'skuTier') + ? (!(empty(publicIPAddressObject.skuTier)) ? publicIPAddressObject.skuTier : 'Regional') + : 'Regional' + roleAssignments: contains(publicIPAddressObject, 'roleAssignments') + ? (!empty(publicIPAddressObject.roleAssignments) ? publicIPAddressObject.roleAssignments : []) + : [] + diagnosticSettings: publicIPAddressObject.?diagnosticSettings + location: location + lock: lock + tags: publicIPAddressObject.?tags ?? tags + zones: zones + enableTelemetry: publicIPAddressObject.?enableTelemetry ?? enableTelemetry } +} // create a Management Public IP address if one is not provided and the flag is true -module managementIPAddress 'br/public:avm/res/network/public-ip-address:0.2.1' = - if (isCreateDefaultManagementIP && azureSkuName == 'AZFW_VNet') { - name: '${uniqueString(deployment().name, location)}-Firewall-MIP' - params: { - name: contains(managementIPAddressObject, 'name') - ? (!(empty(managementIPAddressObject.name)) ? managementIPAddressObject.name : '${name}-mip') - : '${name}-mip' - publicIpPrefixResourceId: contains(managementIPAddressObject, 'managementIPPrefixResourceId') - ? (!(empty(managementIPAddressObject.publicIPPrefixResourceId)) - ? managementIPAddressObject.publicIPPrefixResourceId - : '') - : '' - publicIPAllocationMethod: contains(managementIPAddressObject, 'managementIPAllocationMethod') - ? (!(empty(managementIPAddressObject.publicIPAllocationMethod)) - ? managementIPAddressObject.publicIPAllocationMethod - : 'Static') - : 'Static' - skuName: contains(managementIPAddressObject, 'skuName') - ? (!(empty(managementIPAddressObject.skuName)) ? managementIPAddressObject.skuName : 'Standard') - : 'Standard' - skuTier: contains(managementIPAddressObject, 'skuTier') - ? (!(empty(managementIPAddressObject.skuTier)) ? managementIPAddressObject.skuTier : 'Regional') - : 'Regional' - roleAssignments: contains(managementIPAddressObject, 'roleAssignments') - ? (!empty(managementIPAddressObject.roleAssignments) ? managementIPAddressObject.roleAssignments : []) - : [] - diagnosticSettings: managementIPAddressObject.?diagnosticSettings - location: location - tags: managementIPAddressObject.?tags ?? tags - zones: zones - enableTelemetry: managementIPAddressObject.?enableTelemetry ?? enableTelemetry - } +module managementIPAddress 'br/public:avm/res/network/public-ip-address:0.4.0' = if (isCreateDefaultManagementIP && azureSkuName == 'AZFW_VNet') { + name: '${uniqueString(deployment().name, location)}-Firewall-MIP' + params: { + name: contains(managementIPAddressObject, 'name') + ? (!(empty(managementIPAddressObject.name)) ? managementIPAddressObject.name : '${name}-mip') + : '${name}-mip' + publicIpPrefixResourceId: contains(managementIPAddressObject, 'managementIPPrefixResourceId') + ? (!(empty(managementIPAddressObject.managementIPPrefixResourceId)) + ? managementIPAddressObject.managementIPPrefixResourceId + : '') + : '' + publicIPAllocationMethod: contains(managementIPAddressObject, 'managementIPAllocationMethod') + ? (!(empty(managementIPAddressObject.managementIPAllocationMethod)) + ? managementIPAddressObject.managementIPAllocationMethod + : 'Static') + : 'Static' + skuName: contains(managementIPAddressObject, 'skuName') + ? (!(empty(managementIPAddressObject.skuName)) ? managementIPAddressObject.skuName : 'Standard') + : 'Standard' + skuTier: contains(managementIPAddressObject, 'skuTier') + ? (!(empty(managementIPAddressObject.skuTier)) ? managementIPAddressObject.skuTier : 'Regional') + : 'Regional' + roleAssignments: contains(managementIPAddressObject, 'roleAssignments') + ? (!empty(managementIPAddressObject.roleAssignments) ? managementIPAddressObject.roleAssignments : []) + : [] + diagnosticSettings: managementIPAddressObject.?diagnosticSettings + location: location + tags: managementIPAddressObject.?tags ?? tags + zones: zones + enableTelemetry: managementIPAddressObject.?enableTelemetry ?? enableTelemetry } +} resource azureFirewall 'Microsoft.Network/azureFirewalls@2023-04-01' = { name: name location: location zones: length(zones) == 0 ? null : zones tags: tags - properties: azureSkuName == 'AZFW_VNet' ? { - threatIntelMode: threatIntelMode - firewallPolicy: !empty(firewallPolicyId) ? { - id: firewallPolicyId - } : null - ipConfigurations: ipConfigurations - managementIpConfiguration: requiresManagementIp ? managementIPConfiguration : null - sku: { - name: azureSkuName - tier: azureSkuTier - } - applicationRuleCollections: applicationRuleCollections ?? [] - natRuleCollections: natRuleCollections ?? [] - networkRuleCollections: networkRuleCollections ?? [] - } : { - firewallPolicy: !empty(firewallPolicyId) ? { - id: firewallPolicyId - } : null - sku: { - name: azureSkuName - tier: azureSkuTier - } - hubIPAddresses: !empty(hubIPAddresses) ? hubIPAddresses : null - virtualHub: !empty(virtualHubId) ? { - id: virtualHubId - } : null - } + properties: azureSkuName == 'AZFW_VNet' + ? { + threatIntelMode: threatIntelMode + firewallPolicy: !empty(firewallPolicyId) + ? { + id: firewallPolicyId + } + : null + ipConfigurations: ipConfigurations + managementIpConfiguration: requiresManagementIp ? managementIPConfiguration : null + sku: { + name: azureSkuName + tier: azureSkuTier + } + applicationRuleCollections: applicationRuleCollections ?? [] + natRuleCollections: natRuleCollections ?? [] + networkRuleCollections: networkRuleCollections ?? [] + } + : { + firewallPolicy: !empty(firewallPolicyId) + ? { + id: firewallPolicyId + } + : null + sku: { + name: azureSkuName + tier: azureSkuTier + } + hubIPAddresses: !empty(hubIPAddresses) ? hubIPAddresses : null + virtualHub: !empty(virtualHubId) + ? { + id: virtualHubId + } + : null + } } -resource azureFirewall_lock 'Microsoft.Authorization/locks@2020-05-01' = - if (!empty(lock ?? {}) && lock.?kind != 'None') { - name: lock.?name ?? 'lock-${name}' - properties: { - level: lock.?kind ?? '' - notes: lock.?kind == 'CanNotDelete' - ? 'Cannot delete resource or child resources.' - : 'Cannot delete or modify the resource or child resources.' - } - scope: azureFirewall +resource azureFirewall_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' } + scope: azureFirewall +} resource azureFirewall_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ for (diagnosticSetting, index) in (diagnosticSettings ?? []): { diff --git a/avm/res/network/azure-firewall/main.json b/avm/res/network/azure-firewall/main.json index 877e4dbea24..47361a85e2a 100644 --- a/avm/res/network/azure-firewall/main.json +++ b/avm/res/network/azure-firewall/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "3831870271484638637" + "version": "0.27.1.19265", + "templateHash": "5299175231300175796" }, "name": "Azure Firewalls", "description": "This module deploys an Azure Firewall.", @@ -776,9 +776,9 @@ "zones": { "type": "array", "defaultValue": [ - "1", - "2", - "3" + 1, + 2, + 3 ], "metadata": { "description": "Optional. Zone numbers e.g. 1,2,3." @@ -876,7 +876,7 @@ "location": "[parameters('location')]", "zones": "[if(equals(length(parameters('zones')), 0), null(), parameters('zones'))]", "tags": "[parameters('tags')]", - "properties": "[if(equals(variables('azureSkuName'), 'AZFW_VNet'), createObject('threatIntelMode', parameters('threatIntelMode'), 'firewallPolicy', if(not(empty(parameters('firewallPolicyId'))), createObject('id', parameters('firewallPolicyId')), null()), 'ipConfigurations', concat(createArray(createObject('name', if(not(empty(parameters('publicIPResourceID'))), last(split(parameters('publicIPResourceID'), '/')), reference('publicIPAddress').outputs.name.value), 'properties', union(createObject('subnet', createObject('id', format('{0}/subnets/AzureFirewallSubnet', parameters('virtualNetworkResourceId')))), if(or(not(empty(parameters('publicIPResourceID'))), not(empty(parameters('publicIPAddressObject')))), createObject('publicIPAddress', createObject('id', if(not(empty(parameters('publicIPResourceID'))), parameters('publicIPResourceID'), reference('publicIPAddress').outputs.resourceId.value))), createObject())))), variables('additionalPublicIpConfigurationsVar')), 'managementIpConfiguration', if(variables('requiresManagementIp'), createObject('name', if(not(empty(parameters('managementIPResourceID'))), last(split(parameters('managementIPResourceID'), '/')), reference('managementIPAddress').outputs.name.value), 'properties', union(createObject('subnet', createObject('id', format('{0}/subnets/AzureFirewallManagementSubnet', parameters('virtualNetworkResourceId')))), if(or(not(empty(parameters('publicIPResourceID'))), not(empty(parameters('managementIPAddressObject')))), createObject('publicIPAddress', createObject('id', if(not(empty(parameters('managementIPResourceID'))), parameters('managementIPResourceID'), reference('managementIPAddress').outputs.resourceId.value))), createObject()))), null()), 'sku', createObject('name', variables('azureSkuName'), 'tier', parameters('azureSkuTier')), 'applicationRuleCollections', coalesce(parameters('applicationRuleCollections'), createArray()), 'natRuleCollections', coalesce(parameters('natRuleCollections'), createArray()), 'networkRuleCollections', coalesce(parameters('networkRuleCollections'), createArray())), createObject('firewallPolicy', if(not(empty(parameters('firewallPolicyId'))), createObject('id', parameters('firewallPolicyId')), null()), 'sku', createObject('name', variables('azureSkuName'), 'tier', parameters('azureSkuTier')), 'hubIPAddresses', if(not(empty(parameters('hubIPAddresses'))), parameters('hubIPAddresses'), null()), 'virtualHub', if(not(empty(parameters('virtualHubId'))), createObject('id', parameters('virtualHubId')), null())))]", + "properties": "[if(equals(variables('azureSkuName'), 'AZFW_VNet'), createObject('threatIntelMode', parameters('threatIntelMode'), 'firewallPolicy', if(not(empty(parameters('firewallPolicyId'))), createObject('id', parameters('firewallPolicyId')), null()), 'ipConfigurations', concat(createArray(createObject('name', if(not(empty(parameters('publicIPResourceID'))), last(split(parameters('publicIPResourceID'), '/')), reference('publicIPAddress').outputs.name.value), 'properties', union(createObject('subnet', createObject('id', format('{0}/subnets/AzureFirewallSubnet', parameters('virtualNetworkResourceId')))), if(or(not(empty(parameters('publicIPResourceID'))), not(empty(parameters('publicIPAddressObject')))), createObject('publicIPAddress', createObject('id', if(not(empty(parameters('publicIPResourceID'))), parameters('publicIPResourceID'), reference('publicIPAddress').outputs.resourceId.value))), createObject())))), variables('additionalPublicIpConfigurationsVar')), 'managementIpConfiguration', if(variables('requiresManagementIp'), createObject('name', if(not(empty(parameters('managementIPResourceID'))), last(split(parameters('managementIPResourceID'), '/')), reference('managementIPAddress').outputs.name.value), 'properties', union(createObject('subnet', createObject('id', format('{0}/subnets/AzureFirewallManagementSubnet', parameters('virtualNetworkResourceId')))), if(or(not(empty(parameters('managementIPResourceID'))), not(empty(parameters('managementIPAddressObject')))), createObject('publicIPAddress', createObject('id', if(not(empty(parameters('managementIPResourceID'))), parameters('managementIPResourceID'), reference('managementIPAddress').outputs.resourceId.value))), createObject()))), null()), 'sku', createObject('name', variables('azureSkuName'), 'tier', parameters('azureSkuTier')), 'applicationRuleCollections', coalesce(parameters('applicationRuleCollections'), createArray()), 'natRuleCollections', coalesce(parameters('natRuleCollections'), createArray()), 'networkRuleCollections', coalesce(parameters('networkRuleCollections'), createArray())), createObject('firewallPolicy', if(not(empty(parameters('firewallPolicyId'))), createObject('id', parameters('firewallPolicyId')), null()), 'sku', createObject('name', variables('azureSkuName'), 'tier', parameters('azureSkuTier')), 'hubIPAddresses', if(not(empty(parameters('hubIPAddresses'))), parameters('hubIPAddresses'), null()), 'virtualHub', if(not(empty(parameters('virtualHubId'))), createObject('id', parameters('virtualHubId')), null())))]", "dependsOn": [ "managementIPAddress", "publicIPAddress" @@ -1004,8 +1004,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "3488076626994379707" + "version": "0.26.54.24096", + "templateHash": "4718335757080871925" }, "name": "Public IP Addresses", "description": "This module deploys a Public IP Address.", @@ -1054,7 +1054,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"" + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." } }, "conditionVersion": { @@ -1148,11 +1148,14 @@ "type": "object", "properties": { "id": { - "type": "string" + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } } }, "metadata": { - "description": "Required. The DDoS protection plan ID associated with the public IP address." + "description": "Required. The DDoS protection plan associated with the public IP address." } }, "protectionMode": { @@ -1196,12 +1199,19 @@ "metadata": { "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } } } }, "nullable": true, "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to '' to disable log collection." + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." } }, "metricCategories": { @@ -1214,12 +1224,19 @@ "metadata": { "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } } } }, "nullable": true, "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to '' to disable log collection." + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." } }, "logAnalyticsDestinationType": { @@ -1300,7 +1317,19 @@ }, "zones": { "type": "array", - "nullable": true, + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], "metadata": { "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." } @@ -1418,7 +1447,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.2.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -1436,7 +1465,7 @@ }, "publicIpAddress": { "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2023-04-01", + "apiVersion": "2023-09-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", @@ -1444,7 +1473,7 @@ "name": "[parameters('skuName')]", "tier": "[parameters('skuTier')]" }, - "zones": "[parameters('zones')]", + "zones": "[map(parameters('zones'), lambda('zone', string(lambdaVariables('zone'))))]", "properties": { "ddosSettings": "[parameters('ddosSettings')]", "dnsSettings": "[parameters('dnsSettings')]", @@ -1452,7 +1481,7 @@ "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", - "ipTags": [] + "ipTags": null } }, "publicIpAddress_lock": { @@ -1501,12 +1530,30 @@ "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "metrics": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics', 'timeGrain', null(), 'enabled', true())))]", - "logs": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs', 'enabled', true())))]", "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, @@ -1542,14 +1589,14 @@ "metadata": { "description": "The public IP address of the public IP address resource." }, - "value": "[if(contains(reference('publicIpAddress'), 'ipAddress'), reference('publicIpAddress').ipAddress, '')]" + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('publicIpAddress', '2023-04-01', 'full').location]" + "value": "[reference('publicIpAddress', '2023-09-01', 'full').location]" } } } @@ -1567,8 +1614,8 @@ "mode": "Incremental", "parameters": { "name": "[if(contains(parameters('managementIPAddressObject'), 'name'), if(not(empty(parameters('managementIPAddressObject').name)), createObject('value', parameters('managementIPAddressObject').name), createObject('value', format('{0}-mip', parameters('name')))), createObject('value', format('{0}-mip', parameters('name'))))]", - "publicIpPrefixResourceId": "[if(contains(parameters('managementIPAddressObject'), 'managementIPPrefixResourceId'), if(not(empty(parameters('managementIPAddressObject').publicIPPrefixResourceId)), createObject('value', parameters('managementIPAddressObject').publicIPPrefixResourceId), createObject('value', '')), createObject('value', ''))]", - "publicIPAllocationMethod": "[if(contains(parameters('managementIPAddressObject'), 'managementIPAllocationMethod'), if(not(empty(parameters('managementIPAddressObject').publicIPAllocationMethod)), createObject('value', parameters('managementIPAddressObject').publicIPAllocationMethod), createObject('value', 'Static')), createObject('value', 'Static'))]", + "publicIpPrefixResourceId": "[if(contains(parameters('managementIPAddressObject'), 'managementIPPrefixResourceId'), if(not(empty(parameters('managementIPAddressObject').managementIPPrefixResourceId)), createObject('value', parameters('managementIPAddressObject').managementIPPrefixResourceId), createObject('value', '')), createObject('value', ''))]", + "publicIPAllocationMethod": "[if(contains(parameters('managementIPAddressObject'), 'managementIPAllocationMethod'), if(not(empty(parameters('managementIPAddressObject').managementIPAllocationMethod)), createObject('value', parameters('managementIPAddressObject').managementIPAllocationMethod), createObject('value', 'Static')), createObject('value', 'Static'))]", "skuName": "[if(contains(parameters('managementIPAddressObject'), 'skuName'), if(not(empty(parameters('managementIPAddressObject').skuName)), createObject('value', parameters('managementIPAddressObject').skuName), createObject('value', 'Standard')), createObject('value', 'Standard'))]", "skuTier": "[if(contains(parameters('managementIPAddressObject'), 'skuTier'), if(not(empty(parameters('managementIPAddressObject').skuTier)), createObject('value', parameters('managementIPAddressObject').skuTier), createObject('value', 'Regional')), createObject('value', 'Regional'))]", "roleAssignments": "[if(contains(parameters('managementIPAddressObject'), 'roleAssignments'), if(not(empty(parameters('managementIPAddressObject').roleAssignments)), createObject('value', parameters('managementIPAddressObject').roleAssignments), createObject('value', createArray())), createObject('value', createArray()))]", @@ -1595,8 +1642,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "3488076626994379707" + "version": "0.26.54.24096", + "templateHash": "4718335757080871925" }, "name": "Public IP Addresses", "description": "This module deploys a Public IP Address.", @@ -1645,7 +1692,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"" + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." } }, "conditionVersion": { @@ -1739,11 +1786,14 @@ "type": "object", "properties": { "id": { - "type": "string" + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } } }, "metadata": { - "description": "Required. The DDoS protection plan ID associated with the public IP address." + "description": "Required. The DDoS protection plan associated with the public IP address." } }, "protectionMode": { @@ -1787,12 +1837,19 @@ "metadata": { "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } } } }, "nullable": true, "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to '' to disable log collection." + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." } }, "metricCategories": { @@ -1805,12 +1862,19 @@ "metadata": { "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } } } }, "nullable": true, "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to '' to disable log collection." + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." } }, "logAnalyticsDestinationType": { @@ -1891,7 +1955,19 @@ }, "zones": { "type": "array", - "nullable": true, + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], "metadata": { "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." } @@ -2009,7 +2085,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.2.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -2027,7 +2103,7 @@ }, "publicIpAddress": { "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2023-04-01", + "apiVersion": "2023-09-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", @@ -2035,7 +2111,7 @@ "name": "[parameters('skuName')]", "tier": "[parameters('skuTier')]" }, - "zones": "[parameters('zones')]", + "zones": "[map(parameters('zones'), lambda('zone', string(lambdaVariables('zone'))))]", "properties": { "ddosSettings": "[parameters('ddosSettings')]", "dnsSettings": "[parameters('dnsSettings')]", @@ -2043,7 +2119,7 @@ "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", - "ipTags": [] + "ipTags": null } }, "publicIpAddress_lock": { @@ -2092,12 +2168,30 @@ "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "metrics": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics', 'timeGrain', null(), 'enabled', true())))]", - "logs": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs', 'enabled', true())))]", "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, @@ -2133,14 +2227,14 @@ "metadata": { "description": "The public IP address of the public IP address resource." }, - "value": "[if(contains(reference('publicIpAddress'), 'ipAddress'), reference('publicIpAddress').ipAddress, '')]" + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('publicIpAddress', '2023-04-01', 'full').location]" + "value": "[reference('publicIpAddress', '2023-09-01', 'full').location]" } } } diff --git a/avm/res/network/azure-firewall/tests/e2e/publicipprefix/dependencies.bicep b/avm/res/network/azure-firewall/tests/e2e/publicipprefix/dependencies.bicep new file mode 100644 index 00000000000..fc6a6247519 --- /dev/null +++ b/avm/res/network/azure-firewall/tests/e2e/publicipprefix/dependencies.bicep @@ -0,0 +1,56 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Public IP Prefix to create.') +param publicIPPrefixName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'AzureFirewallSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 20, 0) + } + } + { + name: 'AzureFirewallManagementSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 20, 1) + } + } + ] + } +} + +resource publicIPPrefix 'Microsoft.Network/publicIPPrefixes@2023-11-01' = { + name: publicIPPrefixName + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + prefixLength: 30 + publicIPAddressVersion: 'IPv4' + } + zones: [] +} + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id + +@description('The resource ID of the created Public IP Prefix') +output publicIPPrefixResourceId string = publicIPPrefix.id diff --git a/avm/res/network/azure-firewall/tests/e2e/publicipprefix/main.test.bicep b/avm/res/network/azure-firewall/tests/e2e/publicipprefix/main.test.bicep new file mode 100644 index 00000000000..b047e5199a3 --- /dev/null +++ b/avm/res/network/azure-firewall/tests/e2e/publicipprefix/main.test.bicep @@ -0,0 +1,75 @@ +targetScope = 'subscription' + +metadata name = 'Public-IP-Prefix' +metadata description = 'This instance deploys the module and will use a public IP prefix.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.azurefirewalls-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nafpip' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + publicIPPrefixName: 'dep-${namePrefix}-pip-prefix-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + virtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId + publicIPAddressObject: { + name: 'publicIP01' + publicIPAllocationMethod: 'Static' + publicIPPrefixResourceId: nestedDependencies.outputs.publicIPPrefixResourceId + skuName: 'Standard' + skuTier: 'Regional' + } + azureSkuTier: 'Basic' + managementIPAddressObject: { + name: 'managementIP01' + managementIPAllocationMethod: 'Static' + managementIPPrefixResourceId: nestedDependencies.outputs.publicIPPrefixResourceId + skuName: 'Standard' + skuTier: 'Regional' + } + zones: [] + } + } +] diff --git a/avm/res/network/azure-firewall/version.json b/avm/res/network/azure-firewall/version.json index 1c035df49f2..b3d560b1ad0 100644 --- a/avm/res/network/azure-firewall/version.json +++ b/avm/res/network/azure-firewall/version.json @@ -1,7 +1,7 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.2", + "version": "0.3", "pathFilters": [ "./main.json" ] -} \ No newline at end of file +} From ad5701ac9b1e38ec2f70af9668a31a9f3b1902f1 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Thu, 16 May 2024 17:36:50 +0200 Subject: [PATCH 42/52] fix: Removed migration left-overs from Virtual-Hub module (#1941) ## Description Removed migration left-overs from Virtual-Hub module ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.network.virtual-hub](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.virtual-hub.yml/badge.svg?branch=users%2Falsehr%2FoutdatedTelemetryReferences&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.virtual-hub.yml) | ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting changes) - [x] 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. - [ ] 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 --- .../virtual-hub/hub-route-table/README.md | 9 --- .../virtual-hub/hub-route-table/main.bicep | 22 ------ .../virtual-hub/hub-route-table/main.json | 31 +------- .../hub-virtual-network-connection/README.md | 9 --- .../hub-virtual-network-connection/main.bicep | 22 ------ .../hub-virtual-network-connection/main.json | 31 +------- avm/res/network/virtual-hub/main.bicep | 56 ++++++------- avm/res/network/virtual-hub/main.json | 79 ++----------------- 8 files changed, 37 insertions(+), 222 deletions(-) diff --git a/avm/res/network/virtual-hub/hub-route-table/README.md b/avm/res/network/virtual-hub/hub-route-table/README.md index a7214ef715e..a2075469531 100644 --- a/avm/res/network/virtual-hub/hub-route-table/README.md +++ b/avm/res/network/virtual-hub/hub-route-table/README.md @@ -34,7 +34,6 @@ This module deploys a Virtual Hub Route Table. | Parameter | Type | Description | | :-- | :-- | :-- | -| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | | [`labels`](#parameter-labels) | array | List of labels associated with this route table. | | [`routes`](#parameter-routes) | array | List of all routes. | @@ -52,14 +51,6 @@ The name of the parent virtual hub. Required if the template is used in a standa - Required: Yes - Type: string -### Parameter: `enableTelemetry` - -Enable/Disable usage telemetry for module. - -- Required: No -- Type: bool -- Default: `True` - ### Parameter: `labels` List of labels associated with this route table. diff --git a/avm/res/network/virtual-hub/hub-route-table/main.bicep b/avm/res/network/virtual-hub/hub-route-table/main.bicep index 059374a501c..5fb0aeeffa7 100644 --- a/avm/res/network/virtual-hub/hub-route-table/main.bicep +++ b/avm/res/network/virtual-hub/hub-route-table/main.bicep @@ -14,28 +14,6 @@ param labels array = [] @description('Optional. List of all routes.') param routes array = [] -@description('Optional. Enable/Disable usage telemetry for module.') -param enableTelemetry bool = true - -resource defaultTelemetry 'Microsoft.Resources/deployments@2021-04-01' = - if (enableTelemetry) { - name: '46d3xbcp.res.network-virtualhub.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name), 0, 4)}' - properties: { - mode: 'Incremental' - template: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: '1.0.0.0' - resources: [] - outputs: { - telemetry: { - type: 'String' - value: 'For more information, see https://aka.ms/avm/TelemetryInfo' - } - } - } - } - } - resource virtualHub 'Microsoft.Network/virtualHubs@2022-11-01' existing = { name: virtualHubName } diff --git a/avm/res/network/virtual-hub/hub-route-table/main.json b/avm/res/network/virtual-hub/hub-route-table/main.json index 0188d1b4bc6..88f3d4c3e60 100644 --- a/avm/res/network/virtual-hub/hub-route-table/main.json +++ b/avm/res/network/virtual-hub/hub-route-table/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "8788910381196616673" + "version": "0.27.1.19265", + "templateHash": "13312295345359302348" }, "name": "Virtual Hub Route Tables", "description": "This module deploys a Virtual Hub Route Table.", @@ -37,36 +37,9 @@ "metadata": { "description": "Optional. List of all routes." } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } } }, "resources": [ - { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2021-04-01", - "name": "[format('46d3xbcp.res.network-virtualhub.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, { "type": "Microsoft.Network/virtualHubs/hubRouteTables", "apiVersion": "2022-11-01", diff --git a/avm/res/network/virtual-hub/hub-virtual-network-connection/README.md b/avm/res/network/virtual-hub/hub-virtual-network-connection/README.md index da9f0e13884..43d153f7a76 100644 --- a/avm/res/network/virtual-hub/hub-virtual-network-connection/README.md +++ b/avm/res/network/virtual-hub/hub-virtual-network-connection/README.md @@ -36,7 +36,6 @@ This module deploys a Virtual Hub Virtual Network Connection. | Parameter | Type | Description | | :-- | :-- | :-- | | [`enableInternetSecurity`](#parameter-enableinternetsecurity) | bool | Enable internet security. | -| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | | [`routingConfiguration`](#parameter-routingconfiguration) | object | Routing Configuration indicating the associated and propagated route tables for this connection. | ### Parameter: `name` @@ -68,14 +67,6 @@ Enable internet security. - Type: bool - Default: `True` -### Parameter: `enableTelemetry` - -Enable/Disable usage telemetry for module. - -- Required: No -- Type: bool -- Default: `True` - ### Parameter: `routingConfiguration` Routing Configuration indicating the associated and propagated route tables for this connection. diff --git a/avm/res/network/virtual-hub/hub-virtual-network-connection/main.bicep b/avm/res/network/virtual-hub/hub-virtual-network-connection/main.bicep index 3bc4c7e4ecb..f9751898ec2 100644 --- a/avm/res/network/virtual-hub/hub-virtual-network-connection/main.bicep +++ b/avm/res/network/virtual-hub/hub-virtual-network-connection/main.bicep @@ -17,28 +17,6 @@ param remoteVirtualNetworkId string @description('Optional. Routing Configuration indicating the associated and propagated route tables for this connection.') param routingConfiguration object = {} -@description('Optional. Enable/Disable usage telemetry for module.') -param enableTelemetry bool = true - -resource defaultTelemetry 'Microsoft.Resources/deployments@2021-04-01' = - if (enableTelemetry) { - name: '46d3xbcp.res.network-virtualhub.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name), 0, 4)}' - properties: { - mode: 'Incremental' - template: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: '1.0.0.0' - resources: [] - outputs: { - telemetry: { - type: 'String' - value: 'For more information, see https://aka.ms/avm/TelemetryInfo' - } - } - } - } - } - resource virtualHub 'Microsoft.Network/virtualHubs@2022-11-01' existing = { name: virtualHubName } diff --git a/avm/res/network/virtual-hub/hub-virtual-network-connection/main.json b/avm/res/network/virtual-hub/hub-virtual-network-connection/main.json index 47c9ebd0257..82bb00a3568 100644 --- a/avm/res/network/virtual-hub/hub-virtual-network-connection/main.json +++ b/avm/res/network/virtual-hub/hub-virtual-network-connection/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "10987823499253979342" + "version": "0.27.1.19265", + "templateHash": "449308154693946367" }, "name": "Virtual Hub Virtual Network Connections", "description": "This module deploys a Virtual Hub Virtual Network Connection.", @@ -43,36 +43,9 @@ "metadata": { "description": "Optional. Routing Configuration indicating the associated and propagated route tables for this connection." } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } } }, "resources": [ - { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2021-04-01", - "name": "[format('46d3xbcp.res.network-virtualhub.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, { "type": "Microsoft.Network/virtualHubs/hubVirtualNetworkConnections", "apiVersion": "2022-11-01", diff --git a/avm/res/network/virtual-hub/main.bicep b/avm/res/network/virtual-hub/main.bicep index 58c7ad44d29..138902ccaa3 100644 --- a/avm/res/network/virtual-hub/main.bicep +++ b/avm/res/network/virtual-hub/main.bicep @@ -79,29 +79,26 @@ param lock lockType @description('Optional. Enable/Disable usage telemetry for module.') param enableTelemetry bool = true -var enableReferencedModulesTelemetry = false - -resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = - if (enableTelemetry) { - name: take( - '46d3xbcp.res.network-virtualhub.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}', - 64 - ) - properties: { - mode: 'Incremental' - template: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: '1.0.0.0' - resources: [] - outputs: { - telemetry: { - type: 'String' - value: 'For more information, see https://aka.ms/avm/TelemetryInfo' - } +resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = if (enableTelemetry) { + name: take( + '46d3xbcp.res.network-virtualhub.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}', + 64 + ) + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' } } } } +} resource virtualHub 'Microsoft.Network/virtualHubs@2022-11-01' = { name: name @@ -152,17 +149,16 @@ resource virtualHub 'Microsoft.Network/virtualHubs@2022-11-01' = { } } -resource virtualHub_lock 'Microsoft.Authorization/locks@2020-05-01' = - if (!empty(lock ?? {}) && lock.?kind != 'None') { - name: lock.?name ?? 'lock-${name}' - properties: { - level: lock.?kind ?? '' - notes: lock.?kind == 'CanNotDelete' - ? 'Cannot delete resource or child resources.' - : 'Cannot delete or modify the resource or child resources.' - } - scope: virtualHub +resource virtualHub_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' } + scope: virtualHub +} module virtualHub_routeTables 'hub-route-table/main.bicep' = [ for (routeTable, index) in hubRouteTables: { @@ -172,7 +168,6 @@ module virtualHub_routeTables 'hub-route-table/main.bicep' = [ name: routeTable.name labels: contains(routeTable, 'labels') ? routeTable.labels : [] routes: contains(routeTable, 'routes') ? routeTable.routes : [] - enableTelemetry: enableReferencedModulesTelemetry } } ] @@ -190,7 +185,6 @@ module virtualHub_hubVirtualNetworkConnections 'hub-virtual-network-connection/m routingConfiguration: contains(virtualNetworkConnection, 'routingConfiguration') ? virtualNetworkConnection.routingConfiguration : {} - enableTelemetry: enableReferencedModulesTelemetry } dependsOn: [ virtualHub_routeTables diff --git a/avm/res/network/virtual-hub/main.json b/avm/res/network/virtual-hub/main.json index 5b75ef5cc54..1178d893c23 100644 --- a/avm/res/network/virtual-hub/main.json +++ b/avm/res/network/virtual-hub/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "2150058177195720553" + "version": "0.27.1.19265", + "templateHash": "7421243394882467292" }, "name": "Virtual Hubs", "description": "This module deploys a Virtual Hub.\nIf you are planning to deploy a Secure Virtual Hub (with an Azure Firewall integrated), please refer to the Azure Firewall module.", @@ -201,9 +201,6 @@ } } }, - "variables": { - "enableReferencedModulesTelemetry": false - }, "resources": { "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", @@ -286,10 +283,7 @@ "value": "[parameters('hubRouteTables')[copyIndex()].name]" }, "labels": "[if(contains(parameters('hubRouteTables')[copyIndex()], 'labels'), createObject('value', parameters('hubRouteTables')[copyIndex()].labels), createObject('value', createArray()))]", - "routes": "[if(contains(parameters('hubRouteTables')[copyIndex()], 'routes'), createObject('value', parameters('hubRouteTables')[copyIndex()].routes), createObject('value', createArray()))]", - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } + "routes": "[if(contains(parameters('hubRouteTables')[copyIndex()], 'routes'), createObject('value', parameters('hubRouteTables')[copyIndex()].routes), createObject('value', createArray()))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -297,8 +291,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "8788910381196616673" + "version": "0.27.1.19265", + "templateHash": "13312295345359302348" }, "name": "Virtual Hub Route Tables", "description": "This module deploys a Virtual Hub Route Table.", @@ -330,36 +324,9 @@ "metadata": { "description": "Optional. List of all routes." } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } } }, "resources": [ - { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2021-04-01", - "name": "[format('46d3xbcp.res.network-virtualhub.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, { "type": "Microsoft.Network/virtualHubs/hubRouteTables", "apiVersion": "2022-11-01", @@ -423,10 +390,7 @@ "remoteVirtualNetworkId": { "value": "[parameters('hubVirtualNetworkConnections')[copyIndex()].remoteVirtualNetworkId]" }, - "routingConfiguration": "[if(contains(parameters('hubVirtualNetworkConnections')[copyIndex()], 'routingConfiguration'), createObject('value', parameters('hubVirtualNetworkConnections')[copyIndex()].routingConfiguration), createObject('value', createObject()))]", - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } + "routingConfiguration": "[if(contains(parameters('hubVirtualNetworkConnections')[copyIndex()], 'routingConfiguration'), createObject('value', parameters('hubVirtualNetworkConnections')[copyIndex()].routingConfiguration), createObject('value', createObject()))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -434,8 +398,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "10987823499253979342" + "version": "0.27.1.19265", + "templateHash": "449308154693946367" }, "name": "Virtual Hub Virtual Network Connections", "description": "This module deploys a Virtual Hub Virtual Network Connection.", @@ -473,36 +437,9 @@ "metadata": { "description": "Optional. Routing Configuration indicating the associated and propagated route tables for this connection." } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } } }, "resources": [ - { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2021-04-01", - "name": "[format('46d3xbcp.res.network-virtualhub.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, { "type": "Microsoft.Network/virtualHubs/hubVirtualNetworkConnections", "apiVersion": "2022-11-01", From a11ba135a25ede00de5c5296c04d39ee842aff3c Mon Sep 17 00:00:00 2001 From: hundredacres Date: Fri, 17 May 2024 02:49:46 -0700 Subject: [PATCH 43/52] fix: Minor edits to get version publishing working (#1953) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Minor change to resolve version publishing issues. ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.network.azure-firewall](https://github.com/hundredacres/bicep-registry-modules/actions/workflows/avm.res.network.azure-firewall.yml/badge.svg?branch=fix%2Fazure_firewall%2Fversion)](https://github.com/hundredacres/bicep-registry-modules/actions/workflows/avm.res.network.azure-firewall.yml) | ## Type of Change - [X] Update to CI Environment or utlities (Non-module effecting 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. - [ ] 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`. - [X] 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 --------- Co-authored-by: Máté Barabás Co-authored-by: Rainer Halanek <61878316+rahalan@users.noreply.github.com> Co-authored-by: JFolberth --- avm/res/network/azure-firewall/README.md | 135 +++------------------- avm/res/network/azure-firewall/main.bicep | 6 +- avm/res/network/azure-firewall/main.json | 8 +- 3 files changed, 26 insertions(+), 123 deletions(-) diff --git a/avm/res/network/azure-firewall/README.md b/avm/res/network/azure-firewall/README.md index e821af3f602..33d03091d5a 100644 --- a/avm/res/network/azure-firewall/README.md +++ b/avm/res/network/azure-firewall/README.md @@ -29,113 +29,16 @@ The following section provides usage examples for the module, which were used to >**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/azure-firewall:`. -- [Issue-1867](#example-1-issue-1867) -- [Add-PIP](#example-2-add-pip) -- [Custom-PIP](#example-3-custom-pip) -- [Using only defaults](#example-4-using-only-defaults) -- [Hub-commom](#example-5-hub-commom) -- [Hub-min](#example-6-hub-min) -- [Using large parameter set](#example-7-using-large-parameter-set) -- [Public-IP-Prefix](#example-8-public-ip-prefix) -- [WAF-aligned](#example-9-waf-aligned) +- [Add-PIP](#example-1-add-pip) +- [Custom-PIP](#example-2-custom-pip) +- [Using only defaults](#example-3-using-only-defaults) +- [Hub-commom](#example-4-hub-commom) +- [Hub-min](#example-5-hub-min) +- [Using large parameter set](#example-6-using-large-parameter-set) +- [Public-IP-Prefix](#example-7-public-ip-prefix) +- [WAF-aligned](#example-8-waf-aligned) -### Example 1: _Issue-1867_ - -Validating reported bug 1867 - - -

- -via Bicep module - -```bicep -module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { - name: 'azureFirewallDeployment' - params: { - // Required parameters - name: 'nafcustom001' - // Non-required parameters - azureSkuTier: 'Basic' - firewallPolicyId: '' - location: '' - managementIPAddressObject: { - managementIPAllocationMethod: 'Static' - managementIPPrefixResourceId: '' - name: 'managementIP01' - skuName: 'Standard' - skuTier: 'Regional' - } - publicIPAddressObject: { - name: 'publicIP01' - publicIPAllocationMethod: 'Static' - publicIPPrefixResourceId: '' - skuName: 'Standard' - skuTier: 'Regional' - } - virtualNetworkResourceId: '' - zones: [] - } -} -``` - -
-

- -

- -via JSON Parameter file - -```json -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - // Required parameters - "name": { - "value": "nafcustom001" - }, - // Non-required parameters - "azureSkuTier": { - "value": "Basic" - }, - "firewallPolicyId": { - "value": "" - }, - "location": { - "value": "" - }, - "managementIPAddressObject": { - "value": { - "managementIPAllocationMethod": "Static", - "managementIPPrefixResourceId": "", - "name": "managementIP01", - "skuName": "Standard", - "skuTier": "Regional" - } - }, - "publicIPAddressObject": { - "value": { - "name": "publicIP01", - "publicIPAllocationMethod": "Static", - "publicIPPrefixResourceId": "", - "skuName": "Standard", - "skuTier": "Regional" - } - }, - "virtualNetworkResourceId": { - "value": "" - }, - "zones": { - "value": [] - } - } -} -``` - -
-

- -### Example 2: _Add-PIP_ +### Example 1: _Add-PIP_ This instance deploys the module and attaches an existing public IP address. @@ -227,7 +130,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

-### Example 3: _Custom-PIP_ +### Example 2: _Custom-PIP_ This instance deploys the module and will create a public IP address. @@ -337,7 +240,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

-### Example 4: _Using only defaults_ +### Example 3: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -389,7 +292,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

-### Example 5: _Hub-commom_ +### Example 4: _Hub-commom_ This instance deploys the module a vWAN in a typical hub setting. @@ -457,7 +360,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

-### Example 6: _Hub-min_ +### Example 5: _Hub-min_ This instance deploys the module a vWAN minimum hub setting. @@ -521,7 +424,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

-### Example 7: _Using large parameter set_ +### Example 6: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -875,7 +778,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

-### Example 8: _Public-IP-Prefix_ +### Example 7: _Public-IP-Prefix_ This instance deploys the module and will use a public IP prefix. @@ -967,7 +870,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

-### Example 9: _WAF-aligned_ +### Example 8: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -2234,12 +2137,12 @@ Zone numbers e.g. 1,2,3. | Output | Type | Description | | :-- | :-- | :-- | -| `applicationRuleCollections` | array | List of Application Rule Collections. | +| `applicationRuleCollections` | array | List of Application Rule Collections used by Azure Firewall. | | `ipConfAzureFirewallSubnet` | object | The Public IP configuration object for the Azure Firewall Subnet. | | `location` | string | The location the resource was deployed into. | | `name` | string | The name of the Azure Firewall. | -| `natRuleCollections` | array | Collection of NAT rule collections used by Azure Firewall. | -| `networkRuleCollections` | array | List of Network Rule Collections. | +| `natRuleCollections` | array | List of NAT rule collections used by Azure Firewall. | +| `networkRuleCollections` | array | List of Network Rule Collections used by Azure Firewall. | | `privateIp` | string | The private IP of the Azure firewall. | | `resourceGroupName` | string | The resource group the Azure firewall was deployed into. | | `resourceId` | string | The resource ID of the Azure Firewall. | diff --git a/avm/res/network/azure-firewall/main.bicep b/avm/res/network/azure-firewall/main.bicep index 54d4661cf2c..38c7819be33 100644 --- a/avm/res/network/azure-firewall/main.bicep +++ b/avm/res/network/azure-firewall/main.bicep @@ -372,13 +372,13 @@ output ipConfAzureFirewallSubnet object = contains(azureFirewall.properties, 'ip ? azureFirewall.properties.ipConfigurations[0] : {} -@description('List of Application Rule Collections.') +@description('List of Application Rule Collections used by Azure Firewall.') output applicationRuleCollections array = applicationRuleCollections ?? [] -@description('List of Network Rule Collections.') +@description('List of Network Rule Collections used by Azure Firewall.') output networkRuleCollections array = networkRuleCollections ?? [] -@description('Collection of NAT rule collections used by Azure Firewall.') +@description('List of NAT rule collections used by Azure Firewall.') output natRuleCollections array = natRuleCollections ?? [] @description('The location the resource was deployed into.') diff --git a/avm/res/network/azure-firewall/main.json b/avm/res/network/azure-firewall/main.json index 47361a85e2a..8ff6f7c228b 100644 --- a/avm/res/network/azure-firewall/main.json +++ b/avm/res/network/azure-firewall/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.27.1.19265", - "templateHash": "5299175231300175796" + "templateHash": "18119107920030966169" }, "name": "Azure Firewalls", "description": "This module deploys an Azure Firewall.", @@ -2280,21 +2280,21 @@ "applicationRuleCollections": { "type": "array", "metadata": { - "description": "List of Application Rule Collections." + "description": "List of Application Rule Collections used by Azure Firewall." }, "value": "[coalesce(parameters('applicationRuleCollections'), createArray())]" }, "networkRuleCollections": { "type": "array", "metadata": { - "description": "List of Network Rule Collections." + "description": "List of Network Rule Collections used by Azure Firewall." }, "value": "[coalesce(parameters('networkRuleCollections'), createArray())]" }, "natRuleCollections": { "type": "array", "metadata": { - "description": "Collection of NAT rule collections used by Azure Firewall." + "description": "List of NAT rule collections used by Azure Firewall." }, "value": "[coalesce(parameters('natRuleCollections'), createArray())]" }, From ef6a568da2f255adaa69f1c34fbdb7a7bcc0971b Mon Sep 17 00:00:00 2001 From: hundredacres Date: Sun, 19 May 2024 00:16:33 -0700 Subject: [PATCH 44/52] fix: Adding support for managedidentity (#1972) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Update API version to support adding an identity to the resource. Fixes #1922 Closes #1922 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.app.managed-environment](https://github.com/hundredacres/bicep-registry-modules/actions/workflows/avm.res.app.managed-environment.yml/badge.svg?branch=fix%2Fissue%2F1922)](https://github.com/hundredacres/bicep-registry-modules/actions/workflows/avm.res.app.managed-environment.yml) | ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting changes) - [X] Azure Verified Module updates: - [ ] Bugfix containing backwards compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [X] 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 --------- Co-authored-by: Máté Barabás Co-authored-by: Rainer Halanek <61878316+rahalan@users.noreply.github.com> Co-authored-by: JFolberth --- avm/res/app/managed-environment/README.md | 46 +++++++++++++++++- avm/res/app/managed-environment/main.bicep | 33 ++++++++++++- avm/res/app/managed-environment/main.json | 47 +++++++++++++++++-- .../tests/e2e/max/dependencies.bicep | 3 ++ .../tests/e2e/max/main.test.bicep | 6 +++ avm/res/app/managed-environment/version.json | 2 +- 6 files changed, 130 insertions(+), 7 deletions(-) diff --git a/avm/res/app/managed-environment/README.md b/avm/res/app/managed-environment/README.md index feac29db4e6..935d035505c 100644 --- a/avm/res/app/managed-environment/README.md +++ b/avm/res/app/managed-environment/README.md @@ -15,7 +15,7 @@ This module deploys an App Managed Environment (also known as a Container App En | Resource Type | API Version | | :-- | :-- | -| `Microsoft.App/managedEnvironments` | [2023-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.App/2023-05-01/managedEnvironments) | +| `Microsoft.App/managedEnvironments` | [2023-11-02-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.App/2023-11-02-preview/managedEnvironments) | | `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | | `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | @@ -151,6 +151,12 @@ module managedEnvironment 'br/public:avm/res/app/managed-environment:' kind: 'CanNotDelete' name: 'myCustomLockName' } + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] + } platformReservedCidr: '172.17.17.0/24' platformReservedDnsIP: '172.17.17.17' roleAssignments: [ @@ -227,6 +233,14 @@ module managedEnvironment 'br/public:avm/res/app/managed-environment:' "name": "myCustomLockName" } }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "" + ] + } + }, "platformReservedCidr": { "value": "172.17.17.0/24" }, @@ -460,6 +474,7 @@ module managedEnvironment 'br/public:avm/res/app/managed-environment:' | [`location`](#parameter-location) | string | Location for all Resources. | | [`lock`](#parameter-lock) | object | The lock settings of the service. | | [`logsDestination`](#parameter-logsdestination) | string | Logs destination. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`zoneRedundant`](#parameter-zoneredundant) | bool | Whether or not this Managed Environment is zone-redundant. | @@ -634,6 +649,34 @@ Logs destination. - Type: string - Default: `'log-analytics'` +### Parameter: `managedIdentities` + +The managed identity definition for this resource. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`systemAssigned`](#parameter-managedidentitiessystemassigned) | bool | Enables system assigned managed identity on the resource. | +| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. | + +### Parameter: `managedIdentities.systemAssigned` + +Enables system assigned managed identity on the resource. + +- Required: No +- Type: bool + +### Parameter: `managedIdentities.userAssignedResourceIds` + +The resource ID(s) to assign to the resource. + +- Required: No +- Type: array + ### Parameter: `roleAssignments` Array of role assignments to create. @@ -748,6 +791,7 @@ Whether or not this Managed Environment is zone-redundant. | `name` | string | The name of the Managed Environment. | | `resourceGroupName` | string | The name of the resource group the Managed Environment was deployed into. | | `resourceId` | string | The resource ID of the Managed Environment. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | ## Cross-referenced modules diff --git a/avm/res/app/managed-environment/main.bicep b/avm/res/app/managed-environment/main.bicep index 6ed8dc58fd8..c609ded7159 100644 --- a/avm/res/app/managed-environment/main.bicep +++ b/avm/res/app/managed-environment/main.bicep @@ -14,6 +14,9 @@ param location string = resourceGroup().location @description('Optional. Tags of the resource.') param tags object? +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType + @description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType @@ -69,6 +72,22 @@ param workloadProfiles array = [] @description('Conditional. Name of the infrastructure resource group. If not provided, it will be set with a default value. Required if zoneRedundant is set to true to make the resource WAF compliant.') param infrastructureResourceGroupName string = take('ME_${name}', 63) +var formattedUserAssignedIdentities = reduce( + map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), + {}, + (cur, next) => union(cur, next) +) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + + +var identity = !empty(managedIdentities) + ? { + type: (managedIdentities.?systemAssigned ?? false) + ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') + : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : 'None') + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null + } + : null + var builtInRoleNames = { Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') @@ -108,10 +127,11 @@ resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2021-06 scope: resourceGroup(split(logAnalyticsWorkspaceResourceId, '/')[2], split(logAnalyticsWorkspaceResourceId, '/')[4]) } -resource managedEnvironment 'Microsoft.App/managedEnvironments@2023-05-01' = { +resource managedEnvironment 'Microsoft.App/managedEnvironments@2023-11-02-preview' = { name: name location: location tags: tags + identity: identity properties: { appLogsConfiguration: { destination: logsDestination @@ -184,6 +204,9 @@ output name string = managedEnvironment.name @description('The resource ID of the Managed Environment.') output resourceId string = managedEnvironment.id +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string = managedEnvironment.?identity.?principalId ?? '' + @description('The Default domain of the Managed Environment.') output defaultDomain string = managedEnvironment.properties.defaultDomain @@ -191,6 +214,14 @@ output defaultDomain string = managedEnvironment.properties.defaultDomain // Definitions // // =============== // +type managedIdentitiesType = { + @description('Optional. Enables system assigned managed identity on the resource.') + systemAssigned: bool? + + @description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourceIds: string[]? +}? + type lockType = { @description('Optional. Specify the name of lock.') name: string? diff --git a/avm/res/app/managed-environment/main.json b/avm/res/app/managed-environment/main.json index 13537daa444..2eafa79846d 100644 --- a/avm/res/app/managed-environment/main.json +++ b/avm/res/app/managed-environment/main.json @@ -5,14 +5,37 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "17801833041272323788" + "version": "0.27.1.19265", + "templateHash": "15666134926564437864" }, "name": "App ManagedEnvironments", "description": "This module deploys an App Managed Environment (also known as a Container App Environment).", "owner": "Azure/module-maintainers" }, "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, "lockType": { "type": "object", "properties": { @@ -132,6 +155,12 @@ "description": "Optional. Tags of the resource." } }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "metadata": { @@ -251,6 +280,8 @@ } }, "variables": { + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", @@ -291,10 +322,11 @@ }, "managedEnvironment": { "type": "Microsoft.App/managedEnvironments", - "apiVersion": "2023-05-01", + "apiVersion": "2023-11-02-preview", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", "properties": { "appLogsConfiguration": { "destination": "[parameters('logsDestination')]", @@ -375,7 +407,7 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('managedEnvironment', '2023-05-01', 'full').location]" + "value": "[reference('managedEnvironment', '2023-11-02-preview', 'full').location]" }, "name": { "type": "string", @@ -391,6 +423,13 @@ }, "value": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]" }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('managedEnvironment', '2023-11-02-preview', 'full'), 'identity'), 'principalId'), '')]" + }, "defaultDomain": { "type": "string", "metadata": { diff --git a/avm/res/app/managed-environment/tests/e2e/max/dependencies.bicep b/avm/res/app/managed-environment/tests/e2e/max/dependencies.bicep index ca9894d9dd4..ebeb013d5a3 100644 --- a/avm/res/app/managed-environment/tests/e2e/max/dependencies.bicep +++ b/avm/res/app/managed-environment/tests/e2e/max/dependencies.bicep @@ -67,3 +67,6 @@ output subnetResourceId string = virtualNetwork.properties.subnets[0].id @description('The principal ID of the created Managed Identity.') output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id diff --git a/avm/res/app/managed-environment/tests/e2e/max/main.test.bicep b/avm/res/app/managed-environment/tests/e2e/max/main.test.bicep index c48a95ec30d..919c7ab40f3 100644 --- a/avm/res/app/managed-environment/tests/e2e/max/main.test.bicep +++ b/avm/res/app/managed-environment/tests/e2e/max/main.test.bicep @@ -68,6 +68,12 @@ module testDeployment '../../../main.bicep' = [ platformReservedDnsIP: '172.17.17.17' infrastructureSubnetId: nestedDependencies.outputs.subnetResourceId infrastructureResourceGroupName: 'me-${resourceGroupName}' + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } roleAssignments: [ { roleDefinitionIdOrName: 'Owner' diff --git a/avm/res/app/managed-environment/version.json b/avm/res/app/managed-environment/version.json index 96236a61ba0..04a0dd1a80d 100644 --- a/avm/res/app/managed-environment/version.json +++ b/avm/res/app/managed-environment/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.4", + "version": "0.5", "pathFilters": [ "./main.json" ] From 86cfa8621eec707cba22912affb179b641960b92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20H=C3=A9zser?= Date: Sun, 19 May 2024 09:45:33 +0200 Subject: [PATCH 45/52] chore: `res/app/job` - not orphaned anymore (#1969) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description I removed the orphaned hint. ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.app.job](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.app.job.yml/badge.svg?branch=app-job-owner-change)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.app.job.yml) | The pipeline fails, because the module is marked as orphaned and is expecting the orphaned.md, which I removed ¯\\_(ツ)_/¯ ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting changes) - [x] 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. - [ ] 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`. - [x] 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 --- avm/res/app/job/ORPHANED.md | 4 ---- avm/res/app/job/README.md | 5 ----- avm/res/app/job/main.json | 4 ++-- 3 files changed, 2 insertions(+), 11 deletions(-) delete mode 100644 avm/res/app/job/ORPHANED.md diff --git a/avm/res/app/job/ORPHANED.md b/avm/res/app/job/ORPHANED.md deleted file mode 100644 index ef8fa911d2b..00000000000 --- a/avm/res/app/job/ORPHANED.md +++ /dev/null @@ -1,4 +0,0 @@ -⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️ - -- Only security and bug fixes are being handled by the AVM core team at present. -- If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)! \ No newline at end of file diff --git a/avm/res/app/job/README.md b/avm/res/app/job/README.md index 93e9c6e55a0..ccca0ee8107 100644 --- a/avm/res/app/job/README.md +++ b/avm/res/app/job/README.md @@ -1,10 +1,5 @@ # Container App Jobs `[Microsoft.App/jobs]` -> ⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️ -> -> - Only security and bug fixes are being handled by the AVM core team at present. -> - If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)! - This module deploys a Container App Job. ## Navigation diff --git a/avm/res/app/job/main.json b/avm/res/app/job/main.json index 6d8ee06c25b..58fed4a24e2 100644 --- a/avm/res/app/job/main.json +++ b/avm/res/app/job/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.27.1.19265", - "templateHash": "11649443218681434280" + "version": "0.26.170.59819", + "templateHash": "3096359783958038878" }, "name": "Container App Jobs", "description": "This module deploys a Container App Job.", From bc8d57bf4981567080523edaca9e3b98129fdbe2 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Mon, 20 May 2024 11:04:51 +0200 Subject: [PATCH 46/52] fix: Added `-Culture 'en-US'` to all `Sort-Object` operations (#1976) ## Description - Added `-Culture 'en-US'` to all `Sort-Object` operations to mitigate issues some contributors with a different configured culture have - Re-ran the generation for all files (no changes) Related to https://github.com/Azure/ResourceModules/issues/3722, but needs to be fixed there seperately ## Type of Change - [x] Update to CI Environment or utlities (Non-module effecting 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. - [ ] 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 --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- .../tests/unit/avm.core.team.tests.ps1 | 2 +- .../tests/unit/avm.core.team.tests.ps1 | 2 +- .../Initialize-DeploymentRemoval.ps1 | 4 ++-- .../Get-ResourceIdsAsFormattedObjectList.ps1 | 2 +- .../helper/Remove-Deployment.ps1 | 2 +- .../Invoke-AvmJsonModuleIndexGeneration.ps1 | 6 +++--- .../publish/helper/Get-ModulesToPublish.ps1 | 2 +- .../sharedScripts/Add-YamlListToFile.ps1 | 2 +- .../sharedScripts/Set-EnvironmentOnAgent.ps1 | 2 +- .../sharedScripts/Set-ModuleReadMe.ps1 | 14 ++++++------- .../helper/ConvertTo-OrderedHashtable.ps1 | 8 ++++---- .../helper/Get-CrossReferencedModuleList.ps1 | 8 ++++---- .../helper/Get-SpecsAlignedResourceName.ps1 | 4 ++-- .../Convert-TokensInFileList.ps1 | 2 +- .../compliance/Set-PesterGitHubOutput.ps1 | 8 ++++---- .../compliance/module.tests.ps1 | 20 +++++++++---------- .../psrule/Set-PSRuleGitHubOutput.ps1 | 4 ++-- .../tools/Invoke-WorkflowsForBranch.ps1 | 2 +- avm/utilities/tools/Test-ModuleLocally.ps1 | 2 +- 19 files changed, 48 insertions(+), 48 deletions(-) diff --git a/avm/res/compute/virtual-machine/tests/unit/avm.core.team.tests.ps1 b/avm/res/compute/virtual-machine/tests/unit/avm.core.team.tests.ps1 index 15532c48ed5..a6229b35e40 100644 --- a/avm/res/compute/virtual-machine/tests/unit/avm.core.team.tests.ps1 +++ b/avm/res/compute/virtual-machine/tests/unit/avm.core.team.tests.ps1 @@ -17,7 +17,7 @@ BeforeAll { . (Join-Path $RepoRootPath 'avm' 'utilities' 'pipelines' 'sharedScripts' 'helper' 'Get-IsParameterRequired.ps1') if ($moduleFolderPaths.Count -gt 1) { - $topLevelModuleTemplatePath = $moduleFolderPaths | Sort-Object | Select-Object -First 1 + $topLevelModuleTemplatePath = $moduleFolderPaths | Sort-Object -Culture 'en-US' | Select-Object -First 1 } else { $topLevelModuleTemplatePath = $moduleFolderPaths } diff --git a/avm/res/network/nat-gateway/tests/unit/avm.core.team.tests.ps1 b/avm/res/network/nat-gateway/tests/unit/avm.core.team.tests.ps1 index ee6d4dc0838..eb8c8928b07 100644 --- a/avm/res/network/nat-gateway/tests/unit/avm.core.team.tests.ps1 +++ b/avm/res/network/nat-gateway/tests/unit/avm.core.team.tests.ps1 @@ -17,7 +17,7 @@ BeforeAll { . (Join-Path $RepoRootPath 'avm' 'utilities' 'pipelines' 'sharedScripts' 'helper' 'Get-IsParameterRequired.ps1') if ($moduleFolderPaths.Count -gt 1) { - $topLevelModuleTemplatePath = $moduleFolderPaths | Sort-Object | Select-Object -First 1 + $topLevelModuleTemplatePath = $moduleFolderPaths | Sort-Object -Culture 'en-US' | Select-Object -First 1 } else { $topLevelModuleTemplatePath = $moduleFolderPaths } diff --git a/avm/utilities/pipelines/e2eValidation/resourceRemoval/Initialize-DeploymentRemoval.ps1 b/avm/utilities/pipelines/e2eValidation/resourceRemoval/Initialize-DeploymentRemoval.ps1 index 2ceed9e64b1..d5d4c20503b 100644 --- a/avm/utilities/pipelines/e2eValidation/resourceRemoval/Initialize-DeploymentRemoval.ps1 +++ b/avm/utilities/pipelines/e2eValidation/resourceRemoval/Initialize-DeploymentRemoval.ps1 @@ -134,11 +134,11 @@ function Initialize-DeploymentRemoval { if ($PurgeTestResources) { # Resources $filteredResourceIds = (Get-AzResource).ResourceId | Where-Object { $_ -like '*dep-*' } - $ResourceIds += ($filteredResourceIds | Sort-Object -Unique) + $ResourceIds += ($filteredResourceIds | Sort-Object -Culture 'en-US' -Unique) # Resource groups $filteredResourceGroupIds = (Get-AzResourceGroup).ResourceId | Where-Object { $_ -like '*dep-*' } - $ResourceIds += ($filteredResourceGroupIds | Sort-Object -Unique) + $ResourceIds += ($filteredResourceGroupIds | Sort-Object -Culture 'en-US' -Unique) } # Invoke removal diff --git a/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Get-ResourceIdsAsFormattedObjectList.ps1 b/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Get-ResourceIdsAsFormattedObjectList.ps1 index 69f83360ebd..731b62ee33e 100644 --- a/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Get-ResourceIdsAsFormattedObjectList.ps1 +++ b/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Get-ResourceIdsAsFormattedObjectList.ps1 @@ -78,7 +78,7 @@ function Get-ResourceIdsAsFormattedObjectList { $allResourceGroupResources = Get-AzResource -ResourceGroupName $resourceGroupName -Name '*' } $expandedResources = $allResourceGroupResources | Where-Object { $_.ResourceId.startswith($resourceId) } - $expandedResources = $expandedResources | Sort-Object -Descending -Property { $_.ResourceId.Split('/').Count } + $expandedResources = $expandedResources | Sort-Object -Culture 'en-US' -Descending -Property { $_.ResourceId.Split('/').Count } foreach ($resource in $expandedResources) { $formattedResources += @{ resourceId = $resource.ResourceId diff --git a/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Remove-Deployment.ps1 b/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Remove-Deployment.ps1 index fdea2ed2397..00a0d50676d 100644 --- a/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Remove-Deployment.ps1 +++ b/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Remove-Deployment.ps1 @@ -116,7 +116,7 @@ function Remove-Deployment { # Pre-Filter & order items # ======================== - $rawTargetResourceIdsToRemove = $deployedTargetResources | Sort-Object -Property { $_.Split('/').Count } -Descending | Select-Object -Unique + $rawTargetResourceIdsToRemove = $deployedTargetResources | Sort-Object -Culture 'en-US' -Property { $_.Split('/').Count } -Descending | Select-Object -Unique Write-Verbose ('Total number of deployment target resources after pre-filtering (duplicates) & ordering items [{0}]' -f $rawTargetResourceIdsToRemove.Count) -Verbose # Format items diff --git a/avm/utilities/pipelines/platform/Invoke-AvmJsonModuleIndexGeneration.ps1 b/avm/utilities/pipelines/platform/Invoke-AvmJsonModuleIndexGeneration.ps1 index 2704177b8e6..b48b67f8641 100644 --- a/avm/utilities/pipelines/platform/Invoke-AvmJsonModuleIndexGeneration.ps1 +++ b/avm/utilities/pipelines/platform/Invoke-AvmJsonModuleIndexGeneration.ps1 @@ -98,7 +98,7 @@ function Invoke-AvmJsonModuleIndexGeneration { Write-Error "Error message: $($_.Exception.Message)" continue } - $tags = $tagListResponse.tags | Sort-Object + $tags = $tagListResponse.tags | Sort-Object -Culture 'en-US' $properties = [ordered]@{} foreach ($tag in $tags) { @@ -190,7 +190,7 @@ function Invoke-AvmJsonModuleIndexGeneration { } else { # If the module exists, merge the tags and properties $mergedModule = $initialMergeOfJsonFilesData[$module.moduleName] - $mergedModule.tags = @(($mergedModule.tags + $module.tags) | Sort-Object -Unique) + $mergedModule.tags = @(($mergedModule.tags + $module.tags) | Sort-Object -Culture 'en-US' -Unique) # Merge properties foreach ($property in $module.properties.PSObject.Properties) { @@ -205,7 +205,7 @@ function Invoke-AvmJsonModuleIndexGeneration { $mergedModuleIndexData = $initialMergeOfJsonFilesData.Values # Sort the modules by their names - $sortedMergedModuleIndexData = $mergedModuleIndexData | Sort-Object moduleName + $sortedMergedModuleIndexData = $mergedModuleIndexData | Sort-Object -Culture 'en-US' -Property 'moduleName' Write-Verbose "Convert mergedModuleIndexData variable to JSON and save as 'moduleIndex.json'" -Verbose $sortedMergedModuleIndexData | ConvertTo-Json -Depth 10 | Out-File -FilePath $moduleIndexJsonFilePath diff --git a/avm/utilities/pipelines/publish/helper/Get-ModulesToPublish.ps1 b/avm/utilities/pipelines/publish/helper/Get-ModulesToPublish.ps1 index 0ba3ef62cf2..e7f2ca0471f 100644 --- a/avm/utilities/pipelines/publish/helper/Get-ModulesToPublish.ps1 +++ b/avm/utilities/pipelines/publish/helper/Get-ModulesToPublish.ps1 @@ -102,7 +102,7 @@ function Get-TemplateFileToPublish { $TemplateFilesToPublish = $relevantPaths | ForEach-Object { Find-TemplateFile -Path $_ -Verbose - } | Sort-Object -Unique -Descending + } | Sort-Object -Culture 'en-US' -Unique -Descending if ($TemplateFilesToPublish.Count -eq 0) { Write-Verbose 'No template file found in the modified module.' -Verbose diff --git a/avm/utilities/pipelines/sharedScripts/Add-YamlListToFile.ps1 b/avm/utilities/pipelines/sharedScripts/Add-YamlListToFile.ps1 index b81cec6cad7..4a7732c651b 100644 --- a/avm/utilities/pipelines/sharedScripts/Add-YamlListToFile.ps1 +++ b/avm/utilities/pipelines/sharedScripts/Add-YamlListToFile.ps1 @@ -69,7 +69,7 @@ function Add-YamlListToFile { throw "No key-value pairs found in List: $ListName" } # Process key value pairs in the list - foreach ($Key in ($KeyValuePair.Keys.split(' ') | Sort-Object)) { + foreach ($Key in ($KeyValuePair.Keys.split(' ') | Sort-Object -Culture 'en-US')) { Write-Verbose ('Setting environment variable [{0}] with value [{1}]' -f $Key, $KeyValuePair[$Key]) -Verbose Write-Output "$Key=$($KeyValuePair[$Key])" | Out-File -FilePath $OutputFilePath -Encoding 'utf-8' -Append } diff --git a/avm/utilities/pipelines/sharedScripts/Set-EnvironmentOnAgent.ps1 b/avm/utilities/pipelines/sharedScripts/Set-EnvironmentOnAgent.ps1 index 12de5cec071..bcfb7253abb 100644 --- a/avm/utilities/pipelines/sharedScripts/Set-EnvironmentOnAgent.ps1 +++ b/avm/utilities/pipelines/sharedScripts/Set-EnvironmentOnAgent.ps1 @@ -63,7 +63,7 @@ function Install-CustomModule { $alreadyInstalled = $alreadyInstalled | Where-Object { $_.Version -eq $Module.Version } } else { # Get latest in case of multiple - $alreadyInstalled = ($alreadyInstalled | Sort-Object -Property Version -Descending)[0] + $alreadyInstalled = ($alreadyInstalled | Sort-Object -Culture 'en-US' -Property 'Version' -Descending)[0] } Write-Verbose ('Module [{0}] already installed with version [{1}]' -f $alreadyInstalled.Name, $alreadyInstalled.Version) -Verbose continue diff --git a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 index 43ee7b2dd72..83c923f6011 100644 --- a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 +++ b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 @@ -95,7 +95,7 @@ function Set-ResourceTypesSection { $RelevantResourceTypeObjects = Get-NestedResourceList $TemplateFileContent | Where-Object { $_.type -notin $ResourceTypesToExclude -and $_ - } | Select-Object 'Type', 'ApiVersion' -Unique | Sort-Object Type -Culture 'en-US' + } | Select-Object 'Type', 'ApiVersion' -Unique | Sort-Object -Culture 'en-US' -Property 'Type' $ProgressPreference = 'SilentlyContinue' $VerbosePreference = 'SilentlyContinue' @@ -277,9 +277,9 @@ function Set-DefinitionSection { # Filter to relevant items if (-not $Properties) { # Top-level invocation - [array] $categoryParameters = $TemplateFileContent.parameters.Values | Where-Object { $_.metadata.description -like "$category. *" } | Sort-Object -Property 'Name' -Culture 'en-US' + [array] $categoryParameters = $TemplateFileContent.parameters.Values | Where-Object { $_.metadata.description -like "$category. *" } | Sort-Object -Culture 'en-US' -Property 'Name' } else { - $categoryParameters = $Properties.Values | Where-Object { $_.metadata.description -like "$category. *" } | Sort-Object -Property 'Name' -Culture 'en-US' + $categoryParameters = $Properties.Values | Where-Object { $_.metadata.description -like "$category. *" } | Sort-Object -Culture 'en-US' -Property 'Name' } $tableSectionContent += @( @@ -657,13 +657,13 @@ function Set-CrossReferencesSection { $dependencies = $CrossReferencedModuleList[$FullModuleIdentifier] if ($dependencies.Keys -contains 'localPathReferences' -and $dependencies['localPathReferences']) { - foreach ($reference in ($dependencies['localPathReferences'] | Sort-Object)) { + foreach ($reference in ($dependencies['localPathReferences'] | Sort-Object -Culture 'en-US')) { $SectionContent += ("| ``{0}`` | {1} |" -f $reference, 'Local reference') } } if ($dependencies.Keys -contains 'remoteReferences' -and $dependencies['remoteReferences']) { - foreach ($reference in ($dependencies['remoteReferences'] | Sort-Object)) { + foreach ($reference in ($dependencies['remoteReferences'] | Sort-Object -Culture 'en-US')) { $SectionContent += ("| ``{0}`` | {1} |" -f $reference, 'Remote reference') } } @@ -1283,11 +1283,11 @@ function Set-UsageExamplesSection { $moduleNameCamelCase = $First.Tolower() + (Get-Culture).TextInfo.ToTitleCase($Rest) -Replace '-' } - $testFilePaths = (Get-ChildItem -Path $ModuleRoot -Recurse -Filter 'main.test.bicep').FullName | Sort-Object + $testFilePaths = (Get-ChildItem -Path $ModuleRoot -Recurse -Filter 'main.test.bicep').FullName | Sort-Object -Culture 'en-US' $RequiredParametersList = $TemplateFileContent.parameters.Keys | Where-Object { Get-IsParameterRequired -TemplateFileContent $TemplateFileContent -Parameter $TemplateFileContent.parameters[$_] - } | Sort-Object + } | Sort-Object -Culture 'en-US' ############################ ## Process test files ## diff --git a/avm/utilities/pipelines/sharedScripts/helper/ConvertTo-OrderedHashtable.ps1 b/avm/utilities/pipelines/sharedScripts/helper/ConvertTo-OrderedHashtable.ps1 index cfd446753ea..f2707264997 100644 --- a/avm/utilities/pipelines/sharedScripts/helper/ConvertTo-OrderedHashtable.ps1 +++ b/avm/utilities/pipelines/sharedScripts/helper/ConvertTo-OrderedHashtable.ps1 @@ -63,7 +63,7 @@ function ConvertTo-OrderedHashtable { return $JSONObject # E.g. in primitive data types [1,2,3] } - foreach ($currentLevelKey in ($JSONObject.Keys | Sort-Object)) { + foreach ($currentLevelKey in ($JSONObject.Keys | Sort-Object -Culture 'en-US')) { if ($null -eq $JSONObject[$currentLevelKey]) { # Handle case in which the value is 'null' and hence has no type @@ -83,7 +83,7 @@ function ConvertTo-OrderedHashtable { foreach ($array in $arrayElements) { if ($array.Count -gt 1) { # Only sort for arrays with more than one item. Otherwise single-item arrays are casted - $array = $array | Sort-Object + $array = $array | Sort-Object -Culture 'en-US' } $arrayOutput += , (ConvertTo-OrderedHashtable -JSONInputObject ($array | ConvertTo-Json -Depth 99)) } @@ -97,13 +97,13 @@ function ConvertTo-OrderedHashtable { # Case: Primitive data types $primitiveElements = $JSONObject[$currentLevelKey] | Where-Object { $_.GetType().BaseType.Name -notin @('Array', 'Hashtable') } | ConvertTo-Json -Depth 99 | ConvertFrom-Json -AsHashtable -NoEnumerate -Depth 99 if ($primitiveElements.Count -gt 1) { - $primitiveElements = $primitiveElements | Sort-Object + $primitiveElements = $primitiveElements | Sort-Object -Culture 'en-US' } $arrayOutput += $primitiveElements if ($array.Count -gt 1) { # Only sort for arrays with more than one item. Otherwise single-item arrays are casted - $arrayOutput = $arrayOutput | Sort-Object + $arrayOutput = $arrayOutput | Sort-Object -Culture 'en-US' } $orderedLevel[$currentLevelKey] = $arrayOutput } diff --git a/avm/utilities/pipelines/sharedScripts/helper/Get-CrossReferencedModuleList.ps1 b/avm/utilities/pipelines/sharedScripts/helper/Get-CrossReferencedModuleList.ps1 index 0d34d96f61d..f9031b160ba 100644 --- a/avm/utilities/pipelines/sharedScripts/helper/Get-CrossReferencedModuleList.ps1 +++ b/avm/utilities/pipelines/sharedScripts/helper/Get-CrossReferencedModuleList.ps1 @@ -96,9 +96,9 @@ function Get-ReferenceObject { } return @{ - resourceReferences = $resultSet.resourceReferences | Sort-Object -Unique - remoteReferences = $resultSet.remoteReferences | Sort-Object -Unique - localPathReferences = $resultSet.localPathReferences | Sort-Object -Unique + resourceReferences = $resultSet.resourceReferences | Sort-Object -Culture 'en-US' -Unique + remoteReferences = $resultSet.remoteReferences | Sort-Object -Culture 'en-US' -Unique + localPathReferences = $resultSet.localPathReferences | Sort-Object -Culture 'en-US' -Unique } } #endregion @@ -155,7 +155,7 @@ function Get-CrossReferencedModuleList { $moduleTemplatePaths = (Get-ChildItem -Path $path -Recurse -File -Filter '*.bicep').FullName | Where-Object { # No files inthe [/utilities/tools/] folder and none in the [/tests/] folder $_ -notmatch '.*[\\|\/]tools[\\|\/].*|.*[\\|\/]tests[\\|\/].*' - } | Sort-Object + } | Sort-Object -Culture 'en-US' $templateMap = @{} foreach ($moduleTemplatePath in $moduleTemplatePaths) { $templateMap[$moduleTemplatePath] = Get-Content -Path $moduleTemplatePath diff --git a/avm/utilities/pipelines/sharedScripts/helper/Get-SpecsAlignedResourceName.ps1 b/avm/utilities/pipelines/sharedScripts/helper/Get-SpecsAlignedResourceName.ps1 index 356a552c483..b71fb9d849b 100644 --- a/avm/utilities/pipelines/sharedScripts/helper/Get-SpecsAlignedResourceName.ps1 +++ b/avm/utilities/pipelines/sharedScripts/helper/Get-SpecsAlignedResourceName.ps1 @@ -76,7 +76,7 @@ function Get-SpecsAlignedResourceName { $rawProviderNamespace, $rawResourceType = $reducedResourceIdentifier -Split '[\/|\\]', 2 # e.g. 'keyvault' & 'vaults/keys' # Find provider namespace - $foundProviderNamespaceMatches = ($specs.Keys | Sort-Object) | Where-Object { $_ -like "Microsoft.$rawProviderNamespace*" } + $foundProviderNamespaceMatches = ($specs.Keys | Sort-Object -Culture 'en-US') | Where-Object { $_ -like "Microsoft.$rawProviderNamespace*" } if (-not $foundProviderNamespaceMatches) { $providerNamespace = "Microsoft.$rawProviderNamespace" @@ -86,7 +86,7 @@ function Get-SpecsAlignedResourceName { } # Find resource type - $innerResourceTypes = $specs[$providerNamespace].Keys | Sort-Object + $innerResourceTypes = $specs[$providerNamespace].Keys | Sort-Object -Culture 'en-US' $rawResourceTypeElem = $rawResourceType -split '[\/|\\]' $reducedResourceTypeElements = $rawResourceTypeElem | ForEach-Object { Get-ReducedWordString -StringToReduce $_ } diff --git a/avm/utilities/pipelines/sharedScripts/tokenReplacement/Convert-TokensInFileList.ps1 b/avm/utilities/pipelines/sharedScripts/tokenReplacement/Convert-TokensInFileList.ps1 index bcae7411d64..806041c1220 100644 --- a/avm/utilities/pipelines/sharedScripts/tokenReplacement/Convert-TokensInFileList.ps1 +++ b/avm/utilities/pipelines/sharedScripts/tokenReplacement/Convert-TokensInFileList.ps1 @@ -70,7 +70,7 @@ function Convert-TokensInFileList { process { # Combine All Input Token Types, Remove Duplicates and Only Select entries with on empty values - $FilteredTokens = ($Tokens | Sort-Object -Unique).Clone() + $FilteredTokens = ($Tokens | Sort-Object -Culture 'en-US' -Unique).Clone() @($FilteredTokens.Keys) | ForEach-Object { if ([String]::IsNullOrEmpty($FilteredTokens[$_])) { $FilteredTokens.Remove($_) diff --git a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 index 70e939e949b..d28f09fa20a 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 @@ -128,7 +128,7 @@ function Set-PesterGitHubOutput { '| Name | Error | Source |', '| :-- | :-- | :-- |' ) - foreach ($failedTest in ($failedTests | Sort-Object -Property { $PSItem.ExpandedName })) { + foreach ($failedTest in ($failedTests | Sort-Object -Culture 'en-US' -Property { $PSItem.ExpandedName })) { $intermediateNameElements = $failedTest.Path $intermediateNameElements[-1] = '**{0}**' -f $failedTest.ExpandedName @@ -175,7 +175,7 @@ function Set-PesterGitHubOutput { '| Name | Source |', '| :-- | :-- |' ) - foreach ($passedTest in ($passedTests | Sort-Object -Property { $PSItem.ExpandedName }) ) { + foreach ($passedTest in ($passedTests | Sort-Object -Culture 'en-US' -Property { $PSItem.ExpandedName }) ) { $intermediateNameElements = $passedTest.Path $intermediateNameElements[-1] = '**{0}**' -f $passedTest.ExpandedName @@ -221,7 +221,7 @@ function Set-PesterGitHubOutput { '| Name | Reason | Source |', '| :-- | :-- | :-- |' ) - foreach ($skippedTest in ($skippedTests | Sort-Object -Property { $PSItem.ExpandedName }) ) { + foreach ($skippedTest in ($skippedTests | Sort-Object -Culture 'en-US' -Property { $PSItem.ExpandedName }) ) { $intermediateNameElements = $skippedTest.Path $intermediateNameElements[-1] = '**{0}**' -f $skippedTest.ExpandedName @@ -269,7 +269,7 @@ function Set-PesterGitHubOutput { '| Name | Warning | Source |', '| :-- | :-- | :-- |' ) - foreach ($test in ($testsWithWarnings | Sort-Object -Property { $PSItem.ExpandedName }) ) { + foreach ($test in ($testsWithWarnings | Sort-Object -Culture 'en-US' -Property { $PSItem.ExpandedName }) ) { foreach ($warning in $test.StandardOutput.Warning) { $intermediateNameElements = $test.Path $intermediateNameElements[-1] = '**{0}**' -f $test.ExpandedName diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index 92e9b154c59..86e82537524 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -36,7 +36,7 @@ Import-Module (Join-Path $PSScriptRoot 'helper' 'helper.psm1') -Force $pathsToBuild = [System.Collections.ArrayList]@() $pathsToBuild += $moduleFolderPaths | ForEach-Object { Join-Path $_ 'main.bicep' } foreach ($moduleFolderPath in $moduleFolderPaths) { - if ($testFilePaths = ((Get-ChildItem -Path $moduleFolderPath -Recurse -Filter 'main.test.bicep').FullName | Sort-Object)) { + if ($testFilePaths = ((Get-ChildItem -Path $moduleFolderPath -Recurse -Filter 'main.test.bicep').FullName | Sort-Object -Culture 'en-US')) { $pathsToBuild += $testFilePaths } } @@ -533,7 +533,7 @@ Describe 'Module tests' -Tag 'Module' { } $incorrectParameters = @() - foreach ($parameter in ($templateFileParameters.PSBase.Keys | Sort-Object)) { + foreach ($parameter in ($templateFileParameters.PSBase.Keys | Sort-Object -Culture 'en-US')) { # Parameters in the object are formatted like # - tags # - customerManagedKey.keyVaultResourceId @@ -560,7 +560,7 @@ Describe 'Module tests' -Tag 'Module' { } $incorrectParameters = @() - foreach ($parameter in ($templateFileParameters.PSBase.Keys | Sort-Object)) { + foreach ($parameter in ($templateFileParameters.PSBase.Keys | Sort-Object -Culture 'en-US')) { $data = $templateFileParameters.$parameter.metadata.description if ($data -notmatch '(?s)^[A-Z][a-zA-Z]+\. .+\.$') { $incorrectParameters += $parameter @@ -584,7 +584,7 @@ Describe 'Module tests' -Tag 'Module' { } $incorrectParameters = @() - foreach ($parameter in ($templateFileParameters.PSBase.Keys | Sort-Object)) { + foreach ($parameter in ($templateFileParameters.PSBase.Keys | Sort-Object -Culture 'en-US')) { $data = $templateFileParameters.$parameter.metadata.description switch -regex ($data) { '^Conditional. .*' { @@ -605,7 +605,7 @@ Describe 'Module tests' -Tag 'Module' { ) $incorrectParameters = @() - foreach ($parameter in ($templateFileParameters.PSBase.Keys | Sort-Object)) { + foreach ($parameter in ($templateFileParameters.PSBase.Keys | Sort-Object -Culture 'en-US')) { $isRequired = Get-IsParameterRequired -TemplateFileContent $templateFileContent -Parameter $templateFileParameters.$parameter if (-not $isRequired) { @@ -1184,12 +1184,12 @@ Describe 'Governance tests' { # Should be at correct location $incorrectLines = @() - foreach ($finding in (Compare-Object $listedModules ($listedModules | Sort-Object) -SyncWindow 0)) { + foreach ($finding in (Compare-Object $listedModules ($listedModules | Sort-Object -Culture 'en-US') -SyncWindow 0)) { if ($finding.SideIndicator -eq '<=') { $incorrectLines += $finding.InputObject } } - $incorrectLines = $incorrectLines | Sort-Object -Unique + $incorrectLines = $incorrectLines | Sort-Object -Culture 'en-US' -Unique $incorrectLines.Count | Should -Be 0 -Because ('the number of modules that are not in the correct alphabetical order in the issue template should be zero ([ref](https://azure.github.io/Azure-Verified-Modules/specs/bicep/#id-bcpnfr15---category-contributionsupport---avm-module-issue-template-file)).
However, the following incorrectly located lines were found:

{0}
' -f ($incorrectLines -join '
')) } @@ -1203,7 +1203,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { foreach ($moduleFolderPath in $moduleFolderPaths) { if (Test-Path (Join-Path $moduleFolderPath 'tests')) { - $testFilePaths = (Get-ChildItem -Path $moduleFolderPath -Recurse -Filter 'main.test.bicep').FullName | Sort-Object + $testFilePaths = (Get-ChildItem -Path $moduleFolderPath -Recurse -Filter 'main.test.bicep').FullName | Sort-Object -Culture 'en-US' foreach ($testFilePath in $testFilePaths) { $testFileContent = Get-Content $testFilePath $resourceTypeIdentifier = ($moduleFolderPath -split '[\/|\\]{1}avm[\/|\\]{1}(res|ptn)[\/|\\]{1}')[2] -replace '\\', '/' # 'avm/res|ptn//' would return '/' @@ -1346,7 +1346,7 @@ Describe 'API version tests' -Tag 'ApiCheck' { $nestedResources = Get-NestedResourceList -TemplateFileContent $templateFileContent | Where-Object { $_.type -notin @('Microsoft.Resources/deployments') -and $_ - } | Select-Object 'Type', 'ApiVersion' -Unique | Sort-Object Type + } | Select-Object 'Type', 'ApiVersion' -Unique | Sort-Object -Culture 'en-US' -Property 'Type' foreach ($resource in $nestedResources) { @@ -1449,7 +1449,7 @@ Describe 'API version tests' -Tag 'ApiCheck' { $approvedApiVersions += $resourceTypeApiVersions | Where-Object { $_ -notlike '*-preview' } | Select-Object -Last 5 } - $approvedApiVersions = $approvedApiVersions | Sort-Object -Unique -Descending + $approvedApiVersions = $approvedApiVersions | Sort-Object -Culture 'en-US' -Unique -Descending if ($approvedApiVersions -notcontains $TargetApi) { # Using a warning now instead of an error, as we don't want to block PRs for this. diff --git a/avm/utilities/pipelines/staticValidation/psrule/Set-PSRuleGitHubOutput.ps1 b/avm/utilities/pipelines/staticValidation/psrule/Set-PSRuleGitHubOutput.ps1 index 15a8561bf2d..2bbffee2a18 100644 --- a/avm/utilities/pipelines/staticValidation/psrule/Set-PSRuleGitHubOutput.ps1 +++ b/avm/utilities/pipelines/staticValidation/psrule/Set-PSRuleGitHubOutput.ps1 @@ -46,8 +46,8 @@ function Set-PSRuleGitHubOutput { return '' } else { $results = Import-Csv -Path $inputFilePath - $passedRules += $results | Where-Object { $_.Outcome -EQ 'Pass' } | Sort-Object -Property 'TargetName', 'RuleName' -Unique - $failedRules += $results | Where-Object { $_.Outcome -EQ 'Fail' } | Sort-Object -Property 'TargetName', 'RuleName' -Unique + $passedRules += $results | Where-Object { $_.Outcome -EQ 'Pass' } | Sort-Object -Culture 'en-US' -Property 'TargetName', 'RuleName' -Unique + $failedRules += $results | Where-Object { $_.Outcome -EQ 'Fail' } | Sort-Object -Culture 'en-US' -Property 'TargetName', 'RuleName' -Unique ###################### # Set output content # diff --git a/avm/utilities/tools/Invoke-WorkflowsForBranch.ps1 b/avm/utilities/tools/Invoke-WorkflowsForBranch.ps1 index 848b9864e6f..cde84fa56b4 100644 --- a/avm/utilities/tools/Invoke-WorkflowsForBranch.ps1 +++ b/avm/utilities/tools/Invoke-WorkflowsForBranch.ps1 @@ -285,6 +285,6 @@ function Invoke-WorkflowsForBranch { if ($gitHubWorkflowBadges.Count -gt 0) { Write-Verbose 'GitHub Workflow Badges' -Verbose Write-Verbose '======================' -Verbose - Write-Verbose ($gitHubWorkflowBadges | Sort-Object | Out-String) -Verbose + Write-Verbose ($gitHubWorkflowBadges | Sort-Object -Culture 'en-US' | Out-String) -Verbose } } diff --git a/avm/utilities/tools/Test-ModuleLocally.ps1 b/avm/utilities/tools/Test-ModuleLocally.ps1 index c4595eb8920..f29c2c90c15 100644 --- a/avm/utilities/tools/Test-ModuleLocally.ps1 +++ b/avm/utilities/tools/Test-ModuleLocally.ps1 @@ -216,7 +216,7 @@ function Test-ModuleLocally { foreach ($testFilePath in $moduleTestFiles) { $tokenConfiguration.FilePathList += (Get-LocallyReferencedFileList -FilePath $testFilePath) } - $tokenConfiguration.FilePathList = $tokenConfiguration.FilePathList | Sort-Object -Unique + $tokenConfiguration.FilePathList = $tokenConfiguration.FilePathList | Sort-Object -Culture 'en-US' -Unique # Add other template files as they may contain the 'moduleVersion' $tokenConfiguration.FilePathList += (Get-ChildItem -Path $moduleRoot -Recurse -File).FullName | Where-Object { $_ -match '.+(main.json|main.bicep)$' } From 0b2ee1e5001c9fb4c0fc15ebf999edfc9cbd21e3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 May 2024 10:06:32 +0100 Subject: [PATCH 47/52] chore(deps): bump rexml from 3.2.5 to 3.2.8 in /docs/jekyll (#1954) Bumps [rexml](https://github.com/ruby/rexml) from 3.2.5 to 3.2.8.
Release notes

Sourced from rexml's releases.

REXML 3.2.8 - 2024-05-16

Fixes

  • Suppressed a warning

REXML 3.2.7 - 2024-05-16

Improvements

Fixes

  • XPath: Fixed a bug of normalize_space(array).

  • XPath: Fixed a bug that wrong position is used with nested path.

    • GH-110

    • GH-122

    • Reported by jcavalieri.

    • Patch by NAITOH Jun.

  • Fixed a bug that an exception message can't be generated for invalid encoding XML.

... (truncated)

Changelog

Sourced from rexml's changelog.

3.2.8 - 2024-05-16 {#version-3-2-8}

Fixes

  • Suppressed a warning

3.2.7 - 2024-05-16 {#version-3-2-7}

Improvements

Fixes

  • XPath: Fixed a bug of normalize_space(array).

  • XPath: Fixed a bug that wrong position is used with nested path.

    • GH-110

    • GH-122

    • Reported by jcavalieri.

    • Patch by NAITOH Jun.

  • Fixed a bug that an exception message can't be generated for

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=rexml&package-manager=bundler&previous-version=3.2.5&new-version=3.2.8)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/Azure/bicep-registry-modules/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/jekyll/Gemfile.lock | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/jekyll/Gemfile.lock b/docs/jekyll/Gemfile.lock index e96a5c5a286..ada6db56ccb 100644 --- a/docs/jekyll/Gemfile.lock +++ b/docs/jekyll/Gemfile.lock @@ -63,11 +63,13 @@ GEM rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) - rexml (3.2.5) + rexml (3.2.8) + strscan (>= 3.0.9) rouge (4.0.0) safe_yaml (1.0.5) sassc (2.4.0) ffi (~> 1.9) + strscan (3.1.0) terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) unicode-display_width (2.3.0) From 7f9c0893518f8df23c72733d9c8b64660c226a74 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Mon, 20 May 2024 12:22:51 +0200 Subject: [PATCH 48/52] fix: Fixed nested UDT resolution if array definition is in parameter, not the type (#1970) ## Description - Fixed nested UDT resolution if array definition is in parameter, not the type This is now supported ```bicep param test myArrayType[] type myArrayType = { ... } ``` Before it was only ```bicep param test myArrayType type myArrayType = { ... }[] ``` - Updated how the `Set-ModuleReadMe` script throws errors in case a cateogory is missing. - Fixed incorrect parameter metadata for a module - Re-ran generation for ALL modules ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.document-db.database-account](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.document-db.database-account.yml/badge.svg?branch=users%2Falsehr%2FnestedReadMeFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.document-db.database-account.yml) | | [![avm.res.key-vault.vault](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml/badge.svg?branch=users%2Falsehr%2FnestedReadMeFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml) | ## Type of Change - [x] Update to CI Environment or utlities (Non-module effecting changes) - [ ] Azure Verified Module updates: - [x] 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. - [ ] 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 --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- .../document-db/database-account/README.md | 227 ++++++++++++++++++ .../document-db/database-account/main.bicep | 137 ++++++----- .../document-db/database-account/main.json | 42 ++-- .../registration-definition/README.md | 47 ++++ .../sharedScripts/Set-ModuleReadMe.ps1 | 24 +- 5 files changed, 380 insertions(+), 97 deletions(-) diff --git a/avm/res/document-db/database-account/README.md b/avm/res/document-db/database-account/README.md index fa45217f9cf..30434814bc2 100644 --- a/avm/res/document-db/database-account/README.md +++ b/avm/res/document-db/database-account/README.md @@ -2583,6 +2583,40 @@ Default to the location where the account is deployed. Locations enabled for the - Type: array - Default: `[]` +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`failoverPriority`](#parameter-locationsfailoverpriority) | int | The failover priority of the region. A failover priority of 0 indicates a write region. The maximum value for a failover priority = (total number of regions - 1). Failover priority values must be unique for each of the regions in which the database account exists. | +| [`locationName`](#parameter-locationslocationname) | string | The name of the region. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`isZoneRedundant`](#parameter-locationsiszoneredundant) | bool | Default to true. Flag to indicate whether or not this region is an AvailabilityZone region | + +### Parameter: `locations.failoverPriority` + +The failover priority of the region. A failover priority of 0 indicates a write region. The maximum value for a failover priority = (total number of regions - 1). Failover priority values must be unique for each of the regions in which the database account exists. + +- Required: Yes +- Type: int + +### Parameter: `locations.locationName` + +The name of the region. + +- Required: Yes +- Type: string + +### Parameter: `locations.isZoneRedundant` + +Default to true. Flag to indicate whether or not this region is an AvailabilityZone region + +- Required: No +- Type: bool + ### Parameter: `lock` The lock settings of the service. @@ -3296,6 +3330,199 @@ SQL Databases configurations. - Type: array - Default: `[]` +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-sqldatabasesname) | string | Name of the SQL database . | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`autoscaleSettingsMaxThroughput`](#parameter-sqldatabasesautoscalesettingsmaxthroughput) | int | Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. | +| [`containers`](#parameter-sqldatabasescontainers) | array | Array of containers to deploy in the SQL database. | +| [`throughput`](#parameter-sqldatabasesthroughput) | int | Default to 400. Request units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. | + +### Parameter: `sqlDatabases.name` + +Name of the SQL database . + +- Required: Yes +- Type: string + +### Parameter: `sqlDatabases.autoscaleSettingsMaxThroughput` + +Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. + +- Required: No +- Type: int + +### Parameter: `sqlDatabases.containers` + +Array of containers to deploy in the SQL database. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-sqldatabasescontainersname) | string | Name of the container. | +| [`paths`](#parameter-sqldatabasescontainerspaths) | array | List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`analyticalStorageTtl`](#parameter-sqldatabasescontainersanalyticalstoragettl) | int | Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store. | +| [`autoscaleSettingsMaxThroughput`](#parameter-sqldatabasescontainersautoscalesettingsmaxthroughput) | int | Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. | +| [`conflictResolutionPolicy`](#parameter-sqldatabasescontainersconflictresolutionpolicy) | object | The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions. | +| [`defaultTtl`](#parameter-sqldatabasescontainersdefaultttl) | int | Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to "-1", it is equal to infinity, and items don't expire by default. | +| [`indexingPolicy`](#parameter-sqldatabasescontainersindexingpolicy) | object | Indexing policy of the container. | +| [`kind`](#parameter-sqldatabasescontainerskind) | string | Default to Hash. Indicates the kind of algorithm used for partitioning. | +| [`throughput`](#parameter-sqldatabasescontainersthroughput) | int | Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. | +| [`uniqueKeyPolicyKeys`](#parameter-sqldatabasescontainersuniquekeypolicykeys) | array | The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service. | + +### Parameter: `sqlDatabases.containers.name` + +Name of the container. + +- Required: Yes +- Type: string + +### Parameter: `sqlDatabases.containers.paths` + +List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1. + +- Required: Yes +- Type: array + +### Parameter: `sqlDatabases.containers.analyticalStorageTtl` + +Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store. + +- Required: No +- Type: int + +### Parameter: `sqlDatabases.containers.autoscaleSettingsMaxThroughput` + +Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. + +- Required: No +- Type: int + +### Parameter: `sqlDatabases.containers.conflictResolutionPolicy` + +The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`mode`](#parameter-sqldatabasescontainersconflictresolutionpolicymode) | string | Indicates the conflict resolution mode. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`conflictResolutionPath`](#parameter-sqldatabasescontainersconflictresolutionpolicyconflictresolutionpath) | string | The conflict resolution path in the case of LastWriterWins mode. Required if `mode` is set to 'LastWriterWins'. | +| [`conflictResolutionProcedure`](#parameter-sqldatabasescontainersconflictresolutionpolicyconflictresolutionprocedure) | string | The procedure to resolve conflicts in the case of custom mode. Required if `mode` is set to 'Custom'. | + +### Parameter: `sqlDatabases.containers.conflictResolutionPolicy.mode` + +Indicates the conflict resolution mode. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Custom' + 'LastWriterWins' + ] + ``` + +### Parameter: `sqlDatabases.containers.conflictResolutionPolicy.conflictResolutionPath` + +The conflict resolution path in the case of LastWriterWins mode. Required if `mode` is set to 'LastWriterWins'. + +- Required: No +- Type: string + +### Parameter: `sqlDatabases.containers.conflictResolutionPolicy.conflictResolutionProcedure` + +The procedure to resolve conflicts in the case of custom mode. Required if `mode` is set to 'Custom'. + +- Required: No +- Type: string + +### Parameter: `sqlDatabases.containers.defaultTtl` + +Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to "-1", it is equal to infinity, and items don't expire by default. + +- Required: No +- Type: int + +### Parameter: `sqlDatabases.containers.indexingPolicy` + +Indexing policy of the container. + +- Required: No +- Type: object + +### Parameter: `sqlDatabases.containers.kind` + +Default to Hash. Indicates the kind of algorithm used for partitioning. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Hash' + 'MultiHash' + ] + ``` + +### Parameter: `sqlDatabases.containers.throughput` + +Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. + +- Required: No +- Type: int + +### Parameter: `sqlDatabases.containers.uniqueKeyPolicyKeys` + +The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`paths`](#parameter-sqldatabasescontainersuniquekeypolicykeyspaths) | array | List of paths must be unique for each document in the Azure Cosmos DB service | + +### Parameter: `sqlDatabases.containers.uniqueKeyPolicyKeys.paths` + +List of paths must be unique for each document in the Azure Cosmos DB service + +- Required: Yes +- Type: array + +### Parameter: `sqlDatabases.throughput` + +Default to 400. Request units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. + +- Required: No +- Type: int + ### Parameter: `tags` Tags of the Database Account resource. diff --git a/avm/res/document-db/database-account/main.bicep b/avm/res/document-db/database-account/main.bicep index 5cbfbfe85da..65501fdbbf5 100644 --- a/avm/res/document-db/database-account/main.bicep +++ b/avm/res/document-db/database-account/main.bicep @@ -233,7 +233,7 @@ var virtualNetworkRules = [ } ] -var databaseAccount_properties = union( +var databaseAccountProperties = union( { databaseAccountOfferType: databaseAccountOfferType }, @@ -308,24 +308,23 @@ var builtInRoleNames = { ) } -resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = - if (enableTelemetry) { - name: '46d3xbcp.res.documentdb-databaseaccount.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' - properties: { - mode: 'Incremental' - template: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: '1.0.0.0' - resources: [] - outputs: { - telemetry: { - type: 'String' - value: 'For more information, see https://aka.ms/avm/TelemetryInfo' - } +resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = if (enableTelemetry) { + name: '46d3xbcp.res.documentdb-databaseaccount.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' } } } } +} resource databaseAccount 'Microsoft.DocumentDB/databaseAccounts@2023-04-15' = { name: name @@ -333,20 +332,19 @@ resource databaseAccount 'Microsoft.DocumentDB/databaseAccounts@2023-04-15' = { tags: tags identity: identity kind: kind - properties: databaseAccount_properties + properties: databaseAccountProperties } -resource databaseAccount_lock 'Microsoft.Authorization/locks@2020-05-01' = - if (!empty(lock ?? {}) && lock.?kind != 'None') { - name: lock.?name ?? 'lock-${name}' - properties: { - level: lock.?kind ?? '' - notes: lock.?kind == 'CanNotDelete' - ? 'Cannot delete resource or child resources.' - : 'Cannot delete or modify the resource or child resources.' - } - scope: databaseAccount +resource databaseAccount_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' } + scope: databaseAccount +} resource databaseAccount_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ for (diagnosticSetting, index) in (diagnosticSettings ?? []): { @@ -490,49 +488,48 @@ module databaseAccount_privateEndpoints 'br/public:avm/res/network/private-endpo } ] -module keyVault 'modules/secrets-key-vault.bicep' = - if (secretsKeyVault != null) { - name: '${uniqueString(deployment().name, location)}-secrets-kv' - scope: resourceGroup(secretsKeyVault.?resourceGroupName ?? resourceGroup().name) - params: { - keyVaultName: secretsKeyVault!.keyVaultName +module keyVault 'modules/secrets-key-vault.bicep' = if (secretsKeyVault != null) { + name: '${uniqueString(deployment().name, location)}-secrets-kv' + scope: resourceGroup(secretsKeyVault.?resourceGroupName ?? resourceGroup().name) + params: { + keyVaultName: secretsKeyVault!.keyVaultName - keySecrets: [ - { - secretName: secretsKeyVault.?primaryWriteKeySecretName ?? 'Primary-Write-Key' - secretValue: databaseAccount.listKeys().primaryMasterKey - } - { - secretName: secretsKeyVault.?primaryReadOnlyKeySecretName ?? 'Primary-Readonly-Key' - secretValue: databaseAccount.listKeys().primaryReadonlyMasterKey - } - { - secretName: secretsKeyVault.?primaryWriteConnectionStringSecretName ?? 'Primary-Write-ConnectionString' - secretValue: databaseAccount.listConnectionStrings().connectionStrings[0].connectionString - } - { - secretName: secretsKeyVault.?primaryReadonlyConnectionStringSecretName ?? 'Primary-Readonly-ConnectionString' - secretValue: databaseAccount.listConnectionStrings().connectionStrings[2].connectionString - } - { - secretName: secretsKeyVault.?secondaryWriteKeySecretName ?? 'Secondary-Write-Key' - secretValue: databaseAccount.listKeys().secondaryMasterKey - } - { - secretName: secretsKeyVault.?secondaryReadonlyKeySecretName ?? 'Secondary-Readonly-Key' - secretValue: databaseAccount.listKeys().secondaryReadonlyMasterKey - } - { - secretName: secretsKeyVault.?secondaryWriteConnectionStringSecretName ?? 'Secondary-Write-ConnectionString' - secretValue: databaseAccount.listConnectionStrings().connectionStrings[1].connectionString - } - { - secretName: secretsKeyVault.?secondaryReadonlyConnectionStringSecretName ?? 'Secondary-Readonly-ConnectionString' - secretValue: databaseAccount.listConnectionStrings().connectionStrings[3].connectionString - } - ] - } + keySecrets: [ + { + secretName: secretsKeyVault.?primaryWriteKeySecretName ?? 'Primary-Write-Key' + secretValue: databaseAccount.listKeys().primaryMasterKey + } + { + secretName: secretsKeyVault.?primaryReadOnlyKeySecretName ?? 'Primary-Readonly-Key' + secretValue: databaseAccount.listKeys().primaryReadonlyMasterKey + } + { + secretName: secretsKeyVault.?primaryWriteConnectionStringSecretName ?? 'Primary-Write-ConnectionString' + secretValue: databaseAccount.listConnectionStrings().connectionStrings[0].connectionString + } + { + secretName: secretsKeyVault.?primaryReadonlyConnectionStringSecretName ?? 'Primary-Readonly-ConnectionString' + secretValue: databaseAccount.listConnectionStrings().connectionStrings[2].connectionString + } + { + secretName: secretsKeyVault.?secondaryWriteKeySecretName ?? 'Secondary-Write-Key' + secretValue: databaseAccount.listKeys().secondaryMasterKey + } + { + secretName: secretsKeyVault.?secondaryReadonlyKeySecretName ?? 'Secondary-Readonly-Key' + secretValue: databaseAccount.listKeys().secondaryReadonlyMasterKey + } + { + secretName: secretsKeyVault.?secondaryWriteConnectionStringSecretName ?? 'Secondary-Write-ConnectionString' + secretValue: databaseAccount.listConnectionStrings().connectionStrings[1].connectionString + } + { + secretName: secretsKeyVault.?secondaryReadonlyConnectionStringSecretName ?? 'Secondary-Readonly-ConnectionString' + secretValue: databaseAccount.listConnectionStrings().connectionStrings[3].connectionString + } + ] } +} @description('The name of the database account.') output name string = databaseAccount.name @@ -754,10 +751,10 @@ type sqlDatabaseType = { @description('Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions.') conflictResolutionPolicy: { - @description('Required if mode=LastWriterWins. The conflict resolution path in the case of LastWriterWins mode.') + @description('Conditional. The conflict resolution path in the case of LastWriterWins mode. Required if `mode` is set to \'LastWriterWins\'.') conflictResolutionPath: string? - @description('Required if mode=Custom. The procedure to resolve conflicts in the case of custom mode.') + @description('Conditional. The procedure to resolve conflicts in the case of custom mode. Required if `mode` is set to \'Custom\'.') conflictResolutionProcedure: string? @description('Required. Indicates the conflict resolution mode.') @@ -780,7 +777,7 @@ type sqlDatabaseType = { @description('Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service.') uniqueKeyPolicyKeys: { - @description('List of paths must be unique for each document in the Azure Cosmos DB service') + @description('Required. List of paths must be unique for each document in the Azure Cosmos DB service') paths: string[] }[]? }[]? diff --git a/avm/res/document-db/database-account/main.json b/avm/res/document-db/database-account/main.json index 943fa8af420..e1a6ae712b1 100644 --- a/avm/res/document-db/database-account/main.json +++ b/avm/res/document-db/database-account/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "9794166259717067711" + "version": "0.27.1.19265", + "templateHash": "13227324731926560272" }, "name": "DocumentDB Database Accounts", "description": "This module deploys a DocumentDB Database Account.", @@ -534,14 +534,14 @@ "type": "string", "nullable": true, "metadata": { - "description": "Required if mode=LastWriterWins. The conflict resolution path in the case of LastWriterWins mode." + "description": "Conditional. The conflict resolution path in the case of LastWriterWins mode. Required if `mode` is set to 'LastWriterWins'." } }, "conflictResolutionProcedure": { "type": "string", "nullable": true, "metadata": { - "description": "Required if mode=Custom. The procedure to resolve conflicts in the case of custom mode." + "description": "Conditional. The procedure to resolve conflicts in the case of custom mode. Required if `mode` is set to 'Custom'." } }, "mode": { @@ -605,7 +605,7 @@ "type": "string" }, "metadata": { - "description": "List of paths must be unique for each document in the Azure Cosmos DB service" + "description": "Required. List of paths must be unique for each document in the Azure Cosmos DB service" } } } @@ -1090,7 +1090,7 @@ ], "kind": "[if(or(not(empty(parameters('sqlDatabases'))), not(empty(parameters('gremlinDatabases')))), 'GlobalDocumentDB', if(not(empty(parameters('mongodbDatabases'))), 'MongoDB', 'GlobalDocumentDB'))]", "backupPolicy": "[if(equals(parameters('backupPolicyType'), 'Continuous'), createObject('type', parameters('backupPolicyType'), 'continuousModeProperties', createObject('tier', parameters('backupPolicyContinuousTier'))), createObject('type', parameters('backupPolicyType'), 'periodicModeProperties', createObject('backupIntervalInMinutes', parameters('backupIntervalInMinutes'), 'backupRetentionIntervalInHours', parameters('backupRetentionIntervalInHours'), 'backupStorageRedundancy', parameters('backupStorageRedundancy'))))]", - "databaseAccount_properties": "[union(createObject('databaseAccountOfferType', parameters('databaseAccountOfferType')), if(or(or(not(empty(parameters('sqlDatabases'))), not(empty(parameters('mongodbDatabases')))), not(empty(parameters('gremlinDatabases')))), createObject('consistencyPolicy', variables('consistencyPolicy')[parameters('defaultConsistencyLevel')], 'enableMultipleWriteLocations', parameters('enableMultipleWriteLocations'), 'locations', if(empty(variables('databaseAccount_locations')), variables('defaultFailoverLocation'), variables('databaseAccount_locations')), 'ipRules', variables('ipRules'), 'virtualNetworkRules', variables('virtualNetworkRules'), 'networkAclBypass', coalesce(tryGet(parameters('networkRestrictions'), 'networkAclBypass'), 'AzureServices'), 'publicNetworkAccess', coalesce(tryGet(parameters('networkRestrictions'), 'publicNetworkAccess'), 'Enabled'), 'isVirtualNetworkFilterEnabled', or(not(empty(variables('ipRules'))), not(empty(variables('virtualNetworkRules')))), 'capabilities', variables('capabilities'), 'enableFreeTier', parameters('enableFreeTier'), 'backupPolicy', variables('backupPolicy'), 'enableAutomaticFailover', parameters('automaticFailover'), 'enableAnalyticalStorage', parameters('enableAnalyticalStorage')), createObject()), if(not(empty(parameters('sqlDatabases'))), createObject('disableLocalAuth', parameters('disableLocalAuth'), 'disableKeyBasedMetadataWriteAccess', parameters('disableKeyBasedMetadataWriteAccess')), createObject()), if(not(empty(parameters('mongodbDatabases'))), createObject('apiProperties', createObject('serverVersion', parameters('serverVersion'))), createObject()))]", + "databaseAccountProperties": "[union(createObject('databaseAccountOfferType', parameters('databaseAccountOfferType')), if(or(or(not(empty(parameters('sqlDatabases'))), not(empty(parameters('mongodbDatabases')))), not(empty(parameters('gremlinDatabases')))), createObject('consistencyPolicy', variables('consistencyPolicy')[parameters('defaultConsistencyLevel')], 'enableMultipleWriteLocations', parameters('enableMultipleWriteLocations'), 'locations', if(empty(variables('databaseAccount_locations')), variables('defaultFailoverLocation'), variables('databaseAccount_locations')), 'ipRules', variables('ipRules'), 'virtualNetworkRules', variables('virtualNetworkRules'), 'networkAclBypass', coalesce(tryGet(parameters('networkRestrictions'), 'networkAclBypass'), 'AzureServices'), 'publicNetworkAccess', coalesce(tryGet(parameters('networkRestrictions'), 'publicNetworkAccess'), 'Enabled'), 'isVirtualNetworkFilterEnabled', or(not(empty(variables('ipRules'))), not(empty(variables('virtualNetworkRules')))), 'capabilities', variables('capabilities'), 'enableFreeTier', parameters('enableFreeTier'), 'backupPolicy', variables('backupPolicy'), 'enableAutomaticFailover', parameters('automaticFailover'), 'enableAnalyticalStorage', parameters('enableAnalyticalStorage')), createObject()), if(not(empty(parameters('sqlDatabases'))), createObject('disableLocalAuth', parameters('disableLocalAuth'), 'disableKeyBasedMetadataWriteAccess', parameters('disableKeyBasedMetadataWriteAccess')), createObject()), if(not(empty(parameters('mongodbDatabases'))), createObject('apiProperties', createObject('serverVersion', parameters('serverVersion'))), createObject()))]", "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", "Cosmos DB Account Reader Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fbdf93bf-df7d-467e-a4d2-9458aa1360c8')]", @@ -1133,7 +1133,7 @@ "tags": "[parameters('tags')]", "identity": "[variables('identity')]", "kind": "[variables('kind')]", - "properties": "[variables('databaseAccount_properties')]" + "properties": "[variables('databaseAccountProperties')]" }, "databaseAccount_lock": { "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", @@ -1249,8 +1249,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "3826907101153138616" + "version": "0.27.1.19265", + "templateHash": "15534269553484112693" }, "name": "DocumentDB Database Account SQL Databases", "description": "This module deploys a SQL Database in a CosmosDB Account.", @@ -1379,8 +1379,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "11250469246171251281" + "version": "0.27.1.19265", + "templateHash": "12755071159425783033" }, "name": "DocumentDB Database Account SQL Database Containers", "description": "This module deploys a SQL Database Container in a CosmosDB Account.", @@ -1622,8 +1622,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "7706794569430424680" + "version": "0.27.1.19265", + "templateHash": "1527748615955553712" }, "name": "DocumentDB Database Account MongoDB Databases", "description": "This module deploys a MongoDB Database within a CosmosDB Account.", @@ -1725,8 +1725,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "1989910090472113779" + "version": "0.27.1.19265", + "templateHash": "6235322895830297683" }, "name": "DocumentDB Database Account MongoDB Database Collections", "description": "This module deploys a MongoDB Database Collection.", @@ -1881,8 +1881,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "13414524346849431368" + "version": "0.27.1.19265", + "templateHash": "6889435067791947905" }, "name": "DocumentDB Database Account Gremlin Databases", "description": "This module deploys a Gremlin Database within a CosmosDB Account.", @@ -1985,8 +1985,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "2823004405398378621" + "version": "0.27.1.19265", + "templateHash": "3987394297554402770" }, "name": "DocumentDB Database Accounts Gremlin Databases Graphs", "description": "This module deploys a DocumentDB Database Accounts Gremlin Database Graph.", @@ -2848,8 +2848,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "3376784638805058420" + "version": "0.27.1.19265", + "templateHash": "17423703517558214368" } }, "definitions": { diff --git a/avm/res/managed-services/registration-definition/README.md b/avm/res/managed-services/registration-definition/README.md index 1197adf8ab3..51a35a1643f 100644 --- a/avm/res/managed-services/registration-definition/README.md +++ b/avm/res/managed-services/registration-definition/README.md @@ -412,6 +412,53 @@ Specify an array of objects, containing object of Azure Active Directory princip - Required: Yes - Type: array +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-authorizationsprincipalid) | string | The identifier of the Azure Active Directory principal. | +| [`roleDefinitionId`](#parameter-authorizationsroledefinitionid) | string | The identifier of the Azure built-in role that defines the permissions that the Azure Active Directory principal will have on the projected scope. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`delegatedRoleDefinitionIds`](#parameter-authorizationsdelegatedroledefinitionids) | array | The list of role definition ids which define all the permissions that the user in the authorization can assign to other principals. Required if the `roleDefinitionId` refers to the User Access Administrator Role. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalIdDisplayName`](#parameter-authorizationsprincipaliddisplayname) | string | The display name of the Azure Active Directory principal. | + +### Parameter: `authorizations.principalId` + +The identifier of the Azure Active Directory principal. + +- Required: Yes +- Type: string + +### Parameter: `authorizations.roleDefinitionId` + +The identifier of the Azure built-in role that defines the permissions that the Azure Active Directory principal will have on the projected scope. + +- Required: Yes +- Type: string + +### Parameter: `authorizations.delegatedRoleDefinitionIds` + +The list of role definition ids which define all the permissions that the user in the authorization can assign to other principals. Required if the `roleDefinitionId` refers to the User Access Administrator Role. + +- Required: No +- Type: array + +### Parameter: `authorizations.principalIdDisplayName` + +The display name of the Azure Active Directory principal. + +- Required: No +- Type: string + ### Parameter: `managedByTenantId` Specify the tenant ID of the tenant which homes the principals you are delegating permissions to. diff --git a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 index 83c923f6011..673e5929fe1 100644 --- a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 +++ b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 @@ -248,16 +248,22 @@ function Set-DefinitionSection { $descriptions = $TemplateFileContent.parameters.Values.metadata.description # Add name as property for later reference $TemplateFileContent.parameters.Keys | ForEach-Object { $TemplateFileContent.parameters[$_]['name'] = $_ } + + # Error handling: Throw error if any parameter is missing a category + if ($paramsWithoutCategory = $TemplateFileContent.parameters.Values | Where-Object { $_.metadata.description -notmatch '^\w+?\.' }) { + $formattedParam = $paramsWithoutCategory | ForEach-Object { [PSCustomObject]@{ name = $_.name; description = $_.metadata.description } } | ConvertTo-Json -Compress + Write-Error ("Each parameter description should start with a category like [Required. / Optional. / Conditional. ]. The following parameters are missing such a category: `n$formattedParam`n") + } } else { $descriptions = $Properties.Values.metadata.description # Add name as property for later reference $Properties.Keys | ForEach-Object { $Properties[$_]['name'] = $_ } - } - # Error handling: Throw error if any parameter is missing a category - if ($paramsWithoutCategory = $TemplateFileContent.parameters.Values | Where-Object { $_.metadata.description -notmatch '^\w+?\.' }) { - $formattedParam = $paramsWithoutCategory | ForEach-Object { [PSCustomObject]@{ name = $_.name; description = $_.metadata.description } } | ConvertTo-Json -Compress - throw ("Each parameter description should start with a category like [Required. / Optional. / Conditional. ]. The following parameters are missing such a category: `n$formattedParam`n") + # Error handling: Throw error if any parameter is missing a category + if ($paramsWithoutCategory = $Properties.Values | Where-Object { $_.metadata.description -notmatch '^\w+?\.' }) { + $formattedParam = $paramsWithoutCategory | ForEach-Object { [PSCustomObject]@{ name = $_.name; description = $_.metadata.description } } | ConvertTo-Json -Compress + Write-Error ("Each parameter description should start with a category like [Required. / Optional. / Conditional. ]. The following parameters are missing such a category: `n$formattedParam`n") + } } # Get the module parameter categories @@ -306,10 +312,16 @@ function Set-DefinitionSection { $type = $definition['type'] $rawAllowedValues = $definition['allowedValues'] } elseif ($parameter.Keys -contains 'items' -and $parameter.items.type -in @('object', 'array') -or $parameter.type -eq 'object') { - # Array has nested non-primitive type (array/object) + # Array has nested non-primitive type (array/object) - and if array, the the UDT itself is declared as the array $definition = $parameter $type = $parameter.type $rawAllowedValues = $parameter.allowedValues + } elseif ($parameter.Keys -contains 'items' -and $parameter.items.keys -contains '$ref') { + # Array has nested non-primitive type (array) - and the parameter is defined as an array of the UDT + $identifier = Split-Path $parameter.items.'$ref' -Leaf + $definition = $TemplateFileContent.definitions[$identifier] + $type = $parameter.type + $rawAllowedValues = $definition['allowedValues'] } else { $definition = $null $type = $parameter.type From 17e37eecfff1a5f22e8f117ad8ffe8f7db4d7535 Mon Sep 17 00:00:00 2001 From: Rainer Halanek <61878316+rahalan@users.noreply.github.com> Date: Tue, 21 May 2024 16:08:36 +0200 Subject: [PATCH 49/52] feat: update logic to create a meaningful issue, if the module list template is out of sync with the CSV files (#1918) If the template file is not in sync with the CSV files, an issue was created. The old issue was not very helpful, thus the new issue will show exactly what it is about and shows in detail the diff. Here you can see how such an issue will look like: https://github.com/Azure/GHPolicyTest/issues/189 --- .../platform/Sync-AvmModulesList.ps1 | 134 ++++++++++++++---- 1 file changed, 109 insertions(+), 25 deletions(-) diff --git a/avm/utilities/pipelines/platform/Sync-AvmModulesList.ps1 b/avm/utilities/pipelines/platform/Sync-AvmModulesList.ps1 index 7a2af595fa9..d816729452d 100644 --- a/avm/utilities/pipelines/platform/Sync-AvmModulesList.ps1 +++ b/avm/utilities/pipelines/platform/Sync-AvmModulesList.ps1 @@ -30,42 +30,122 @@ function Sync-AvmModulesList { . (Join-Path $RepoRoot 'avm' 'utilities' 'pipelines' 'platform' 'helper' 'Get-AvmCsvData.ps1') . (Join-Path $RepoRoot 'avm' 'utilities' 'pipelines' 'platform' 'helper' 'Add-GithubIssueToProject.ps1') - $workflowFilePath = Join-Path $RepoRoot '.github' 'ISSUE_TEMPLATE' 'avm_module_issue.yml' - # get CSV data - $modules = Get-AvmCsvData -ModuleIndex 'Bicep-Resource' | Select-Object -Property 'ModuleName' - $patterns = Get-AvmCsvData -ModuleIndex 'Bicep-Pattern' | Select-Object -Property 'ModuleName' - - # build new strings - $prefix = ' - "' - $postfix = '"' - $newModuleLines = $modules | ForEach-Object { $prefix + $_.ModuleName + $postfix } - $newPatternLines = $patterns | ForEach-Object { $prefix + $_.ModuleName + $postfix } + $targetModules = Get-AvmCsvData -ModuleIndex 'Bicep-Resource' | Where-Object { ($_.ModuleStatus -eq 'Available :green_circle:') -or ($_.ModuleStatus -eq 'Orphaned :eyes:') } | Select-Object -ExpandProperty 'ModuleName' | Sort-Object + $targetPatterns = Get-AvmCsvData -ModuleIndex 'Bicep-Pattern' | Where-Object { ($_.ModuleStatus -eq 'Available :green_circle:') -or ($_.ModuleStatus -eq 'Orphaned :eyes:') } | Select-Object -ExpandProperty 'ModuleName' | Sort-Object - # parse workflow file - $workflowFileLines = Get-Content $workflowFilePath + $issueTemplatePath = Join-Path $RepoRoot '.github' 'ISSUE_TEMPLATE' 'avm_module_issue.yml' + $issueTemplateContent = Get-Content $issueTemplatePath + + # Identify listed modules $startIndex = 0 - $endIndex = 0 + while ($issueTemplateContent[$startIndex] -notmatch '^\s*#?\s*\-\s+\"avm\/.+\"' -and $startIndex -ne $issueTemplateContent.Length) { + $startIndex++ + } + + $endIndex = $startIndex + while ($issueTemplateContent[$endIndex] -match '.*- "avm\/.*' -and $endIndex -ne $issueTemplateContent.Length) { + $endIndex++ + } + $endIndex-- # Go one back to last module line + + $listedModules = $issueTemplateContent[$startIndex..$endIndex] | ForEach-Object { $_ -replace '.*- "(avm\/.*)".*', '$1' } | Where-Object { $_ -match 'avm\/res\/.*' } + $listedPatterns = $issueTemplateContent[$startIndex..$endIndex] | ForEach-Object { $_ -replace '.*- "(avm\/.*)".*', '$1' } | Where-Object { $_ -match 'avm\/ptn\/.*' } + + $body = '' + + $missingModules = $targetModules | Where { $listedModules -NotContains $_ } + $unexpectedModules = $listedModules | Where { $targetModules -NotContains $_ } + $unexpectedPatterns = $listedPatterns | Where { $targetPatterns -NotContains $_ } + $missingPatterns = $targetPatterns | Where { $listedPatterns -NotContains $_ } + + if ($missingModules.Count -gt 0) + { + $body += @" +**Missing resource modules:** + +$($missingModules -join ([Environment]::NewLine)) +$([Environment]::NewLine) +"@ + } + + if ($unexpectedModules.Count -gt 0) + { + $body += @" +**Unexpected resource modules:** + +$($unexpectedModules -join ([Environment]::NewLine)) +$([Environment]::NewLine) +"@ + } - for ($lineNumber = 0; $lineNumber -lt $workflowFileLines.Count; $lineNumber++) { - if ($startIndex -gt 0 -and (-not ($workflowFileLines[$lineNumber]).Trim().StartsWith('- "avm/'))) { - $endIndex = $lineNumber - break + if ($missingPatterns.Count -gt 0) + { + $body += @" +**Missing pattern modules:** + +$($missingPatterns -join ([Environment]::NewLine)) +$([Environment]::NewLine) +"@ + } + + if ($unexpectedPatterns.Count -gt 0) + { + $body += @" +**Unexpected pattern modules:** + +$($unexpectedPatterns -join ([Environment]::NewLine)) +$([Environment]::NewLine) +"@ + } + + # Should be at correct location + $incorrectModuleLines = @() + foreach ($finding in (Compare-Object $listedModules ($listedModules | Sort-Object) -SyncWindow 0)) { + if ($finding.SideIndicator -eq '<=') { + $incorrectModuleLines += $finding.InputObject } + } + $incorrectModuleLines = $incorrectModuleLines | Sort-Object -Unique - if (($workflowFileLines[$lineNumber]).Trim() -eq '- "Other, as defined below..."') { - $startIndex = $lineNumber + if ($incorrectModuleLines.Count -gt 0) + { + $body += @" +**Resource modules that are not correctly sorted:** + +$($incorrectModuleLines -join ([Environment]::NewLine)) +$([Environment]::NewLine) +"@ + } + + $incorrectPatternLines = @() + foreach ($finding in (Compare-Object $listedPatterns ($listedPatterns | Sort-Object) -SyncWindow 0)) { + if ($finding.SideIndicator -eq '<=') { + $incorrectPatternLines += $finding.InputObject } } + $incorrectPatternLines = $incorrectPatternLines | Sort-Object -Unique - $oldLines = $workflowFileLines[($startIndex + 1)..($endIndex - 1)] - $newLines = $newModuleLines + $newPatternLines - $body = $newLines -join ([Environment]::NewLine) + if ($incorrectPatternLines.Count -gt 0) + { + $body += @" +**Pattern modules that are not correctly sorted:** - if ($oldLines -ne $newLines) { - $title = '[AVM core] Module(s) missing from AVM Module Issue template' +$($incorrectPatternLines -join ([Environment]::NewLine)) +$([Environment]::NewLine) +"@ + } + + if ($body -ne '') { + $title = '[AVM core] AVM Module Issue template is not in sync with published resource modules and pattern modules list' $label = 'Type: AVM :a: :v: :m:,Type: Hygiene :broom:,Needs: Triage :mag:' - $issues = gh issue list --state open --limit 500 --label $label --json 'title' --repo $Repo | ConvertFrom-Json -Depth 100 + $issues = gh issue list --state open --limit 500 --label $label --json 'title,url' --repo $Repo | ConvertFrom-Json -Depth 100 + + $body = @" +> [!IMPORTANT] +> The file [avm_module_issue.yml](https://github.com/Azure/bicep-registry-modules/blob/main/.github/ISSUE_TEMPLATE/avm_module_issue.yml?plain=1) which lists all modules when creating a new issue, is not in sync with the CSV files, that can be found under [resource modules](https://aka.ms/avm/index/bicep/res/csv) and [pattern modules](https://aka.ms/avm/index/bicep/ptn/csv). These CSV files are the single source of truth regarding published modules. Please update the ``avm_module_issue.yml`` accordingly. Please see the following differences that were found. +$([Environment]::NewLine) +"@ + $body if ($issues.title -notcontains $title) { # create issue @@ -74,5 +154,9 @@ function Sync-AvmModulesList { $ProjectNumber = 538 # AVM - Issue Triage Add-GithubIssueToProject -Repo $Repo -ProjectNumber $ProjectNumber -IssueUrl $issueUrl } + else { + # update body + gh issue edit $issues[0].url --body $body --repo $Repo + } } } From 7954f1657dd5494ff730f5f12ba4ec2f9b40e5e7 Mon Sep 17 00:00:00 2001 From: rodney-almeida <64196999+rodney-almeida@users.noreply.github.com> Date: Tue, 21 May 2024 15:23:48 +0100 Subject: [PATCH 50/52] fix: Add check to only apply quarantinePolicyStatus and trustPolicyStatus on Premium SKUs (#1967) --- avm/res/container-registry/registry/README.md | 8 +- .../container-registry/registry/main.bicep | 109 +++++++++--------- avm/res/container-registry/registry/main.json | 31 +++-- 3 files changed, 71 insertions(+), 77 deletions(-) diff --git a/avm/res/container-registry/registry/README.md b/avm/res/container-registry/registry/README.md index 5d0fd4ae87c..90db8524cde 100644 --- a/avm/res/container-registry/registry/README.md +++ b/avm/res/container-registry/registry/README.md @@ -611,7 +611,7 @@ module registry 'br/public:avm/res/container-registry/registry:' = { | [`networkRuleSetIpRules`](#parameter-networkrulesetiprules) | array | The IP ACL rules. Note, requires the 'acrSku' to be 'Premium'. | | [`privateEndpoints`](#parameter-privateendpoints) | array | Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Note, requires the 'acrSku' to be 'Premium'. | | [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkRuleSetIpRules are not set. Note, requires the 'acrSku' to be 'Premium'. | -| [`quarantinePolicyStatus`](#parameter-quarantinepolicystatus) | string | The value that indicates whether the quarantine policy is enabled or not. | +| [`quarantinePolicyStatus`](#parameter-quarantinepolicystatus) | string | The value that indicates whether the quarantine policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'. | | [`replications`](#parameter-replications) | array | All replications to create. | | [`retentionPolicyDays`](#parameter-retentionpolicydays) | int | The number of days to retain an untagged manifest after which it gets purged. | | [`retentionPolicyStatus`](#parameter-retentionpolicystatus) | string | The value that indicates whether the retention policy is enabled or not. | @@ -619,7 +619,7 @@ module registry 'br/public:avm/res/container-registry/registry:' = { | [`softDeletePolicyDays`](#parameter-softdeletepolicydays) | int | The number of days after which a soft-deleted item is permanently deleted. | | [`softDeletePolicyStatus`](#parameter-softdeletepolicystatus) | string | Soft Delete policy status. Default is disabled. | | [`tags`](#parameter-tags) | object | Tags of the resource. | -| [`trustPolicyStatus`](#parameter-trustpolicystatus) | string | The value that indicates whether the trust policy is enabled or not. | +| [`trustPolicyStatus`](#parameter-trustpolicystatus) | string | The value that indicates whether the trust policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'. | | [`webhooks`](#parameter-webhooks) | array | All webhooks to create. | | [`zoneRedundancy`](#parameter-zoneredundancy) | string | Whether or not zone redundancy is enabled for this container registry. | @@ -1362,7 +1362,7 @@ Whether or not public network access is allowed for this resource. For security ### Parameter: `quarantinePolicyStatus` -The value that indicates whether the quarantine policy is enabled or not. +The value that indicates whether the quarantine policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'. - Required: No - Type: string @@ -1526,7 +1526,7 @@ Tags of the resource. ### Parameter: `trustPolicyStatus` -The value that indicates whether the trust policy is enabled or not. +The value that indicates whether the trust policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'. - Required: No - Type: string diff --git a/avm/res/container-registry/registry/main.bicep b/avm/res/container-registry/registry/main.bicep index 126074e0665..059b59f804d 100644 --- a/avm/res/container-registry/registry/main.bicep +++ b/avm/res/container-registry/registry/main.bicep @@ -35,14 +35,14 @@ param exportPolicyStatus string = 'disabled' 'disabled' 'enabled' ]) -@description('Optional. The value that indicates whether the quarantine policy is enabled or not.') +@description('Optional. The value that indicates whether the quarantine policy is enabled or not. Note, requires the \'acrSku\' to be \'Premium\'.') param quarantinePolicyStatus string = 'disabled' @allowed([ 'disabled' 'enabled' ]) -@description('Optional. The value that indicates whether the trust policy is enabled or not.') +@description('Optional. The value that indicates whether the trust policy is enabled or not. Note, requires the \'acrSku\' to be \'Premium\'.') param trustPolicyStatus string = 'disabled' @allowed([ @@ -148,8 +148,8 @@ var formattedUserAssignedIdentities = reduce( var identity = !empty(managedIdentities) ? { type: (managedIdentities.?systemAssigned ?? false) - ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') - : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : null) + ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned, UserAssigned' : 'SystemAssigned') + : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : 'None') userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null } : null @@ -183,47 +183,43 @@ var builtInRoleNames = { ) } -resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = - if (enableTelemetry) { - name: '46d3xbcp.res.containerregistry-registry.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' - properties: { - mode: 'Incremental' - template: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: '1.0.0.0' - resources: [] - outputs: { - telemetry: { - type: 'String' - value: 'For more information, see https://aka.ms/avm/TelemetryInfo' - } +resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = if (enableTelemetry) { + name: '46d3xbcp.res.containerregistry-registry.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' } } } } +} -resource cMKKeyVault 'Microsoft.KeyVault/vaults@2023-02-01' existing = - if (!empty(customerManagedKey.?keyVaultResourceId)) { - name: last(split((customerManagedKey.?keyVaultResourceId ?? 'dummyVault'), '/')) - scope: resourceGroup( - split((customerManagedKey.?keyVaultResourceId ?? '//'), '/')[2], - split((customerManagedKey.?keyVaultResourceId ?? '////'), '/')[4] - ) - - resource cMKKey 'keys@2023-02-01' existing = - if (!empty(customerManagedKey.?keyVaultResourceId) && !empty(customerManagedKey.?keyName)) { - name: customerManagedKey.?keyName ?? 'dummyKey' - } - } +resource cMKKeyVault 'Microsoft.KeyVault/vaults@2023-02-01' existing = if (!empty(customerManagedKey.?keyVaultResourceId)) { + name: last(split((customerManagedKey.?keyVaultResourceId ?? 'dummyVault'), '/')) + scope: resourceGroup( + split((customerManagedKey.?keyVaultResourceId ?? '//'), '/')[2], + split((customerManagedKey.?keyVaultResourceId ?? '////'), '/')[4] + ) -resource cMKUserAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' existing = - if (!empty(customerManagedKey.?userAssignedIdentityResourceId)) { - name: last(split(customerManagedKey.?userAssignedIdentityResourceId ?? 'dummyMsi', '/')) - scope: resourceGroup( - split((customerManagedKey.?userAssignedIdentityResourceId ?? '//'), '/')[2], - split((customerManagedKey.?userAssignedIdentityResourceId ?? '////'), '/')[4] - ) + resource cMKKey 'keys@2023-02-01' existing = if (!empty(customerManagedKey.?keyVaultResourceId) && !empty(customerManagedKey.?keyName)) { + name: customerManagedKey.?keyName ?? 'dummyKey' } +} + +resource cMKUserAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' existing = if (!empty(customerManagedKey.?userAssignedIdentityResourceId)) { + name: last(split(customerManagedKey.?userAssignedIdentityResourceId ?? 'dummyMsi', '/')) + scope: resourceGroup( + split((customerManagedKey.?userAssignedIdentityResourceId ?? '//'), '/')[2], + split((customerManagedKey.?userAssignedIdentityResourceId ?? '////'), '/')[4] + ) +} resource registry 'Microsoft.ContainerRegistry/registries@2023-06-01-preview' = { name: name @@ -258,13 +254,17 @@ resource registry 'Microsoft.ContainerRegistry/registries@2023-06-01-preview' = status: exportPolicyStatus } : null - quarantinePolicy: { - status: quarantinePolicyStatus - } - trustPolicy: { - type: 'Notary' - status: trustPolicyStatus - } + quarantinePolicy: acrSku == 'Premium' + ? { + status: quarantinePolicyStatus + } + : null + trustPolicy: acrSku == 'Premium' + ? { + type: 'Notary' + status: trustPolicyStatus + } + : null retentionPolicy: acrSku == 'Premium' ? { days: retentionPolicyDays @@ -341,17 +341,16 @@ module registry_webhooks 'webhook/main.bicep' = [ } ] -resource registry_lock 'Microsoft.Authorization/locks@2020-05-01' = - if (!empty(lock ?? {}) && lock.?kind != 'None') { - name: lock.?name ?? 'lock-${name}' - properties: { - level: lock.?kind ?? '' - notes: lock.?kind == 'CanNotDelete' - ? 'Cannot delete resource or child resources.' - : 'Cannot delete or modify the resource or child resources.' - } - scope: registry +resource registry_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' } + scope: registry +} resource registry_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ for (diagnosticSetting, index) in (diagnosticSettings ?? []): { diff --git a/avm/res/container-registry/registry/main.json b/avm/res/container-registry/registry/main.json index b1762109724..d9cba422988 100644 --- a/avm/res/container-registry/registry/main.json +++ b/avm/res/container-registry/registry/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "15445287807627348186" + "version": "0.27.1.19265", + "templateHash": "10889694252440800848" }, "name": "Azure Container Registries (ACR)", "description": "This module deploys an Azure Container Registry (ACR).", @@ -523,7 +523,7 @@ "enabled" ], "metadata": { - "description": "Optional. The value that indicates whether the quarantine policy is enabled or not." + "description": "Optional. The value that indicates whether the quarantine policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." } }, "trustPolicyStatus": { @@ -534,7 +534,7 @@ "enabled" ], "metadata": { - "description": "Optional. The value that indicates whether the trust policy is enabled or not." + "description": "Optional. The value that indicates whether the trust policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." } }, "retentionPolicyStatus": { @@ -717,7 +717,7 @@ }, "variables": { "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", "builtInRoleNames": { "AcrDelete": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c2f4ef07-c644-48eb-af81-4b1b4947fb11')]", "AcrImageSigner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6cef56e8-d556-48e5-a04f-b8e64114680f')]", @@ -802,13 +802,8 @@ "status": "[parameters('azureADAuthenticationAsArmPolicyStatus')]" }, "exportPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('exportPolicyStatus')), null())]", - "quarantinePolicy": { - "status": "[parameters('quarantinePolicyStatus')]" - }, - "trustPolicy": { - "type": "Notary", - "status": "[parameters('trustPolicyStatus')]" - }, + "quarantinePolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('quarantinePolicyStatus')), null())]", + "trustPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('type', 'Notary', 'status', parameters('trustPolicyStatus')), null())]", "retentionPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('days', parameters('retentionPolicyDays'), 'status', parameters('retentionPolicyStatus')), null())]", "softDeletePolicy": { "retentionDays": "[parameters('softDeletePolicyDays')]", @@ -943,8 +938,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "16451316437757175736" + "version": "0.27.1.19265", + "templateHash": "17370607380629293508" }, "name": "Azure Container Registry (ACR) Replications", "description": "This module deploys an Azure Container Registry (ACR) Replication.", @@ -1091,8 +1086,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "17108035841365544326" + "version": "0.27.1.19265", + "templateHash": "15228477210534278013" }, "name": "Container Registries Cache", "description": "Cache for Azure Container Registry (Preview) feature allows users to cache container images in a private container registry. Cache for ACR, is a preview feature available in Basic, Standard, and Premium service tiers ([ref](https://learn.microsoft.com/en-us/azure/container-registry/tutorial-registry-cache)).", @@ -1232,8 +1227,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "10731035117081750792" + "version": "0.27.1.19265", + "templateHash": "12261942841024526503" }, "name": "Azure Container Registry (ACR) Webhooks", "description": "This module deploys an Azure Container Registry (ACR) Webhook.", From 5cd812498a197ef7268bddf41114127b4c77146a Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Tue, 21 May 2024 18:24:02 +0200 Subject: [PATCH 51/52] fix: Fixed nested UDT resolution in compliance tests (#1971) ## Description - Added missing case from parameter resolution in tests similar to #1970 - Fixed Cosmos DB - Ran script for all modules Supporting ```bicep param test myArrayType[] type myArrayType = { ... } ``` Before it was only ```bicep param test myArrayType type myArrayType = { ... }[] ``` ## Pipeline Reference | Pipeline | | -------- | [![avm.ptn.authorization.policy-assignment](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.ptn.authorization.policy-assignment.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.ptn.authorization.policy-assignment.yml) [![avm.ptn.authorization.role-assignment](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.ptn.authorization.role-assignment.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.ptn.authorization.role-assignment.yml) [![avm.ptn.policy-insights.remediation](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.ptn.policy-insights.remediation.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.ptn.policy-insights.remediation.yml) [![avm.ptn.security.security-center](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.ptn.security.security-center.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.ptn.security.security-center.yml) [![avm.res.aad.domain-service](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.aad.domain-service.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.aad.domain-service.yml) [![avm.res.analysis-services.server](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.analysis-services.server.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.analysis-services.server.yml) [![avm.res.api-management.service](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.api-management.service.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.api-management.service.yml) [![avm.res.app-configuration.configuration-store](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.app-configuration.configuration-store.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.app-configuration.configuration-store.yml) [![avm.res.app.container-app](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.app.container-app.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.app.container-app.yml) [![avm.res.app.job](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.app.job.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.app.job.yml) [![avm.res.app.managed-environment](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.app.managed-environment.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.app.managed-environment.yml) [![avm.res.automation.automation-account](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.automation.automation-account.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.automation.automation-account.yml) [![avm.res.batch.batch-account](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.batch.batch-account.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.batch.batch-account.yml) [![avm.res.cache.redis](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.cache.redis.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.cache.redis.yml) [![avm.res.cdn.profile](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.cdn.profile.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.cdn.profile.yml) [![avm.res.cognitive-services.account](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml) [![avm.res.communication.communication-service](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.communication.communication-service.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.communication.communication-service.yml) [![avm.res.communication.email-service](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.communication.email-service.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.communication.email-service.yml) [![avm.res.compute.availability-set](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.compute.availability-set.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.compute.availability-set.yml) [![avm.res.compute.disk-encryption-set](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.compute.disk-encryption-set.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.compute.disk-encryption-set.yml) [![avm.res.compute.disk](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.compute.disk.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.compute.disk.yml) [![avm.res.compute.gallery](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.compute.gallery.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.compute.gallery.yml) [![avm.res.compute.image](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.compute.image.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.compute.image.yml) [![avm.res.compute.proximity-placement-group](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.compute.proximity-placement-group.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.compute.proximity-placement-group.yml) [![avm.res.compute.ssh-public-key](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.compute.ssh-public-key.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.compute.ssh-public-key.yml) [![avm.res.compute.virtual-machine-scale-set](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.compute.virtual-machine-scale-set.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.compute.virtual-machine-scale-set.yml) [![avm.res.compute.virtual-machine](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.compute.virtual-machine.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.compute.virtual-machine.yml) [![avm.res.consumption.budget](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.consumption.budget.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.consumption.budget.yml) [![avm.res.container-instance.container-group](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.container-instance.container-group.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.container-instance.container-group.yml) [![avm.res.container-registry.registry](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.container-registry.registry.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.container-registry.registry.yml) [![avm.res.container-service.managed-cluster](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.container-service.managed-cluster.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.container-service.managed-cluster.yml) [![avm.res.data-factory.factory](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.data-factory.factory.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.data-factory.factory.yml) [![avm.res.data-protection.backup-vault](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.data-protection.backup-vault.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.data-protection.backup-vault.yml) [![avm.res.databricks.access-connector](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.databricks.access-connector.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.databricks.access-connector.yml) [![avm.res.databricks.workspace](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.databricks.workspace.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.databricks.workspace.yml) [![avm.res.db-for-my-sql.flexible-server](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.db-for-my-sql.flexible-server.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.db-for-my-sql.flexible-server.yml) [![avm.res.db-for-postgre-sql.flexible-server](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.db-for-postgre-sql.flexible-server.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.db-for-postgre-sql.flexible-server.yml) (unrelated) [![avm.res.desktop-virtualization.application-group](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.application-group.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.application-group.yml) [![avm.res.desktop-virtualization.host-pool](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.host-pool.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.host-pool.yml) [![avm.res.desktop-virtualization.scaling-plan](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.scaling-plan.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.scaling-plan.yml) [![avm.res.desktop-virtualization.workspace](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.workspace.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.workspace.yml) [![avm.res.dev-test-lab.lab](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.dev-test-lab.lab.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.dev-test-lab.lab.yml) [![avm.res.digital-twins.digital-twins-instance](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.digital-twins.digital-twins-instance.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.digital-twins.digital-twins-instance.yml) [![avm.res.document-db.database-account](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.document-db.database-account.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.document-db.database-account.yml) [![avm.res.event-grid.domain](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.event-grid.domain.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.event-grid.domain.yml) [![avm.res.event-grid.namespace](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.event-grid.namespace.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.event-grid.namespace.yml) [![avm.res.event-grid.system-topic](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.event-grid.system-topic.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.event-grid.system-topic.yml) [![avm.res.event-grid.topic](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.event-grid.topic.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.event-grid.topic.yml) [![avm.res.event-hub.namespace](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.event-hub.namespace.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.event-hub.namespace.yml) [![avm.res.health-bot.health-bot](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.health-bot.health-bot.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.health-bot.health-bot.yml) [![avm.res.healthcare-apis.workspace](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.healthcare-apis.workspace.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.healthcare-apis.workspace.yml) [![avm.res.insights.action-group](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.insights.action-group.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.insights.action-group.yml) [![avm.res.insights.activity-log-alert](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.insights.activity-log-alert.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.insights.activity-log-alert.yml) [![avm.res.insights.component](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.insights.component.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.insights.component.yml) [![avm.res.insights.data-collection-endpoint](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.insights.data-collection-endpoint.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.insights.data-collection-endpoint.yml) [![avm.res.insights.data-collection-rule](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.insights.data-collection-rule.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.insights.data-collection-rule.yml) [![avm.res.insights.diagnostic-setting](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.insights.diagnostic-setting.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.insights.diagnostic-setting.yml) [![avm.res.insights.metric-alert](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.insights.metric-alert.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.insights.metric-alert.yml) [![avm.res.insights.private-link-scope](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.insights.private-link-scope.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.insights.private-link-scope.yml) [![avm.res.insights.scheduled-query-rule](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.insights.scheduled-query-rule.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.insights.scheduled-query-rule.yml) [![avm.res.insights.webtest](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.insights.webtest.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.insights.webtest.yml) [![avm.res.key-vault.vault](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml) [![avm.res.kubernetes-configuration.extension](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.kubernetes-configuration.extension.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.kubernetes-configuration.extension.yml) [![avm.res.kubernetes-configuration.flux-configuration](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.kubernetes-configuration.flux-configuration.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.kubernetes-configuration.flux-configuration.yml) [![avm.res.load-test-service.load-test](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.load-test-service.load-test.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.load-test-service.load-test.yml) [![avm.res.logic.workflow](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.logic.workflow.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.logic.workflow.yml) [![avm.res.machine-learning-services.workspace](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.machine-learning-services.workspace.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.machine-learning-services.workspace.yml) [![avm.res.maintenance.maintenance-configuration](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.maintenance.maintenance-configuration.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.maintenance.maintenance-configuration.yml) [![avm.res.managed-identity.user-assigned-identity](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.managed-identity.user-assigned-identity.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.managed-identity.user-assigned-identity.yml) [![avm.res.managed-services.registration-definition](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.managed-services.registration-definition.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.managed-services.registration-definition.yml) [![avm.res.management.management-group](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.management.management-group.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.management.management-group.yml) [![avm.res.net-app.net-app-account](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.net-app.net-app-account.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.net-app.net-app-account.yml) [![avm.res.network.application-gateway-web-application-firewall-policy](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.application-gateway-web-application-firewall-policy.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.application-gateway-web-application-firewall-policy.yml) [![avm.res.network.application-gateway](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.application-gateway.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.application-gateway.yml) [![avm.res.network.application-security-group](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.application-security-group.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.application-security-group.yml) [![avm.res.network.azure-firewall](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.azure-firewall.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.azure-firewall.yml) [![avm.res.network.bastion-host](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.bastion-host.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.bastion-host.yml) [![avm.res.network.connection](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.connection.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.connection.yml) [![avm.res.network.ddos-protection-plan](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.ddos-protection-plan.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.ddos-protection-plan.yml) [![avm.res.network.dns-forwarding-ruleset](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.dns-forwarding-ruleset.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.dns-forwarding-ruleset.yml) [![avm.res.network.dns-resolver](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.dns-resolver.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.dns-resolver.yml) [![avm.res.network.dns-zone](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.dns-zone.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.dns-zone.yml) [![avm.res.network.express-route-circuit](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.express-route-circuit.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.express-route-circuit.yml) [![avm.res.network.express-route-gateway](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.express-route-gateway.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.express-route-gateway.yml) [![avm.res.network.firewall-policy](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.firewall-policy.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.firewall-policy.yml) [![avm.res.network.front-door-web-application-firewall-policy](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.front-door-web-application-firewall-policy.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.front-door-web-application-firewall-policy.yml) [![avm.res.network.front-door](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.front-door.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.front-door.yml) [![avm.res.network.ip-group](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.ip-group.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.ip-group.yml) [![avm.res.network.load-balancer](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.load-balancer.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.load-balancer.yml) [![avm.res.network.local-network-gateway](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.local-network-gateway.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.local-network-gateway.yml) [![avm.res.network.nat-gateway](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.nat-gateway.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.nat-gateway.yml) [![avm.res.network.network-interface](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.network-interface.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.network-interface.yml) [![avm.res.network.network-manager](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.network-manager.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.network-manager.yml) [![avm.res.network.network-security-group](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.network-security-group.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.network-security-group.yml) [![avm.res.network.network-watcher](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.network-watcher.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.network-watcher.yml) [![avm.res.network.private-dns-zone](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.private-dns-zone.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.private-dns-zone.yml) [![avm.res.network.private-endpoint](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.private-endpoint.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.private-endpoint.yml) [![avm.res.network.private-link-service](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.private-link-service.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.private-link-service.yml) [![avm.res.network.public-ip-address](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.public-ip-address.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.public-ip-address.yml) [![avm.res.network.public-ip-prefix](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.public-ip-prefix.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.public-ip-prefix.yml) [![avm.res.network.route-table](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.route-table.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.route-table.yml) [![avm.res.network.service-endpoint-policy](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.service-endpoint-policy.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.service-endpoint-policy.yml) [![avm.res.network.trafficmanagerprofile](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.trafficmanagerprofile.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.trafficmanagerprofile.yml) [![avm.res.network.virtual-hub](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.virtual-hub.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.virtual-hub.yml) [![avm.res.network.virtual-network-gateway](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network-gateway.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network-gateway.yml) [![avm.res.network.virtual-network](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network.yml) [![avm.res.network.virtual-wan](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.virtual-wan.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.virtual-wan.yml) [![avm.res.network.vpn-gateway](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.vpn-gateway.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.vpn-gateway.yml) [![avm.res.network.vpn-site](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.vpn-site.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.network.vpn-site.yml) [![avm.res.operational-insights.workspace](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.operational-insights.workspace.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.operational-insights.workspace.yml) [![avm.res.operations-management.solution](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.operations-management.solution.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.operations-management.solution.yml) [![avm.res.power-bi-dedicated.capacity](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.power-bi-dedicated.capacity.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.power-bi-dedicated.capacity.yml) [![avm.res.purview.account](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.purview.account.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.purview.account.yml) [![avm.res.recovery-services.vault](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.recovery-services.vault.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.recovery-services.vault.yml) [![avm.res.relay.namespace](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.relay.namespace.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.relay.namespace.yml) [![avm.res.resource-graph.query](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.resource-graph.query.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.resource-graph.query.yml) [![avm.res.resources.deployment-script](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.resources.deployment-script.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.resources.deployment-script.yml) [![avm.res.resources.resource-group](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.resources.resource-group.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.resources.resource-group.yml) [![avm.res.search.search-service](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.search.search-service.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.search.search-service.yml) [![avm.res.service-bus.namespace](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.service-bus.namespace.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.service-bus.namespace.yml) [![avm.res.service-fabric.cluster](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.service-fabric.cluster.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.service-fabric.cluster.yml) [![avm.res.signal-r-service.signal-r](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.signal-r-service.signal-r.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.signal-r-service.signal-r.yml) [![avm.res.signal-r-service.web-pub-sub](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.signal-r-service.web-pub-sub.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.signal-r-service.web-pub-sub.yml) [![avm.res.sql.instance-pool](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.sql.instance-pool.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.sql.instance-pool.yml) [![avm.res.sql.managed-instance](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.sql.managed-instance.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.sql.managed-instance.yml) [![avm.res.sql.server](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.sql.server.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.sql.server.yml) [![avm.res.storage.storage-account](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.storage.storage-account.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.storage.storage-account.yml) (unrelated) [![avm.res.synapse.private-link-hub](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.synapse.private-link-hub.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.synapse.private-link-hub.yml) [![avm.res.synapse.workspace](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.synapse.workspace.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.synapse.workspace.yml) [![avm.res.virtual-machine-images.image-template](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.virtual-machine-images.image-template.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.virtual-machine-images.image-template.yml) [![avm.res.web.connection](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.web.connection.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.web.connection.yml) [![avm.res.web.hosting-environment](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.web.hosting-environment.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.web.hosting-environment.yml) [![avm.res.web.serverfarm](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.web.serverfarm.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.web.serverfarm.yml) [![avm.res.web.site](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.web.site.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.web.site.yml) [![avm.res.web.static-site](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.web.static-site.yml/badge.svg?branch=users%2Falsehr%2FudtTestsFix&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.web.static-site.yml) ## Type of Change - [x] Update to CI Environment or utlities (Non-module effecting 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. - [ ] 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 --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- avm/res/document-db/database-account/README.md | 8 ++++---- avm/res/document-db/database-account/main.bicep | 4 ++-- avm/res/document-db/database-account/main.json | 6 +++--- .../staticValidation/compliance/helper/helper.psm1 | 6 +++++- .../staticValidation/compliance/module.tests.ps1 | 4 ++-- 5 files changed, 16 insertions(+), 12 deletions(-) diff --git a/avm/res/document-db/database-account/README.md b/avm/res/document-db/database-account/README.md index 30434814bc2..73c60b1d9be 100644 --- a/avm/res/document-db/database-account/README.md +++ b/avm/res/document-db/database-account/README.md @@ -2594,7 +2594,7 @@ Default to the location where the account is deployed. Locations enabled for the | Parameter | Type | Description | | :-- | :-- | :-- | -| [`isZoneRedundant`](#parameter-locationsiszoneredundant) | bool | Default to true. Flag to indicate whether or not this region is an AvailabilityZone region | +| [`isZoneRedundant`](#parameter-locationsiszoneredundant) | bool | Default to true. Flag to indicate whether or not this region is an AvailabilityZone region. | ### Parameter: `locations.failoverPriority` @@ -2612,7 +2612,7 @@ The name of the region. ### Parameter: `locations.isZoneRedundant` -Default to true. Flag to indicate whether or not this region is an AvailabilityZone region +Default to true. Flag to indicate whether or not this region is an AvailabilityZone region. - Required: No - Type: bool @@ -3507,11 +3507,11 @@ The unique key policy configuration containing a list of unique keys that enforc | Parameter | Type | Description | | :-- | :-- | :-- | -| [`paths`](#parameter-sqldatabasescontainersuniquekeypolicykeyspaths) | array | List of paths must be unique for each document in the Azure Cosmos DB service | +| [`paths`](#parameter-sqldatabasescontainersuniquekeypolicykeyspaths) | array | List of paths must be unique for each document in the Azure Cosmos DB service. | ### Parameter: `sqlDatabases.containers.uniqueKeyPolicyKeys.paths` -List of paths must be unique for each document in the Azure Cosmos DB service +List of paths must be unique for each document in the Azure Cosmos DB service. - Required: Yes - Type: array diff --git a/avm/res/document-db/database-account/main.bicep b/avm/res/document-db/database-account/main.bicep index 65501fdbbf5..9e95fc47a22 100644 --- a/avm/res/document-db/database-account/main.bicep +++ b/avm/res/document-db/database-account/main.bicep @@ -715,7 +715,7 @@ type failoverLocationsType = { @description('Required. The failover priority of the region. A failover priority of 0 indicates a write region. The maximum value for a failover priority = (total number of regions - 1). Failover priority values must be unique for each of the regions in which the database account exists.') failoverPriority: int - @description('Optional. Default to true. Flag to indicate whether or not this region is an AvailabilityZone region') + @description('Optional. Default to true. Flag to indicate whether or not this region is an AvailabilityZone region.') isZoneRedundant: bool? @description('Required. The name of the region.') @@ -777,7 +777,7 @@ type sqlDatabaseType = { @description('Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service.') uniqueKeyPolicyKeys: { - @description('Required. List of paths must be unique for each document in the Azure Cosmos DB service') + @description('Required. List of paths must be unique for each document in the Azure Cosmos DB service.') paths: string[] }[]? }[]? diff --git a/avm/res/document-db/database-account/main.json b/avm/res/document-db/database-account/main.json index e1a6ae712b1..f5121fe2cd4 100644 --- a/avm/res/document-db/database-account/main.json +++ b/avm/res/document-db/database-account/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.27.1.19265", - "templateHash": "13227324731926560272" + "templateHash": "8399904898851436683" }, "name": "DocumentDB Database Accounts", "description": "This module deploys a DocumentDB Database Account.", @@ -456,7 +456,7 @@ "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Default to true. Flag to indicate whether or not this region is an AvailabilityZone region" + "description": "Optional. Default to true. Flag to indicate whether or not this region is an AvailabilityZone region." } }, "locationName": { @@ -605,7 +605,7 @@ "type": "string" }, "metadata": { - "description": "Required. List of paths must be unique for each document in the Azure Cosmos DB service" + "description": "Required. List of paths must be unique for each document in the Azure Cosmos DB service." } } } diff --git a/avm/utilities/pipelines/staticValidation/compliance/helper/helper.psm1 b/avm/utilities/pipelines/staticValidation/compliance/helper/helper.psm1 index cd761d66a9d..d5839c3cafc 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/helper/helper.psm1 +++ b/avm/utilities/pipelines/staticValidation/compliance/helper/helper.psm1 @@ -246,8 +246,12 @@ function Resolve-ReadMeParameterList { $definition = $TemplateFileContent.definitions[$identifier] # $type = $definition['type'] } elseif ($parameter.Keys -contains 'items' -and $parameter.items.type -in @('object', 'array') -or $parameter.type -eq 'object') { - # Array has nested non-primitive type (array/object) + # Array has nested non-primitive type (array/object) - and if array, the the UDT itself is declared as the array $definition = $parameter + } elseif ($parameter.Keys -contains 'items' -and $parameter.items.keys -contains '$ref') { + # Array has nested non-primitive type (array) - and the parameter is defined as an array of the UDT + $identifier = Split-Path $parameter.items.'$ref' -Leaf + $definition = $TemplateFileContent.definitions[$identifier] } else { $definition = $null } diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index 86e82537524..6ac67f95ac5 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -814,9 +814,9 @@ Describe 'Module tests' -Tag 'Module' { $Variables = $templateFileContent.variables.Keys foreach ($variable in $Variables) { - # ^[a-z]+[a-zA-Z]+$ = starts with lower-case letter & may have uppercase letter later + # ^[a-z]+[a-zA-Z0-9]+$ = starts with lower-case letter & may have uppercase letter or numbers later # ^\$fxv#[0-9]+$ = starts with [$fxv#] & ends with a number. This function value is created as a variable when using a Bicep function like loadFileAsBase64() or loadFromJson() - if ($variable -cnotmatch '^[a-z]+[a-zA-Z]+$|^\$fxv#[0-9]+$' -or $variable -match '-') { + if ($variable -cnotmatch '^[a-z]+[a-zA-Z0-9]+$|^\$fxv#[0-9]+$' -or $variable -match '-') { $incorrectVariables += $variable } } From 07699bdb709809e49fd61d85b931f280a6407d58 Mon Sep 17 00:00:00 2001 From: MichielVanHerreweghe <169037533+MichielVanHerreweghe@users.noreply.github.com> Date: Tue, 21 May 2024 22:10:02 +0200 Subject: [PATCH 52/52] feat: Container App added Sticky Session Afinity options (#1936) ## Description Added the option to enable session affinity on the container app ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.app.container-app](https://github.com/MichielVanHerreweghe/bicep-registry-modules/actions/workflows/avm.res.app.container-app.yml/badge.svg?branch=users%2Fmichielvanherreweghe%2Fcontainer-app-ingress-affinity)](https://github.com/MichielVanHerreweghe/bicep-registry-modules/actions/workflows/avm.res.app.container-app.yml) | ## Type of Change - [ ] Update to CI Environment or utlities (Non-module effecting changes) - [x] 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 --------- Co-authored-by: Zach Trocinski <30884663+oZakari@users.noreply.github.com> --- avm/res/app/container-app/README.md | 16 ++++++++ avm/res/app/container-app/main.bicep | 56 +++++++++++++++----------- avm/res/app/container-app/main.json | 18 ++++++++- avm/res/app/container-app/version.json | 4 +- 4 files changed, 66 insertions(+), 28 deletions(-) diff --git a/avm/res/app/container-app/README.md b/avm/res/app/container-app/README.md index 236de183449..794ec770c08 100644 --- a/avm/res/app/container-app/README.md +++ b/avm/res/app/container-app/README.md @@ -484,6 +484,7 @@ module containerApp 'br/public:avm/res/app/container-app:' = { | [`scaleMinReplicas`](#parameter-scaleminreplicas) | int | Minimum number of container replicas. Defaults to 3 if not set. | | [`scaleRules`](#parameter-scalerules) | array | Scaling rules. | | [`secrets`](#parameter-secrets) | secureObject | The secrets of the Container App. | +| [`stickySessionsAffinity`](#parameter-stickysessionsaffinity) | string | Bool indicating if the Container App should enable session affinity. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`trafficLabel`](#parameter-trafficlabel) | string | Associates a traffic label with a revision. Label name should be consist of lower case alphanumeric characters or dashes. | | [`trafficLatestRevision`](#parameter-trafficlatestrevision) | bool | Indicates that the traffic weight belongs to a latest stable revision. | @@ -834,6 +835,21 @@ The secrets of the Container App. - Type: secureObject - Default: `{}` +### Parameter: `stickySessionsAffinity` + +Bool indicating if the Container App should enable session affinity. + +- Required: No +- Type: string +- Default: `'none'` +- Allowed: + ```Bicep + [ + 'none' + 'sticky' + ] + ``` + ### Parameter: `tags` Tags of the resource. diff --git a/avm/res/app/container-app/main.bicep b/avm/res/app/container-app/main.bicep index 7ef6ed7246e..8ff404eaf96 100644 --- a/avm/res/app/container-app/main.bicep +++ b/avm/res/app/container-app/main.bicep @@ -11,6 +11,13 @@ param location string = resourceGroup().location @description('Optional. Bool indicating if the App exposes an external HTTP endpoint.') param ingressExternal bool = true +@allowed([ + 'none' + 'sticky' +]) +@description('Optional. Bool indicating if the Container App should enable session affinity.') +param stickySessionsAffinity string = 'none' + @allowed([ 'auto' 'http' @@ -144,24 +151,23 @@ var builtInRoleNames = { ) } -resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = - if (enableTelemetry) { - name: '46d3xbcp.res.app-containerapp.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' - properties: { - mode: 'Incremental' - template: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: '1.0.0.0' - resources: [] - outputs: { - telemetry: { - type: 'String' - value: 'For more information, see https://aka.ms/avm/TelemetryInfo' - } +resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = if (enableTelemetry) { + name: '46d3xbcp.res.app-containerapp.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' } } } } +} resource containerApp 'Microsoft.App/containerApps@2023-05-01' = { name: name @@ -180,6 +186,9 @@ resource containerApp 'Microsoft.App/containerApps@2023-05-01' = { external: ingressExternal ipSecurityRestrictions: !empty(ipSecurityRestrictions) ? ipSecurityRestrictions : null targetPort: ingressTargetPort + stickySessions: { + affinity: stickySessionsAffinity + } traffic: [ { label: trafficLabel @@ -209,17 +218,16 @@ resource containerApp 'Microsoft.App/containerApps@2023-05-01' = { } } -resource containerApp_lock 'Microsoft.Authorization/locks@2020-05-01' = - if (!empty(lock ?? {}) && lock.?kind != 'None') { - name: lock.?name ?? 'lock-${name}' - properties: { - level: lock.?kind ?? '' - notes: lock.?kind == 'CanNotDelete' - ? 'Cannot delete resource or child resources.' - : 'Cannot delete or modify the resource or child resources.' - } - scope: containerApp +resource containerApp_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' } + scope: containerApp +} resource containerApp_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ for (roleAssignment, index) in (roleAssignments ?? []): { diff --git a/avm/res/app/container-app/main.json b/avm/res/app/container-app/main.json index 97c1bf140af..2139556b3b8 100644 --- a/avm/res/app/container-app/main.json +++ b/avm/res/app/container-app/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "11829581770848647649" + "version": "0.27.1.19265", + "templateHash": "6545722573689550634" }, "name": "Container Apps", "description": "This module deploys a Container App.", @@ -149,6 +149,17 @@ "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." } }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, "ingressTransport": { "type": "string", "defaultValue": "auto", @@ -411,6 +422,9 @@ "external": "[parameters('ingressExternal')]", "ipSecurityRestrictions": "[if(not(empty(parameters('ipSecurityRestrictions'))), parameters('ipSecurityRestrictions'), null())]", "targetPort": "[parameters('ingressTargetPort')]", + "stickySessions": { + "affinity": "[parameters('stickySessionsAffinity')]" + }, "traffic": [ { "label": "[parameters('trafficLabel')]", diff --git a/avm/res/app/container-app/version.json b/avm/res/app/container-app/version.json index 9481fea58ee..c177b1bb58b 100644 --- a/avm/res/app/container-app/version.json +++ b/avm/res/app/container-app/version.json @@ -1,7 +1,7 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.2", + "version": "0.3", "pathFilters": [ "./main.json" ] -} +} \ No newline at end of file