From fa3bf6d344965945fcd35cc18dcfec2ca97d8481 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Tue, 7 May 2024 19:34:02 +0200 Subject: [PATCH 1/9] 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 42f521b9ce..5e87380e79 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 2/9] 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 e9c2ed3d87..b6e1145f7d 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 066f7e0fc8..28d05dbcb0 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 271127387b..035c2446ed 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 2ea410a71c..d8084ee5ad 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 3d27d57753..ed724f3b13 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 0b1d63d088..3a1fc5b7f0 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 27e2388ffd..4b9652bdd6 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 1fcfbe4d43..aa68b074b5 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 dfe9571383..70e0dbae60 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 7755709e24..c2c1f5f676 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 988eaf2864..a237081b2e 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 4ba593a5d0..1b78ae2598 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 2f6d85f681..0617252bd1 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 4185e69934..6662bd82a2 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 6cd7818490..6d09badaaf 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 9493a14f81..0495f28941 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 7cbe596947..520f9b79e2 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 bcc85b93c7..38eb129189 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 3e801241ff..028546766c 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 943e45acec..ca424f76ef 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 0183742502..1de03468ef 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 b987bfb1ae..b5d2046b5f 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 45080f9d3b..623e3bb6b7 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 3/9] 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 2ac9fbe0ea..69f83360eb 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 4/9] 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 a40a89b354..89c91dc696 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 c2c2606880..7dfe560b5b 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 86701b3773..8baee24736 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 15a83a63cc..91d7321088 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 46f4c8e9ae..a9b32d3996 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 395c88a36f..cf3db6cbdf 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 b343e9a4ef..be761a1b54 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 1d924b040c..3f406d0cbb 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 16b71c7187..5e2d1c21bd 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 b2ba653765..65c0c3ca53 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 e5db6e691e..794a226e2f 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 3e87e184d8..608831a29c 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 13669e6601..41fc8c654f 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 5/9] 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 098db0b7a9..c3134f3fbe 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 68b5ff6ceb..7e00e44faa 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 9dd7e7ea69..70e67da18f 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 1432d407c5..ca8ccda147 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 0cb4f68bd5..43ee7b2dd7 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 6/9] 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 2f8a7b1a01..2ceed9e64b 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 0c94365267..26ec90a2b3 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 e15a259a87..fdea2ed239 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 7/9] 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 e370d6fdae..9fa730d390 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 4c46be1680..2a61c05386 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 e2bef8c3df..f3894b7f80 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 2bd4869dd5..49eba449c6 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 7fa401bdf7..9481fea58e 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 8/9] 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 a35c3158ea..893e030b61 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 459c075404..bd18fad337 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 0000000000..1d91926f99 --- /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 0000000000..ef8fa911d2 --- /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 0000000000..93e9c6e55a --- /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 0000000000..2d9a0f6ba6 --- /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 0000000000..6d8ee06c25 --- /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 0000000000..bb2af3d0f8 --- /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 0000000000..546fa7c4c8 --- /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 0000000000..b03d4aca93 --- /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 0000000000..18ae51956b --- /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 0000000000..b03d4aca93 --- /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 0000000000..93b2d344ab --- /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 0000000000..7fa401bdf7 --- /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 9/9] 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 933815b8f8..0000000000 --- a/avm/ptn/readme.md +++ /dev/null @@ -1 +0,0 @@ -TODO: Add patterns