From 20ac8b7116cf7781600646dc0d5d85dcdae0df45 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Tue, 7 Nov 2023 22:23:26 +0100 Subject: [PATCH 01/55] Added skeleton --- .../compliance/module.tests.ps1 | 272 ++++++++++++------ 1 file changed, 185 insertions(+), 87 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index 700771fe11..c1a0174819 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -3,7 +3,7 @@ param ( [Parameter(Mandatory = $false)] [array] $moduleFolderPaths = ((Get-ChildItem $repoRootPath -Recurse -Directory -Force).FullName | Where-Object { - (Get-ChildItem $_ -File -Depth 0 -Include @('main.json', 'main.bicep') -Force).Count -gt 0 + (Get-ChildItem $_ -File -Depth 0 -Include @('main.bicep') -Force).Count -gt 0 }), [Parameter(Mandatory = $false)] @@ -27,7 +27,6 @@ $script:convertedTemplates = @{} # Shared exception messages $script:bicepTemplateCompilationFailedException = "Unable to compile the main.bicep template's content. This can happen if there is an error in the template. Please check if you can run the command ``bicep build {0} --stdout | ConvertFrom-Json -AsHashtable``." # -f $templateFilePath -$script:jsonTemplateLoadFailedException = "Unable to load the main.json template's content. This can happen if there is an error in the template. Please check if you can run the command `Get-Content {0} -Raw | ConvertFrom-Json -AsHashtable`." # -f $templateFilePath $script:templateNotFoundException = 'No template file found in folder [{0}]' # -f $moduleFolderPath # Import any helper function used in this test script @@ -203,24 +202,14 @@ Describe 'Module tests' -Tag 'Module' { if (-not $templateContent) { throw ($bicepTemplateCompilationFailedException -f $templateFilePath) } - } - elseIf (Test-Path (Join-Path $moduleFolderPath 'main.json')) { - $templateFilePath = Join-Path $moduleFolderPath 'main.json' - $templateContent = Get-Content $templateFilePath -Raw | ConvertFrom-Json -AsHashtable - - if (-not $templateContent) { - throw ($jsonTemplateLoadFailedException -f $templateFilePath) - } - } - else { + } else { throw ($templateNotFoundException -f $moduleFolderPath) } $convertedTemplates[$moduleFolderPathKey] = @{ templateFilePath = $templateFilePath templateContent = $templateContent } - } - else { + } else { $templateContent = $convertedTemplates[$moduleFolderPathKey].templateContent $templateFilePath = $convertedTemplates[$moduleFolderPathKey].templateFilePath } @@ -342,24 +331,14 @@ Describe 'Module tests' -Tag 'Module' { if (-not $templateContent) { throw ($bicepTemplateCompilationFailedException -f $templateFilePath) } - } - elseIf (Test-Path (Join-Path $moduleFolderPath 'main.json')) { - $templateFilePath = Join-Path $moduleFolderPath 'main.json' - $templateContent = Get-Content $templateFilePath -Raw | ConvertFrom-Json -AsHashtable - - if (-not $templateContent) { - throw ($jsonTemplateLoadFailedException -f $templateFilePath) - } - } - else { + } else { throw ($templateNotFoundException -f $moduleFolderPath) } $convertedTemplates[$moduleFolderPathKey] = @{ templateFilePath = $templateFilePath templateContent = $templateContent } - } - else { + } else { $templateContent = $convertedTemplates[$moduleFolderPathKey].templateContent $templateFilePath = $convertedTemplates[$moduleFolderPathKey].templateFilePath } @@ -423,17 +402,13 @@ Describe 'Module tests' -Tag 'Module' { $SchemaArray = @() if ($Schemaverion -eq $RgDeploymentSchema) { $SchemaOutput = $true - } - elseIf ($Schemaverion -eq $SubscriptionDeploymentSchema) { + } elseIf ($Schemaverion -eq $SubscriptionDeploymentSchema) { $SchemaOutput = $true - } - elseIf ($Schemaverion -eq $MgDeploymentSchema) { + } elseIf ($Schemaverion -eq $MgDeploymentSchema) { $SchemaOutput = $true - } - elseIf ($Schemaverion -eq $TenantDeploymentSchema) { + } elseIf ($Schemaverion -eq $TenantDeploymentSchema) { $SchemaOutput = $true - } - else { + } else { $SchemaOutput = $false } $SchemaArray += $SchemaOutput @@ -496,8 +471,7 @@ Describe 'Module tests' -Tag 'Module' { foreach ($Param in $Parameter) { if ($Param.substring(0, 1) -cnotmatch '[a-z]' -or $Param -match '-' -or $Param -match '_') { $CamelCasingFlag += $false - } - else { + } else { $CamelCasingFlag += $true } } @@ -522,8 +496,7 @@ Describe 'Module tests' -Tag 'Module' { foreach ($Variab in $Variable) { if ($Variab.substring(0, 1) -cnotmatch '[a-z]' -or $Variab -match '-') { $CamelCasingFlag += $false - } - else { + } else { $CamelCasingFlag += $true } } @@ -542,8 +515,7 @@ Describe 'Module tests' -Tag 'Module' { foreach ($Output in $Outputs) { if ($Output.substring(0, 1) -cnotmatch '[a-z]' -or $Output -match '-' -or $Output -match '_') { $CamelCasingFlag += $false - } - else { + } else { $CamelCasingFlag += $true } } @@ -560,8 +532,7 @@ Describe 'Module tests' -Tag 'Module' { # With the introduction of user defined types, the way resources are configured in the schema slightly changed. We have to account for that. if ($templateContent.resources.GetType().Name -eq 'Object[]') { $templateResources = $templateContent.resources - } - else { + } else { $templateResources = $templateContent.resources.Keys | ForEach-Object { $templateContent.resources[$_] } } @@ -579,8 +550,7 @@ Describe 'Module tests' -Tag 'Module' { # With the introduction of user defined types, the way resources are configured in the schema slightly changed. We have to account for that. if ($templateContent.resources.GetType().Name -eq 'Object[]') { $templateResources = $templateContent.resources - } - else { + } else { $templateResources = $templateContent.resources.Keys | ForEach-Object { $templateContent.resources[$_] } } @@ -604,8 +574,7 @@ Describe 'Module tests' -Tag 'Module' { # With the introduction of user defined types, the way resources are configured in the schema slightly changed. We have to account for that. if ($templateContent.resources.GetType().Name -eq 'Object[]') { $templateResources = $templateContent.resources - } - else { + } else { $templateResources = $templateContent.resources.Keys | ForEach-Object { $templateContent.resources[$_] } } @@ -634,8 +603,7 @@ Describe 'Module tests' -Tag 'Module' { if ($Locationparamoutput -contains 'Location') { if ($Locationparamoutputvalue -eq '[resourceGroup().Location]' -or $Locationparamoutputvalue -eq 'global') { $LocationFlag = $true - } - else { + } else { $LocationFlag = $false } @@ -696,8 +664,7 @@ Describe 'Module tests' -Tag 'Module' { $readMeFileContentHeader = (Get-Content -Path $readMeFilePath)[0] if ($readMeFileContentHeader -match '^.*`\[(.+)\]`.*') { $primaryResourceType = $matches[1] - } - else { + } else { Write-Error "Cannot identity primary resource type in readme header [$readMeFileContentHeader] and cannot execute the test." return } @@ -705,8 +672,7 @@ Describe 'Module tests' -Tag 'Module' { # With the introduction of user defined types, the way resources are configured in the schema slightly changed. We have to account for that. if ($templateContent.resources.GetType().Name -eq 'Object[]') { $templateResources = $templateContent.resources - } - else { + } else { $templateResources = $templateContent.resources.Keys | ForEach-Object { $templateContent.resources[$_] } } @@ -732,8 +698,7 @@ Describe 'Module tests' -Tag 'Module' { $readMeFileContentHeader = (Get-Content -Path $readMeFilePath)[0] if ($readMeFileContentHeader -match '^.*`\[(.+)\]`.*') { $primaryResourceType = $matches[1] - } - else { + } else { Write-Error "Cannot identity primary resource type in readme header [$readMeFileContentHeader] and cannot execute the test." return } @@ -741,8 +706,7 @@ Describe 'Module tests' -Tag 'Module' { # With the introduction of user defined types, the way resources are configured in the schema slightly changed. We have to account for that. if ($templateContent.resources.GetType().Name -eq 'Object[]') { $templateResources = $templateContent.resources - } - else { + } else { $templateResources = $templateContent.resources.Keys | ForEach-Object { $templateContent.resources[$_] } } @@ -856,7 +820,6 @@ Describe 'Module tests' -Tag 'Module' { $incorrectOutputs | Should -BeNullOrEmpty } - # Update to work with nullable parameters It '[] All non-required parameters in template file should not have description that start with "Required.".' -TestCases $deploymentFolderTestCases { param ( [hashtable[]] $testFileTestCases, @@ -895,23 +858,13 @@ Describe 'Module tests' -Tag 'Module' { if (-not $templateContent) { throw ($bicepTemplateCompilationFailedException -f $templateFilePath) } - } - elseIf (Test-Path (Join-Path $moduleFolderPath 'main.json')) { - $templateFilePath = Join-Path $moduleFolderPath 'main.json' - $templateContent = Get-Content $templateFilePath -Raw | ConvertFrom-Json -AsHashtable - - if (-not $templateContent) { - throw ($jsonTemplateLoadFailedException -f $templateFilePath) - } - } - else { + } else { throw ($templateNotFoundException -f $moduleFolderPath) } $convertedTemplates[$moduleFolderPathKey] = @{ templateContent = $templateContent } - } - else { + } else { $templateContent = $convertedTemplates[$moduleFolderPathKey].templateContent } @@ -954,6 +907,96 @@ Describe 'Module tests' -Tag 'Module' { $templateFileContent.metadata.owner | Should -Not -BeNullOrEmpty } } + + Context 'User-defined-types tests' -Tag 'UDT' { + + $udtTestCases = [System.Collections.ArrayList] @() + foreach ($moduleFolderPath in $moduleFolderPaths) { + + $resourceTypeIdentifier = ($moduleFolderPath -split '[\/|\\]{1}avm[\/|\\]{1}(res|ptn)[\/|\\]{1}')[2] -replace '\\', '/' # avm/res// + + # For runtime purposes, we cache the compiled template in a hashtable that uses a formatted relative module path as a key + $moduleFolderPathKey = $moduleFolderPath.Replace('\', '/').Split('/avm/')[1].Trim('/').Replace('/', '-') + if (-not ($convertedTemplates.Keys -contains $moduleFolderPathKey)) { + if (Test-Path (Join-Path $moduleFolderPath 'main.bicep')) { + $templateFilePath = Join-Path $moduleFolderPath 'main.bicep' + $templateContent = bicep build $templateFilePath --stdout | ConvertFrom-Json -AsHashtable + + if (-not $templateContent) { + throw ($bicepTemplateCompilationFailedException -f $templateFilePath) + } + } else { + throw ($templateNotFoundException -f $moduleFolderPath) + } + $convertedTemplates[$moduleFolderPathKey] = @{ + templateContent = $templateContent + } + } else { + $templateContent = $convertedTemplates[$moduleFolderPathKey].templateContent + } + + $udtTestCases += @{ + moduleFolderName = $resourceTypeIdentifier + templateFileContent = $templateContent + } + } + + + It "[] If template has [roleAssignments] parameter, it should implement the expected user-defined-type" -TestCases $udtTestCases { + + param( + [object[]] $templateFileContent + ) + throw 'Not implemented' + + } + + It "[] If template has [privateEndpoints] parameter, it should implement the expected user-defined-type" -TestCases $udtTestCases { + + param( + [object[]] $templateFileContent + ) + throw 'Not implemented' + + } + + It "[] If template has [diagnosticSettings] parameter, it should implement the expected user-defined-type" -TestCases $udtTestCases { + + param( + [object[]] $templateFileContent + ) + throw 'Not implemented' + + } + + It "[] If template has [lock] parameter, it should implement the expected user-defined-type" -TestCases $udtTestCases { + + param( + [object[]] $templateFileContent + ) + throw 'Not implemented' + + } + + It "[] If template has [customerManagedKey] parameter, it should implement the expected user-defined-type" -TestCases $udtTestCases { + + param( + [object[]] $templateFileContent + ) + throw 'Not implemented' + + } + + It "[] If template has [diagnosticSettings] parameter, it should implement the expected user-defined-type" -TestCases $udtTestCases { + + param( + [object[]] $templateFileContent + ) + throw 'Not implemented' + + } + + } } Describe 'Test file tests' -Tag 'TestTemplate' { @@ -978,6 +1021,74 @@ Describe 'Test file tests' -Tag 'TestTemplate' { } } + It "[] Bicep test deployment files should contain serviceShort parameter" -TestCases $deploymentTestFileTestCases { + + param( + [object[]] $testFileContent + ) + throw 'Not implemented' + + } + + It "[] Bicep test deployment files in a [default] folder should contain a service short with ending [min]" -TestCases $deploymentTestFileTestCases { + + param( + [string] $testFilePath, + [object[]] $testFileContent + ) + #TODO: must consider that the folder name is more than just 'default' + throw 'Not implemented' + + } + + It "[] Bicep test deployment files in a [max] folder should contain a service short with ending [max]" -TestCases $deploymentTestFileTestCases { + + param( + [string] $testFilePath, + [object[]] $testFileContent + ) + #TODO: must consider that the folder name is more than just 'max' + throw 'Not implemented' + + } + + It "[] Bicep test deployment files in a [waf-aligned] folder should contain a service short with ending [waf]" -TestCases $deploymentTestFileTestCases { + + param( + [string] $testFilePath, + [object[]] $testFileContent + ) + #TODO: must consider that the folder name is more than just 'waf' + throw 'Not implemented' + + } + + It "[] Bicep test deployment files should contain a test name" -TestCases $deploymentTestFileTestCases { + + param( + [object[]] $testFileContent + ) + throw 'Not implemented' + + } + + It "[] Bicep test deployment files should contain a test description" -TestCases $deploymentTestFileTestCases { + + param( + [object[]] $testFileContent + ) + throw 'Not implemented' + + } + + It "[] Bicep test deployment files should contain namePrefix parameter with value ['#_namePrefix_#']" -TestCases $deploymentTestFileTestCases { + + param( + [object[]] $testFileContent + ) + throw 'Not implemented' + } + It "[] Bicep test deployment files should invoke test like [`module testDeployment '../.*main.bicep' = {`]" -TestCases $deploymentTestFileTestCases { param( @@ -1021,8 +1132,7 @@ Describe 'API version tests' -Tag 'ApiCheck' { try { $apiSpecs = Invoke-WebRequest -Uri $ApiSpecsFileUri $ApiVersions = ConvertFrom-Json $apiSpecs.Content -AsHashtable - } - catch { + } catch { Write-Warning "Failed to download API specs file from [$ApiSpecsFileUri]. Skipping API tests" Set-ItResult -Skipped -Because "Failed to download API specs file from [$ApiSpecsFileUri]. Skipping API tests." return @@ -1042,24 +1152,14 @@ Describe 'API version tests' -Tag 'ApiCheck' { if (-not $templateContent) { throw ($bicepTemplateCompilationFailedException -f $templateFilePath) } - } - elseIf (Test-Path (Join-Path $moduleFolderPath 'main.json')) { - $templateFilePath = Join-Path $moduleFolderPath 'main.json' - $templateContent = Get-Content $templateFilePath -Raw | ConvertFrom-Json -AsHashtable - - if (-not $templateContent) { - throw ($jsonTemplateLoadFailedException -f $templateFilePath) - } - } - else { + } else { throw ($templateNotFoundException -f $moduleFolderPath) } $convertedTemplates[$moduleFolderPathKey] = @{ templateFilePath = $templateFilePath templateContent = $templateContent } - } - else { + } else { $templateContent = $convertedTemplates[$moduleFolderPathKey].templateContent $templateFilePath = $convertedTemplates[$moduleFolderPathKey].templateFilePath } @@ -1165,8 +1265,7 @@ Describe 'API version tests' -Tag 'ApiCheck' { # We allow the latest 5 including previews (in case somebody wants to use preview), or the latest 3 non-preview $approvedApiVersions += $resourceTypeApiVersions | Select-Object -Last 5 $approvedApiVersions += $resourceTypeApiVersions | Where-Object { $_ -notlike '*-preview' } | Select-Object -Last 5 - } - else { + } else { # We allow the latest 5 non-preview preview $approvedApiVersions += $resourceTypeApiVersions | Where-Object { $_ -notlike '*-preview' } | Select-Object -Last 5 } @@ -1179,8 +1278,7 @@ Describe 'API version tests' -Tag 'ApiCheck' { # The original failed test was # $approvedApiVersions | Should -Contain $TargetApi - } - else { + } else { # Provide a warning if an API version is second to next to expire. $indexOfVersion = $approvedApiVersions.IndexOf($TargetApi) From 4939b4d2e85ac2db8d8b2a67cb17fac7363196c7 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 00:38:44 +0100 Subject: [PATCH 02/55] Implemented first new tests --- avm/res/key-vault/vault/main.bicep | 3 - avm/res/key-vault/vault/main.json | 26 +-- .../compliance/module.tests.ps1 | 148 +++++++++++------- 3 files changed, 103 insertions(+), 74 deletions(-) diff --git a/avm/res/key-vault/vault/main.bicep b/avm/res/key-vault/vault/main.bicep index ae038cf1f5..4e62950d9c 100644 --- a/avm/res/key-vault/vault/main.bicep +++ b/avm/res/key-vault/vault/main.bicep @@ -353,9 +353,6 @@ type roleAssignmentType = { @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/key-vault/vault/main.json b/avm/res/key-vault/vault/main.json index f10c40c0fb..bfcfb41b93 100644 --- a/avm/res/key-vault/vault/main.json +++ b/avm/res/key-vault/vault/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.22.6.54827", - "templateHash": "9188769706526490100" + "version": "0.23.1.45101", + "templateHash": "8353941507512521049" }, "name": "Key Vaults", "description": "This module deploys a Key Vault.", @@ -164,16 +164,6 @@ "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, @@ -682,8 +672,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.22.6.54827", - "templateHash": "9999250509448584761" + "version": "0.23.1.45101", + "templateHash": "4111939022872407830" }, "name": "Key Vault Access Policies", "description": "This module deploys a Key Vault Access Policy.", @@ -815,8 +805,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.22.6.54827", - "templateHash": "11139788551431901948" + "version": "0.23.1.45101", + "templateHash": "9180551172362989336" }, "name": "Key Vault Secrets", "description": "This module deploys a Key Vault Secret.", @@ -1104,8 +1094,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.22.6.54827", - "templateHash": "15591839680984542683" + "version": "0.23.1.45101", + "templateHash": "2691621623448325959" }, "name": "Key Vault Keys", "description": "This module deploys a Key Vault Key.", diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index c1a0174819..f3ab52891e 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -935,67 +935,109 @@ Describe 'Module tests' -Tag 'Module' { $templateContent = $convertedTemplates[$moduleFolderPathKey].templateContent } - $udtTestCases += @{ - moduleFolderName = $resourceTypeIdentifier - templateFileContent = $templateContent - } - } - - - It "[] If template has [roleAssignments] parameter, it should implement the expected user-defined-type" -TestCases $udtTestCases { - - param( - [object[]] $templateFileContent + # Setting expected URL only for those that doen't have multiple different variants + $avmInterfaceSpecsBase = 'https://raw.githubusercontent.com/Azure/Azure-Verified-Modules/main/docs/static/includes/interfaces' + $udtCases = @( + @{ + parameterName = 'diagnosticSettings' + udtName = 'diagnosticSettingType' + } + @{ + parameterName = 'roleAssignments' + udtName = 'roleAssignmentType' + udtExpectedUrl = "$avmInterfaceSpecsBase/int.rbac.udt.schema.bicep" + } + @{ + parameterName = 'lock' + udtName = 'lockType' + udtExpectedUrl = "$avmInterfaceSpecsBase/int.locks.udt.schema.bicep" + } + @{ + parameterName = 'managedIdentities' + udtName = 'managedIdentitiesType' + } + @{ + parameterName = 'privateEndpoints' + udtName = 'privateEndpointType' + } + @{ + parameterName = 'customerManagedKey' + udtName = 'customerManagedKeyType' + } ) - throw 'Not implemented' + foreach ($udtCase in $udtCases) { + $udtTestCases += @{ + moduleFolderName = $resourceTypeIdentifier + templateFileContent = $templateContent + templateFileContentBicep = Get-Content $templateFilePath + parameterName = $udtCase.parameterName + udtName = $udtCase.udtName + expectedUdtUrl = $udtCase.udtExpectedUrl ? $udtCase.udtExpectedUrl : '' + } + } } - It "[] If template has [privateEndpoints] parameter, it should implement the expected user-defined-type" -TestCases $udtTestCases { - param( - [object[]] $templateFileContent - ) - throw 'Not implemented' - - } - - It "[] If template has [diagnosticSettings] parameter, it should implement the expected user-defined-type" -TestCases $udtTestCases { + It "[] If template has [] parameter, it should implement the expected user-defined type []" -TestCases $udtTestCases { param( - [object[]] $templateFileContent + [hashtable] $templateFileContent, + [string[]] $templateFileContentBicep, + [string] $parameterName, + [string] $udtName, + [string] $expectedUdtUrl ) - throw 'Not implemented' - - } - It "[] If template has [lock] parameter, it should implement the expected user-defined-type" -TestCases $udtTestCases { + if ($templateFileContent.parameters.Keys -contains $parameterName) { + $templateFileContent.parameters.$parameterName.Keys | Should -Contain '$ref' -Because "the [$parameterName] parameter should use a user-defined type." + $templateFileContent.parameters.$parameterName.'$ref' | Should -Be "#/definitions/$udtName" -Because "the [$parameterName] parameter should use a user-defined type [$udtName]." - param( - [object[]] $templateFileContent - ) - throw 'Not implemented' - - } - - It "[] If template has [customerManagedKey] parameter, it should implement the expected user-defined-type" -TestCases $udtTestCases { + if (-not [String]::IsNullOrEmpty($expectedUdtUrl)) { + $implementedSchemaStartIndex = $templateFileContentBicep.IndexOf("type $udtName = {") + $implementedSchemaEndIndex = $implementedSchemaStartIndex + 1 + while ($templateFileContentBicep[$implementedSchemaEndIndex] -notmatch '^\}.*' -and $implementedSchemaEndIndex -lt $templateFileContentBicep.Length) { + $implementedSchemaEndIndex++ + } + if ($implementedSchemaEndIndex -eq $templateFileContentBicep.Length) { + throw "Failed to identify [$udtName] user-defined type in template." + } + $implementedSchema = $templateFileContentBicep[$implementedSchemaStartIndex..$implementedSchemaEndIndex] - param( - [object[]] $templateFileContent - ) - throw 'Not implemented' + $expectedSchemaFull = (Invoke-WebRequest -Uri $expectedUdtUrl).Content -split "\n" + $expectedSchemaStartIndex = $expectedSchemaFull.IndexOf("type $udtName = {") + $expectedSchemaEndIndex = $expectedSchemaStartIndex + 1 + while ($expectedSchemaFull[$expectedSchemaEndIndex] -notmatch '^\}.*' -and $expectedSchemaEndIndex -lt $expectedSchemaFull.Length) { + $expectedSchemaEndIndex++ + } + if ($expectedSchemaEndIndex -eq $expectedSchemaFull.Length) { + throw "Failed to identify [$udtName] user-defined type in expected schema at URL [$expectedUdtUrl]." + } + $expectedSchema = $expectedSchemaFull[$expectedSchemaStartIndex..$expectedSchemaEndIndex] + + $formattedDiff = @() + foreach ($finding in (Compare-Object $implementedSchema $expectedSchema)) { + if ($finding.SideIndicator -eq '=>') { + $formattedDiff += ('+ {0}' -f $finding.InputObject) + } elseif ($finding.SideIndicator -eq '<=') { + $formattedDiff += ('- {0}' -f $finding.InputObject) + } + } + if ($formattedDiff.Count -gt 0) { + Write-Warning ($formattedDiff | Out-String) -Verbose + $mdFormattedDiff = ($formattedDiff -join '
') -replace '\|', '\|' + } + ($implementedSchema | Out-String) | Should -Be ($expectedSchema | Out-String) -Because ('The implemented user-defined type should be the same as the expected user-defined type of url [{0}] and should not have diff
{1}
.' -f $expectedUdtUrl, $mdFormattedDiff) + } + } else { + Set-ItResult -Skipped -Because "the module template has no [$parameterName] parameter." + } } - It "[] If template has [diagnosticSettings] parameter, it should implement the expected user-defined-type" -TestCases $udtTestCases { - - param( - [object[]] $templateFileContent - ) - throw 'Not implemented' - - } + # TODO Add test for tags + # TODO add tests for msi principal id output } } @@ -1026,7 +1068,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { param( [object[]] $testFileContent ) - throw 'Not implemented' + Write-Error 'Not implemented' } @@ -1037,7 +1079,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { [object[]] $testFileContent ) #TODO: must consider that the folder name is more than just 'default' - throw 'Not implemented' + Write-Error 'Not implemented' } @@ -1048,7 +1090,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { [object[]] $testFileContent ) #TODO: must consider that the folder name is more than just 'max' - throw 'Not implemented' + Write-Error 'Not implemented' } @@ -1059,7 +1101,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { [object[]] $testFileContent ) #TODO: must consider that the folder name is more than just 'waf' - throw 'Not implemented' + Write-Error 'Not implemented' } @@ -1068,7 +1110,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { param( [object[]] $testFileContent ) - throw 'Not implemented' + Write-Error 'Not implemented' } @@ -1077,7 +1119,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { param( [object[]] $testFileContent ) - throw 'Not implemented' + Write-Error 'Not implemented' } @@ -1086,7 +1128,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { param( [object[]] $testFileContent ) - throw 'Not implemented' + Write-Error 'Not implemented' } It "[] Bicep test deployment files should invoke test like [`module testDeployment '../.*main.bicep' = {`]" -TestCases $deploymentTestFileTestCases { From 4e1d86f3848f9aa4e858f834bb373af04d64c179 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 09:19:19 +0100 Subject: [PATCH 03/55] Changed to warning --- .../pipelines/staticValidation/compliance/module.tests.ps1 | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index f3ab52891e..dd9c9fb5e1 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -1023,12 +1023,10 @@ Describe 'Module tests' -Tag 'Module' { $formattedDiff += ('- {0}' -f $finding.InputObject) } } + if ($formattedDiff.Count -gt 0) { - Write-Warning ($formattedDiff | Out-String) -Verbose - $mdFormattedDiff = ($formattedDiff -join '
') -replace '\|', '\|' + Write-Warning ("The implemented user-defined type should be the same as the expected user-defined type of url [{0}] and should not have diff`n{1}" -f $expectedUdtUrl, ($formattedDiff | Out-String)) } - - ($implementedSchema | Out-String) | Should -Be ($expectedSchema | Out-String) -Because ('The implemented user-defined type should be the same as the expected user-defined type of url [{0}] and should not have diff
{1}
.' -f $expectedUdtUrl, $mdFormattedDiff) } } else { Set-ItResult -Skipped -Because "the module template has no [$parameterName] parameter." From 94fff0ba27001ed731cd18daee02d1b06b7cef21 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 14:19:32 +0100 Subject: [PATCH 04/55] Expanded test verbosity & added additional tets --- .../compliance/module.tests.ps1 | 59 +++++++++++++++---- 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index dd9c9fb5e1..cc36fb716e 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -910,7 +910,8 @@ Describe 'Module tests' -Tag 'Module' { Context 'User-defined-types tests' -Tag 'UDT' { - $udtTestCases = [System.Collections.ArrayList] @() + $udtTestCases = [System.Collections.ArrayList] @() # General UDT tests (e.g. param should exist) + $udtSpecificTestCases = [System.Collections.ArrayList] @() # Specific UDT test cases for singular UDTs (e.g. tags) foreach ($moduleFolderPath in $moduleFolderPaths) { $resourceTypeIdentifier = ($moduleFolderPath -split '[\/|\\]{1}avm[\/|\\]{1}(res|ptn)[\/|\\]{1}')[2] -replace '\\', '/' # avm/res// @@ -935,34 +936,47 @@ Describe 'Module tests' -Tag 'Module' { $templateContent = $convertedTemplates[$moduleFolderPathKey].templateContent } + $udtSpecificTestCases += @{ + moduleFolderName = $resourceTypeIdentifier + templateFileContent = $templateContent + templateFileContentBicep = Get-Content $templateFilePath + } + # Setting expected URL only for those that doen't have multiple different variants - $avmInterfaceSpecsBase = 'https://raw.githubusercontent.com/Azure/Azure-Verified-Modules/main/docs/static/includes/interfaces' + $avmInterfaceSpecsTemplateBase = 'https://raw.githubusercontent.com/Azure/Azure-Verified-Modules/main/docs/static/includes/interfaces' + $avmInterfaceSpecsBase = 'https://azure.github.io/Azure-Verified-Modules/specs/shared/interfaces' $udtCases = @( @{ parameterName = 'diagnosticSettings' udtName = 'diagnosticSettingType' + link = "$avmInterfaceSpecsBase#diagnostic-settings" } @{ parameterName = 'roleAssignments' udtName = 'roleAssignmentType' - udtExpectedUrl = "$avmInterfaceSpecsBase/int.rbac.udt.schema.bicep" + udtExpectedUrl = "$avmInterfaceSpecsTemplateBase/int.rbac.udt.schema.bicep" + link = "$avmInterfaceSpecsBase#role-assignments" } @{ parameterName = 'lock' udtName = 'lockType' - udtExpectedUrl = "$avmInterfaceSpecsBase/int.locks.udt.schema.bicep" + udtExpectedUrl = "$avmInterfaceSpecsTemplateBase/int.locks.udt.schema.bicep" + link = "$avmInterfaceSpecsBase#resource-locks" } @{ parameterName = 'managedIdentities' udtName = 'managedIdentitiesType' + link = "$avmInterfaceSpecsBase#managed-identities" } @{ parameterName = 'privateEndpoints' udtName = 'privateEndpointType' + link = "$avmInterfaceSpecsBase#private-endpoints" } @{ parameterName = 'customerManagedKey' udtName = 'customerManagedKeyType' + link = "$avmInterfaceSpecsBase#customer-managed-keys" } ) @@ -979,19 +993,20 @@ Describe 'Module tests' -Tag 'Module' { } - It "[] If template has [] parameter, it should implement the expected user-defined type []" -TestCases $udtTestCases { + It "[] If template has [] parameter, it should implement the user-defined type []" -TestCases $udtTestCases { param( [hashtable] $templateFileContent, [string[]] $templateFileContentBicep, [string] $parameterName, [string] $udtName, - [string] $expectedUdtUrl + [string] $expectedUdtUrl, + [string] $link ) if ($templateFileContent.parameters.Keys -contains $parameterName) { - $templateFileContent.parameters.$parameterName.Keys | Should -Contain '$ref' -Because "the [$parameterName] parameter should use a user-defined type." - $templateFileContent.parameters.$parameterName.'$ref' | Should -Be "#/definitions/$udtName" -Because "the [$parameterName] parameter should use a user-defined type [$udtName]." + $templateFileContent.parameters.$parameterName.Keys | Should -Contain '$ref' -Because "the [$parameterName] parameter should use a user-defined type. For for information please review the [AVM Specs]($link)." + $templateFileContent.parameters.$parameterName.'$ref' | Should -Be "#/definitions/$udtName" -Because "the [$parameterName] parameter should use a user-defined type [$udtName]. For for information please review the [AVM Specs]($link)." if (-not [String]::IsNullOrEmpty($expectedUdtUrl)) { $implementedSchemaStartIndex = $templateFileContentBicep.IndexOf("type $udtName = {") @@ -1025,7 +1040,7 @@ Describe 'Module tests' -Tag 'Module' { } if ($formattedDiff.Count -gt 0) { - Write-Warning ("The implemented user-defined type should be the same as the expected user-defined type of url [{0}] and should not have diff`n{1}" -f $expectedUdtUrl, ($formattedDiff | Out-String)) + Write-Warning ("The implemented user-defined type is not the same as the expected [user-defined type]({0}) defined in the [AVM specs]({1}) and should not have diff`n{2}" -f $expectedUdtUrl, $link, ($formattedDiff | Out-String)) } } } else { @@ -1033,9 +1048,31 @@ Describe 'Module tests' -Tag 'Module' { } } + It "[] If a [managedIdentitiesType] UDT definition exists and supports system-assigned-identities, the template should have an output for its principal ID." -TestCases $udtSpecificTestCases { + + param( + [hashtable] $templateFileContent + ) + + if ($templateFileContent.definitions.Keys -contains 'managedIdentitiesType' -and $templateFileContent.definitions.managedIdentitiesType.properties.keys -contains 'systemAssigned') { + $templateFileContent.outputs.Keys | Should -Contain 'systemAssignedMIPrincipalId' -Because 'The AVM specs require a this output. For for information please review the [AVM Specs](https://azure.github.io/Azure-Verified-Modules/specs/shared/interfaces#managed-identities).' + } else { + Set-ItResult -Skipped -Because "the module template has no [managedIdentitiesType] UDT definition or does not support system-assigned-identities." + } + } + + It "[] If a [tags] parameter exists it should be nullable." -TestCases $udtTestCases { - # TODO Add test for tags - # TODO add tests for msi principal id output + param( + [hashtable] $templateFileContent + ) + + if ($templateFileContent.parameters.Keys -contains 'tags') { + $templateFileContent.parameters.tags.nullable | Should -Be $true -Because 'The AVM specs require a specific format. For for information please review the [AVM Specs](https://azure.github.io/Azure-Verified-Modules/specs/shared/interfaces#tags).' + } else { + Set-ItResult -Skipped -Because "the module template has no [tags] parameter." + } + } } } From c18ce6baea39a873b231c956c2439b3913935dc1 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 15:45:41 +0100 Subject: [PATCH 05/55] Finalized further tests --- .../compliance/module.tests.ps1 | 38 +++++++++++-------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index cc36fb716e..24dbbc5c5f 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -1061,7 +1061,7 @@ Describe 'Module tests' -Tag 'Module' { } } - It "[] If a [tags] parameter exists it should be nullable." -TestCases $udtTestCases { + It "[] If a [tags] parameter exists it should be nullable." -TestCases $udtSpecificTestCases { param( [hashtable] $templateFileContent @@ -1103,41 +1103,49 @@ Describe 'Test file tests' -Tag 'TestTemplate' { param( [object[]] $testFileContent ) - Write-Error 'Not implemented' - + ($testFileContent -match "^param serviceShort string = '(.*)$") | Should -Not -BeNullOrEmpty -Because 'the module test deployment file should contain a service short parameter using the syntax [param serviceShort string = ''*''].' } - It "[] Bicep test deployment files in a [default] folder should contain a service short with ending [min]" -TestCases $deploymentTestFileTestCases { + It "[] Bicep test deployment files in a [default] folder should contain a service short with ending [min]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]defaults[\\|\/].*' }) { param( - [string] $testFilePath, [object[]] $testFileContent ) - #TODO: must consider that the folder name is more than just 'default' - Write-Error 'Not implemented' + if (($testFileContent | Out-String) -match "param serviceShort string = '(.*)'") { + $serviceShort = $Matches[1] + $serviceShort | Should -BeLike "*min" + } else { + Set-ItResult -Skipped -Because 'the module test deployment file should contain a service short parameter using the syntax [param serviceShort string = ''*min''] but it doesn''t.' + } } - It "[] Bicep test deployment files in a [max] folder should contain a service short with ending [max]" -TestCases $deploymentTestFileTestCases { + It "[] Bicep test deployment files in a [max] folder should contain a service short with ending [max]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]max[\\|\/].*' }) { param( - [string] $testFilePath, [object[]] $testFileContent ) - #TODO: must consider that the folder name is more than just 'max' - Write-Error 'Not implemented' + if (($testFileContent | Out-String) -match "param serviceShort string = '(.*)'") { + $serviceShort = $Matches[1] + $serviceShort | Should -BeLike "*max" + } else { + Set-ItResult -Skipped -Because 'the module test deployment file should contain a service short parameter using the syntax [param serviceShort string = ''*max''] but it doesn''t.' + } } - It "[] Bicep test deployment files in a [waf-aligned] folder should contain a service short with ending [waf]" -TestCases $deploymentTestFileTestCases { + It "[] Bicep test deployment files in a [waf-aligned] folder should contain a service short with ending [waf]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]waf\-aligned[\\|\/].*' }) { param( - [string] $testFilePath, [object[]] $testFileContent ) - #TODO: must consider that the folder name is more than just 'waf' - Write-Error 'Not implemented' + if (($testFileContent | Out-String) -match "param serviceShort string = '(.*)'") { + $serviceShort = $Matches[1] + $serviceShort | Should -BeLike "*waf" + } else { + Set-ItResult -Skipped -Because 'the module test deployment file should contain a service short parameter using the syntax [param serviceShort string = ''*waf''] but it doesn''t.' + } } It "[] Bicep test deployment files should contain a test name" -TestCases $deploymentTestFileTestCases { From a3436942147ce7690ab14a9c12ce11f1bc5c628b Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 16:18:05 +0100 Subject: [PATCH 06/55] Update to latest --- .../staticValidation/compliance/module.tests.ps1 | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index 24dbbc5c5f..98caa78e5d 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -1113,8 +1113,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { ) if (($testFileContent | Out-String) -match "param serviceShort string = '(.*)'") { - $serviceShort = $Matches[1] - $serviceShort | Should -BeLike "*min" + $Matches[1] | Should -BeLike "*min" } else { Set-ItResult -Skipped -Because 'the module test deployment file should contain a service short parameter using the syntax [param serviceShort string = ''*min''] but it doesn''t.' } @@ -1127,8 +1126,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { ) if (($testFileContent | Out-String) -match "param serviceShort string = '(.*)'") { - $serviceShort = $Matches[1] - $serviceShort | Should -BeLike "*max" + $Matches[1] | Should -BeLike "*max" } else { Set-ItResult -Skipped -Because 'the module test deployment file should contain a service short parameter using the syntax [param serviceShort string = ''*max''] but it doesn''t.' } @@ -1141,8 +1139,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { ) if (($testFileContent | Out-String) -match "param serviceShort string = '(.*)'") { - $serviceShort = $Matches[1] - $serviceShort | Should -BeLike "*waf" + $Matches[1] | Should -BeLike "*waf" } else { Set-ItResult -Skipped -Because 'the module test deployment file should contain a service short parameter using the syntax [param serviceShort string = ''*waf''] but it doesn''t.' } @@ -1153,8 +1150,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { param( [object[]] $testFileContent ) - Write-Error 'Not implemented' - + (($testFileContent | Out-String) -match "metadata name = ") | Should -Be $true -Because 'Test cases should contain a test name in the format `metadata name = ''This is one hell of a test name''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' } It "[] Bicep test deployment files should contain a test description" -TestCases $deploymentTestFileTestCases { @@ -1162,8 +1158,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { param( [object[]] $testFileContent ) - Write-Error 'Not implemented' - + (($testFileContent | Out-String) -match "metadata description = ") | Should -Be $true -Because 'Test cases should contain a test description in the format `metadata description = ''This is one hell of a description''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' } It "[] Bicep test deployment files should contain namePrefix parameter with value ['#_namePrefix_#']" -TestCases $deploymentTestFileTestCases { From 3a6f0a2b56d426ce7e54bfc5145f45cf28dbd440 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 16:27:54 +0100 Subject: [PATCH 07/55] Update to latest --- .../staticValidation/compliance/module.tests.ps1 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index 98caa78e5d..013972eabb 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -1150,7 +1150,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { param( [object[]] $testFileContent ) - (($testFileContent | Out-String) -match "metadata name = ") | Should -Be $true -Because 'Test cases should contain a test name in the format `metadata name = ''This is one hell of a test name''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' + (($testFileContent | Out-String) -match "metadata name = .+") | Should -Be $true -Because 'Test cases should contain a test name in the format `metadata name = ''This is one hell of a test name''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' } It "[] Bicep test deployment files should contain a test description" -TestCases $deploymentTestFileTestCases { @@ -1158,7 +1158,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { param( [object[]] $testFileContent ) - (($testFileContent | Out-String) -match "metadata description = ") | Should -Be $true -Because 'Test cases should contain a test description in the format `metadata description = ''This is one hell of a description''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' + (($testFileContent | Out-String) -match "metadata description = .+") | Should -Be $true -Because 'Test cases should contain a test description in the format `metadata description = ''This is one hell of a description''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' } It "[] Bicep test deployment files should contain namePrefix parameter with value ['#_namePrefix_#']" -TestCases $deploymentTestFileTestCases { @@ -1166,7 +1166,9 @@ Describe 'Test file tests' -Tag 'TestTemplate' { param( [object[]] $testFileContent ) - Write-Error 'Not implemented' + + (($testFileContent | Out-String) -match "@description('Optional\. A token to inject into the name of each resource\. This value can be automatically injected by the CI\.')") | Should -Be $true -Because 'The parameter `namePrefix` should have a meaningful description.' + (($testFileContent | Out-String) -match "param namePrefix string = '#_namePrefix_#'") | Should -Be $true -Because 'The test CI needs this value to ensure that deployed resources have unique names.' } It "[] Bicep test deployment files should invoke test like [`module testDeployment '../.*main.bicep' = {`]" -TestCases $deploymentTestFileTestCases { From 4ab6a5bb23b592796960daf61cb831fcf91cd3ac Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 16:38:29 +0100 Subject: [PATCH 08/55] Added module name + small fix --- .../compliance/module.tests.ps1 | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index 013972eabb..d5dd1215c6 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -1090,6 +1090,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { $resourceTypeIdentifier = ($moduleFolderPath -split '[\/|\\]{1}avm[\/|\\]{1}(res|ptn)[\/|\\]{1}')[2] -replace '\\', '/' # avm/res// $deploymentTestFileTestCases += @{ + testName = Split-Path (Split-Path $testFilePath) -Leaf testFilePath = $testFilePath testFileContent = $testFileContent moduleFolderName = $resourceTypeIdentifier @@ -1098,7 +1099,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { } } - It "[] Bicep test deployment files should contain serviceShort parameter" -TestCases $deploymentTestFileTestCases { + It "[] [] Bicep test deployment files should contain serviceShort parameter" -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent @@ -1106,7 +1107,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { ($testFileContent -match "^param serviceShort string = '(.*)$") | Should -Not -BeNullOrEmpty -Because 'the module test deployment file should contain a service short parameter using the syntax [param serviceShort string = ''*''].' } - It "[] Bicep test deployment files in a [default] folder should contain a service short with ending [min]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]defaults[\\|\/].*' }) { + It "[] [] Bicep test deployment files in a [default] folder should contain a service short with ending [min]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]defaults[\\|\/].*' }) { param( [object[]] $testFileContent @@ -1119,7 +1120,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { } } - It "[] Bicep test deployment files in a [max] folder should contain a service short with ending [max]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]max[\\|\/].*' }) { + It "[] [] Bicep test deployment files in a [max] folder should contain a service short with ending [max]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]max[\\|\/].*' }) { param( [object[]] $testFileContent @@ -1132,7 +1133,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { } } - It "[] Bicep test deployment files in a [waf-aligned] folder should contain a service short with ending [waf]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]waf\-aligned[\\|\/].*' }) { + It "[] [] Bicep test deployment files in a [waf-aligned] folder should contain a service short with ending [waf]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]waf\-aligned[\\|\/].*' }) { param( [object[]] $testFileContent @@ -1145,7 +1146,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { } } - It "[] Bicep test deployment files should contain a test name" -TestCases $deploymentTestFileTestCases { + It "[] [] Bicep test deployment files should contain a test name" -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent @@ -1153,7 +1154,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { (($testFileContent | Out-String) -match "metadata name = .+") | Should -Be $true -Because 'Test cases should contain a test name in the format `metadata name = ''This is one hell of a test name''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' } - It "[] Bicep test deployment files should contain a test description" -TestCases $deploymentTestFileTestCases { + It "[] [] Bicep test deployment files should contain a test description" -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent @@ -1161,17 +1162,17 @@ Describe 'Test file tests' -Tag 'TestTemplate' { (($testFileContent | Out-String) -match "metadata description = .+") | Should -Be $true -Because 'Test cases should contain a test description in the format `metadata description = ''This is one hell of a description''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' } - It "[] Bicep test deployment files should contain namePrefix parameter with value ['#_namePrefix_#']" -TestCases $deploymentTestFileTestCases { + It "[] [] Bicep test deployment files should contain namePrefix parameter with value ['#_namePrefix_#']" -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent ) - (($testFileContent | Out-String) -match "@description('Optional\. A token to inject into the name of each resource\. This value can be automatically injected by the CI\.')") | Should -Be $true -Because 'The parameter `namePrefix` should have a meaningful description.' + (($testFileContent | Out-String) -match "@description\('Optional\. A token to inject into the name of each resource\. This value can be automatically injected by the CI\.'\)") | Should -Be $true -Because 'The parameter `namePrefix` should have a meaningful description.' (($testFileContent | Out-String) -match "param namePrefix string = '#_namePrefix_#'") | Should -Be $true -Because 'The test CI needs this value to ensure that deployed resources have unique names.' } - It "[] Bicep test deployment files should invoke test like [`module testDeployment '../.*main.bicep' = {`]" -TestCases $deploymentTestFileTestCases { + It "[] [] Bicep test deployment files should invoke test like [`module testDeployment '../.*main.bicep' = {`]" -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent @@ -1182,7 +1183,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { $testIndex -ne -1 | Should -Be $true -Because 'the module test invocation should be in the expected format to allow identification.' } - It '[] Bicep test deployment name should contain [`-test-`].' -TestCases $deploymentTestFileTestCases { + It '[] [] Bicep test deployment name should contain [`-test-`].' -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent @@ -1193,7 +1194,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { $expectedNameFormat | Should -Be $true -Because 'the handle ''-test-'' should be part of the module test invocation''s resource name to allow identification.' } - It '[] Bicep test deployment should have parameter [`serviceShort`].' -TestCases $deploymentTestFileTestCases { + It '[] [] Bicep test deployment should have parameter [`serviceShort`].' -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent From 9bb64bde34d8b5de3d1b2bda2a0fe2687855b35f Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 17:31:08 +0100 Subject: [PATCH 09/55] Fixed kvlt --- avm/res/key-vault/vault/access-policy/main.json | 4 ++-- avm/res/key-vault/vault/key/main.json | 4 ++-- avm/res/key-vault/vault/main.bicep | 3 +++ avm/res/key-vault/vault/main.json | 12 +++++++++++- avm/res/key-vault/vault/secret/main.json | 4 ++-- 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/avm/res/key-vault/vault/access-policy/main.json b/avm/res/key-vault/vault/access-policy/main.json index 9b6725ecc4..8aa7ea483d 100644 --- a/avm/res/key-vault/vault/access-policy/main.json +++ b/avm/res/key-vault/vault/access-policy/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.22.6.54827", - "templateHash": "9999250509448584761" + "version": "0.23.1.45101", + "templateHash": "4111939022872407830" }, "name": "Key Vault Access Policies", "description": "This module deploys a Key Vault Access Policy.", diff --git a/avm/res/key-vault/vault/key/main.json b/avm/res/key-vault/vault/key/main.json index 6ecce215ac..6e85c7d6ad 100644 --- a/avm/res/key-vault/vault/key/main.json +++ b/avm/res/key-vault/vault/key/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.22.6.54827", - "templateHash": "15591839680984542683" + "version": "0.23.1.45101", + "templateHash": "2691621623448325959" }, "name": "Key Vault Keys", "description": "This module deploys a Key Vault Key.", diff --git a/avm/res/key-vault/vault/main.bicep b/avm/res/key-vault/vault/main.bicep index 4e62950d9c..ae038cf1f5 100644 --- a/avm/res/key-vault/vault/main.bicep +++ b/avm/res/key-vault/vault/main.bicep @@ -353,6 +353,9 @@ type roleAssignmentType = { @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/key-vault/vault/main.json b/avm/res/key-vault/vault/main.json index bfcfb41b93..8478ccde4e 100644 --- a/avm/res/key-vault/vault/main.json +++ b/avm/res/key-vault/vault/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "8353941507512521049" + "templateHash": "1913015049301539374" }, "name": "Key Vaults", "description": "This module deploys a Key Vault.", @@ -164,6 +164,16 @@ "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, diff --git a/avm/res/key-vault/vault/secret/main.json b/avm/res/key-vault/vault/secret/main.json index 62c5c52a19..f778252db1 100644 --- a/avm/res/key-vault/vault/secret/main.json +++ b/avm/res/key-vault/vault/secret/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.22.6.54827", - "templateHash": "11139788551431901948" + "version": "0.23.1.45101", + "templateHash": "9180551172362989336" }, "name": "Key Vault Secrets", "description": "This module deploys a Key Vault Secret.", From 68e2bd2fbc6301b199fd0258411da31781ba4380 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 17:56:38 +0100 Subject: [PATCH 10/55] Small caching fix --- .../pipelines/staticValidation/compliance/module.tests.ps1 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index d5dd1215c6..8dc880fdb9 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -930,10 +930,12 @@ Describe 'Module tests' -Tag 'Module' { throw ($templateNotFoundException -f $moduleFolderPath) } $convertedTemplates[$moduleFolderPathKey] = @{ - templateContent = $templateContent + templateContent = $templateContent + templateFilePath = $templateFilePath } } else { $templateContent = $convertedTemplates[$moduleFolderPathKey].templateContent + $templateFilePath = $convertedTemplates[$moduleFolderPathKey].templateFilePath } $udtSpecificTestCases += @{ From 1a013c2a4115610d4260515205158ed831860de8 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 19:25:21 +0100 Subject: [PATCH 11/55] Small fix and enabled passthru of warnings to GH --- .../compliance/Set-PesterGitHubOutput.ps1 | 72 ++++++++++++++++--- .../compliance/module.tests.ps1 | 9 ++- 2 files changed, 69 insertions(+), 12 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 index 4c84e61eaf..ada2dc98e9 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 @@ -81,10 +81,12 @@ function Set-PesterGitHubOutput { $passedTests = $PesterTestResults.Passed $failedTests = $PesterTestResults.Failed $skippedTests = $PesterTestResults.Skipped + $testsWithWarnings = ($passedTests + $failedTests + $skippedTests) | Where-Object { $_.StandardOutput.Keys -eq 'Warning' } Write-Verbose ('Formatting [{0}] passed tests' -f $passedTests.Count) Write-Verbose ('Formatting [{0}] failed tests' -f $failedTests.Count) Write-Verbose ('Formatting [{0}] skipped tests' -f $skippedTests.Count) + Write-Verbose ('Formatting [{0}] tests with explicit warnings' -f $warnings.Count) ###################### # Set output content # @@ -98,9 +100,9 @@ function Set-PesterGitHubOutput { ## Header table $fileContent += [System.Collections.ArrayList]@( - '| Total No. of Processed Tests| Passed Tests :white_check_mark: | Failed Tests :x: | Skipped Tests :paperclip: |', - '| :-- | :-- | :-- | :-- |' - ('| {0} | {1} | {2} | {3} |' -f $PesterTestResults.TotalCount, $passedTests.count , $failedTests.count, $skippedTests.count), + '| Total No. of Processed Tests| Passed Tests :white_check_mark: | Failed Tests :x: | Skipped Tests :paperclip: | Tests with warnings :warning: |', + '| :-- | :-- | :-- | :-- |', + ('| {0} | {1} | {2} | {3} |' -f $PesterTestResults.TotalCount, $passedTests.count , $failedTests.count, $skippedTests.count, $testsWithWarnings.count), '' ) @@ -140,8 +142,7 @@ function Set-PesterGitHubOutput { $fileContent += '| {0} | {1} | {2} |' -f $testName, $errorMessage, $testReference } - } - else { + } else { $fileContent += ('No tests failed.') } @@ -164,6 +165,8 @@ function Set-PesterGitHubOutput { if (($passedTests.Count -gt 0)) { + # TODO: Add support for outputs + $fileContent += [System.Collections.ArrayList]@( '| Name | Source |', '| :-- | :-- |' @@ -185,8 +188,7 @@ function Set-PesterGitHubOutput { $fileContent += '| {0} | {1} |' -f $testName, $testReference } - } - else { + } else { $fileContent += ('No tests passed.') } @@ -222,8 +224,8 @@ function Set-PesterGitHubOutput { $reason = ('Test {0}' -f $skippedTest.ErrorRecord.Exception.Message -replace '\|', '\|').Trim() - $testLine = $passedTest.ScriptBlock.StartPosition.StartLine - $testFile = (($passedTest.ScriptBlock.File -split '[\/|\\](avm[\/|\\])')[-2, -1] -join '') -replace '\\', '/' # e.g., [avm\res\cognitive-services\account\tests\unit\custom.tests.ps1] + $testLine = $skippedTest.ScriptBlock.StartPosition.StartLine + $testFile = (($skippedTest.ScriptBlock.File -split '[\/|\\](avm[\/|\\])')[-2, -1] -join '') -replace '\\', '/' # e.g., [avm\res\cognitive-services\account\tests\unit\custom.tests.ps1] $testReference = '{0}:{1}' -f (Split-Path $testFile -Leaf), $testLine if (-not [String]::IsNullOrEmpty($GitHubRepository) -and -not [String]::IsNullOrEmpty($BranchName)) { @@ -233,8 +235,7 @@ function Set-PesterGitHubOutput { $fileContent += '| {0} | {1} | {2} |' -f $testName, $reason, $testReference } - } - else { + } else { $fileContent += ('No tests were skipped.') } @@ -244,6 +245,55 @@ function Set-PesterGitHubOutput { '' ) + ################## + ## Warnings ## + ################## + + Write-Verbose 'Adding warnings' + $fileContent += [System.Collections.ArrayList]@( + '', + '
', + 'List of explicit warnings', + '' + ) + + if ($testsWithWarnings.Count -gt 0) { + + $fileContent += [System.Collections.ArrayList]@( + '| Name | Warning | Source |', + '| :-- | :-- | :-- |' + ) + foreach ($test in ($testsWithWarnings | Sort-Object -Property { $PSItem.ExpandedName }) ) { + foreach ($warning in $test.StandardOutput.Warning) { + $intermediateNameElements = $test.Path + $intermediateNameElements[-1] = '**{0}**' -f $test.ExpandedName + $testName = (($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|').Trim() + + $testLine = $test.ScriptBlock.StartPosition.StartLine + $testFile = (($test.ScriptBlock.File -split '[\/|\\](avm[\/|\\])')[-2, -1] -join '') -replace '\\', '/' # e.g., [avm\res\cognitive-services\account\tests\unit\custom.tests.ps1] + + $testReference = '{0}:{1}' -f (Split-Path $testFile -Leaf), $testLine + if (-not [String]::IsNullOrEmpty($GitHubRepository) -and -not [String]::IsNullOrEmpty($BranchName)) { + # Creating URL to test file to enable users to 'click' on it + $testReference = "[$testReference](https://github.com/$GitHubRepository/blob/$BranchName/$testFile#L$testLine)" + } + + $fileContent += '| {0} | {1} | {2} |' -f $testName, ($warning -replace '\|', '\|'), $testReference + } + } + } else { + $fileContent += ('No tests with warnings.') + } + + $fileContent += [System.Collections.ArrayList]@( + '', + '
', + '' + ) + + + + if ($PSCmdlet.ShouldProcess("Test results file in path [$OutputFilePath]", 'Create')) { $null = New-Item -Path $OutputFilePath -Force -Value ($fileContent | Out-String) } diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index 8dc880fdb9..8ba6483758 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -990,6 +990,7 @@ Describe 'Module tests' -Tag 'Module' { parameterName = $udtCase.parameterName udtName = $udtCase.udtName expectedUdtUrl = $udtCase.udtExpectedUrl ? $udtCase.udtExpectedUrl : '' + link = $udtCase.link } } } @@ -1042,7 +1043,13 @@ Describe 'Module tests' -Tag 'Module' { } if ($formattedDiff.Count -gt 0) { - Write-Warning ("The implemented user-defined type is not the same as the expected [user-defined type]({0}) defined in the [AVM specs]({1}) and should not have diff`n{2}" -f $expectedUdtUrl, $link, ($formattedDiff | Out-String)) + $warningMessage = "The implemented user-defined type is not the same as the expected [user-defined type]({0}) defined in the [AVM specs]({1}) and should not have diff`n{2}" -f $expectedUdtUrl, $link, ($formattedDiff | Out-String) + Write-Warning $warningMessage + + # Adding also to output to show in GitHub CI + Write-Output @{ + Warning = $warningMessage + } } } } else { From 1c2fc8ab54eafaef98ab28b8feaa3073d9469436 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 19:31:09 +0100 Subject: [PATCH 12/55] More updates --- .../staticValidation/compliance/Set-PesterGitHubOutput.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 index ada2dc98e9..e716f14f5b 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 @@ -101,8 +101,8 @@ function Set-PesterGitHubOutput { ## Header table $fileContent += [System.Collections.ArrayList]@( '| Total No. of Processed Tests| Passed Tests :white_check_mark: | Failed Tests :x: | Skipped Tests :paperclip: | Tests with warnings :warning: |', - '| :-- | :-- | :-- | :-- |', - ('| {0} | {1} | {2} | {3} |' -f $PesterTestResults.TotalCount, $passedTests.count , $failedTests.count, $skippedTests.count, $testsWithWarnings.count), + '| :-- | :-- | :-- | :-- | :-- |', + ('| {0} | {1} | {2} | {3} | {4} |' -f $PesterTestResults.TotalCount, $passedTests.count , $failedTests.count, $skippedTests.count, $testsWithWarnings.count), '' ) @@ -278,7 +278,7 @@ function Set-PesterGitHubOutput { $testReference = "[$testReference](https://github.com/$GitHubRepository/blob/$BranchName/$testFile#L$testLine)" } - $fileContent += '| {0} | {1} | {2} |' -f $testName, ($warning -replace '\|', '\|'), $testReference + $fileContent += '| {0} | {1} | {2} |' -f $testName, (($warning -join '
') -replace '\|', '\|'), $testReference } } } else { From d9c6dd5deffd8fd307107e5ce8be98961163996a Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 20:16:57 +0100 Subject: [PATCH 13/55] Update to latest --- .../staticValidation/compliance/Set-PesterGitHubOutput.ps1 | 4 +--- .../pipelines/staticValidation/compliance/module.tests.ps1 | 6 ++++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 index e716f14f5b..e1c207936d 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 @@ -165,8 +165,6 @@ function Set-PesterGitHubOutput { if (($passedTests.Count -gt 0)) { - # TODO: Add support for outputs - $fileContent += [System.Collections.ArrayList]@( '| Name | Source |', '| :-- | :-- |' @@ -278,7 +276,7 @@ function Set-PesterGitHubOutput { $testReference = "[$testReference](https://github.com/$GitHubRepository/blob/$BranchName/$testFile#L$testLine)" } - $fileContent += '| {0} | {1} | {2} |' -f $testName, (($warning -join '
') -replace '\|', '\|'), $testReference + $fileContent += ('| {0} | {1} | {2} |' -f $testName, $warning, $testReference) } } } else { diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index 8ba6483758..997ac427a6 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -1043,12 +1043,14 @@ Describe 'Module tests' -Tag 'Module' { } if ($formattedDiff.Count -gt 0) { - $warningMessage = "The implemented user-defined type is not the same as the expected [user-defined type]({0}) defined in the [AVM specs]({1}) and should not have diff`n{2}" -f $expectedUdtUrl, $link, ($formattedDiff | Out-String) + $warningMessage = "The implemented user-defined type is not the same as the expected user-defined type ({0}) defined in the AVM specs ({1}) and should not have diff`n{2}" -f $expectedUdtUrl, $link, ($formattedDiff | Out-String) Write-Warning $warningMessage # Adding also to output to show in GitHub CI + $mdFormattedDiff = ($formattedDiff -join '
') -replace '\|', '\|' + $mdFormattedWarningMessage = "The implemented user-defined type is not the same as the expected [user-defined type]({0}) defined in the [AVM specs]({1}) and should not have diff
{2}
" -f $expectedUdtUrl, $link, $mdFormattedDiff Write-Output @{ - Warning = $warningMessage + Warning = $mdFormattedWarningMessage } } } From dd0c343fb884869740436c238b367d13029fc549 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 21:00:06 +0100 Subject: [PATCH 14/55] Updated test names --- .../compliance/module.tests.ps1 | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index 997ac427a6..e46c6fc17d 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -996,7 +996,7 @@ Describe 'Module tests' -Tag 'Module' { } - It "[] If template has [] parameter, it should implement the user-defined type []" -TestCases $udtTestCases { + It "[] If template has a parameter [], it should implement the user-defined type []" -TestCases $udtTestCases { param( [hashtable] $templateFileContent, @@ -1059,7 +1059,7 @@ Describe 'Module tests' -Tag 'Module' { } } - It "[] If a [managedIdentitiesType] UDT definition exists and supports system-assigned-identities, the template should have an output for its principal ID." -TestCases $udtSpecificTestCases { + It "[] If a UDT definition [managedIdentitiesType] exists and supports system-assigned-identities, the template should have an output for its principal ID." -TestCases $udtSpecificTestCases { param( [hashtable] $templateFileContent @@ -1072,7 +1072,7 @@ Describe 'Module tests' -Tag 'Module' { } } - It "[] If a [tags] parameter exists it should be nullable." -TestCases $udtSpecificTestCases { + It "[] If a parameter [tags] exists it should be nullable." -TestCases $udtSpecificTestCases { param( [hashtable] $templateFileContent @@ -1110,15 +1110,15 @@ Describe 'Test file tests' -Tag 'TestTemplate' { } } - It "[] [] Bicep test deployment files should contain serviceShort parameter" -TestCases $deploymentTestFileTestCases { + It "[] [] Bicep test deployment files should contain a parameter [serviceShort]" -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent ) - ($testFileContent -match "^param serviceShort string = '(.*)$") | Should -Not -BeNullOrEmpty -Because 'the module test deployment file should contain a service short parameter using the syntax [param serviceShort string = ''*''].' + ($testFileContent -match "^param serviceShort string = '(.*)$") | Should -Not -BeNullOrEmpty -Because 'the module test deployment file should contain a parameter [serviceShort] using the syntax [param serviceShort string = ''*''].' } - It "[] [] Bicep test deployment files in a [default] folder should contain a service short with ending [min]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]defaults[\\|\/].*' }) { + It "[] [] Bicep test deployment files in a [waf-aligned] folder should have a parameter [serviceShort] with a value ending with [min]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]defaults[\\|\/].*' }) { param( [object[]] $testFileContent @@ -1127,11 +1127,11 @@ Describe 'Test file tests' -Tag 'TestTemplate' { if (($testFileContent | Out-String) -match "param serviceShort string = '(.*)'") { $Matches[1] | Should -BeLike "*min" } else { - Set-ItResult -Skipped -Because 'the module test deployment file should contain a service short parameter using the syntax [param serviceShort string = ''*min''] but it doesn''t.' + Set-ItResult -Skipped -Because 'the module test deployment file should contain a parameter [serviceShort] using the syntax [param serviceShort string = ''*min''] but it doesn''t.' } } - It "[] [] Bicep test deployment files in a [max] folder should contain a service short with ending [max]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]max[\\|\/].*' }) { + It "[] [] Bicep test deployment files in a [waf-aligned] folder should have a [serviceShort] parameter with a value ending with [max]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]max[\\|\/].*' }) { param( [object[]] $testFileContent @@ -1140,11 +1140,11 @@ Describe 'Test file tests' -Tag 'TestTemplate' { if (($testFileContent | Out-String) -match "param serviceShort string = '(.*)'") { $Matches[1] | Should -BeLike "*max" } else { - Set-ItResult -Skipped -Because 'the module test deployment file should contain a service short parameter using the syntax [param serviceShort string = ''*max''] but it doesn''t.' + Set-ItResult -Skipped -Because 'the module test deployment file should contain a parameter [serviceShort] using the syntax [param serviceShort string = ''*max''] but it doesn''t.' } } - It "[] [] Bicep test deployment files in a [waf-aligned] folder should contain a service short with ending [waf]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]waf\-aligned[\\|\/].*' }) { + It "[] [] Bicep test deployment files in a [waf-aligned] folder should have a [serviceShort] parameter with a value ending with [waf]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]waf\-aligned[\\|\/].*' }) { param( [object[]] $testFileContent @@ -1153,34 +1153,34 @@ Describe 'Test file tests' -Tag 'TestTemplate' { if (($testFileContent | Out-String) -match "param serviceShort string = '(.*)'") { $Matches[1] | Should -BeLike "*waf" } else { - Set-ItResult -Skipped -Because 'the module test deployment file should contain a service short parameter using the syntax [param serviceShort string = ''*waf''] but it doesn''t.' + Set-ItResult -Skipped -Because 'the module test deployment file should contain a parameter [serviceShort] using the syntax [param serviceShort string = ''*waf''] but it doesn''t.' } } - It "[] [] Bicep test deployment files should contain a test name" -TestCases $deploymentTestFileTestCases { + It "[] [] Bicep test deployment files should contain a metadata string [name]" -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent ) - (($testFileContent | Out-String) -match "metadata name = .+") | Should -Be $true -Because 'Test cases should contain a test name in the format `metadata name = ''This is one hell of a test name''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' + (($testFileContent | Out-String) -match "metadata name = .+") | Should -Be $true -Because 'Test cases should contain a metadata string [name] in the format `metadata name = ''This is one hell of a test name''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' } - It "[] [] Bicep test deployment files should contain a test description" -TestCases $deploymentTestFileTestCases { + It "[] [] Bicep test deployment files should contain a metadata string [description]" -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent ) - (($testFileContent | Out-String) -match "metadata description = .+") | Should -Be $true -Because 'Test cases should contain a test description in the format `metadata description = ''This is one hell of a description''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' + (($testFileContent | Out-String) -match "metadata description = .+") | Should -Be $true -Because 'Test cases should contain a metadata string [description] in the format `metadata description = ''This is one hell of a description''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' } - It "[] [] Bicep test deployment files should contain namePrefix parameter with value ['#_namePrefix_#']" -TestCases $deploymentTestFileTestCases { + It "[] [] Bicep test deployment files should contain a parameter [namePrefix] with value ['#_namePrefix_#']" -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent ) - (($testFileContent | Out-String) -match "@description\('Optional\. A token to inject into the name of each resource\. This value can be automatically injected by the CI\.'\)") | Should -Be $true -Because 'The parameter `namePrefix` should have a meaningful description.' - (($testFileContent | Out-String) -match "param namePrefix string = '#_namePrefix_#'") | Should -Be $true -Because 'The test CI needs this value to ensure that deployed resources have unique names.' + (($testFileContent | Out-String) -match "@description\('Optional\. A token to inject into the name of each resource\. This value can be automatically injected by the CI\.'\)") | Should -Be $true -Because 'The parameter [namePrefix] should have the expected description.' + (($testFileContent | Out-String) -match "param namePrefix string = '#_namePrefix_#'") | Should -Be $true -Because 'The test CI needs this value to ensure that deployed resources have unique names per fork.' } It "[] [] Bicep test deployment files should invoke test like [`module testDeployment '../.*main.bicep' = {`]" -TestCases $deploymentTestFileTestCases { From 2ebd45891d75ce145710733437cb82c5814128c4 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 23:32:08 +0100 Subject: [PATCH 15/55] JSON rollback --- avm/res/key-vault/vault/access-policy/main.json | 4 ++-- avm/res/key-vault/vault/key/main.json | 4 ++-- avm/res/key-vault/vault/main.json | 16 ++++++++-------- avm/res/key-vault/vault/secret/main.json | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/avm/res/key-vault/vault/access-policy/main.json b/avm/res/key-vault/vault/access-policy/main.json index 8aa7ea483d..9b6725ecc4 100644 --- a/avm/res/key-vault/vault/access-policy/main.json +++ b/avm/res/key-vault/vault/access-policy/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "4111939022872407830" + "version": "0.22.6.54827", + "templateHash": "9999250509448584761" }, "name": "Key Vault Access Policies", "description": "This module deploys a Key Vault Access Policy.", diff --git a/avm/res/key-vault/vault/key/main.json b/avm/res/key-vault/vault/key/main.json index 6e85c7d6ad..6ecce215ac 100644 --- a/avm/res/key-vault/vault/key/main.json +++ b/avm/res/key-vault/vault/key/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "2691621623448325959" + "version": "0.22.6.54827", + "templateHash": "15591839680984542683" }, "name": "Key Vault Keys", "description": "This module deploys a Key Vault Key.", diff --git a/avm/res/key-vault/vault/main.json b/avm/res/key-vault/vault/main.json index 8478ccde4e..f10c40c0fb 100644 --- a/avm/res/key-vault/vault/main.json +++ b/avm/res/key-vault/vault/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "1913015049301539374" + "version": "0.22.6.54827", + "templateHash": "9188769706526490100" }, "name": "Key Vaults", "description": "This module deploys a Key Vault.", @@ -682,8 +682,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "4111939022872407830" + "version": "0.22.6.54827", + "templateHash": "9999250509448584761" }, "name": "Key Vault Access Policies", "description": "This module deploys a Key Vault Access Policy.", @@ -815,8 +815,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "9180551172362989336" + "version": "0.22.6.54827", + "templateHash": "11139788551431901948" }, "name": "Key Vault Secrets", "description": "This module deploys a Key Vault Secret.", @@ -1104,8 +1104,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "2691621623448325959" + "version": "0.22.6.54827", + "templateHash": "15591839680984542683" }, "name": "Key Vault Keys", "description": "This module deploys a Key Vault Key.", diff --git a/avm/res/key-vault/vault/secret/main.json b/avm/res/key-vault/vault/secret/main.json index f778252db1..62c5c52a19 100644 --- a/avm/res/key-vault/vault/secret/main.json +++ b/avm/res/key-vault/vault/secret/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "9180551172362989336" + "version": "0.22.6.54827", + "templateHash": "11139788551431901948" }, "name": "Key Vault Secrets", "description": "This module deploys a Key Vault Secret.", From f6caf7e44eadf5ed72103aa3bcada9c3cf1c8fce Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 23:49:57 +0100 Subject: [PATCH 16/55] Updated regex --- .../compliance/Set-PesterGitHubOutput.ps1 | 2 +- .../staticValidation/compliance/module.tests.ps1 | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 index e1c207936d..a8a773640e 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 @@ -131,7 +131,7 @@ function Set-PesterGitHubOutput { $errorTestLine = $failedTest.ErrorRecord.TargetObject.Line $errorTestFile = (($failedTest.ErrorRecord.TargetObject.File -split '[\/|\\](avm[\/|\\])')[-2, -1] -join '') -replace '\\', '/' # e.g., [avm\res\cognitive-services\account\tests\unit\custom.tests.ps1] - $errorMessage = $failedTest.ErrorRecord.TargetObject.Message.Trim() -replace '\n', '
' # Replace new lines with
to enable line breaks in markdown + $errorMessage = ($failedTest.ErrorRecord.TargetObject.Message.Trim() -replace '_', '\_') -replace '\n', '
' # Replace new lines with
to enable line breaks in markdown $testReference = '{0}:{1}' -f (Split-Path $errorTestFile -Leaf), $errorTestLine diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index e46c6fc17d..6b7c50807b 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -1162,7 +1162,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { param( [object[]] $testFileContent ) - (($testFileContent | Out-String) -match "metadata name = .+") | Should -Be $true -Because 'Test cases should contain a metadata string [name] in the format `metadata name = ''This is one hell of a test name''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' + ($testFileContent | Out-String) | Should -Match "metadata name = .+" -Because 'Test cases should contain a metadata string [name] in the format `metadata name = ''This is one hell of a test name''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' } It "[] [] Bicep test deployment files should contain a metadata string [description]" -TestCases $deploymentTestFileTestCases { @@ -1170,7 +1170,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { param( [object[]] $testFileContent ) - (($testFileContent | Out-String) -match "metadata description = .+") | Should -Be $true -Because 'Test cases should contain a metadata string [description] in the format `metadata description = ''This is one hell of a description''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' + ($testFileContent | Out-String) | Should -Match "metadata description = .+" -Because 'Test cases should contain a metadata string [description] in the format `metadata description = ''This is one hell of a description''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' } It "[] [] Bicep test deployment files should contain a parameter [namePrefix] with value ['#_namePrefix_#']" -TestCases $deploymentTestFileTestCases { @@ -1179,8 +1179,8 @@ Describe 'Test file tests' -Tag 'TestTemplate' { [object[]] $testFileContent ) - (($testFileContent | Out-String) -match "@description\('Optional\. A token to inject into the name of each resource\. This value can be automatically injected by the CI\.'\)") | Should -Be $true -Because 'The parameter [namePrefix] should have the expected description.' - (($testFileContent | Out-String) -match "param namePrefix string = '#_namePrefix_#'") | Should -Be $true -Because 'The test CI needs this value to ensure that deployed resources have unique names per fork.' + ($testFileContent | Out-String) | Should -Match "@description\('Optional\. A token to inject into the name of each resource\. This value can be automatically injected by the CI\.'\)" -Because 'The parameter [namePrefix] should have the expected description.' + ($testFileContent | Out-String) | Should -Match "param namePrefix string = '#_namePrefix_#'" -Because 'The test CI needs this value to ensure that deployed resources have unique names per fork.' } It "[] [] Bicep test deployment files should invoke test like [`module testDeployment '../.*main.bicep' = {`]" -TestCases $deploymentTestFileTestCases { From f56f66af2a884495d5eeafb4f580d76960ee93f3 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 23:52:45 +0100 Subject: [PATCH 17/55] Removed assertion --- .../pipelines/staticValidation/compliance/module.tests.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index 6b7c50807b..b7c9ab905f 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -1179,7 +1179,6 @@ Describe 'Test file tests' -Tag 'TestTemplate' { [object[]] $testFileContent ) - ($testFileContent | Out-String) | Should -Match "@description\('Optional\. A token to inject into the name of each resource\. This value can be automatically injected by the CI\.'\)" -Because 'The parameter [namePrefix] should have the expected description.' ($testFileContent | Out-String) | Should -Match "param namePrefix string = '#_namePrefix_#'" -Because 'The test CI needs this value to ensure that deployed resources have unique names per fork.' } From 282b640a884885ba59db841457ddfdc5ea1ec59e Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 8 Nov 2023 23:58:17 +0100 Subject: [PATCH 18/55] Update to latest --- .../compliance/Set-PesterGitHubOutput.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 index a8a773640e..d23f8d4f8f 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 @@ -127,7 +127,7 @@ function Set-PesterGitHubOutput { $intermediateNameElements = $failedTest.Path $intermediateNameElements[-1] = '**{0}**' -f $failedTest.ExpandedName - $testName = (($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|').Trim() + $testName = ((($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|') -replace '_', '\_').Trim() $errorTestLine = $failedTest.ErrorRecord.TargetObject.Line $errorTestFile = (($failedTest.ErrorRecord.TargetObject.File -split '[\/|\\](avm[\/|\\])')[-2, -1] -join '') -replace '\\', '/' # e.g., [avm\res\cognitive-services\account\tests\unit\custom.tests.ps1] @@ -173,7 +173,7 @@ function Set-PesterGitHubOutput { $intermediateNameElements = $passedTest.Path $intermediateNameElements[-1] = '**{0}**' -f $passedTest.ExpandedName - $testName = (($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|').Trim() + $testName = ((($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|') -replace '_', '\_').Trim() $testLine = $passedTest.ScriptBlock.StartPosition.StartLine $testFile = (($passedTest.ScriptBlock.File -split '[\/|\\](avm[\/|\\])')[-2, -1] -join '') -replace '\\', '/' # e.g., [avm\res\cognitive-services\account\tests\unit\custom.tests.ps1] @@ -218,7 +218,7 @@ function Set-PesterGitHubOutput { $intermediateNameElements = $skippedTest.Path $intermediateNameElements[-1] = '**{0}**' -f $skippedTest.ExpandedName - $testName = (($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|').Trim() + $testName = ((($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|') -replace '_', '\_').Trim() $reason = ('Test {0}' -f $skippedTest.ErrorRecord.Exception.Message -replace '\|', '\|').Trim() @@ -265,7 +265,7 @@ function Set-PesterGitHubOutput { foreach ($warning in $test.StandardOutput.Warning) { $intermediateNameElements = $test.Path $intermediateNameElements[-1] = '**{0}**' -f $test.ExpandedName - $testName = (($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|').Trim() + $testName = ((($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|') -replace '_', '\_').Trim() $testLine = $test.ScriptBlock.StartPosition.StartLine $testFile = (($test.ScriptBlock.File -split '[\/|\\](avm[\/|\\])')[-2, -1] -join '') -replace '\\', '/' # e.g., [avm\res\cognitive-services\account\tests\unit\custom.tests.ps1] From c025f526216b35a93c6ffee5dfe4beb3dc29cada Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Thu, 9 Nov 2023 07:32:30 +0100 Subject: [PATCH 19/55] Update avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- .../pipelines/staticValidation/compliance/module.tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index b7c9ab905f..cdd40eb5ed 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -1131,7 +1131,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { } } - It "[] [] Bicep test deployment files in a [waf-aligned] folder should have a [serviceShort] parameter with a value ending with [max]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]max[\\|\/].*' }) { + It "[] [] Bicep test deployment files in a [max] folder should have a [serviceShort] parameter with a value ending with [max]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]max[\\|\/].*' }) { param( [object[]] $testFileContent From 405901aff9656cb669db03eb90cfb96f2fa13908 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Thu, 9 Nov 2023 07:33:08 +0100 Subject: [PATCH 20/55] Update avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- .../pipelines/staticValidation/compliance/module.tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index cdd40eb5ed..a2ac22d565 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -1118,7 +1118,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { ($testFileContent -match "^param serviceShort string = '(.*)$") | Should -Not -BeNullOrEmpty -Because 'the module test deployment file should contain a parameter [serviceShort] using the syntax [param serviceShort string = ''*''].' } - It "[] [] Bicep test deployment files in a [waf-aligned] folder should have a parameter [serviceShort] with a value ending with [min]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]defaults[\\|\/].*' }) { + It "[] [] Bicep test deployment files in a [defaults] folder should have a parameter [serviceShort] with a value ending with [min]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]defaults[\\|\/].*' }) { param( [object[]] $testFileContent From ef24d1f1e65cad599a9f8eaf311a4aa41f1452db Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Thu, 9 Nov 2023 19:29:56 +0100 Subject: [PATCH 21/55] Rollback of unrelated changes --- .../compliance/Set-PesterGitHubOutput.ps1 | 71 +---- .../compliance/module.tests.ps1 | 291 +++--------------- 2 files changed, 45 insertions(+), 317 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 index d23f8d4f8f..66561b92fe 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 @@ -81,12 +81,10 @@ function Set-PesterGitHubOutput { $passedTests = $PesterTestResults.Passed $failedTests = $PesterTestResults.Failed $skippedTests = $PesterTestResults.Skipped - $testsWithWarnings = ($passedTests + $failedTests + $skippedTests) | Where-Object { $_.StandardOutput.Keys -eq 'Warning' } Write-Verbose ('Formatting [{0}] passed tests' -f $passedTests.Count) Write-Verbose ('Formatting [{0}] failed tests' -f $failedTests.Count) Write-Verbose ('Formatting [{0}] skipped tests' -f $skippedTests.Count) - Write-Verbose ('Formatting [{0}] tests with explicit warnings' -f $warnings.Count) ###################### # Set output content # @@ -100,9 +98,9 @@ function Set-PesterGitHubOutput { ## Header table $fileContent += [System.Collections.ArrayList]@( - '| Total No. of Processed Tests| Passed Tests :white_check_mark: | Failed Tests :x: | Skipped Tests :paperclip: | Tests with warnings :warning: |', - '| :-- | :-- | :-- | :-- | :-- |', - ('| {0} | {1} | {2} | {3} | {4} |' -f $PesterTestResults.TotalCount, $passedTests.count , $failedTests.count, $skippedTests.count, $testsWithWarnings.count), + '| Total No. of Processed Tests| Passed Tests :white_check_mark: | Failed Tests :x: | Skipped Tests :paperclip: |', + '| :-- | :-- | :-- | :-- |' + ('| {0} | {1} | {2} | {3} |' -f $PesterTestResults.TotalCount, $passedTests.count , $failedTests.count, $skippedTests.count), '' ) @@ -127,11 +125,11 @@ function Set-PesterGitHubOutput { $intermediateNameElements = $failedTest.Path $intermediateNameElements[-1] = '**{0}**' -f $failedTest.ExpandedName - $testName = ((($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|') -replace '_', '\_').Trim() + $testName = (($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|').Trim() $errorTestLine = $failedTest.ErrorRecord.TargetObject.Line $errorTestFile = (($failedTest.ErrorRecord.TargetObject.File -split '[\/|\\](avm[\/|\\])')[-2, -1] -join '') -replace '\\', '/' # e.g., [avm\res\cognitive-services\account\tests\unit\custom.tests.ps1] - $errorMessage = ($failedTest.ErrorRecord.TargetObject.Message.Trim() -replace '_', '\_') -replace '\n', '
' # Replace new lines with
to enable line breaks in markdown + $errorMessage = $failedTest.ErrorRecord.TargetObject.Message.Trim() -replace '\n', '
' # Replace new lines with
to enable line breaks in markdown $testReference = '{0}:{1}' -f (Split-Path $errorTestFile -Leaf), $errorTestLine @@ -173,7 +171,7 @@ function Set-PesterGitHubOutput { $intermediateNameElements = $passedTest.Path $intermediateNameElements[-1] = '**{0}**' -f $passedTest.ExpandedName - $testName = ((($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|') -replace '_', '\_').Trim() + $testName = (($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|').Trim() $testLine = $passedTest.ScriptBlock.StartPosition.StartLine $testFile = (($passedTest.ScriptBlock.File -split '[\/|\\](avm[\/|\\])')[-2, -1] -join '') -replace '\\', '/' # e.g., [avm\res\cognitive-services\account\tests\unit\custom.tests.ps1] @@ -218,12 +216,12 @@ function Set-PesterGitHubOutput { $intermediateNameElements = $skippedTest.Path $intermediateNameElements[-1] = '**{0}**' -f $skippedTest.ExpandedName - $testName = ((($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|') -replace '_', '\_').Trim() + $testName = (($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|').Trim() $reason = ('Test {0}' -f $skippedTest.ErrorRecord.Exception.Message -replace '\|', '\|').Trim() - $testLine = $skippedTest.ScriptBlock.StartPosition.StartLine - $testFile = (($skippedTest.ScriptBlock.File -split '[\/|\\](avm[\/|\\])')[-2, -1] -join '') -replace '\\', '/' # e.g., [avm\res\cognitive-services\account\tests\unit\custom.tests.ps1] + $testLine = $passedTest.ScriptBlock.StartPosition.StartLine + $testFile = (($passedTest.ScriptBlock.File -split '[\/|\\](avm[\/|\\])')[-2, -1] -join '') -replace '\\', '/' # e.g., [avm\res\cognitive-services\account\tests\unit\custom.tests.ps1] $testReference = '{0}:{1}' -f (Split-Path $testFile -Leaf), $testLine if (-not [String]::IsNullOrEmpty($GitHubRepository) -and -not [String]::IsNullOrEmpty($BranchName)) { @@ -243,57 +241,8 @@ function Set-PesterGitHubOutput { '' ) - ################## - ## Warnings ## - ################## - - Write-Verbose 'Adding warnings' - $fileContent += [System.Collections.ArrayList]@( - '', - '
', - 'List of explicit warnings', - '' - ) - - if ($testsWithWarnings.Count -gt 0) { - - $fileContent += [System.Collections.ArrayList]@( - '| Name | Warning | Source |', - '| :-- | :-- | :-- |' - ) - foreach ($test in ($testsWithWarnings | Sort-Object -Property { $PSItem.ExpandedName }) ) { - foreach ($warning in $test.StandardOutput.Warning) { - $intermediateNameElements = $test.Path - $intermediateNameElements[-1] = '**{0}**' -f $test.ExpandedName - $testName = ((($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|') -replace '_', '\_').Trim() - - $testLine = $test.ScriptBlock.StartPosition.StartLine - $testFile = (($test.ScriptBlock.File -split '[\/|\\](avm[\/|\\])')[-2, -1] -join '') -replace '\\', '/' # e.g., [avm\res\cognitive-services\account\tests\unit\custom.tests.ps1] - - $testReference = '{0}:{1}' -f (Split-Path $testFile -Leaf), $testLine - if (-not [String]::IsNullOrEmpty($GitHubRepository) -and -not [String]::IsNullOrEmpty($BranchName)) { - # Creating URL to test file to enable users to 'click' on it - $testReference = "[$testReference](https://github.com/$GitHubRepository/blob/$BranchName/$testFile#L$testLine)" - } - - $fileContent += ('| {0} | {1} | {2} |' -f $testName, $warning, $testReference) - } - } - } else { - $fileContent += ('No tests with warnings.') - } - - $fileContent += [System.Collections.ArrayList]@( - '', - '
', - '' - ) - - - - if ($PSCmdlet.ShouldProcess("Test results file in path [$OutputFilePath]", 'Create')) { $null = New-Item -Path $OutputFilePath -Force -Value ($fileContent | Out-String) } Write-Verbose "Create results file [$outputFilePath]" -} +} \ No newline at end of file diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index a2ac22d565..d975dea940 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -3,7 +3,7 @@ param ( [Parameter(Mandatory = $false)] [array] $moduleFolderPaths = ((Get-ChildItem $repoRootPath -Recurse -Directory -Force).FullName | Where-Object { - (Get-ChildItem $_ -File -Depth 0 -Include @('main.bicep') -Force).Count -gt 0 + (Get-ChildItem $_ -File -Depth 0 -Include @('main.json', 'main.bicep') -Force).Count -gt 0 }), [Parameter(Mandatory = $false)] @@ -27,6 +27,7 @@ $script:convertedTemplates = @{} # Shared exception messages $script:bicepTemplateCompilationFailedException = "Unable to compile the main.bicep template's content. This can happen if there is an error in the template. Please check if you can run the command ``bicep build {0} --stdout | ConvertFrom-Json -AsHashtable``." # -f $templateFilePath +$script:jsonTemplateLoadFailedException = "Unable to load the main.json template's content. This can happen if there is an error in the template. Please check if you can run the command `Get-Content {0} -Raw | ConvertFrom-Json -AsHashtable`." # -f $templateFilePath $script:templateNotFoundException = 'No template file found in folder [{0}]' # -f $moduleFolderPath # Import any helper function used in this test script @@ -202,6 +203,13 @@ Describe 'Module tests' -Tag 'Module' { if (-not $templateContent) { throw ($bicepTemplateCompilationFailedException -f $templateFilePath) } + } elseIf (Test-Path (Join-Path $moduleFolderPath 'main.json')) { + $templateFilePath = Join-Path $moduleFolderPath 'main.json' + $templateContent = Get-Content $templateFilePath -Raw | ConvertFrom-Json -AsHashtable + + if (-not $templateContent) { + throw ($jsonTemplateLoadFailedException -f $templateFilePath) + } } else { throw ($templateNotFoundException -f $moduleFolderPath) } @@ -331,6 +339,13 @@ Describe 'Module tests' -Tag 'Module' { if (-not $templateContent) { throw ($bicepTemplateCompilationFailedException -f $templateFilePath) } + } elseIf (Test-Path (Join-Path $moduleFolderPath 'main.json')) { + $templateFilePath = Join-Path $moduleFolderPath 'main.json' + $templateContent = Get-Content $templateFilePath -Raw | ConvertFrom-Json -AsHashtable + + if (-not $templateContent) { + throw ($jsonTemplateLoadFailedException -f $templateFilePath) + } } else { throw ($templateNotFoundException -f $moduleFolderPath) } @@ -820,6 +835,7 @@ Describe 'Module tests' -Tag 'Module' { $incorrectOutputs | Should -BeNullOrEmpty } + # Update to work with nullable parameters It '[] All non-required parameters in template file should not have description that start with "Required.".' -TestCases $deploymentFolderTestCases { param ( [hashtable[]] $testFileTestCases, @@ -858,6 +874,13 @@ Describe 'Module tests' -Tag 'Module' { if (-not $templateContent) { throw ($bicepTemplateCompilationFailedException -f $templateFilePath) } + } elseIf (Test-Path (Join-Path $moduleFolderPath 'main.json')) { + $templateFilePath = Join-Path $moduleFolderPath 'main.json' + $templateContent = Get-Content $templateFilePath -Raw | ConvertFrom-Json -AsHashtable + + if (-not $templateContent) { + throw ($jsonTemplateLoadFailedException -f $templateFilePath) + } } else { throw ($templateNotFoundException -f $moduleFolderPath) } @@ -907,184 +930,6 @@ Describe 'Module tests' -Tag 'Module' { $templateFileContent.metadata.owner | Should -Not -BeNullOrEmpty } } - - Context 'User-defined-types tests' -Tag 'UDT' { - - $udtTestCases = [System.Collections.ArrayList] @() # General UDT tests (e.g. param should exist) - $udtSpecificTestCases = [System.Collections.ArrayList] @() # Specific UDT test cases for singular UDTs (e.g. tags) - foreach ($moduleFolderPath in $moduleFolderPaths) { - - $resourceTypeIdentifier = ($moduleFolderPath -split '[\/|\\]{1}avm[\/|\\]{1}(res|ptn)[\/|\\]{1}')[2] -replace '\\', '/' # avm/res// - - # For runtime purposes, we cache the compiled template in a hashtable that uses a formatted relative module path as a key - $moduleFolderPathKey = $moduleFolderPath.Replace('\', '/').Split('/avm/')[1].Trim('/').Replace('/', '-') - if (-not ($convertedTemplates.Keys -contains $moduleFolderPathKey)) { - if (Test-Path (Join-Path $moduleFolderPath 'main.bicep')) { - $templateFilePath = Join-Path $moduleFolderPath 'main.bicep' - $templateContent = bicep build $templateFilePath --stdout | ConvertFrom-Json -AsHashtable - - if (-not $templateContent) { - throw ($bicepTemplateCompilationFailedException -f $templateFilePath) - } - } else { - throw ($templateNotFoundException -f $moduleFolderPath) - } - $convertedTemplates[$moduleFolderPathKey] = @{ - templateContent = $templateContent - templateFilePath = $templateFilePath - } - } else { - $templateContent = $convertedTemplates[$moduleFolderPathKey].templateContent - $templateFilePath = $convertedTemplates[$moduleFolderPathKey].templateFilePath - } - - $udtSpecificTestCases += @{ - moduleFolderName = $resourceTypeIdentifier - templateFileContent = $templateContent - templateFileContentBicep = Get-Content $templateFilePath - } - - # Setting expected URL only for those that doen't have multiple different variants - $avmInterfaceSpecsTemplateBase = 'https://raw.githubusercontent.com/Azure/Azure-Verified-Modules/main/docs/static/includes/interfaces' - $avmInterfaceSpecsBase = 'https://azure.github.io/Azure-Verified-Modules/specs/shared/interfaces' - $udtCases = @( - @{ - parameterName = 'diagnosticSettings' - udtName = 'diagnosticSettingType' - link = "$avmInterfaceSpecsBase#diagnostic-settings" - } - @{ - parameterName = 'roleAssignments' - udtName = 'roleAssignmentType' - udtExpectedUrl = "$avmInterfaceSpecsTemplateBase/int.rbac.udt.schema.bicep" - link = "$avmInterfaceSpecsBase#role-assignments" - } - @{ - parameterName = 'lock' - udtName = 'lockType' - udtExpectedUrl = "$avmInterfaceSpecsTemplateBase/int.locks.udt.schema.bicep" - link = "$avmInterfaceSpecsBase#resource-locks" - } - @{ - parameterName = 'managedIdentities' - udtName = 'managedIdentitiesType' - link = "$avmInterfaceSpecsBase#managed-identities" - } - @{ - parameterName = 'privateEndpoints' - udtName = 'privateEndpointType' - link = "$avmInterfaceSpecsBase#private-endpoints" - } - @{ - parameterName = 'customerManagedKey' - udtName = 'customerManagedKeyType' - link = "$avmInterfaceSpecsBase#customer-managed-keys" - } - ) - - foreach ($udtCase in $udtCases) { - $udtTestCases += @{ - moduleFolderName = $resourceTypeIdentifier - templateFileContent = $templateContent - templateFileContentBicep = Get-Content $templateFilePath - parameterName = $udtCase.parameterName - udtName = $udtCase.udtName - expectedUdtUrl = $udtCase.udtExpectedUrl ? $udtCase.udtExpectedUrl : '' - link = $udtCase.link - } - } - } - - - It "[] If template has a parameter [], it should implement the user-defined type []" -TestCases $udtTestCases { - - param( - [hashtable] $templateFileContent, - [string[]] $templateFileContentBicep, - [string] $parameterName, - [string] $udtName, - [string] $expectedUdtUrl, - [string] $link - ) - - if ($templateFileContent.parameters.Keys -contains $parameterName) { - $templateFileContent.parameters.$parameterName.Keys | Should -Contain '$ref' -Because "the [$parameterName] parameter should use a user-defined type. For for information please review the [AVM Specs]($link)." - $templateFileContent.parameters.$parameterName.'$ref' | Should -Be "#/definitions/$udtName" -Because "the [$parameterName] parameter should use a user-defined type [$udtName]. For for information please review the [AVM Specs]($link)." - - if (-not [String]::IsNullOrEmpty($expectedUdtUrl)) { - $implementedSchemaStartIndex = $templateFileContentBicep.IndexOf("type $udtName = {") - $implementedSchemaEndIndex = $implementedSchemaStartIndex + 1 - while ($templateFileContentBicep[$implementedSchemaEndIndex] -notmatch '^\}.*' -and $implementedSchemaEndIndex -lt $templateFileContentBicep.Length) { - $implementedSchemaEndIndex++ - } - if ($implementedSchemaEndIndex -eq $templateFileContentBicep.Length) { - throw "Failed to identify [$udtName] user-defined type in template." - } - $implementedSchema = $templateFileContentBicep[$implementedSchemaStartIndex..$implementedSchemaEndIndex] - - $expectedSchemaFull = (Invoke-WebRequest -Uri $expectedUdtUrl).Content -split "\n" - $expectedSchemaStartIndex = $expectedSchemaFull.IndexOf("type $udtName = {") - $expectedSchemaEndIndex = $expectedSchemaStartIndex + 1 - while ($expectedSchemaFull[$expectedSchemaEndIndex] -notmatch '^\}.*' -and $expectedSchemaEndIndex -lt $expectedSchemaFull.Length) { - $expectedSchemaEndIndex++ - } - if ($expectedSchemaEndIndex -eq $expectedSchemaFull.Length) { - throw "Failed to identify [$udtName] user-defined type in expected schema at URL [$expectedUdtUrl]." - } - $expectedSchema = $expectedSchemaFull[$expectedSchemaStartIndex..$expectedSchemaEndIndex] - - $formattedDiff = @() - foreach ($finding in (Compare-Object $implementedSchema $expectedSchema)) { - if ($finding.SideIndicator -eq '=>') { - $formattedDiff += ('+ {0}' -f $finding.InputObject) - } elseif ($finding.SideIndicator -eq '<=') { - $formattedDiff += ('- {0}' -f $finding.InputObject) - } - } - - if ($formattedDiff.Count -gt 0) { - $warningMessage = "The implemented user-defined type is not the same as the expected user-defined type ({0}) defined in the AVM specs ({1}) and should not have diff`n{2}" -f $expectedUdtUrl, $link, ($formattedDiff | Out-String) - Write-Warning $warningMessage - - # Adding also to output to show in GitHub CI - $mdFormattedDiff = ($formattedDiff -join '
') -replace '\|', '\|' - $mdFormattedWarningMessage = "The implemented user-defined type is not the same as the expected [user-defined type]({0}) defined in the [AVM specs]({1}) and should not have diff
{2}
" -f $expectedUdtUrl, $link, $mdFormattedDiff - Write-Output @{ - Warning = $mdFormattedWarningMessage - } - } - } - } else { - Set-ItResult -Skipped -Because "the module template has no [$parameterName] parameter." - } - } - - It "[] If a UDT definition [managedIdentitiesType] exists and supports system-assigned-identities, the template should have an output for its principal ID." -TestCases $udtSpecificTestCases { - - param( - [hashtable] $templateFileContent - ) - - if ($templateFileContent.definitions.Keys -contains 'managedIdentitiesType' -and $templateFileContent.definitions.managedIdentitiesType.properties.keys -contains 'systemAssigned') { - $templateFileContent.outputs.Keys | Should -Contain 'systemAssignedMIPrincipalId' -Because 'The AVM specs require a this output. For for information please review the [AVM Specs](https://azure.github.io/Azure-Verified-Modules/specs/shared/interfaces#managed-identities).' - } else { - Set-ItResult -Skipped -Because "the module template has no [managedIdentitiesType] UDT definition or does not support system-assigned-identities." - } - } - - It "[] If a parameter [tags] exists it should be nullable." -TestCases $udtSpecificTestCases { - - param( - [hashtable] $templateFileContent - ) - - if ($templateFileContent.parameters.Keys -contains 'tags') { - $templateFileContent.parameters.tags.nullable | Should -Be $true -Because 'The AVM specs require a specific format. For for information please review the [AVM Specs](https://azure.github.io/Azure-Verified-Modules/specs/shared/interfaces#tags).' - } else { - Set-ItResult -Skipped -Because "the module template has no [tags] parameter." - } - } - } } Describe 'Test file tests' -Tag 'TestTemplate' { @@ -1101,7 +946,6 @@ Describe 'Test file tests' -Tag 'TestTemplate' { $resourceTypeIdentifier = ($moduleFolderPath -split '[\/|\\]{1}avm[\/|\\]{1}(res|ptn)[\/|\\]{1}')[2] -replace '\\', '/' # avm/res// $deploymentTestFileTestCases += @{ - testName = Split-Path (Split-Path $testFilePath) -Leaf testFilePath = $testFilePath testFileContent = $testFileContent moduleFolderName = $resourceTypeIdentifier @@ -1110,79 +954,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { } } - It "[] [] Bicep test deployment files should contain a parameter [serviceShort]" -TestCases $deploymentTestFileTestCases { - - param( - [object[]] $testFileContent - ) - ($testFileContent -match "^param serviceShort string = '(.*)$") | Should -Not -BeNullOrEmpty -Because 'the module test deployment file should contain a parameter [serviceShort] using the syntax [param serviceShort string = ''*''].' - } - - It "[] [] Bicep test deployment files in a [defaults] folder should have a parameter [serviceShort] with a value ending with [min]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]defaults[\\|\/].*' }) { - - param( - [object[]] $testFileContent - ) - - if (($testFileContent | Out-String) -match "param serviceShort string = '(.*)'") { - $Matches[1] | Should -BeLike "*min" - } else { - Set-ItResult -Skipped -Because 'the module test deployment file should contain a parameter [serviceShort] using the syntax [param serviceShort string = ''*min''] but it doesn''t.' - } - } - - It "[] [] Bicep test deployment files in a [max] folder should have a [serviceShort] parameter with a value ending with [max]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]max[\\|\/].*' }) { - - param( - [object[]] $testFileContent - ) - - if (($testFileContent | Out-String) -match "param serviceShort string = '(.*)'") { - $Matches[1] | Should -BeLike "*max" - } else { - Set-ItResult -Skipped -Because 'the module test deployment file should contain a parameter [serviceShort] using the syntax [param serviceShort string = ''*max''] but it doesn''t.' - } - } - - It "[] [] Bicep test deployment files in a [waf-aligned] folder should have a [serviceShort] parameter with a value ending with [waf]" -TestCases ($deploymentTestFileTestCases | Where-Object { $_.testFilePath -match '.*[\\|\/]waf\-aligned[\\|\/].*' }) { - - param( - [object[]] $testFileContent - ) - - if (($testFileContent | Out-String) -match "param serviceShort string = '(.*)'") { - $Matches[1] | Should -BeLike "*waf" - } else { - Set-ItResult -Skipped -Because 'the module test deployment file should contain a parameter [serviceShort] using the syntax [param serviceShort string = ''*waf''] but it doesn''t.' - } - } - - It "[] [] Bicep test deployment files should contain a metadata string [name]" -TestCases $deploymentTestFileTestCases { - - param( - [object[]] $testFileContent - ) - ($testFileContent | Out-String) | Should -Match "metadata name = .+" -Because 'Test cases should contain a metadata string [name] in the format `metadata name = ''This is one hell of a test name''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' - } - - It "[] [] Bicep test deployment files should contain a metadata string [description]" -TestCases $deploymentTestFileTestCases { - - param( - [object[]] $testFileContent - ) - ($testFileContent | Out-String) | Should -Match "metadata description = .+" -Because 'Test cases should contain a metadata string [description] in the format `metadata description = ''This is one hell of a description''` to be more descriptive. If provided, the tooling will automatically inject it into the module''s readme.md file.' - } - - It "[] [] Bicep test deployment files should contain a parameter [namePrefix] with value ['#_namePrefix_#']" -TestCases $deploymentTestFileTestCases { - - param( - [object[]] $testFileContent - ) - - ($testFileContent | Out-String) | Should -Match "param namePrefix string = '#_namePrefix_#'" -Because 'The test CI needs this value to ensure that deployed resources have unique names per fork.' - } - - It "[] [] Bicep test deployment files should invoke test like [`module testDeployment '../.*main.bicep' = {`]" -TestCases $deploymentTestFileTestCases { + It "[] Bicep test deployment files should invoke test like [`module testDeployment '../.*main.bicep' = {`]" -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent @@ -1193,7 +965,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { $testIndex -ne -1 | Should -Be $true -Because 'the module test invocation should be in the expected format to allow identification.' } - It '[] [] Bicep test deployment name should contain [`-test-`].' -TestCases $deploymentTestFileTestCases { + It '[] Bicep test deployment name should contain [`-test-`].' -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent @@ -1204,7 +976,7 @@ Describe 'Test file tests' -Tag 'TestTemplate' { $expectedNameFormat | Should -Be $true -Because 'the handle ''-test-'' should be part of the module test invocation''s resource name to allow identification.' } - It '[] [] Bicep test deployment should have parameter [`serviceShort`].' -TestCases $deploymentTestFileTestCases { + It '[] Bicep test deployment should have parameter [`serviceShort`].' -TestCases $deploymentTestFileTestCases { param( [object[]] $testFileContent @@ -1245,6 +1017,13 @@ Describe 'API version tests' -Tag 'ApiCheck' { if (-not $templateContent) { throw ($bicepTemplateCompilationFailedException -f $templateFilePath) } + } elseIf (Test-Path (Join-Path $moduleFolderPath 'main.json')) { + $templateFilePath = Join-Path $moduleFolderPath 'main.json' + $templateContent = Get-Content $templateFilePath -Raw | ConvertFrom-Json -AsHashtable + + if (-not $templateContent) { + throw ($jsonTemplateLoadFailedException -f $templateFilePath) + } } else { throw ($templateNotFoundException -f $moduleFolderPath) } @@ -1389,4 +1168,4 @@ Describe 'API version tests' -Tag 'ApiCheck' { } } } -} +} \ No newline at end of file From 31213359a56dd36e38e4afc6b6a9537f9534ee16 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Tue, 14 Nov 2023 09:43:39 +0100 Subject: [PATCH 22/55] Update to latest --- .../staticValidation/compliance/Set-PesterGitHubOutput.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 index 3563bc5f4f..38f43808ee 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/Set-PesterGitHubOutput.ps1 @@ -293,4 +293,4 @@ function Set-PesterGitHubOutput { $null = New-Item -Path $OutputFilePath -Force -Value ($fileContent | Out-String) } Write-Verbose "Create results file [$outputFilePath]" -} \ No newline at end of file +} From 3d4f5c6bef1e492cd25a6d0c334088ab8afa49b7 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Sun, 26 Nov 2023 11:18:23 +0100 Subject: [PATCH 23/55] Added pipeline to main for testing --- .../workflows/avm.platform.publish.tag.yml | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 .github/workflows/avm.platform.publish.tag.yml diff --git a/.github/workflows/avm.platform.publish.tag.yml b/.github/workflows/avm.platform.publish.tag.yml new file mode 100644 index 0000000000..e81a3c1c78 --- /dev/null +++ b/.github/workflows/avm.platform.publish.tag.yml @@ -0,0 +1,63 @@ +name: "Publish AVM module with tag" + +on: + workflow_dispatch: + inputs: + tag: + description: "The git tag of the module to publish." + required: true + type: string + +permissions: + id-token: write + contents: read + +jobs: + job_publish_module_with_tag: + runs-on: ubuntu-latest + name: "Publish module with tag" + steps: + - name: Checkout tag + uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.tag }} + + - name: Log in to Azure + uses: azure/login@v1 + with: + client-id: ${{ env.PUBLISH_CLIENT_ID }} + tenant-id: ${{ env.PUBLISH_TENANT_ID }} + subscription-id: ${{ env.PUBLISH_SUBSCRIPTION_ID }} + + # Adding a step to explicitly install the latest Bicep CLI because there is + # always a delay in updating Bicep CLI in the job runner environments. + - name: Install the latest Bicep CLI + shell: bash + run: | + curl -Lo bicep https://github.com/Azure/bicep/releases/latest/download/bicep-linux-x64 + chmod +x ./bicep + sudo mv ./bicep /usr/local/bin/bicep + bicep --version + + - name: "Publish tagged module to public bicep registry" + uses: azure/powershell@v1 + with: + azPSVersion: "latest" + inlineScript: | + # Grouping task logs + Write-Output '::group::Publish tagged module to public bicep registry' + + # Load used functions + . (Join-Path $env:GITHUB_WORKSPACE 'avm' 'utilities' 'pipelines' 'publish' 'Publish-ModuleFromTagToPBR.ps1') + + $functionInput = @{ + ModuleReleaseTagName = '${{ github.event.inputs.tag }}' + PublicRegistryServer = ConvertTo-SecureString '${{ env.PUBLISH_REGISTRY_SERVER }}' -AsPlainText -Force + } + + Write-Verbose "Invoke function with" -Verbose + Write-Verbose ($functionInput | ConvertTo-Json | Out-String) -Verbose + + Publish-ModuleFromTagToPBR @functionInput -Verbose + + Write-Output '::endgroup::' \ No newline at end of file From 917a7614c603ffd3c74e81992dabcc292aa0959a Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Mon, 4 Dec 2023 10:29:17 +0100 Subject: [PATCH 24/55] TEst disable pipe --- .github/workflows/test.workflow.yml | 51 +++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 .github/workflows/test.workflow.yml diff --git a/.github/workflows/test.workflow.yml b/.github/workflows/test.workflow.yml new file mode 100644 index 0000000000..acad22ebf7 --- /dev/null +++ b/.github/workflows/test.workflow.yml @@ -0,0 +1,51 @@ +name: 'avm.platform.toggle-avm-workflows' + +on: + workflow_dispatch: + inputs: + workMode: + type: choice + description: "Enable or disable workflows" + required: true + options: + - "enable" + - "disable" + default: "disable" + includePattern: + type: string + description: "RegEx which workflows are included" + required: false + default: "avm\\.(?:res|ptn)" + excludePattern: + type: string + description: "RegEx which workflows are excluded" + required: false + default: "^$" + +jobs: + toggle-avm-workflows: + if: github.repository != 'Azure/bicep-registry-modules' + runs-on: ubuntu-latest + steps: + - name: 'Checkout' + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - env: + GH_TOKEN: ${{ github.token }} + name: ${{ inputs.workMode }} AVM workflows + shell: pwsh + run: | + $repo = "${{ github.repository_owner }}/${{ github.event.repository.name }}" + $workflows = gh workflow list --repo $repo --all --json 'name,state,id' | ConvertFrom-Json -Depth 100 + $relevantWorkflows = $workflows | Where-Object { + $_.name -match "${{ inputs.includePattern }}" -and $_.name -notmatch "${{ inputs.excludePattern }}" + } + + foreach ($workflow in $relevantWorkflows) { + if (("${{ inputs.workMode }}" -eq "disable" -and $workflow.state -eq 'active') -or ("${{ inputs.workMode }}" -eq "enable" -and $workflow.state -ne 'active')) + { + Write-Verbose "${{ inputs.workMode }} $($workflow.name)" -Verbose + gh workflow ${{ inputs.workMode }} $workflow.id --repo $repo + } + } \ No newline at end of file From feb981ece77a7c31e5e80931a993613846bfe628 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Mon, 4 Dec 2023 10:32:18 +0100 Subject: [PATCH 25/55] Update to latest --- .../workflows/avm.platform.publish.tag.yml | 63 ------------------- .github/workflows/test.workflow.yml | 51 --------------- 2 files changed, 114 deletions(-) delete mode 100644 .github/workflows/avm.platform.publish.tag.yml delete mode 100644 .github/workflows/test.workflow.yml diff --git a/.github/workflows/avm.platform.publish.tag.yml b/.github/workflows/avm.platform.publish.tag.yml deleted file mode 100644 index e81a3c1c78..0000000000 --- a/.github/workflows/avm.platform.publish.tag.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: "Publish AVM module with tag" - -on: - workflow_dispatch: - inputs: - tag: - description: "The git tag of the module to publish." - required: true - type: string - -permissions: - id-token: write - contents: read - -jobs: - job_publish_module_with_tag: - runs-on: ubuntu-latest - name: "Publish module with tag" - steps: - - name: Checkout tag - uses: actions/checkout@v4 - with: - ref: ${{ github.event.inputs.tag }} - - - name: Log in to Azure - uses: azure/login@v1 - with: - client-id: ${{ env.PUBLISH_CLIENT_ID }} - tenant-id: ${{ env.PUBLISH_TENANT_ID }} - subscription-id: ${{ env.PUBLISH_SUBSCRIPTION_ID }} - - # Adding a step to explicitly install the latest Bicep CLI because there is - # always a delay in updating Bicep CLI in the job runner environments. - - name: Install the latest Bicep CLI - shell: bash - run: | - curl -Lo bicep https://github.com/Azure/bicep/releases/latest/download/bicep-linux-x64 - chmod +x ./bicep - sudo mv ./bicep /usr/local/bin/bicep - bicep --version - - - name: "Publish tagged module to public bicep registry" - uses: azure/powershell@v1 - with: - azPSVersion: "latest" - inlineScript: | - # Grouping task logs - Write-Output '::group::Publish tagged module to public bicep registry' - - # Load used functions - . (Join-Path $env:GITHUB_WORKSPACE 'avm' 'utilities' 'pipelines' 'publish' 'Publish-ModuleFromTagToPBR.ps1') - - $functionInput = @{ - ModuleReleaseTagName = '${{ github.event.inputs.tag }}' - PublicRegistryServer = ConvertTo-SecureString '${{ env.PUBLISH_REGISTRY_SERVER }}' -AsPlainText -Force - } - - Write-Verbose "Invoke function with" -Verbose - Write-Verbose ($functionInput | ConvertTo-Json | Out-String) -Verbose - - Publish-ModuleFromTagToPBR @functionInput -Verbose - - Write-Output '::endgroup::' \ No newline at end of file diff --git a/.github/workflows/test.workflow.yml b/.github/workflows/test.workflow.yml deleted file mode 100644 index acad22ebf7..0000000000 --- a/.github/workflows/test.workflow.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: 'avm.platform.toggle-avm-workflows' - -on: - workflow_dispatch: - inputs: - workMode: - type: choice - description: "Enable or disable workflows" - required: true - options: - - "enable" - - "disable" - default: "disable" - includePattern: - type: string - description: "RegEx which workflows are included" - required: false - default: "avm\\.(?:res|ptn)" - excludePattern: - type: string - description: "RegEx which workflows are excluded" - required: false - default: "^$" - -jobs: - toggle-avm-workflows: - if: github.repository != 'Azure/bicep-registry-modules' - runs-on: ubuntu-latest - steps: - - name: 'Checkout' - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - env: - GH_TOKEN: ${{ github.token }} - name: ${{ inputs.workMode }} AVM workflows - shell: pwsh - run: | - $repo = "${{ github.repository_owner }}/${{ github.event.repository.name }}" - $workflows = gh workflow list --repo $repo --all --json 'name,state,id' | ConvertFrom-Json -Depth 100 - $relevantWorkflows = $workflows | Where-Object { - $_.name -match "${{ inputs.includePattern }}" -and $_.name -notmatch "${{ inputs.excludePattern }}" - } - - foreach ($workflow in $relevantWorkflows) { - if (("${{ inputs.workMode }}" -eq "disable" -and $workflow.state -eq 'active') -or ("${{ inputs.workMode }}" -eq "enable" -and $workflow.state -ne 'active')) - { - Write-Verbose "${{ inputs.workMode }} $($workflow.name)" -Verbose - gh workflow ${{ inputs.workMode }} $workflow.id --repo $repo - } - } \ No newline at end of file From 45873b498ecbe741f7efd91dafab00c745669e81 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Tue, 5 Dec 2023 23:02:27 +0100 Subject: [PATCH 26/55] Enabled roles to be added to the readme --- avm/res/batch/batch-account/README.md | 17 ++++ .../sharedScripts/Set-ModuleReadMe.ps1 | 88 ++++++++++++++++++- 2 files changed, 102 insertions(+), 3 deletions(-) diff --git a/avm/res/batch/batch-account/README.md b/avm/res/batch/batch-account/README.md index f49d0517f8..8b8b125308 100644 --- a/avm/res/batch/batch-account/README.md +++ b/avm/res/batch/batch-account/README.md @@ -1106,6 +1106,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1225,6 +1236,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 index b613f8796c..6efe22c592 100644 --- a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 +++ b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 @@ -191,6 +191,65 @@ function Set-ParametersSection { return $updatedFileContent } +<# +.SYNOPSIS +Flatten the (nested) resources of a given template file content + +.DESCRIPTION +Flatten the (nested) resources of a given template file content. Keys are either the identifier in the template file or a concatenation of the parent and their child identifiers +For example: +- batchAccount_roleAssignments +- batchAccount_privateEndpoints.privateEndpoint_roleAssignments + +.PARAMETER TemplateFileContent +Optional. The template file content who's resources to extract + +.PARAMETER Identifier +Optional. A parent identifier to prepend to a resource's identifier + +.EXAMPLE +Get-FlattenedResourceList -TemplateFileContent $templateContent @{ resource = @{}; ... } + +Extract all resources from the given template file content and return them as a flat hashtable + +.NOTES +This only works if the template uses language version 2 (i.e., resources are defined in an object instead of an array) +#> +function Get-FlattenedResourceList { + + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [hashtable] $TemplateFileContent, + + [Parameter(Mandatory = $false)] + [string] $Identifier + ) + + $result = @{} + + if ($TemplateFileContent.Keys -contains 'resources') { + # Collect the immediate defined resource(s) + $TemplateFileContent.resources.Keys | ForEach-Object { + $levelIdentifier = $Identifier ? "$Identifier.$_" : $_ + $result[$levelIdentifier] = $TemplateFileContent.resources.$_ + } + + foreach ($innerKey in $TemplateFileContent['resources'].Keys) { + # Only investigate items that have an actual nested template (and are not just resource properties) + if ($TemplateFileContent['resources'][$innerKey].Keys -contains 'properties' -and $TemplateFileContent['resources'][$innerKey].properties.Keys -contains 'template') { + $template = $TemplateFileContent['resources'][$innerKey].properties.template + # But only if the nested template has resources + if ($template.resources.count -gt 0) { + $result += Get-FlattenedResourceList -TemplateFileContent $template -Identifier $innerKey + } + } + } + } + + return $result +} + <# .SYNOPSIS Update parts of the 'parameters' section of the given readme file, if user defined types are used @@ -356,7 +415,7 @@ function Set-DefinitionSection { ) } } else { - $formattedDefaultValue = $null + $formattedDefaultValue = $null # Reset value for future iterations } # Format allowed values @@ -386,7 +445,29 @@ function Set-DefinitionSection { ) } } else { - $formattedAllowedValues = $null + $formattedAllowedValues = $null # Reset value for future iterations + } + + # Special case for 'roleAssignments' parameter + if (($parameter.name -eq 'roleAssignments') -and ($TemplateFileContent.variables.keys -contains 'builtInRoleNames')) { + if ([String]::IsNullOrEmpty($ParentName)) { + # Top-level invocation + $roles = $TemplateFileContent.variables.builtInRoleNames.Keys + } else { + # Nested-invocation (requires e.g., roles for of nested private endpoint template) + $flattendResources = Get-FlattenedResourceList -TemplateFileContent $TemplateFileContent + if ($resourceIdentifier = $flattendResources.Keys | Where-Object { $_ -match '^.*_privateEndpoints$' }) { + $roles = $flattendResources[$resourceIdentifier].properties.template.variables.builtInRoleNames.Keys + } else { + Write-Warning ('Failed to identify roles for parameter [{0}] of type [{1}] as resource with identifier [{2}] was not found in the corresponding linked template.' -f $parameter.name, $ParentName, "*_$ParentName") + } + } + $formattedRoleNames = $roles.count -gt 0 ? @( + '- Roles configurable by name:', + ($roles | ForEach-Object { " - ``'$_'``" } | Out-String).TrimEnd() + ) : $null + } else { + $formattedRoleNames = $null # Reset value for future iterations } # Build list item @@ -399,7 +480,8 @@ function Set-DefinitionSection { ('- Required: {0}' -f $isRequired), ('- Type: {0}' -f $type), ((-not [String]::IsNullOrEmpty($formattedDefaultValue)) ? $formattedDefaultValue : $null), - ((-not [String]::IsNullOrEmpty($formattedAllowedValues)) ? $formattedAllowedValues : $null) + ((-not [String]::IsNullOrEmpty($formattedAllowedValues)) ? $formattedAllowedValues : $null), + ((-not [String]::IsNullOrEmpty($formattedRoleNames)) ? $formattedRoleNames : $null), '' ) | Where-Object { $null -ne $_ } From a8b8d8faee82301cc391a90779ab59b1e2f78d38 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Tue, 19 Dec 2023 21:06:28 +0100 Subject: [PATCH 27/55] Update to latest --- avm/res/key-vault/vault/README.md | 26 +++++++++++++++++++ .../key-vault/vault/access-policy/main.json | 4 +-- avm/res/key-vault/vault/key/README.md | 15 +++++++++++ avm/res/key-vault/vault/key/main.json | 4 +-- avm/res/key-vault/vault/main.json | 16 ++++++------ avm/res/key-vault/vault/secret/README.md | 15 +++++++++++ avm/res/key-vault/vault/secret/main.json | 4 +-- 7 files changed, 70 insertions(+), 14 deletions(-) diff --git a/avm/res/key-vault/vault/README.md b/avm/res/key-vault/vault/README.md index 2f66fb86bd..9e25dc0fed 100644 --- a/avm/res/key-vault/vault/README.md +++ b/avm/res/key-vault/vault/README.md @@ -1406,6 +1406,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1525,6 +1536,21 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Key Vault Administrator'` + - `'Key Vault Certificates Officer'` + - `'Key Vault Contributor'` + - `'Key Vault Crypto Officer'` + - `'Key Vault Crypto Service Encryption User'` + - `'Key Vault Crypto User'` + - `'Key Vault Reader'` + - `'Key Vault Secrets Officer'` + - `'Key Vault Secrets User'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/key-vault/vault/access-policy/main.json b/avm/res/key-vault/vault/access-policy/main.json index f2a4aa32b9..5c6bd2e050 100644 --- a/avm/res/key-vault/vault/access-policy/main.json +++ b/avm/res/key-vault/vault/access-policy/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "3185669298547069044" + "version": "0.24.24.22086", + "templateHash": "11258728276348640403" }, "name": "Key Vault Access Policies", "description": "This module deploys a Key Vault Access Policy.", diff --git a/avm/res/key-vault/vault/key/README.md b/avm/res/key-vault/vault/key/README.md index 8b0e33b1a1..e6dab4d7fc 100644 --- a/avm/res/key-vault/vault/key/README.md +++ b/avm/res/key-vault/vault/key/README.md @@ -147,6 +147,21 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Key Vault Administrator'` + - `'Key Vault Certificates Officer'` + - `'Key Vault Contributor'` + - `'Key Vault Crypto Officer'` + - `'Key Vault Crypto Service Encryption User'` + - `'Key Vault Crypto User'` + - `'Key Vault Reader'` + - `'Key Vault Secrets Officer'` + - `'Key Vault Secrets User'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/key-vault/vault/key/main.json b/avm/res/key-vault/vault/key/main.json index 9b4008e4c8..bf6158d207 100644 --- a/avm/res/key-vault/vault/key/main.json +++ b/avm/res/key-vault/vault/key/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "18051755205410983972" + "version": "0.24.24.22086", + "templateHash": "4099993970676199085" }, "name": "Key Vault Keys", "description": "This module deploys a Key Vault Key.", diff --git a/avm/res/key-vault/vault/main.json b/avm/res/key-vault/vault/main.json index c3bc831762..871faf1d0e 100644 --- a/avm/res/key-vault/vault/main.json +++ b/avm/res/key-vault/vault/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "1282169260807050154" + "version": "0.24.24.22086", + "templateHash": "508032866977705079" }, "name": "Key Vaults", "description": "This module deploys a Key Vault.", @@ -839,8 +839,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "3185669298547069044" + "version": "0.24.24.22086", + "templateHash": "11258728276348640403" }, "name": "Key Vault Access Policies", "description": "This module deploys a Key Vault Access Policy.", @@ -1105,8 +1105,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "14810918598323806738" + "version": "0.24.24.22086", + "templateHash": "16592835639027653488" }, "name": "Key Vault Secrets", "description": "This module deploys a Key Vault Secret.", @@ -1394,8 +1394,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "18051755205410983972" + "version": "0.24.24.22086", + "templateHash": "4099993970676199085" }, "name": "Key Vault Keys", "description": "This module deploys a Key Vault Key.", diff --git a/avm/res/key-vault/vault/secret/README.md b/avm/res/key-vault/vault/secret/README.md index e5feb98dec..c4a40296f6 100644 --- a/avm/res/key-vault/vault/secret/README.md +++ b/avm/res/key-vault/vault/secret/README.md @@ -98,6 +98,21 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Key Vault Administrator'` + - `'Key Vault Certificates Officer'` + - `'Key Vault Contributor'` + - `'Key Vault Crypto Officer'` + - `'Key Vault Crypto Service Encryption User'` + - `'Key Vault Crypto User'` + - `'Key Vault Reader'` + - `'Key Vault Secrets Officer'` + - `'Key Vault Secrets User'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/key-vault/vault/secret/main.json b/avm/res/key-vault/vault/secret/main.json index 2b87479bd6..2f391eda6b 100644 --- a/avm/res/key-vault/vault/secret/main.json +++ b/avm/res/key-vault/vault/secret/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "14810918598323806738" + "version": "0.24.24.22086", + "templateHash": "16592835639027653488" }, "name": "Key Vault Secrets", "description": "This module deploys a Key Vault Secret.", From 7452d0bd97606ea0ce798905a4ea9e2a46deb7e0 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Thu, 21 Dec 2023 18:05:41 +0100 Subject: [PATCH 28/55] Moved script to enable reusability --- .../Get-FlattenedResourceList.ps1 | 52 ++++++++++++++++ .../sharedScripts/Set-ModuleReadMe.ps1 | 60 +------------------ 2 files changed, 53 insertions(+), 59 deletions(-) create mode 100644 avm/utilities/pipelines/sharedScripts/Get-FlattenedResourceList.ps1 diff --git a/avm/utilities/pipelines/sharedScripts/Get-FlattenedResourceList.ps1 b/avm/utilities/pipelines/sharedScripts/Get-FlattenedResourceList.ps1 new file mode 100644 index 0000000000..2991022f06 --- /dev/null +++ b/avm/utilities/pipelines/sharedScripts/Get-FlattenedResourceList.ps1 @@ -0,0 +1,52 @@ +<# +.SYNOPSIS +Flatten the (nested) resources of a given template file content +.DESCRIPTION +Flatten the (nested) resources of a given template file content. Keys are either the identifier in the template file or a concatenation of the parent and their child identifiers +For example: +- batchAccount_roleAssignments +- batchAccount_privateEndpoints.privateEndpoint_roleAssignments +.PARAMETER TemplateFileContent +Optional. The template file content who's resources to extract +.PARAMETER Identifier +Optional. A parent identifier to prepend to a resource's identifier +.EXAMPLE +Get-FlattenedResourceList -TemplateFileContent $templateContent @{ resource = @{}; ... } +Extract all resources from the given template file content and return them as a flat hashtable +.NOTES +This only works if the template uses language version 2 (i.e., resources are defined in an object instead of an array) +#> +function Get-FlattenedResourceList { + + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [hashtable] $TemplateFileContent, + + [Parameter(Mandatory = $false)] + [string] $Identifier + ) + + $result = @{} + + if ($TemplateFileContent.Keys -contains 'resources') { + # Collect the immediate defined resource(s) + if ($TemplateFileContent.resources.count -gt 1) { + $TemplateFileContent.resources.Keys | ForEach-Object { + $levelIdentifier = $Identifier ? "$Identifier.$_" : $_ + $result[$levelIdentifier] = $TemplateFileContent.resources.$_ + } + } + + foreach ($innerKey in $TemplateFileContent['resources'].Keys) { + # Only investigate items that have an actual nested template (and are not just resource properties) + if ($TemplateFileContent['resources'][$innerKey].Keys -contains 'properties' -and $TemplateFileContent['resources'][$innerKey].properties.Keys -contains 'template') { + $template = $TemplateFileContent['resources'][$innerKey].properties.template + # But only if the nested template has resources + if ($template.resources.count -gt 0) { + $result += Get-FlattenedResourceList -TemplateFileContent $template -Identifier $innerKey + } + } + } + } +} \ No newline at end of file diff --git a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 index c9c5965885..43a0a034d7 100644 --- a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 +++ b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 @@ -191,65 +191,6 @@ function Set-ParametersSection { return $updatedFileContent } -<# -.SYNOPSIS -Flatten the (nested) resources of a given template file content - -.DESCRIPTION -Flatten the (nested) resources of a given template file content. Keys are either the identifier in the template file or a concatenation of the parent and their child identifiers -For example: -- batchAccount_roleAssignments -- batchAccount_privateEndpoints.privateEndpoint_roleAssignments - -.PARAMETER TemplateFileContent -Optional. The template file content who's resources to extract - -.PARAMETER Identifier -Optional. A parent identifier to prepend to a resource's identifier - -.EXAMPLE -Get-FlattenedResourceList -TemplateFileContent $templateContent @{ resource = @{}; ... } - -Extract all resources from the given template file content and return them as a flat hashtable - -.NOTES -This only works if the template uses language version 2 (i.e., resources are defined in an object instead of an array) -#> -function Get-FlattenedResourceList { - - [CmdletBinding()] - param ( - [Parameter(Mandatory = $true)] - [hashtable] $TemplateFileContent, - - [Parameter(Mandatory = $false)] - [string] $Identifier - ) - - $result = @{} - - if ($TemplateFileContent.Keys -contains 'resources') { - # Collect the immediate defined resource(s) - $TemplateFileContent.resources.Keys | ForEach-Object { - $levelIdentifier = $Identifier ? "$Identifier.$_" : $_ - $result[$levelIdentifier] = $TemplateFileContent.resources.$_ - } - - foreach ($innerKey in $TemplateFileContent['resources'].Keys) { - # Only investigate items that have an actual nested template (and are not just resource properties) - if ($TemplateFileContent['resources'][$innerKey].Keys -contains 'properties' -and $TemplateFileContent['resources'][$innerKey].properties.Keys -contains 'template') { - $template = $TemplateFileContent['resources'][$innerKey].properties.template - # But only if the nested template has resources - if ($template.resources.count -gt 0) { - $result += Get-FlattenedResourceList -TemplateFileContent $template -Identifier $innerKey - } - } - } - } - - return $result -} - <# .SYNOPSIS Update parts of the 'parameters' section of the given readme file, if user defined types are used @@ -1686,6 +1627,7 @@ function Set-ModuleReadMe { . (Join-Path $PSScriptRoot 'helper' 'Get-SpecsAlignedResourceName.ps1') . (Join-Path $PSScriptRoot 'helper' 'ConvertTo-OrderedHashtable.ps1') . (Join-Path $PSScriptRoot 'Get-BRMRepositoryName.ps1') + . (Join-Path $PSScriptRoot 'Get-FlattenedResourceList.ps1') # Check template & make full path $TemplateFilePath = Resolve-Path -Path $TemplateFilePath -ErrorAction Stop From bf45ea11cc010fb87a9e7d93fdd9ea30f39385c6 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Thu, 21 Dec 2023 18:10:49 +0100 Subject: [PATCH 29/55] Update to latest --- .../pipelines/sharedScripts/Get-FlattenedResourceList.ps1 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/avm/utilities/pipelines/sharedScripts/Get-FlattenedResourceList.ps1 b/avm/utilities/pipelines/sharedScripts/Get-FlattenedResourceList.ps1 index 2991022f06..bc5917a17f 100644 --- a/avm/utilities/pipelines/sharedScripts/Get-FlattenedResourceList.ps1 +++ b/avm/utilities/pipelines/sharedScripts/Get-FlattenedResourceList.ps1 @@ -1,18 +1,23 @@ <# .SYNOPSIS Flatten the (nested) resources of a given template file content + .DESCRIPTION Flatten the (nested) resources of a given template file content. Keys are either the identifier in the template file or a concatenation of the parent and their child identifiers For example: - batchAccount_roleAssignments - batchAccount_privateEndpoints.privateEndpoint_roleAssignments + .PARAMETER TemplateFileContent Optional. The template file content who's resources to extract + .PARAMETER Identifier Optional. A parent identifier to prepend to a resource's identifier + .EXAMPLE Get-FlattenedResourceList -TemplateFileContent $templateContent @{ resource = @{}; ... } Extract all resources from the given template file content and return them as a flat hashtable + .NOTES This only works if the template uses language version 2 (i.e., resources are defined in an object instead of an array) #> From cefe2669b760cdfd38548b015be68910942b2fd0 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Thu, 21 Dec 2023 18:44:42 +0100 Subject: [PATCH 30/55] Update to latest --- .../pipelines/sharedScripts/Get-FlattenedResourceList.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/avm/utilities/pipelines/sharedScripts/Get-FlattenedResourceList.ps1 b/avm/utilities/pipelines/sharedScripts/Get-FlattenedResourceList.ps1 index bc5917a17f..d240e4bfcb 100644 --- a/avm/utilities/pipelines/sharedScripts/Get-FlattenedResourceList.ps1 +++ b/avm/utilities/pipelines/sharedScripts/Get-FlattenedResourceList.ps1 @@ -54,4 +54,6 @@ function Get-FlattenedResourceList { } } } + + return $result } \ No newline at end of file From 393a03cd9251437105722da78d6d03f3987e7566 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Thu, 21 Dec 2023 20:15:13 +0100 Subject: [PATCH 31/55] Enabled language version 1 & 2 --- .../Get-FlattenedResourceList.ps1 | 89 ++++++++++++++----- 1 file changed, 68 insertions(+), 21 deletions(-) diff --git a/avm/utilities/pipelines/sharedScripts/Get-FlattenedResourceList.ps1 b/avm/utilities/pipelines/sharedScripts/Get-FlattenedResourceList.ps1 index d240e4bfcb..47f0243a86 100644 --- a/avm/utilities/pipelines/sharedScripts/Get-FlattenedResourceList.ps1 +++ b/avm/utilities/pipelines/sharedScripts/Get-FlattenedResourceList.ps1 @@ -3,10 +3,14 @@ Flatten the (nested) resources of a given template file content .DESCRIPTION -Flatten the (nested) resources of a given template file content. Keys are either the identifier in the template file or a concatenation of the parent and their child identifiers +Flatten the (nested) resources of a given template file content. Keys are either the identifier in the template file, a concatenation of the parent and their child identifiers, or the identifier with a numbered suffix in case a nested template uses a different language version For example: - batchAccount_roleAssignments - batchAccount_privateEndpoints.privateEndpoint_roleAssignments +- batchAccount_roleAssignments_0 + +This is a relevant differentiation as the language version changes based on whether newer features like user-defined types are implemented in the template. +As a consequence, the resources in the template are either defined in an array (language version 1) or an object (language version 2). This function supports both. .PARAMETER TemplateFileContent Optional. The template file content who's resources to extract @@ -16,10 +20,8 @@ Optional. A parent identifier to prepend to a resource's identifier .EXAMPLE Get-FlattenedResourceList -TemplateFileContent $templateContent @{ resource = @{}; ... } -Extract all resources from the given template file content and return them as a flat hashtable -.NOTES -This only works if the template uses language version 2 (i.e., resources are defined in an object instead of an array) +Extract all resources from the given template file content and return them as a flat hashtable #> function Get-FlattenedResourceList { @@ -32,28 +34,73 @@ function Get-FlattenedResourceList { [string] $Identifier ) - $result = @{} - if ($TemplateFileContent.Keys -contains 'resources') { - # Collect the immediate defined resource(s) - if ($TemplateFileContent.resources.count -gt 1) { - $TemplateFileContent.resources.Keys | ForEach-Object { - $levelIdentifier = $Identifier ? "$Identifier.$_" : $_ - $result[$levelIdentifier] = $TemplateFileContent.resources.$_ + if ($TemplateFileContent.resources -is [array]) { + # Language version 1 + $result = @() + foreach ($resource in $TemplateFileContent.resources) { + + if ($resource.existing) { + continue + } + + $result += $resource + + if ($resource.Keys -contains 'properties' -and $resource.properties.Keys -contains 'template') { + $template = $resource.properties.template + if ($template.resources.count -gt 0) { + $innerReturn = Get-FlattenedResourceList -TemplateFileContent $template + if ($innerReturn) { + if ($innerReturn -is [array] -or $innerReturn.Keys -contains 'apiVersion') { + # child uses language version 1 + $result += $innerReturn + } else { + # child uses language version 2 + $result += $innerReturn.values + } + } + } + } } - } + } else { + # Language version 2 + $result = @{} + if ($TemplateFileContent.resources.values.count -gt 1) { + # if it's 1 then we're looking at a single resource that was already added + $counter = 0 # Counter used for nested Language Version 1 resources that don't have an resource identifier + foreach ($innerKey in $TemplateFileContent.resources.Keys) { - foreach ($innerKey in $TemplateFileContent['resources'].Keys) { - # Only investigate items that have an actual nested template (and are not just resource properties) - if ($TemplateFileContent['resources'][$innerKey].Keys -contains 'properties' -and $TemplateFileContent['resources'][$innerKey].properties.Keys -contains 'template') { - $template = $TemplateFileContent['resources'][$innerKey].properties.template - # But only if the nested template has resources - if ($template.resources.count -gt 0) { - $result += Get-FlattenedResourceList -TemplateFileContent $template -Identifier $innerKey + $resource = $TemplateFileContent.resources.$innerKey + if ($resource.existing) { + continue + } + + # Collect the immediate defined resource(s) + $levelIdentifier = $Identifier ? "$Identifier.$innerKey" : $innerKey + $result[$levelIdentifier] = $resource + + # Only investigate items that have an actual nested template (and are not just resource properties) + if ($resource.Keys -contains 'properties' -and $resource.properties.Keys -contains 'template') { + $template = $resource.properties.template + # But only if the nested template has resources + if ($template.resources.count -gt 0) { + $innerReturn = Get-FlattenedResourceList -TemplateFileContent $template -Identifier $innerKey + if ($innerReturn) { + if ($innerReturn.Keys -contains 'apiVersion') { + # child uses language version 1 + $innerLevelIdentifier = '{0}_{1}' -f $levelIdentifier, $counter + $result[$innerLevelIdentifier] = $innerReturn + $counter++ + } else { + # child uses language version 2 + $result += $innerReturn + } + } + } + } } } } } - return $result -} \ No newline at end of file +} From 28934cde1cac651195c6048025b57dac60fbb115 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Thu, 21 Dec 2023 22:01:16 +0100 Subject: [PATCH 32/55] Update to latest --- .../sharedScripts/Get-NestedResourceList.ps1 | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/avm/utilities/pipelines/sharedScripts/Get-NestedResourceList.ps1 b/avm/utilities/pipelines/sharedScripts/Get-NestedResourceList.ps1 index 917a467990..df38f9eb2f 100644 --- a/avm/utilities/pipelines/sharedScripts/Get-NestedResourceList.ps1 +++ b/avm/utilities/pipelines/sharedScripts/Get-NestedResourceList.ps1 @@ -29,23 +29,30 @@ function Get-NestedResourceList { if ($TemplateFileContent.resources -is [System.Collections.Hashtable]) { # With the introduction of user defined types, a compiled template's resources are not part of an ordered hashtable instead of an array. $currLevelResources += $TemplateFileContent.resources.Keys | ForEach-Object { - $TemplateFileContent.resources[$_] + $elem = $TemplateFileContent.resources[$_] + $elem['identifier'] = $_ + $elem } | Where-Object { $_.existing -ne $true } - } - else { + } else { # Default array - $currLevelResources += $TemplateFileContent.resources + $currLevelResources += $TemplateFileContent.resources | ForEach-Object { + $_['identifier'] = $_.name + $_ + } | Where-Object { + $_.existing -ne $true + } } } foreach ($resource in $currLevelResources) { $res += $resource if ($resource.type -eq 'Microsoft.Resources/deployments') { - $res += Get-NestedResourceList -TemplateFileContent $resource.properties.template - } - else { + if ($resource.properties.template -is [System.Collections.Hashtable]) { + $res += Get-NestedResourceList -TemplateFileContent $resource.properties.template + } + } else { $res += Get-NestedResourceList -TemplateFileContent $resource } } From afbacbaa50702389bcb0834e95cda5ee43f9ac92 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Thu, 21 Dec 2023 22:13:55 +0100 Subject: [PATCH 33/55] Update to latest --- .../Get-FlattenedResourceList.ps1 | 106 ------------------ .../sharedScripts/Set-ModuleReadMe.ps1 | 9 +- 2 files changed, 5 insertions(+), 110 deletions(-) delete mode 100644 avm/utilities/pipelines/sharedScripts/Get-FlattenedResourceList.ps1 diff --git a/avm/utilities/pipelines/sharedScripts/Get-FlattenedResourceList.ps1 b/avm/utilities/pipelines/sharedScripts/Get-FlattenedResourceList.ps1 deleted file mode 100644 index 47f0243a86..0000000000 --- a/avm/utilities/pipelines/sharedScripts/Get-FlattenedResourceList.ps1 +++ /dev/null @@ -1,106 +0,0 @@ -<# -.SYNOPSIS -Flatten the (nested) resources of a given template file content - -.DESCRIPTION -Flatten the (nested) resources of a given template file content. Keys are either the identifier in the template file, a concatenation of the parent and their child identifiers, or the identifier with a numbered suffix in case a nested template uses a different language version -For example: -- batchAccount_roleAssignments -- batchAccount_privateEndpoints.privateEndpoint_roleAssignments -- batchAccount_roleAssignments_0 - -This is a relevant differentiation as the language version changes based on whether newer features like user-defined types are implemented in the template. -As a consequence, the resources in the template are either defined in an array (language version 1) or an object (language version 2). This function supports both. - -.PARAMETER TemplateFileContent -Optional. The template file content who's resources to extract - -.PARAMETER Identifier -Optional. A parent identifier to prepend to a resource's identifier - -.EXAMPLE -Get-FlattenedResourceList -TemplateFileContent $templateContent @{ resource = @{}; ... } - -Extract all resources from the given template file content and return them as a flat hashtable -#> -function Get-FlattenedResourceList { - - [CmdletBinding()] - param ( - [Parameter(Mandatory = $true)] - [hashtable] $TemplateFileContent, - - [Parameter(Mandatory = $false)] - [string] $Identifier - ) - - if ($TemplateFileContent.Keys -contains 'resources') { - if ($TemplateFileContent.resources -is [array]) { - # Language version 1 - $result = @() - foreach ($resource in $TemplateFileContent.resources) { - - if ($resource.existing) { - continue - } - - $result += $resource - - if ($resource.Keys -contains 'properties' -and $resource.properties.Keys -contains 'template') { - $template = $resource.properties.template - if ($template.resources.count -gt 0) { - $innerReturn = Get-FlattenedResourceList -TemplateFileContent $template - if ($innerReturn) { - if ($innerReturn -is [array] -or $innerReturn.Keys -contains 'apiVersion') { - # child uses language version 1 - $result += $innerReturn - } else { - # child uses language version 2 - $result += $innerReturn.values - } - } - } - } - } - } else { - # Language version 2 - $result = @{} - if ($TemplateFileContent.resources.values.count -gt 1) { - # if it's 1 then we're looking at a single resource that was already added - $counter = 0 # Counter used for nested Language Version 1 resources that don't have an resource identifier - foreach ($innerKey in $TemplateFileContent.resources.Keys) { - - $resource = $TemplateFileContent.resources.$innerKey - if ($resource.existing) { - continue - } - - # Collect the immediate defined resource(s) - $levelIdentifier = $Identifier ? "$Identifier.$innerKey" : $innerKey - $result[$levelIdentifier] = $resource - - # Only investigate items that have an actual nested template (and are not just resource properties) - if ($resource.Keys -contains 'properties' -and $resource.properties.Keys -contains 'template') { - $template = $resource.properties.template - # But only if the nested template has resources - if ($template.resources.count -gt 0) { - $innerReturn = Get-FlattenedResourceList -TemplateFileContent $template -Identifier $innerKey - if ($innerReturn) { - if ($innerReturn.Keys -contains 'apiVersion') { - # child uses language version 1 - $innerLevelIdentifier = '{0}_{1}' -f $levelIdentifier, $counter - $result[$innerLevelIdentifier] = $innerReturn - $counter++ - } else { - # child uses language version 2 - $result += $innerReturn - } - } - } - } - } - } - } - } - return $result -} diff --git a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 index 43a0a034d7..17e34f1731 100644 --- a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 +++ b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 @@ -396,9 +396,11 @@ function Set-DefinitionSection { $roles = $TemplateFileContent.variables.builtInRoleNames.Keys } else { # Nested-invocation (requires e.g., roles for of nested private endpoint template) - $flattendResources = Get-FlattenedResourceList -TemplateFileContent $TemplateFileContent - if ($resourceIdentifier = $flattendResources.Keys | Where-Object { $_ -match '^.*_privateEndpoints$' }) { - $roles = $flattendResources[$resourceIdentifier].properties.template.variables.builtInRoleNames.Keys + $flattendResources = Get-NestedResourceList -TemplateFileContent $TemplateFileContent + if ($resourceIdentifier = $flattendResources.identifier | Where-Object { $_ -match "^.*_$ParentName`$" }) { + $roles = ($flattendResources | Where-Object { + $_.identifier -eq $resourceIdentifier + }).properties.template.variables.builtInRoleNames.Keys } else { Write-Warning ('Failed to identify roles for parameter [{0}] of type [{1}] as resource with identifier [{2}] was not found in the corresponding linked template.' -f $parameter.name, $ParentName, "*_$ParentName") } @@ -1627,7 +1629,6 @@ function Set-ModuleReadMe { . (Join-Path $PSScriptRoot 'helper' 'Get-SpecsAlignedResourceName.ps1') . (Join-Path $PSScriptRoot 'helper' 'ConvertTo-OrderedHashtable.ps1') . (Join-Path $PSScriptRoot 'Get-BRMRepositoryName.ps1') - . (Join-Path $PSScriptRoot 'Get-FlattenedResourceList.ps1') # Check template & make full path $TemplateFilePath = Resolve-Path -Path $TemplateFilePath -ErrorAction Stop From f4136ecc4bc806790f908046979c3045f3cb0e5e Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Fri, 22 Dec 2023 10:47:59 +0100 Subject: [PATCH 34/55] Added SA workflow --- .../avm.res.storage.storage-account.yml | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 .github/workflows/avm.res.storage.storage-account.yml diff --git a/.github/workflows/avm.res.storage.storage-account.yml b/.github/workflows/avm.res.storage.storage-account.yml new file mode 100644 index 0000000000..061ef0be68 --- /dev/null +++ b/.github/workflows/avm.res.storage.storage-account.yml @@ -0,0 +1,83 @@ +name: "avm.res.storage.storage-account" + +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 + + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.res.storage.storage-account.yml" + - "avm/res/storage/storage-account/**" + - "avm/utilities/pipelines/**" + - "!*/**/README.md" + +env: + modulePath: "avm/res/storage/storage-account" + workflowPath: ".github/workflows/avm.res.storage.storage-account.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-20.04 + 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" + 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 From e55e73257d0fcf23b3c8bae557fbcf54e5ac5ea0 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Mon, 1 Jan 2024 19:15:54 +0100 Subject: [PATCH 35/55] Added workflow --- ....virtual-machine-images.image-template.yml | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 .github/workflows/avm.res.virtual-machine-images.image-template.yml diff --git a/.github/workflows/avm.res.virtual-machine-images.image-template.yml b/.github/workflows/avm.res.virtual-machine-images.image-template.yml new file mode 100644 index 0000000000..08c03c7560 --- /dev/null +++ b/.github/workflows/avm.res.virtual-machine-images.image-template.yml @@ -0,0 +1,83 @@ +name: "avm.res.resource-graph.query" + +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 + + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.res.virtual-machine-images.image-template.yml" + - "avm/res/virtual-machine-images/image-template/**" + - "avm/utilities/pipelines/**" + - "!*/**/README.md" + +env: + modulePath: "avm/res/virtual-machine-images/image-template" + workflowPath: ".github/workflows/avm.res.virtual-machine-images.image-template.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-20.04 + 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" + 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 From 5c6aa5e64d2e7f6ac3c9a7e1522ac8590b019f30 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Mon, 1 Jan 2024 19:16:30 +0100 Subject: [PATCH 36/55] Update to latest --- .../workflows/avm.res.virtual-machine-images.image-template.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/avm.res.virtual-machine-images.image-template.yml b/.github/workflows/avm.res.virtual-machine-images.image-template.yml index 08c03c7560..37bb62af5e 100644 --- a/.github/workflows/avm.res.virtual-machine-images.image-template.yml +++ b/.github/workflows/avm.res.virtual-machine-images.image-template.yml @@ -1,4 +1,4 @@ -name: "avm.res.resource-graph.query" +name: "avm.res.virtual-machine-images.image-template" on: schedule: From 4012fdd51e0f4a7e1fd34e62abf40b97794dfd26 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Thu, 18 Jan 2024 21:16:44 +0100 Subject: [PATCH 37/55] Update to latest --- .github/workflows/avm.res.storage.storage-account.yml | 2 +- .../workflows/avm.res.virtual-machine-images.image-template.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/avm.res.storage.storage-account.yml b/.github/workflows/avm.res.storage.storage-account.yml index 061ef0be68..d6c72b0bdd 100644 --- a/.github/workflows/avm.res.storage.storage-account.yml +++ b/.github/workflows/avm.res.storage.storage-account.yml @@ -44,7 +44,7 @@ jobs: # Initialize pipeline # ########################### job_initialize_pipeline: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest name: "Initialize pipeline" steps: - name: "Checkout" diff --git a/.github/workflows/avm.res.virtual-machine-images.image-template.yml b/.github/workflows/avm.res.virtual-machine-images.image-template.yml index 37bb62af5e..63fe597668 100644 --- a/.github/workflows/avm.res.virtual-machine-images.image-template.yml +++ b/.github/workflows/avm.res.virtual-machine-images.image-template.yml @@ -44,7 +44,7 @@ jobs: # Initialize pipeline # ########################### job_initialize_pipeline: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest name: "Initialize pipeline" steps: - name: "Checkout" From 3f225f9214821b8f18271db355d6f650b26c678c Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Tue, 23 Jan 2024 19:48:09 +0100 Subject: [PATCH 38/55] Removed outdated metadata --- avm/res/compute/ssh-public-key/README.md | 2 -- .../ssh-public-key/tests/e2e/defaults/main.test.bicep | 5 +---- avm/res/key-vault/vault/README.md | 2 -- avm/res/key-vault/vault/tests/e2e/defaults/main.test.bicep | 5 +---- avm/res/kubernetes-configuration/extension/README.md | 2 -- .../extension/tests/e2e/defaults/main.test.bicep | 5 +---- .../kubernetes-configuration/flux-configuration/README.md | 2 -- .../flux-configuration/tests/e2e/defaults/main.test.bicep | 5 +---- avm/res/logic/workflow/README.md | 2 -- avm/res/logic/workflow/tests/e2e/defaults/main.test.bicep | 5 +---- avm/res/network/dns-forwarding-ruleset/README.md | 2 -- .../tests/e2e/defaults/main.test.bicep | 5 +---- avm/res/network/dns-resolver/README.md | 2 -- .../network/dns-resolver/tests/e2e/defaults/main.test.bicep | 5 +---- avm/res/network/private-dns-zone/README.md | 2 -- .../private-dns-zone/tests/e2e/defaults/main.test.bicep | 5 +---- avm/res/network/private-endpoint/README.md | 2 -- .../private-endpoint/tests/e2e/defaults/main.test.bicep | 5 +---- avm/res/network/public-ip-address/README.md | 2 -- .../public-ip-address/tests/e2e/defaults/main.test.bicep | 5 +---- .../deployment-script/tests/e2e/defaults/main.test.bicep | 5 +---- 21 files changed, 11 insertions(+), 64 deletions(-) diff --git a/avm/res/compute/ssh-public-key/README.md b/avm/res/compute/ssh-public-key/README.md index 6f71b01603..61009d7cbc 100644 --- a/avm/res/compute/ssh-public-key/README.md +++ b/avm/res/compute/ssh-public-key/README.md @@ -36,8 +36,6 @@ The following section provides usage examples for the module, which were used to ### Example 1: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. -> **Note:** The test currently implements additional non-required parameters to cater for a test-specific limitation. -
diff --git a/avm/res/compute/ssh-public-key/tests/e2e/defaults/main.test.bicep b/avm/res/compute/ssh-public-key/tests/e2e/defaults/main.test.bicep index a0aa5bb9c3..4c413e5147 100644 --- a/avm/res/compute/ssh-public-key/tests/e2e/defaults/main.test.bicep +++ b/avm/res/compute/ssh-public-key/tests/e2e/defaults/main.test.bicep @@ -1,10 +1,7 @@ targetScope = 'subscription' metadata name = 'Using only defaults' -metadata description = ''' -This instance deploys the module with the minimum set of required parameters. -> **Note:** The test currently implements additional non-required parameters to cater for a test-specific limitation. -''' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' // ========== // // Parameters // // ========== // diff --git a/avm/res/key-vault/vault/README.md b/avm/res/key-vault/vault/README.md index 8baf02b7f8..80f7541711 100644 --- a/avm/res/key-vault/vault/README.md +++ b/avm/res/key-vault/vault/README.md @@ -41,8 +41,6 @@ The following section provides usage examples for the module, which were used to ### Example 1: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. -> **Note:** The test currently implements additional non-required parameters to cater for a test-specific limitation. -
diff --git a/avm/res/key-vault/vault/tests/e2e/defaults/main.test.bicep b/avm/res/key-vault/vault/tests/e2e/defaults/main.test.bicep index 8297b5cf1d..5206ce36da 100644 --- a/avm/res/key-vault/vault/tests/e2e/defaults/main.test.bicep +++ b/avm/res/key-vault/vault/tests/e2e/defaults/main.test.bicep @@ -1,10 +1,7 @@ targetScope = 'subscription' metadata name = 'Using only defaults' -metadata description = ''' -This instance deploys the module with the minimum set of required parameters. -> **Note:** The test currently implements additional non-required parameters to cater for a test-specific limitation. -''' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' // ========== // // Parameters // diff --git a/avm/res/kubernetes-configuration/extension/README.md b/avm/res/kubernetes-configuration/extension/README.md index 7d56403794..e22acb4757 100644 --- a/avm/res/kubernetes-configuration/extension/README.md +++ b/avm/res/kubernetes-configuration/extension/README.md @@ -34,8 +34,6 @@ The following section provides usage examples for the module, which were used to ### Example 1: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. -> **Note:** The test currently implements additional non-required parameters to cater for a test-specific limitation. -
diff --git a/avm/res/kubernetes-configuration/extension/tests/e2e/defaults/main.test.bicep b/avm/res/kubernetes-configuration/extension/tests/e2e/defaults/main.test.bicep index 27e1da7346..8297beab10 100644 --- a/avm/res/kubernetes-configuration/extension/tests/e2e/defaults/main.test.bicep +++ b/avm/res/kubernetes-configuration/extension/tests/e2e/defaults/main.test.bicep @@ -1,10 +1,7 @@ targetScope = 'subscription' metadata name = 'Using only defaults' -metadata description = ''' -This instance deploys the module with the minimum set of required parameters. -> **Note:** The test currently implements additional non-required parameters to cater for a test-specific limitation. -''' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' // ========== // // Parameters // // ========== // diff --git a/avm/res/kubernetes-configuration/flux-configuration/README.md b/avm/res/kubernetes-configuration/flux-configuration/README.md index 75e174b03b..313b025b8f 100644 --- a/avm/res/kubernetes-configuration/flux-configuration/README.md +++ b/avm/res/kubernetes-configuration/flux-configuration/README.md @@ -33,8 +33,6 @@ The following section provides usage examples for the module, which were used to ### Example 1: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. -> **Note:** The test currently implements additional non-required parameters to cater for a test-specific limitation. -
diff --git a/avm/res/kubernetes-configuration/flux-configuration/tests/e2e/defaults/main.test.bicep b/avm/res/kubernetes-configuration/flux-configuration/tests/e2e/defaults/main.test.bicep index 4b195f6b1a..5e44b0a2e9 100644 --- a/avm/res/kubernetes-configuration/flux-configuration/tests/e2e/defaults/main.test.bicep +++ b/avm/res/kubernetes-configuration/flux-configuration/tests/e2e/defaults/main.test.bicep @@ -1,10 +1,7 @@ targetScope = 'subscription' metadata name = 'Using only defaults' -metadata description = ''' -This instance deploys the module with the minimum set of required parameters. -> **Note:** The test currently implements additional non-required parameters to cater for a test-specific limitation. -''' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' // ========== // // Parameters // diff --git a/avm/res/logic/workflow/README.md b/avm/res/logic/workflow/README.md index 6233d8aa19..552b5adce5 100644 --- a/avm/res/logic/workflow/README.md +++ b/avm/res/logic/workflow/README.md @@ -36,8 +36,6 @@ The following section provides usage examples for the module, which were used to ### Example 1: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. -> **Note:** The test currently implements additional non-required parameters to cater for a test-specific limitation. -
diff --git a/avm/res/logic/workflow/tests/e2e/defaults/main.test.bicep b/avm/res/logic/workflow/tests/e2e/defaults/main.test.bicep index c48184ea65..c7cdd8e3aa 100644 --- a/avm/res/logic/workflow/tests/e2e/defaults/main.test.bicep +++ b/avm/res/logic/workflow/tests/e2e/defaults/main.test.bicep @@ -1,10 +1,7 @@ targetScope = 'subscription' metadata name = 'Using only defaults' -metadata description = ''' -This instance deploys the module with the minimum set of required parameters. -> **Note:** The test currently implements additional non-required parameters to cater for a test-specific limitation. -''' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' // ========== // // Parameters // diff --git a/avm/res/network/dns-forwarding-ruleset/README.md b/avm/res/network/dns-forwarding-ruleset/README.md index 2f78e29c7e..76cf692df8 100644 --- a/avm/res/network/dns-forwarding-ruleset/README.md +++ b/avm/res/network/dns-forwarding-ruleset/README.md @@ -36,8 +36,6 @@ The following section provides usage examples for the module, which were used to ### Example 1: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. -> **Note:** The test currently implements additional non-required parameters to cater for a test-specific limitation. -
diff --git a/avm/res/network/dns-forwarding-ruleset/tests/e2e/defaults/main.test.bicep b/avm/res/network/dns-forwarding-ruleset/tests/e2e/defaults/main.test.bicep index 937fabd992..c6fc0e9319 100644 --- a/avm/res/network/dns-forwarding-ruleset/tests/e2e/defaults/main.test.bicep +++ b/avm/res/network/dns-forwarding-ruleset/tests/e2e/defaults/main.test.bicep @@ -1,10 +1,7 @@ targetScope = 'subscription' metadata name = 'Using only defaults' -metadata description = ''' -This instance deploys the module with the minimum set of required parameters. -> **Note:** The test currently implements additional non-required parameters to cater for a test-specific limitation. -''' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' // ========== // // Parameters // diff --git a/avm/res/network/dns-resolver/README.md b/avm/res/network/dns-resolver/README.md index 2513e2ceb9..ba788edc3a 100644 --- a/avm/res/network/dns-resolver/README.md +++ b/avm/res/network/dns-resolver/README.md @@ -36,8 +36,6 @@ The following section provides usage examples for the module, which were used to ### Example 1: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. -> **Note:** The test currently implements additional non-required parameters to cater for a test-specific limitation. -
diff --git a/avm/res/network/dns-resolver/tests/e2e/defaults/main.test.bicep b/avm/res/network/dns-resolver/tests/e2e/defaults/main.test.bicep index aff32456f8..171177a2c7 100644 --- a/avm/res/network/dns-resolver/tests/e2e/defaults/main.test.bicep +++ b/avm/res/network/dns-resolver/tests/e2e/defaults/main.test.bicep @@ -1,10 +1,7 @@ targetScope = 'subscription' metadata name = 'Using only defaults' -metadata description = ''' -This instance deploys the module with the minimum set of required parameters. -> **Note:** The test currently implements additional non-required parameters to cater for a test-specific limitation. -''' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' // ========== // // Parameters // diff --git a/avm/res/network/private-dns-zone/README.md b/avm/res/network/private-dns-zone/README.md index 1159c1dddc..633c3b8e3e 100644 --- a/avm/res/network/private-dns-zone/README.md +++ b/avm/res/network/private-dns-zone/README.md @@ -43,8 +43,6 @@ The following section provides usage examples for the module, which were used to ### Example 1: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. -> **Note:** The test currently implements additional non-required parameters to cater for a test-specific limitation. -
diff --git a/avm/res/network/private-dns-zone/tests/e2e/defaults/main.test.bicep b/avm/res/network/private-dns-zone/tests/e2e/defaults/main.test.bicep index 0c43e4878b..1edd244cee 100644 --- a/avm/res/network/private-dns-zone/tests/e2e/defaults/main.test.bicep +++ b/avm/res/network/private-dns-zone/tests/e2e/defaults/main.test.bicep @@ -1,10 +1,7 @@ targetScope = 'subscription' metadata name = 'Using only defaults' -metadata description = ''' -This instance deploys the module with the minimum set of required parameters. -> **Note:** The test currently implements additional non-required parameters to cater for a test-specific limitation. -''' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' // ========== // // Parameters // diff --git a/avm/res/network/private-endpoint/README.md b/avm/res/network/private-endpoint/README.md index f813411f2d..0721d58688 100644 --- a/avm/res/network/private-endpoint/README.md +++ b/avm/res/network/private-endpoint/README.md @@ -35,8 +35,6 @@ The following section provides usage examples for the module, which were used to ### Example 1: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. -> **Note:** The test currently implements additional non-required parameters to cater for a test-specific limitation. -
diff --git a/avm/res/network/private-endpoint/tests/e2e/defaults/main.test.bicep b/avm/res/network/private-endpoint/tests/e2e/defaults/main.test.bicep index 14c6f0e2d9..d07daeae23 100644 --- a/avm/res/network/private-endpoint/tests/e2e/defaults/main.test.bicep +++ b/avm/res/network/private-endpoint/tests/e2e/defaults/main.test.bicep @@ -1,10 +1,7 @@ targetScope = 'subscription' metadata name = 'Using only defaults' -metadata description = ''' -This instance deploys the module with the minimum set of required parameters. -> **Note:** The test currently implements additional non-required parameters to cater for a test-specific limitation. -''' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' // ========== // // Parameters // diff --git a/avm/res/network/public-ip-address/README.md b/avm/res/network/public-ip-address/README.md index dfdb4ca6be..dc1843b3c5 100644 --- a/avm/res/network/public-ip-address/README.md +++ b/avm/res/network/public-ip-address/README.md @@ -35,8 +35,6 @@ The following section provides usage examples for the module, which were used to ### Example 1: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. -> **Note:** The test currently implements additional non-required parameters to cater for a test-specific limitation. -
diff --git a/avm/res/network/public-ip-address/tests/e2e/defaults/main.test.bicep b/avm/res/network/public-ip-address/tests/e2e/defaults/main.test.bicep index b4e293d5f8..1c2dd866e5 100644 --- a/avm/res/network/public-ip-address/tests/e2e/defaults/main.test.bicep +++ b/avm/res/network/public-ip-address/tests/e2e/defaults/main.test.bicep @@ -1,10 +1,7 @@ targetScope = 'subscription' metadata name = 'Using only defaults' -metadata description = ''' -This instance deploys the module with the minimum set of required parameters. -> **Note:** The test currently implements additional non-required parameters to cater for a test-specific limitation. -''' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' // ========== // // Parameters // diff --git a/avm/res/resources/deployment-script/tests/e2e/defaults/main.test.bicep b/avm/res/resources/deployment-script/tests/e2e/defaults/main.test.bicep index 926bc535be..f1f7fbdb3e 100644 --- a/avm/res/resources/deployment-script/tests/e2e/defaults/main.test.bicep +++ b/avm/res/resources/deployment-script/tests/e2e/defaults/main.test.bicep @@ -1,10 +1,7 @@ targetScope = 'subscription' metadata name = 'Using only defaults' -metadata description = ''' -This instance deploys the module with the minimum set of required parameters. -> **Note:** The test currently implements additional non-required parameters to cater for a test-specific limitation. -''' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' // ========== // // Parameters // From f2bd197f65c6bb2f81183e720d71c3037a79e195 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Tue, 23 Jan 2024 19:51:52 +0100 Subject: [PATCH 39/55] Update to latest --- ....virtual-machine-images.image-template.yml | 83 ------------------- 1 file changed, 83 deletions(-) delete mode 100644 .github/workflows/avm.res.virtual-machine-images.image-template.yml diff --git a/.github/workflows/avm.res.virtual-machine-images.image-template.yml b/.github/workflows/avm.res.virtual-machine-images.image-template.yml deleted file mode 100644 index 63fe597668..0000000000 --- a/.github/workflows/avm.res.virtual-machine-images.image-template.yml +++ /dev/null @@ -1,83 +0,0 @@ -name: "avm.res.virtual-machine-images.image-template" - -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 - - push: - branches: - - main - paths: - - ".github/actions/templates/avm-**" - - ".github/workflows/avm.template.module.yml" - - ".github/workflows/avm.res.virtual-machine-images.image-template.yml" - - "avm/res/virtual-machine-images/image-template/**" - - "avm/utilities/pipelines/**" - - "!*/**/README.md" - -env: - modulePath: "avm/res/virtual-machine-images/image-template" - workflowPath: ".github/workflows/avm.res.virtual-machine-images.image-template.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" - 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 From 9d063cebdd15c84d6ae6bcc64802fce41e39ca7b Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Mon, 29 Jan 2024 18:03:01 +0100 Subject: [PATCH 40/55] Refereshed docs --- avm/res/resources/deployment-script/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/avm/res/resources/deployment-script/README.md b/avm/res/resources/deployment-script/README.md index 69e3012079..c71dd592e5 100644 --- a/avm/res/resources/deployment-script/README.md +++ b/avm/res/resources/deployment-script/README.md @@ -135,8 +135,6 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script: ### Example 2: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. -> **Note:** In this scenario, In this scenario, the `Storage File Data Privileged Contributor` role needs to be assigned to the user-assigned managed identity and the deployment principal needs to have permissions to list the storage account keys. -
From 005581fcfedef93e2c7be21eb549da7d131a6a90 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Sat, 9 Mar 2024 23:35:42 +0100 Subject: [PATCH 41/55] Update to latest --- .../pipelines/staticValidation/compliance/module.tests.ps1 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index 5ca94a1b60..6929015820 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -214,8 +214,9 @@ Describe 'File/folder tests' -Tag 'Modules' { $e2eTestFolderPathList = Get-ChildItem -Directory (Join-Path -Path $moduleFolderPath 'tests' 'e2e') foreach ($e2eTestFolderPath in $e2eTestFolderPathList) { - $pathExisting = Test-Path (Join-Path -Path $e2eTestFolderPath 'main.test.bicep') - $pathExisting | Should -Be $true + $filePath = Join-Path -Path $e2eTestFolderPath 'main.test.bicep' + $pathExisting = Test-Path $filePath + $pathExisting | Should -Be $true -Because "path [$filePath] is expected to exist." } } } From 15a7ed52c54ad8dbae388df5cd4fdfab49133634 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Sat, 9 Mar 2024 23:40:37 +0100 Subject: [PATCH 42/55] Update to latest --- avm/res/key-vault/vault/main.bicep | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/avm/res/key-vault/vault/main.bicep b/avm/res/key-vault/vault/main.bicep index bae76f0c3f..7193baf425 100644 --- a/avm/res/key-vault/vault/main.bicep +++ b/avm/res/key-vault/vault/main.bicep @@ -209,7 +209,7 @@ module keyVault_secrets 'secret/main.bicep' = [for (secret, index) in secretList name: secret.name value: secret.value keyVaultName: keyVault.name - attributesEnabled: secret.?attributesEnabled ?? true + attributesEnabled: secret.?attributesEnabled attributesExp: secret.?attributesExp attributesNbf: secret.?attributesNbf contentType: secret.?contentType @@ -223,7 +223,7 @@ module keyVault_keys 'key/main.bicep' = [for (key, index) in (keys ?? []): { params: { name: key.name keyVaultName: keyVault.name - attributesEnabled: key.?attributesEnabled ?? true + attributesEnabled: key.?attributesEnabled attributesExp: key.?attributesExp attributesNbf: key.?attributesNbf curveName: key.?curveName ?? 'P-256' From 922fd79e6c13b6af3eed44b8c2ed8d0f41c782b6 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Sat, 9 Mar 2024 23:43:10 +0100 Subject: [PATCH 43/55] Update to latest --- avm/res/key-vault/vault/main.json | 6 +++--- .../{private-endpoint/tests => max}/connectivity.tests.ps1 | 0 avm/res/key-vault/vault/tests/e2e/max/main.test.bicep | 2 ++ .../e2e/{private-endpoint/tests => max}/resource.tests.ps1 | 0 4 files changed, 5 insertions(+), 3 deletions(-) rename avm/res/key-vault/vault/tests/e2e/{private-endpoint/tests => max}/connectivity.tests.ps1 (100%) rename avm/res/key-vault/vault/tests/e2e/{private-endpoint/tests => max}/resource.tests.ps1 (100%) diff --git a/avm/res/key-vault/vault/main.json b/avm/res/key-vault/vault/main.json index aeae460874..40adf90666 100644 --- a/avm/res/key-vault/vault/main.json +++ b/avm/res/key-vault/vault/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.25.53.49325", - "templateHash": "18302928297760675801" + "templateHash": "5604749365634791124" }, "name": "Key Vaults", "description": "This module deploys a Key Vault.", @@ -1126,7 +1126,7 @@ "value": "[parameters('name')]" }, "attributesEnabled": { - "value": "[coalesce(tryGet(variables('secretList')[copyIndex()], 'attributesEnabled'), true())]" + "value": "[tryGet(variables('secretList')[copyIndex()], 'attributesEnabled')]" }, "attributesExp": { "value": "[tryGet(variables('secretList')[copyIndex()], 'attributesExp')]" @@ -1403,7 +1403,7 @@ "value": "[parameters('name')]" }, "attributesEnabled": { - "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributesEnabled'), true())]" + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributesEnabled')]" }, "attributesExp": { "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributesExp')]" diff --git a/avm/res/key-vault/vault/tests/e2e/private-endpoint/tests/connectivity.tests.ps1 b/avm/res/key-vault/vault/tests/e2e/max/connectivity.tests.ps1 similarity index 100% rename from avm/res/key-vault/vault/tests/e2e/private-endpoint/tests/connectivity.tests.ps1 rename to avm/res/key-vault/vault/tests/e2e/max/connectivity.tests.ps1 diff --git a/avm/res/key-vault/vault/tests/e2e/max/main.test.bicep b/avm/res/key-vault/vault/tests/e2e/max/main.test.bicep index 280869b9b8..e6cc12bba1 100644 --- a/avm/res/key-vault/vault/tests/e2e/max/main.test.bicep +++ b/avm/res/key-vault/vault/tests/e2e/max/main.test.bicep @@ -292,3 +292,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' diagnosticDependencies ] }] + +output resourceId string = testDeployment[0].outputs.resourceId diff --git a/avm/res/key-vault/vault/tests/e2e/private-endpoint/tests/resource.tests.ps1 b/avm/res/key-vault/vault/tests/e2e/max/resource.tests.ps1 similarity index 100% rename from avm/res/key-vault/vault/tests/e2e/private-endpoint/tests/resource.tests.ps1 rename to avm/res/key-vault/vault/tests/e2e/max/resource.tests.ps1 From d861c45585a65f8f04aa5235c8352570af7b049e Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Sat, 9 Mar 2024 18:13:32 -0500 Subject: [PATCH 44/55] Update to latest --- .../vault/tests/e2e/max/resource.tests.ps1 | 24 ------------------- .../max/{ => tests}/connectivity.tests.ps1 | 0 2 files changed, 24 deletions(-) delete mode 100644 avm/res/key-vault/vault/tests/e2e/max/resource.tests.ps1 rename avm/res/key-vault/vault/tests/e2e/max/{ => tests}/connectivity.tests.ps1 (100%) diff --git a/avm/res/key-vault/vault/tests/e2e/max/resource.tests.ps1 b/avm/res/key-vault/vault/tests/e2e/max/resource.tests.ps1 deleted file mode 100644 index 4c68a6cd00..0000000000 --- a/avm/res/key-vault/vault/tests/e2e/max/resource.tests.ps1 +++ /dev/null @@ -1,24 +0,0 @@ -###################################### -## Additional post-deployment tests ## -###################################### -## -## You can add any custom post-deployment validation tests you want here, or add them spread accross multiple test files in the test case folder. -## -########################### - -param ( - [Parameter(Mandatory = $false)] - [hashtable] $TestInputData = @{} -) - -Describe 'Validate Key Vault' { - - It 'Public endpoint should be disabled' { - - $keyVaultResourceId = $TestInputData.DeploymentOutputs.resourceId.Value - - $deployedResource = Get-AzResource -ResourceId $keyVaultResourceId - - $deployedResource.Properties.publicNetworkAccess | Should -Be 'Disabled' - } -} \ No newline at end of file diff --git a/avm/res/key-vault/vault/tests/e2e/max/connectivity.tests.ps1 b/avm/res/key-vault/vault/tests/e2e/max/tests/connectivity.tests.ps1 similarity index 100% rename from avm/res/key-vault/vault/tests/e2e/max/connectivity.tests.ps1 rename to avm/res/key-vault/vault/tests/e2e/max/tests/connectivity.tests.ps1 From 776bed838150118c7d363382cbcf93628d75e3d7 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Mon, 25 Mar 2024 21:51:55 +0100 Subject: [PATCH 45/55] Retired / refactored workflows --- .../workflows/fork-on-push-brm-generate.yml | 92 ------------- .../fork-on-push-format-workflow.yml | 49 ------- .github/workflows/get-changed-module.yml | 26 ---- .github/workflows/on-pull-request.yml | 83 ------------ .github/workflows/on-push-main.yml | 63 --------- ...k.psrule.yml => platform.check.psrule.yml} | 2 +- ...yml => platform.manage-workflow-issue.yml} | 2 +- ...platform.on-pull-request-check-labels.yml} | 2 +- ...atform.on-pull-request-check-pr-title.yml} | 2 +- ....yml => platform.publish-module-index.yml} | 2 +- ...blish-tag.yml => platform.publish-tag.yml} | 2 +- ...orm.set-avm-github-issue-owner-config.yml} | 2 +- ...=> platform.sync-repo-labels-from-csv.yml} | 2 +- ....yml => platform.toggle-avm-workflows.yml} | 2 +- .github/workflows/publish-module.yml | 126 ------------------ 15 files changed, 9 insertions(+), 448 deletions(-) delete mode 100644 .github/workflows/fork-on-push-brm-generate.yml delete mode 100644 .github/workflows/fork-on-push-format-workflow.yml delete mode 100644 .github/workflows/get-changed-module.yml delete mode 100644 .github/workflows/on-pull-request.yml delete mode 100644 .github/workflows/on-push-main.yml rename .github/workflows/{avm.platform.check.psrule.yml => platform.check.psrule.yml} (99%) rename .github/workflows/{avm.platform.manage-workflow-issue.yml => platform.manage-workflow-issue.yml} (95%) rename .github/workflows/{on-pull-request-check-labels.yml => platform.on-pull-request-check-labels.yml} (95%) rename .github/workflows/{on-pull-request-check-pr-title.yml => platform.on-pull-request-check-pr-title.yml} (89%) rename .github/workflows/{publish-module-index.yml => platform.publish-module-index.yml} (98%) rename .github/workflows/{avm.platform.publish-tag.yml => platform.publish-tag.yml} (99%) rename .github/workflows/{avm.platform.set-avm-github-issue-owner-config.yml => platform.set-avm-github-issue-owner-config.yml} (95%) rename .github/workflows/{avm.platform.sync-repo-labels-from-csv.yml => platform.sync-repo-labels-from-csv.yml} (95%) rename .github/workflows/{avm.platform.toggle-avm-workflows.yml => platform.toggle-avm-workflows.yml} (97%) delete mode 100644 .github/workflows/publish-module.yml diff --git a/.github/workflows/fork-on-push-brm-generate.yml b/.github/workflows/fork-on-push-brm-generate.yml deleted file mode 100644 index 06a832098c..0000000000 --- a/.github/workflows/fork-on-push-brm-generate.yml +++ /dev/null @@ -1,92 +0,0 @@ -name: On push run brm generate # fork only, optional - -on: - push: - branches-ignore: - - main - paths: - - modules/**/*.bicep - - modules/**/*.sh - - modules/**/metadata.json - -jobs: - check-secret: - runs-on: ubuntu-latest - outputs: - my-key: ${{ steps.my-key.outputs.defined }} - steps: - - id: my-key - if: "${{ env.MY_KEY != '' }}" - run: echo "defined=true" >> $GITHUB_OUTPUT - env: - MY_KEY: ${{ secrets.PAT }} - - get-module-to-validate: - needs: [check-secret] - if: needs.check-secret.outputs.my-key == 'true' - uses: ./.github/workflows/get-changed-module.yml - - push-brm-generate: - runs-on: ubuntu-latest - needs: get-module-to-validate - if: needs.get-module-to-validate.outputs.module_dir - steps: - - uses: actions/checkout@v4 - with: - token: ${{ secrets.PAT }} # A PAT must be used to re-trigger workflows after commit. This PAT should NOT have the workflow scope. - - # Adding a step to explicitly install the latest Bicep CLI because there is - # always a delay in updating Bicep CLI in the job runner environments. - - name: Install the latest Bicep CLI - run: | - curl -Lo bicep https://github.com/Azure/bicep/releases/latest/download/bicep-linux-x64 - chmod +x ./bicep - sudo mv ./bicep /usr/local/bin/bicep - bicep --version - - uses: jungwinter/split@master - id: branch - with: - msg: ${{ needs.get-module-to-validate.outputs.module_dir }} - separator: "/" - maxsplit: -1 - - - name: Bump version and push tag - id: tag_version - uses: mathieudutour/github-tag-action@v6.2 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - tag_prefix: "${{ steps.branch.outputs._1 }}/${{ steps.branch.outputs._2 }}/" - dry_run: true - default_bump: false - - - name: Update Version - if: steps.tag_version.outputs.release_type - shell: bash - env: - OLD_VERSION: ${{ steps.tag_version.outputs.previous_version }} - VERSION: ${{ steps.tag_version.outputs.new_version }} - SAMPLEFOLDER_PATH: ${{ needs.get-module-to-validate.outputs.module_dir }} - MODULE: "${{ steps.branch.outputs._1 }}/${{ steps.branch.outputs._2 }}" - run: | - cd $SAMPLEFOLDER_PATH - NEW_VERSION=${VERSION%%-*} - # The following sed command searches for the specified module in README.md and replaces its version number - # (in formats X.Y.Z, X.Y, X, or a single lowercase letter) or adds a version number if it's not present. - REGEX=$(echo "s|($MODULE:)([0-9]+(\.[0-9]+){0,2})?|\1$NEW_VERSION|") - sed -ri "$REGEX" "README.md" || exit 1 - - - name: Run brm generate - env: - SAMPLEFOLDER_PATH: ${{ needs.get-module-to-validate.outputs.module_dir }} - run: | - dotnet tool install --global Azure.Bicep.RegistryModuleTool - - cd $SAMPLEFOLDER_PATH - brm generate - - - uses: EndBug/add-and-commit@v9 - with: - message: Autogenerate Bicep Files - committer_name: GitHub Actions - committer_email: actions@github.com - add: modules diff --git a/.github/workflows/fork-on-push-format-workflow.yml b/.github/workflows/fork-on-push-format-workflow.yml deleted file mode 100644 index 263a03088f..0000000000 --- a/.github/workflows/fork-on-push-format-workflow.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: On push format workflow files # fork only, optional - -on: - workflow_dispatch: - push: - branches-ignore: - - main - paths: - - .github/** - - CONTRIBUTING.md - -jobs: - check-secret: - runs-on: ubuntu-latest - outputs: - my-key: ${{ steps.my-key.outputs.defined }} - steps: - - id: my-key - if: "${{ env.MY_KEY != '' }}" - run: echo "defined=true" >> $GITHUB_OUTPUT - env: - MY_KEY: ${{ secrets.WORKFLOW_PAT }} - - push-prettier: - runs-on: ubuntu-latest - needs: [check-secret] - if: needs.check-secret.outputs.my-key == 'true' - steps: - - uses: actions/checkout@v4 - with: - token: ${{ secrets.WORKFLOW_PAT }} # A WORKFLOW_PAT must be used to re-trigger workflows after commit. This PAT must have the workflow scope. This is not generally recommended. - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: "16" - - - name: Install packages - run: npm ci - - - name: Check formatting - run: npm run prettier --write . - - - uses: EndBug/add-and-commit@v9 - with: - message: Autogenerate Bicep Files - committer_name: GitHub Actions - committer_email: actions@github.com - add: .github CONTRIBUTING.md diff --git a/.github/workflows/get-changed-module.yml b/.github/workflows/get-changed-module.yml deleted file mode 100644 index 696faa3062..0000000000 --- a/.github/workflows/get-changed-module.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Get changed module - -on: - workflow_call: - outputs: - module_dir: - description: "The directory of the added or updated module. Empty if no module was changed." - value: ${{ jobs.main.outputs.module_dir }} - -jobs: - main: - runs-on: ubuntu-latest - outputs: - module_dir: ${{ steps.get-changed-module.outputs.result }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Get changed module - uses: actions/github-script@v7 - id: get-changed-module - with: - result-encoding: string - script: | - const script = require("./scripts/github-actions/get-changed-module.js") - return await script({ require, github, context, core }) diff --git a/.github/workflows/on-pull-request.yml b/.github/workflows/on-pull-request.yml deleted file mode 100644 index 588b11f8ea..0000000000 --- a/.github/workflows/on-pull-request.yml +++ /dev/null @@ -1,83 +0,0 @@ -name: On pull request - -on: - pull_request: - branches: - - main - -jobs: - get-module-to-validate: - uses: ./.github/workflows/get-changed-module.yml - - validate-module-files: - runs-on: ubuntu-latest - needs: get-module-to-validate - if: needs.get-module-to-validate.outputs.module_dir - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - dotnet-version: 7.0.x - - # Adding a step to explicitly install the latest Bicep CLI because there is - # always a delay in updating Bicep CLI in the job runner environments. - - name: Install the latest Bicep CLI - run: | - curl -Lo bicep https://github.com/Azure/bicep/releases/latest/download/bicep-linux-x64 - chmod +x ./bicep - sudo mv ./bicep /usr/local/bin/bicep - bicep --version - - - name: Install Bicep registry module tool - run: dotnet tool install --global Azure.Bicep.RegistryModuleTool - - - name: Validate module files - run: brm validate - working-directory: ${{ needs.get-module-to-validate.outputs.module_dir }} - - - run: mv ${{ needs.get-module-to-validate.outputs.module_dir }}/main.json ${{ needs.get-module-to-validate.outputs.module_dir }}/mainTemplate.json - - - name: Run ARM-TTK (optional) - uses: microsoft/action-armttk@v1 - continue-on-error: true - with: - workdir: "${{ needs.get-module-to-validate.outputs.module_dir }}" - - shellcheck: - name: runner - runs-on: ubuntu-latest - needs: get-module-to-validate - if: needs.get-module-to-validate.outputs.module_dir - steps: - - uses: actions/checkout@v4 - - - name: shellcheck - uses: reviewdog/action-shellcheck@v1 - continue-on-error: true - with: - github_token: ${{ secrets.PAT || github.token }} - reporter: github-pr-review # Change reporter. - path: ${{ needs.get-module-to-validate.outputs.module_dir }} - - validate-non-module-files: - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: "16" - - - name: Install packages - run: npm ci - - - name: Lint - run: npm run lint - - - name: Check formatting - run: npm run prettier:check diff --git a/.github/workflows/on-push-main.yml b/.github/workflows/on-push-main.yml deleted file mode 100644 index 1e862b6a18..0000000000 --- a/.github/workflows/on-push-main.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: On push main - -on: - push: - branches: - - main - -jobs: - get-module-to-publish: - uses: ./.github/workflows/get-changed-module.yml - - create-tag: - runs-on: ubuntu-latest - needs: get-module-to-publish - if: ${{ needs.get-module-to-publish.outputs.module_dir }} - outputs: - tag: ${{ steps.create-tag.outputs.result }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Install semver - run: npm install semver - - - name: Get base and head versions - id: get-versions - env: - PublicRelease: true - run: | - echo ::set-output name=base_version::$(nbgv get-version ${{ github.event.before }} --format json | jq '.SemVer2') - echo ::set-output name=head_version::$(nbgv get-version ${{ github.event.after }} --format json | jq '.SemVer2') - working-directory: ${{ needs.get-module-to-publish.outputs.module_dir }} - - - name: Create tag - id: create-tag - uses: actions/github-script@v7 - with: - result-encoding: string - script: | - const script = require("./scripts/github-actions/create-tag.js") - return await script({ - require, - github, - context, - core, - moduleDir: "${{ needs.get-module-to-publish.outputs.module_dir }}", - baseVersion: ${{ steps.get-versions.outputs.base_version }}, - headVersion: ${{ steps.get-versions.outputs.head_version }}, - }) - - publish-module: - needs: create-tag - if: needs.create-tag.outputs.tag - uses: ./.github/workflows/publish-module.yml - with: - tag: ${{ needs.create-tag.outputs.tag }} - secrets: - PUBLISH_CLIENT_ID: ${{ secrets.PUBLISH_CLIENT_ID }} - PUBLISH_TENANT_ID: ${{ secrets.PUBLISH_TENANT_ID }} - PUBLISH_SUBSCRIPTION_ID: ${{ secrets.PUBLISH_SUBSCRIPTION_ID }} - PUBLISH_REGISTRY_SERVER: ${{ secrets.PUBLISH_REGISTRY_SERVER }} diff --git a/.github/workflows/avm.platform.check.psrule.yml b/.github/workflows/platform.check.psrule.yml similarity index 99% rename from .github/workflows/avm.platform.check.psrule.yml rename to .github/workflows/platform.check.psrule.yml index fd7a7d9308..5607cea835 100644 --- a/.github/workflows/avm.platform.check.psrule.yml +++ b/.github/workflows/platform.check.psrule.yml @@ -1,4 +1,4 @@ -name: "avm.platform.check.psrule" +name: Platform - Check PSRule on: workflow_dispatch: diff --git a/.github/workflows/avm.platform.manage-workflow-issue.yml b/.github/workflows/platform.manage-workflow-issue.yml similarity index 95% rename from .github/workflows/avm.platform.manage-workflow-issue.yml rename to .github/workflows/platform.manage-workflow-issue.yml index 8d37f57d3d..d91a1f16d7 100644 --- a/.github/workflows/avm.platform.manage-workflow-issue.yml +++ b/.github/workflows/platform.manage-workflow-issue.yml @@ -1,4 +1,4 @@ -name: "avm.platform.manage-workflow-issue" +name: Platform - Manage workflow issue on: schedule: diff --git a/.github/workflows/on-pull-request-check-labels.yml b/.github/workflows/platform.on-pull-request-check-labels.yml similarity index 95% rename from .github/workflows/on-pull-request-check-labels.yml rename to .github/workflows/platform.on-pull-request-check-labels.yml index 011c0790e6..03734eb591 100644 --- a/.github/workflows/on-pull-request-check-labels.yml +++ b/.github/workflows/platform.on-pull-request-check-labels.yml @@ -1,4 +1,4 @@ -name: Check Labels +name: Platform - Check Labels on: pull_request_target: diff --git a/.github/workflows/on-pull-request-check-pr-title.yml b/.github/workflows/platform.on-pull-request-check-pr-title.yml similarity index 89% rename from .github/workflows/on-pull-request-check-pr-title.yml rename to .github/workflows/platform.on-pull-request-check-pr-title.yml index a5e349f52c..9b7a4ed878 100644 --- a/.github/workflows/on-pull-request-check-pr-title.yml +++ b/.github/workflows/platform.on-pull-request-check-pr-title.yml @@ -1,4 +1,4 @@ -name: "Semantic PR Check" +name: Platform - Semantic PR Check on: pull_request_target: diff --git a/.github/workflows/publish-module-index.yml b/.github/workflows/platform.publish-module-index.yml similarity index 98% rename from .github/workflows/publish-module-index.yml rename to .github/workflows/platform.publish-module-index.yml index 885451f81b..b27b0be52f 100644 --- a/.github/workflows/publish-module-index.yml +++ b/.github/workflows/platform.publish-module-index.yml @@ -1,6 +1,6 @@ # This publishes the list of all public bicep modules to an index file that the Bicep vscode extension can read for intellisense # and also a human-readable HTML version. -name: Publish module index +name: Platform - Publish module index on: schedule: - cron: 45 11 * * * # Run daily at 3:45 AM PST diff --git a/.github/workflows/avm.platform.publish-tag.yml b/.github/workflows/platform.publish-tag.yml similarity index 99% rename from .github/workflows/avm.platform.publish-tag.yml rename to .github/workflows/platform.publish-tag.yml index 3f1488ebd3..60706b4114 100644 --- a/.github/workflows/avm.platform.publish-tag.yml +++ b/.github/workflows/platform.publish-tag.yml @@ -1,4 +1,4 @@ -name: "avm.platform.publish-tag" +name: Platform - Publish tag on: workflow_dispatch: diff --git a/.github/workflows/avm.platform.set-avm-github-issue-owner-config.yml b/.github/workflows/platform.set-avm-github-issue-owner-config.yml similarity index 95% rename from .github/workflows/avm.platform.set-avm-github-issue-owner-config.yml rename to .github/workflows/platform.set-avm-github-issue-owner-config.yml index 775d83c94d..ab3343e24e 100644 --- a/.github/workflows/avm.platform.set-avm-github-issue-owner-config.yml +++ b/.github/workflows/platform.set-avm-github-issue-owner-config.yml @@ -1,5 +1,5 @@ # Workflow for notifying and assigning issues on creation -name: avm.platform.set-avm-github-issue-owner-config +name: Platform - Set GitHub issue ownerconfig on: issues: diff --git a/.github/workflows/avm.platform.sync-repo-labels-from-csv.yml b/.github/workflows/platform.sync-repo-labels-from-csv.yml similarity index 95% rename from .github/workflows/avm.platform.sync-repo-labels-from-csv.yml rename to .github/workflows/platform.sync-repo-labels-from-csv.yml index d33fb79970..0c0fe50809 100644 --- a/.github/workflows/avm.platform.sync-repo-labels-from-csv.yml +++ b/.github/workflows/platform.sync-repo-labels-from-csv.yml @@ -1,5 +1,5 @@ # Workflow for syncing CSV labels to GitHub Labels -name: avm.platform.sync-repo-labels-from-csv +name: Platform - Sync repo labels from CSV on: schedule: diff --git a/.github/workflows/avm.platform.toggle-avm-workflows.yml b/.github/workflows/platform.toggle-avm-workflows.yml similarity index 97% rename from .github/workflows/avm.platform.toggle-avm-workflows.yml rename to .github/workflows/platform.toggle-avm-workflows.yml index 04381bea14..ff2f82109d 100644 --- a/.github/workflows/avm.platform.toggle-avm-workflows.yml +++ b/.github/workflows/platform.toggle-avm-workflows.yml @@ -1,4 +1,4 @@ -name: "avm.platform.toggle-avm-workflows" +name: Platform - Toggle AVM workflows on: workflow_dispatch: diff --git a/.github/workflows/publish-module.yml b/.github/workflows/publish-module.yml deleted file mode 100644 index d573607b20..0000000000 --- a/.github/workflows/publish-module.yml +++ /dev/null @@ -1,126 +0,0 @@ -name: Publish module - -on: - workflow_call: - inputs: - tag: - description: "The git tag of the module to publish." - required: true - type: string - secrets: - # Secrets must be passed from the caller workflow explicitly. - PUBLISH_CLIENT_ID: - required: true - PUBLISH_TENANT_ID: - required: true - PUBLISH_SUBSCRIPTION_ID: - required: true - PUBLISH_REGISTRY_SERVER: - required: true - workflow_dispatch: - inputs: - tag: - description: "The git tag of the module to publish." - required: true - type: string - -permissions: - id-token: write - contents: read - -jobs: - main: - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Parse tag - id: parse-tag - uses: actions/github-script@v7 - with: - result-encoding: string - script: | - const script = require("./scripts/github-actions/parse-tag.js") - const tag = "${{ github.event.inputs.tag || inputs.tag }}" - script({ core, tag }) - - - name: Checkout tag - uses: actions/checkout@v4 - with: - # Input contexts for workflow_dispatch and workflow_call are inconsistent. - # For workflow_dispatch, use ${{ github.event.inputs. }} - # For workflow_call, use ${{ inputs. }} - ref: ${{ github.event.inputs.tag || inputs.tag }} - - - name: Log in to Azure - uses: azure/login@v2 - with: - client-id: ${{ secrets.PUBLISH_CLIENT_ID }} - tenant-id: ${{ secrets.PUBLISH_TENANT_ID }} - subscription-id: ${{ secrets.PUBLISH_SUBSCRIPTION_ID }} - - # Adding a step to explicitly install the latest Bicep CLI because there is - # always a delay in updating Bicep CLI in the job runner environments. - - name: Install the latest Bicep CLI - run: | - curl -Lo bicep https://github.com/Azure/bicep/releases/latest/download/bicep-linux-x64 - chmod +x ./bicep - sudo mv ./bicep /usr/local/bin/bicep - bicep --version - - - name: Publish module - run: bicep publish "modules/${{ steps.parse-tag.outputs.module_path }}/main.bicep" --target "br:${{ secrets.PUBLISH_REGISTRY_SERVER }}/public/bicep/${{ steps.parse-tag.outputs.module_path }}:${{ steps.parse-tag.outputs.version }}" --documentationUri "${{ steps.parse-tag.outputs.documentation_uri }}" --with-source --force - - - name: Validate publish - run: | - Version="${{ steps.parse-tag.outputs.version }}" - ModulePath="${{ steps.parse-tag.outputs.module_path }}" - - time_limit_seconds=3600 - end_time=$((SECONDS+time_limit_seconds)) - retry_seconds=5 - - while true; do - CATALOG=https://mcr.microsoft.com/v2/_catalog - echo curl -sLo catalog $CATALOG - curl -sLo catalog $CATALOG - cat catalog | fgrep "bicep/" > bicepcatalog - echo "Bicep modules found in MCR catalog:" - cat bicepcatalog - - if fgrep -q "\"bicep/$ModulePath\"" catalog; then - echo "Passed: Found module $ModulePath in the MCR catalog" - break - else - echo "Error: Module $ModulePath is not in the MCR catalog. Retrying in $retry_seconds seconds" - sleep $retry_seconds - fi - - if [ $SECONDS -ge $end_time ]; then - echo "Time limit reached. Failed to validate publish within the specified time." - exit 1 - fi - done - - while true; do - TAGS=https://mcr.microsoft.com/v2/bicep/$ModulePath/tags/list - echo curl -sLo tags $TAGS - curl -sLo tags $TAGS - echo "Tags:" - cat tags - - echo - if fgrep -q "$Version" tags; then - echo "Passed: Found new tag $Version for published module" - break - else - echo "Error: Coud not find new tag $Version for published module. Retrying in $retry_seconds seconds" - sleep $retry_seconds - fi - - if [ $SECONDS -ge $end_time ]; then - echo "Time limit reached. Failed to validate publish within the specified time." - exit 1 - fi - done From a4c516d8fccf2253502dd33f344fdc3df14d0bf5 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Sun, 31 Mar 2024 14:02:33 +0200 Subject: [PATCH 46/55] Applied suggestion --- .github/workflows/platform.check.psrule.yml | 2 +- .github/workflows/platform.manage-workflow-issue.yml | 2 +- .github/workflows/platform.on-pull-request-check-labels.yml | 2 +- .github/workflows/platform.on-pull-request-check-pr-title.yml | 2 +- .github/workflows/platform.publish-module-index.yml | 2 +- .github/workflows/platform.publish-tag.yml | 2 +- .../workflows/platform.set-avm-github-issue-owner-config.yml | 2 +- .github/workflows/platform.sync-repo-labels-from-csv.yml | 2 +- .github/workflows/platform.toggle-avm-workflows.yml | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/platform.check.psrule.yml b/.github/workflows/platform.check.psrule.yml index 450bfa33ca..9c60895944 100644 --- a/.github/workflows/platform.check.psrule.yml +++ b/.github/workflows/platform.check.psrule.yml @@ -1,4 +1,4 @@ -name: Platform - Check PSRule +name: .Platform - Check PSRule on: workflow_dispatch: diff --git a/.github/workflows/platform.manage-workflow-issue.yml b/.github/workflows/platform.manage-workflow-issue.yml index d91a1f16d7..a573251b2a 100644 --- a/.github/workflows/platform.manage-workflow-issue.yml +++ b/.github/workflows/platform.manage-workflow-issue.yml @@ -1,4 +1,4 @@ -name: Platform - Manage workflow issue +name: .Platform - Manage workflow issue on: schedule: diff --git a/.github/workflows/platform.on-pull-request-check-labels.yml b/.github/workflows/platform.on-pull-request-check-labels.yml index 03734eb591..805c215f41 100644 --- a/.github/workflows/platform.on-pull-request-check-labels.yml +++ b/.github/workflows/platform.on-pull-request-check-labels.yml @@ -1,4 +1,4 @@ -name: Platform - Check Labels +name: .Platform - Check Labels on: pull_request_target: diff --git a/.github/workflows/platform.on-pull-request-check-pr-title.yml b/.github/workflows/platform.on-pull-request-check-pr-title.yml index 9b7a4ed878..ae9b65137f 100644 --- a/.github/workflows/platform.on-pull-request-check-pr-title.yml +++ b/.github/workflows/platform.on-pull-request-check-pr-title.yml @@ -1,4 +1,4 @@ -name: Platform - Semantic PR Check +name: .Platform - Semantic PR Check on: pull_request_target: diff --git a/.github/workflows/platform.publish-module-index.yml b/.github/workflows/platform.publish-module-index.yml index b27b0be52f..af3dc79bb8 100644 --- a/.github/workflows/platform.publish-module-index.yml +++ b/.github/workflows/platform.publish-module-index.yml @@ -1,6 +1,6 @@ # This publishes the list of all public bicep modules to an index file that the Bicep vscode extension can read for intellisense # and also a human-readable HTML version. -name: Platform - Publish module index +name: .Platform - Publish module index on: schedule: - cron: 45 11 * * * # Run daily at 3:45 AM PST diff --git a/.github/workflows/platform.publish-tag.yml b/.github/workflows/platform.publish-tag.yml index d1264d1369..643e3fd516 100644 --- a/.github/workflows/platform.publish-tag.yml +++ b/.github/workflows/platform.publish-tag.yml @@ -1,4 +1,4 @@ -name: Platform - Publish tag +name: .Platform - Publish tag on: workflow_dispatch: diff --git a/.github/workflows/platform.set-avm-github-issue-owner-config.yml b/.github/workflows/platform.set-avm-github-issue-owner-config.yml index ab3343e24e..ac674f6e1c 100644 --- a/.github/workflows/platform.set-avm-github-issue-owner-config.yml +++ b/.github/workflows/platform.set-avm-github-issue-owner-config.yml @@ -1,5 +1,5 @@ # Workflow for notifying and assigning issues on creation -name: Platform - Set GitHub issue ownerconfig +name: .Platform - Set GitHub issue ownerconfig on: issues: diff --git a/.github/workflows/platform.sync-repo-labels-from-csv.yml b/.github/workflows/platform.sync-repo-labels-from-csv.yml index 0c0fe50809..893a9ec3fc 100644 --- a/.github/workflows/platform.sync-repo-labels-from-csv.yml +++ b/.github/workflows/platform.sync-repo-labels-from-csv.yml @@ -1,5 +1,5 @@ # Workflow for syncing CSV labels to GitHub Labels -name: Platform - Sync repo labels from CSV +name: .Platform - Sync repo labels from CSV on: schedule: diff --git a/.github/workflows/platform.toggle-avm-workflows.yml b/.github/workflows/platform.toggle-avm-workflows.yml index ff2f82109d..468f942a5b 100644 --- a/.github/workflows/platform.toggle-avm-workflows.yml +++ b/.github/workflows/platform.toggle-avm-workflows.yml @@ -1,4 +1,4 @@ -name: Platform - Toggle AVM workflows +name: .Platform - Toggle AVM workflows on: workflow_dispatch: From 16899f2cd8ee302691caa654291c68c3620a5029 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Sun, 31 Mar 2024 14:11:04 +0200 Subject: [PATCH 47/55] Removed scripts --- .../azure-pipelines/Find-ChangedModule.ps1 | 53 -- scripts/azure-pipelines/Get-TargetScope.ps1 | 35 - scripts/azure-pipelines/Get-TestFile.ps1 | 21 - .../azure-pipelines/New-TestResourceGroup.ps1 | 51 -- .../Remove-TestResourceGroup.ps1 | 80 --- .../utils/AzurePipelinesUtils.psm1 | 33 - .../utils/AzureResourceUtils.psm1 | 596 ------------------ scripts/github-actions/create-tag.js | 59 -- scripts/github-actions/get-changed-module.js | 81 --- scripts/github-actions/parse-tag.js | 50 -- scripts/local/approve-autogenerated-prs.js | 55 -- scripts/local/create-prs.js | 102 --- scripts/local/fix-all-readme-examples.js | 25 - scripts/local/regenerate-all.js | 87 --- scripts/local/util/colors.js | 6 - .../util/getLatestModuleVersionsAsync.js | 46 -- scripts/local/util/runAsync.js | 72 --- scripts/local/util/updateReadmeExamples.js | 70 -- 18 files changed, 1522 deletions(-) delete mode 100644 scripts/azure-pipelines/Find-ChangedModule.ps1 delete mode 100644 scripts/azure-pipelines/Get-TargetScope.ps1 delete mode 100644 scripts/azure-pipelines/Get-TestFile.ps1 delete mode 100644 scripts/azure-pipelines/New-TestResourceGroup.ps1 delete mode 100644 scripts/azure-pipelines/Remove-TestResourceGroup.ps1 delete mode 100644 scripts/azure-pipelines/utils/AzurePipelinesUtils.psm1 delete mode 100644 scripts/azure-pipelines/utils/AzureResourceUtils.psm1 delete mode 100644 scripts/github-actions/create-tag.js delete mode 100644 scripts/github-actions/get-changed-module.js delete mode 100644 scripts/github-actions/parse-tag.js delete mode 100644 scripts/local/approve-autogenerated-prs.js delete mode 100644 scripts/local/create-prs.js delete mode 100644 scripts/local/fix-all-readme-examples.js delete mode 100644 scripts/local/regenerate-all.js delete mode 100644 scripts/local/util/colors.js delete mode 100644 scripts/local/util/getLatestModuleVersionsAsync.js delete mode 100644 scripts/local/util/runAsync.js delete mode 100644 scripts/local/util/updateReadmeExamples.js diff --git a/scripts/azure-pipelines/Find-ChangedModule.ps1 b/scripts/azure-pipelines/Find-ChangedModule.ps1 deleted file mode 100644 index 000c25e6c2..0000000000 --- a/scripts/azure-pipelines/Find-ChangedModule.ps1 +++ /dev/null @@ -1,53 +0,0 @@ -<# -.SYNOPSIS - Finds changed module. - -.DESCRIPTION - The script finds the changed module in the pull request that triggers the pipeline. - -.PARAMETER GitHubToken - The GitHub personal access token to use for authentication. - -.PARAMETER Repository - The Bicep registry module repository name. - -.PARAMETER PullRequestNumber - The pull request number. -#> -param( - # TODO: remove the PAT once the Bicep registry repo goes public. - [Parameter(mandatory = $True)] - [string]$GitHubToken, - - [Parameter(mandatory = $True)] - [string]$Repository, - - [Parameter(mandatory = $True)] - [string]$PullRequestNumber -) - -Import-Module .\scripts\azure-pipelines\utils\AzurePipelinesUtils.psm1 -Force - -$pullRequestFiles = Invoke-RestMethod ` - -Uri "https://api.github.com/repos/$Repository/pulls/$PullRequestNumber/files" ` - -Authentication OAuth ` - -Token (ConvertTo-SecureString $GitHubToken -AsPlainText -Force) - -$separator = [IO.Path]::DirectorySeparatorChar -$changedModuleDirectories = @( - $pullRequestFiles | - Where-Object { $_.filename.StartsWith("modules") } | # Get changed module files. - ForEach-Object { Split-Path $_.filename } | # Get directories of changed module files. - Where-Object { $_.Split($separator).Length -ge 3 } | # Ignore changes outside a module folder, e.g., modules/bicepconfig.json. - ForEach-Object { - $_.Split($separator) | - Select-Object -First 3 | - Join-String -Separator $separator - } | # Get module root directories. - Select-Object -Unique | # Remove duplicates. - Where-Object { Test-Path $_ } # Ignore removed directories. -) - -# If no test file or more than one test file was found, set an empty string to skip the subsequent steps. -$changedModuleDirectory = if ($changedModuleDirectories.Length -eq 1) { $changedModuleDirectories[0] } else { "" } -Set-AzurePipelinesVariable -VariableName "ChangedModuleDirectory" -VariableValue $changedModuleDirectory diff --git a/scripts/azure-pipelines/Get-TargetScope.ps1 b/scripts/azure-pipelines/Get-TargetScope.ps1 deleted file mode 100644 index 52c872c648..0000000000 --- a/scripts/azure-pipelines/Get-TargetScope.ps1 +++ /dev/null @@ -1,35 +0,0 @@ -<# -.SYNOPSIS - Gets the target scope of the module. - -.DESCRIPTION - The script gets the target scope of the main module file. - -.PARAMETER ChangedModuleDirectory - The directory of the changed module. -#> -param( - [Parameter(mandatory = $True)] - [string]$ChangedModuleDirectory -) - -Import-Module .\scripts\azure-pipelines\utils\AzurePipelinesUtils.psm1 -Force - -$armTemplateFilePath = Join-Path $ChangedModuleDirectory -ChildPath "main.json" -$targetScope = "" - -if (Test-Path $armTemplateFilePath -PathType "Leaf") { - $armTemplateFile = Get-Content -Raw -Path $armTemplateFilePath | ConvertFrom-Json - $armTemplateSchema = $armTemplateFile.'$schema' - $armTemplateSchemaPattern = "https?://schema\.management\.azure\.com/schemas/[0-9a-zA-Z-]+/{0}Template\.json#?" - - $targetScope = switch -Regex ($armTemplateSchema) { - $($armTemplateSchemaPattern -f "deployment") { "resourceGroup" } - $($armTemplateSchemaPattern -f "subscriptionDeployment") { "subscription" } - $($armTemplateSchemaPattern -f "managementGroupDeployment") { "managementGroup" } - $($armTemplateSchemaPattern -f "tenantDeployment") { "tenant" } - default { "" } - } -} - -Set-AzurePipelinesVariable -VariableName "TargetScope" -VariableValue $targetScope diff --git a/scripts/azure-pipelines/Get-TestFile.ps1 b/scripts/azure-pipelines/Get-TestFile.ps1 deleted file mode 100644 index 53ca1ed713..0000000000 --- a/scripts/azure-pipelines/Get-TestFile.ps1 +++ /dev/null @@ -1,21 +0,0 @@ -<# -.SYNOPSIS - Gets the module test file. - -.DESCRIPTION - The script gets path to the test file in the directory of the changed module. - -.PARAMETER ChangedModuleDirectory - The directory of the changed module. -#> -param( - [Parameter(mandatory = $True)] - [string]$ChangedModuleDirectory -) - -Import-Module .\scripts\azure-pipelines\utils\AzurePipelinesUtils.psm1 -Force - -$testFilePath = Join-Path $ChangedModuleDirectory -ChildPath "test\main.test.bicep" -$testFilePath = if (Test-Path $testFilePath -PathType "Leaf") { $testFilePath } else { "" } - -Set-AzurePipelinesVariable -VariableName "TestFilePath" -VariableValue $testFilePath diff --git a/scripts/azure-pipelines/New-TestResourceGroup.ps1 b/scripts/azure-pipelines/New-TestResourceGroup.ps1 deleted file mode 100644 index 11487fcd3d..0000000000 --- a/scripts/azure-pipelines/New-TestResourceGroup.ps1 +++ /dev/null @@ -1,51 +0,0 @@ -<# -.SYNOPSIS - Creates a test resource group. - -.DESCRIPTION - The script creates a resource group and grants a service principal access to that resource group for deploying the test Bicep file. - -.PARAMETER PrincipalId - The service principal ID (object ID). - -.PARAMETER Location - The Location of the test resource group to create. Defaults to "westus". -#> -Param( - [Parameter(mandatory = $true)] - [string]$PrincipalId, - - [string]$Location = "westus" -) - -Import-Module .\scripts\azure-pipelines\utils\AzurePipelinesUtils.psm1 -Force -Import-Module .\scripts\azure-pipelines\utils\AzureResourceUtils.psm1 -Force - -Invoke-AzurePipelinesTask { - $pullRequestNumber = $env:SYSTEM_PULLREQUEST_PULLREQUESTNUMBER - $commitId = $env:BUILD_SOURCEVERSION.Substring(0, 7) - $timestamp = Get-Date -Format "yyyyMMddHHmmss" -AsUTC - $guid = [GUID]::NewGuid().ToString('N') - $resourceGroupName = "$pullRequestNumber-$commitId-$timestamp-$guid" - - # Create the resource group and wait for replication. - New-AzResourceGroup -Name $resourceGroupName -Location $Location -Verbose - Wait-Replication { (Get-AzResourceGroup -Name $resourceGroupName -Verbose -ErrorAction "SilentlyContinue") -ne $null } - Set-AzurePipelinesVariable -VariableName "ResourceGroupName" -VariableValue $resourceGroupName - - Write-Host "Granting service principal $PrincipalId access to resource group $resourceGroupName..." - - # Can only use -ObjectId instead of -ApplicationId because the connected service principal doesn't have AAD read permision. - $roleAssignment = New-AzRoleAssignment -ResourceGroupName $resourceGroupName -ObjectId $PrincipalId -RoleDefinitionName "Owner" - $roleAssignmentPath = "$($roleAssignment.RoleAssignmentId)?api-version=2021-04-01-preview" - - # Sometimes it takes a while for an RBAC change to propagate. Calling Wait-Replication to ensure - # 6 succesive successful GET operations on the role assignment to reduce the chance of getting - # RBAC errors later due to slow replication. - Wait-Replication { - $getResult = Invoke-AzRestMethod -Method "GET" -Path $roleAssignmentPath - Write-Host $getResult.StatusCode "GET" $roleAssignmentPath - - $getResult.StatusCode -eq 200 - } -SuccessCount 6 -DelayInSeconds 4 -} diff --git a/scripts/azure-pipelines/Remove-TestResourceGroup.ps1 b/scripts/azure-pipelines/Remove-TestResourceGroup.ps1 deleted file mode 100644 index 2874109920..0000000000 --- a/scripts/azure-pipelines/Remove-TestResourceGroup.ps1 +++ /dev/null @@ -1,80 +0,0 @@ -<# -.SYNOPSIS - Removes a test resource group. - -.DESCRIPTION - This script attempts to remove a resource group. If the resource group cannot be removed, it will try cleaning up all the things - that prevent removing resource groups, such as resource locks, backup protection, geo-pairing, etc. The source code is largely - copied from https://github.com/Azure/azure-quickstart-templates/blob/master/test/ci-scripts/Kill-AzResourceGroup.ps1. - -.PARAMETER ResourceGroupName - The name of the resource group to remove. -#> -param( - [string][Parameter(mandatory = $true)] $ResourceGroupName -) - -Import-Module .\scripts\azure-pipelines\utils\AzurePipelinesUtils.psm1 -Force -Import-Module .\scripts\azure-pipelines\utils\AzureResourceUtils.psm1 -Force - - -Invoke-AzurePipelinesTask { - Write-Host "Removing resource group:" $ResourceGroupName "..." - - # First, try removing and purging soft-delete enabled resources... - Write-Host "Removing soft-delete enabled resources..." - - Write-Host "Checking for Key vaults..." - Remove-AzKeyVaultInResourceGroup -ResourceGroupName $ResourceGroupName - - Write-Host "Checking for Cognitive Services accounts..." - Remove-AzCognitiveServicesAccountInResourceGroup -ResourceGroupName $ResourceGroupName - - Write-Host "Checking for API Management services..." - Remove-AzApiManagementServiceInResourceGroup -ResourceGroupName $ResourceGroupName - - Write-Host "Checking for Operational Insights workspaces..." - Remove-AzOperationalInsightsWorkspaceInResourceGroup -ResourceGroupName $ResourceGroupName - - # Try removing the resource group. - if (Remove-AzResourceGroup -Name $ResourceGroupName -Force -Verbose -ErrorAction "SilentlyContinue") { - exit - } - - # Failed to remove the resource group - try cleaning up resources that can prevent removing resource groups. - Write-Host "Failed to remove the resource group. Try cleaning up resources first..." - - Write-Host "Checking for resource locks..." - Remove-AzResourceLockInResourceGroup -ResourceGroupName $ResourceGroupName - - Write-Host "Checking for Recovery Services vaults..." - Remove-AzRecoveryServicesVaultInResourceGroup -ResourceGroupName $ResourceGroupName - - Write-Host "Checking for Backup vaults..." - Remove-AzDataProtectionBackupVaultInResourceGroup -ResourceGroupName $ResourceGroupName - - Write-Host "Checking for Event Hubs Geo-disaster recovery configurations..." - Remove-AzEventHubGeoDRConfigurationInResourceGroup -ResourceGroupName $ResourceGroupName - - Write-Host "Checking for Service Bus Hubs Geo-disaster recovery configurations and migrations..." - Remove-AzServiceBusGeoDRConfigurationAndMigrationInResourceGroup -ResourceGroupName $ResourceGroupName - - Write-Host "Checking for Web App Swift Virtual Network connections..." - Remove-AzWebAppSwiftVnetConnectionInResourceGroup -ResourceGroupName $ResourceGroupName - - Write-Host "Checking for Redis Cache geo-replication links..." - Remove-AzRedisCacheLinkInResourceGroup -ResourceGroupName $ResourceGroupName - - Write-Host "Checking for Subnet delegations..." - Remove-AzSubnetDelegationInResourceGroup -ResourceGroupName $ResourceGroupName - - Write-Host "Checking for Virtual Hub IP configurations..." - Remove-AzVirtualHubIPConfigurationInResourceGroup -ResourceGroupName $ResourceGroupName - - Write-Host "Checking for Private Endpoint connections..." - Remove-AzPrivateEndpointConnectionInResourceGroup -ResourceGroupName $ResourceGroupName - - # Finally... - Write-Host "Removed resources preventing removing the resource group. Attempting to remove the resource group again..." - Remove-AzResourceGroup -Force -Verbose -Name $ResourceGroupName -} diff --git a/scripts/azure-pipelines/utils/AzurePipelinesUtils.psm1 b/scripts/azure-pipelines/utils/AzurePipelinesUtils.psm1 deleted file mode 100644 index e9186dd953..0000000000 --- a/scripts/azure-pipelines/utils/AzurePipelinesUtils.psm1 +++ /dev/null @@ -1,33 +0,0 @@ -function Invoke-AzurePipelinesTask { - [CmdletBinding()] - param ( - [Parameter(mandatory = $true)] - [ScriptBlock]$ScriptBlock - ) - - try { - $ScriptBlock.Invoke(); - } - catch { - Write-Host "##vso[task.logissue type=error;]An error occurred: $_" - Write-Output "##vso[task.complete result=Failed;]" - } - - Exit $LASTEXITCODE -} - -function Set-AzurePipelinesVariable { - [CmdletBinding()] - param ( - [Parameter(mandatory = $true)] - [string]$VariableName, - - [Parameter(mandatory = $true)] - [AllowEmptyString()] - [string]$VariableValue - ) - - Write-Host "##vso[task.setvariable variable=$VariableName;]$VariableValue" -} - -Export-ModuleMember -Function Invoke-AzurePipelinesTask, Set-AzurePipelinesVariable, Set-AzurePipelinesOutputVariable diff --git a/scripts/azure-pipelines/utils/AzureResourceUtils.psm1 b/scripts/azure-pipelines/utils/AzureResourceUtils.psm1 deleted file mode 100644 index 568b9e9fd3..0000000000 --- a/scripts/azure-pipelines/utils/AzureResourceUtils.psm1 +++ /dev/null @@ -1,596 +0,0 @@ -function Wait-Replication { - [CmdletBinding()] - Param( - [Parameter(mandatory = $true)] - [scriptblock]$ScriptBlock, - - [int]$SuccessCount = 2, - - [int]$DelayInSeconds = 2, - - [int]$MaximumFailureCount = 20 - ) - - Begin { - $successiveSuccessCount = 0 - $failureCount = 0 - } - - Process { - while ($successiveSuccessCount -lt $SuccessCount) { - if ($ScriptBlock.Invoke()) { - $successiveSuccessCount++ - } - else { - $successiveSuccessCount = 0 - $failureCount++ - - if ($failureCount -eq $MaximumFailureCount) { - throw "Reached maximum failure count: $MaximumFailureCount." - } - } - } - - Start-Sleep $DelayInSeconds - } -} - -<# -.SYNOPSIS - Clears a Recovery Services vault. - -.DESCRIPTION - The function removes all backup items and configuration in a Recovery Services vault so it can be removed. - The source code was copied from https://docs.microsoft.com/en-us/azure/backup/scripts/delete-recovery-services-vault. - -.PARAMETER Vault - The vault to clear. -#> -function Clear-AzRecoveryServicesVault { - [CmdletBinding()] - param ( - [Parameter(mandatory = $true, ValueFromPipeline = $true)] - [Microsoft.Azure.Commands.RecoveryServices.ARSVault]$Vault - ) - - process { - Write-Host "Clearing Recovery Services vault" $vault.Name "..." - - Set-AzRecoveryServicesAsrVaultContext -Vault $Vault - Set-AzRecoveryServicesVaultProperty -Vault $Vault.ID -SoftDeleteFeatureState Disable #disable soft delete - Write-Host "Soft delete disabled for the vault" $Vault.Name - - $containerSoftDelete = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureVM -WorkloadType AzureVM -VaultId $Vault.ID | Where-Object { $_.DeleteState -eq "ToBeDeleted" } #fetch backup items in soft delete state - foreach ($softitem in $containerSoftDelete) { - Undo-AzRecoveryServicesBackupItemDeletion -Item $softitem -VaultId $Vault.ID -Force #undelete items in soft delete state - } - #Invoking API to disable enhanced security - $body = @{properties = @{enhancedSecurityState = "Disabled" } } - $vaultPath = $Vault.ID + "/backupconfig/vaultconfig?api-version=2020-05-13" - - Invoke-AzRestMethod -Method "PATCH" -Path $vaultPath -Payload ($body | ConvertTo-JSON -Depth 5) - - #Fetch all protected items and servers - $backupItemsVM = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureVM -WorkloadType AzureVM -VaultId $Vault.ID - $backupItemsSQL = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureWorkload -WorkloadType MSSQL -VaultId $Vault.ID - $backupItemsAFS = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureStorage -WorkloadType AzureFiles -VaultId $Vault.ID - $backupItemsSAP = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureWorkload -WorkloadType SAPHanaDatabase -VaultId $Vault.ID - $backupContainersSQL = Get-AzRecoveryServicesBackupContainer -ContainerType AzureVMAppContainer -Status Registered -VaultId $Vault.ID | Where-Object { $_.ExtendedInfo.WorkloadType -eq "SQL" } - $protectableItemsSQL = Get-AzRecoveryServicesBackupProtectableItem -WorkloadType MSSQL -VaultId $Vault.ID | Where-Object { $_.IsAutoProtected -eq $true } - $backupContainersSAP = Get-AzRecoveryServicesBackupContainer -ContainerType AzureVMAppContainer -Status Registered -VaultId $Vault.ID | Where-Object { $_.ExtendedInfo.WorkloadType -eq "SAPHana" } - $StorageAccounts = Get-AzRecoveryServicesBackupContainer -ContainerType AzureStorage -Status Registered -VaultId $Vault.ID - $backupServersMARS = Get-AzRecoveryServicesBackupContainer -ContainerType "Windows" -BackupManagementType MAB -VaultId $Vault.ID - $backupServersMABS = Get-AzRecoveryServicesBackupManagementServer -VaultId $Vault.ID | Where-Object { $_.BackupManagementType -eq "AzureBackupServer" } - $backupServersDPM = Get-AzRecoveryServicesBackupManagementServer -VaultId $Vault.ID | Where-Object { $_.BackupManagementType -eq "SCDPM" } - $pvtendpoints = Get-AzPrivateEndpointConnection -PrivateLinkResourceId $Vault.ID - - foreach ($item in $backupItemsVM) { - Disable-AzRecoveryServicesBackupProtection -Item $item -VaultId $Vault.ID -RemoveRecoveryPoints -Force #stop backup and delete Azure VM backup items - } - Write-Host "Disabled and deleted Azure VM backup items" - - foreach ($item in $backupItemsSQL) { - Disable-AzRecoveryServicesBackupProtection -Item $item -VaultId $Vault.ID -RemoveRecoveryPoints -Force #stop backup and delete SQL Server in Azure VM backup items - } - Write-Host "Disabled and deleted SQL Server backup items" - - foreach ($item in $protectableItemsSQL) { - Disable-AzRecoveryServicesBackupAutoProtection -BackupManagementType AzureWorkload -WorkloadType MSSQL -InputItem $item -VaultId $Vault.ID #disable auto-protection for SQL - } - Write-Host "Disabled auto-protection and deleted SQL protectable items" - - foreach ($item in $backupContainersSQL) { - Unregister-AzRecoveryServicesBackupContainer -Container $item -Force -VaultId $Vault.ID #unregister SQL Server in Azure VM protected server - } - Write-Host "Deleted SQL Servers in Azure VM containers" - - foreach ($item in $backupItemsSAP) { - Disable-AzRecoveryServicesBackupProtection -Item $item -VaultId $Vault.ID -RemoveRecoveryPoints -Force #stop backup and delete SAP HANA in Azure VM backup items - } - Write-Host "Disabled and deleted SAP HANA backup items" - - foreach ($item in $backupContainersSAP) { - Unregister-AzRecoveryServicesBackupContainer -Container $item -Force -VaultId $Vault.ID #unregister SAP HANA in Azure VM protected server - } - Write-Host "Deleted SAP HANA in Azure VM containers" - - foreach ($item in $backupItemsAFS) { - Disable-AzRecoveryServicesBackupProtection -Item $item -VaultId $Vault.ID -RemoveRecoveryPoints -Force #stop backup and delete Azure File Shares backup items - } - Write-Host "Disabled and deleted Azure File Share backups" - - foreach ($item in $StorageAccounts) { - Unregister-AzRecoveryServicesBackupContainer -container $item -Force -VaultId $Vault.ID #unregister storage accounts - } - Write-Host "Unregistered Storage Accounts" - - foreach ($item in $backupServersMARS) { - Unregister-AzRecoveryServicesBackupContainer -Container $item -Force -VaultId $Vault.ID #unregister MARS servers and delete corresponding backup items - } - Write-Host "Deleted MARS Servers" - - foreach ($item in $backupServersMABS) { - Unregister-AzRecoveryServicesBackupManagementServer -AzureRmBackupManagementServer $item -VaultId $Vault.ID #unregister MABS servers and delete corresponding backup items - } - Write-Host "Deleted MAB Servers" - - foreach ($item in $backupServersDPM) { - Unregister-AzRecoveryServicesBackupManagementServer -AzureRmBackupManagementServer $item -VaultId $Vault.ID #unregister DPM servers and delete corresponding backup items - } - Write-Host "Deleted DPM Servers" - - #Deletion of ASR Items - - $fabricObjects = Get-AzRecoveryServicesAsrFabric - if ($null -ne $fabricObjects) { - # First DisableDR all VMs. - foreach ($fabricObject in $fabricObjects) { - $containerObjects = Get-AzRecoveryServicesAsrProtectionContainer -Fabric $fabricObject - foreach ($containerObject in $containerObjects) { - $protectedItems = Get-AzRecoveryServicesAsrReplicationProtectedItem -ProtectionContainer $containerObject - # DisableDR all protected items - foreach ($protectedItem in $protectedItems) { - Write-Host "Triggering DisableDR(Purge) for item:" $protectedItem.Name - Remove-AzRecoveryServicesAsrReplicationProtectedItem -InputObject $protectedItem -Force - Write-Host "DisableDR(Purge) completed" - } - - $containerMappings = Get-AzRecoveryServicesAsrProtectionContainerMapping ` - -ProtectionContainer $containerObject - # Remove all Container Mappings - foreach ($containerMapping in $containerMappings) { - Write-Host "Triggering Remove Container Mapping: " $containerMapping.Name - Remove-AzRecoveryServicesAsrProtectionContainerMapping -ProtectionContainerMapping $containerMapping -Force - Write-Host "Removed Container Mapping." - } - } - $NetworkObjects = Get-AzRecoveryServicesAsrNetwork -Fabric $fabricObject - foreach ($networkObject in $NetworkObjects) { - #Get the PrimaryNetwork - $PrimaryNetwork = Get-AzRecoveryServicesAsrNetwork -Fabric $fabricObject -FriendlyName $networkObject - $NetworkMappings = Get-AzRecoveryServicesAsrNetworkMapping -Network $PrimaryNetwork - foreach ($networkMappingObject in $NetworkMappings) { - #Get the Neetwork Mappings - $NetworkMapping = Get-AzRecoveryServicesAsrNetworkMapping -Name $networkMappingObject.Name -Network $PrimaryNetwork - Remove-AzRecoveryServicesAsrNetworkMapping -InputObject $NetworkMapping - } - } - # Remove Fabric - Write-Host "Triggering Remove Fabric:" $fabricObject.FriendlyName - Remove-AzRecoveryServicesAsrFabric -InputObject $fabricObject -Force - Write-Host "Removed Fabric." - } - } - - foreach ($item in $pvtendpoints) { - $penamesplit = $item.Name.Split(".") - $pename = $penamesplit[1] - Remove-AzPrivateEndpointConnection -ResourceId $item.PrivateEndpoint.Id -Force #remove private endpoint connections - Remove-AzPrivateEndpoint -Name $pename -ResourceGroupName $Vault.ResourceGroupName -Force #remove private endpoints - } - Write-Host "Removed Private Endpoints" - - #Recheck ASR items in vault - $fabricCount = 1 - $ASRProtectedItems = 1 - $ASRPolicyMappings = 1 - $fabricObjects = Get-AzRecoveryServicesAsrFabric - if ($null -ne $fabricObjects) { - foreach ($fabricObject in $fabricObjects) { - $containerObjects = Get-AzRecoveryServicesAsrProtectionContainer -Fabric $fabricObject - foreach ($containerObject in $containerObjects) { - $protectedItems = Get-AzRecoveryServicesAsrReplicationProtectedItem -ProtectionContainer $containerObject - foreach ($protectedItem in $protectedItems) { - $ASRProtectedItems++ - } - $containerMappings = Get-AzRecoveryServicesAsrProtectionContainerMapping ` - -ProtectionContainer $containerObject - foreach ($containerMapping in $containerMappings) { - $ASRPolicyMappings++ - } - } - $fabricCount++ - } - } - #Recheck presence of backup items in vault - $backupItemsVMFin = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureVM -WorkloadType AzureVM -VaultId $Vault.ID - $backupItemsSQLFin = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureWorkload -WorkloadType MSSQL -VaultId $Vault.ID - $backupContainersSQLFin = Get-AzRecoveryServicesBackupContainer -ContainerType AzureVMAppContainer -Status Registered -VaultId $Vault.ID | Where-Object { $_.ExtendedInfo.WorkloadType -eq "SQL" } - $protectableItemsSQLFin = Get-AzRecoveryServicesBackupProtectableItem -WorkloadType MSSQL -VaultId $Vault.ID | Where-Object { $_.IsAutoProtected -eq $true } - $backupItemsSAPFin = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureWorkload -WorkloadType SAPHanaDatabase -VaultId $Vault.ID - $backupContainersSAPFin = Get-AzRecoveryServicesBackupContainer -ContainerType AzureVMAppContainer -Status Registered -VaultId $Vault.ID | Where-Object { $_.ExtendedInfo.WorkloadType -eq "SAPHana" } - $backupItemsAFSFin = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureStorage -WorkloadType AzureFiles -VaultId $Vault.ID - $StorageAccountsFin = Get-AzRecoveryServicesBackupContainer -ContainerType AzureStorage -Status Registered -VaultId $Vault.ID - $backupServersMARSFin = Get-AzRecoveryServicesBackupContainer -ContainerType "Windows" -BackupManagementType MAB -VaultId $Vault.ID - $backupServersMABSFin = Get-AzRecoveryServicesBackupManagementServer -VaultId $Vault.ID | Where-Object { $_.BackupManagementType -eq "AzureBackupServer" } - $backupServersDPMFin = Get-AzRecoveryServicesBackupManagementServer -VaultId $Vault.ID | Where-Object { $_.BackupManagementType -eq "SCDPM" } - $pvtendpointsFin = Get-AzPrivateEndpointConnection -PrivateLinkResourceId $Vault.ID - Write-Host "Number of backup items left in the vault and which need to be deleted:" $backupItemsVMFin.count "Azure VMs" $backupItemsSQLFin.count "SQL Server Backup Items" $backupContainersSQLFin.count "SQL Server Backup Containers" $protectableItemsSQLFin.count "SQL Server Instances" $backupItemsSAPFin.count "SAP HANA backup items" $backupContainersSAPFin.count "SAP HANA Backup Containers" $backupItemsAFSFin.count "Azure File Shares" $StorageAccountsFin.count "Storage Accounts" $backupServersMARSFin.count "MARS Servers" $backupServersMABSFin.count "MAB Servers" $backupServersDPMFin.count "DPM Servers" $pvtendpointsFin.count "Private endpoints" - Write-Host "Number of ASR items left in the vault and which need to be deleted:" $ASRProtectedItems "ASR protected items" $ASRPolicyMappings "ASR policy mappings" $fabricCount "ASR Fabrics" $pvtendpointsFin.count "Private endpoints. Warning: This script will only remove the replication configuration from Azure Site Recovery and not from the source. Please cleanup the source manually. Visit https://go.microsoft.com/fwlink/?linkid=2182782 to learn more" - - $Vault - } -} - -function Remove-AzResourceLockInResourceGroup { - [CmdletBinding()] - param ( - [Parameter(mandatory = $true)] - [string]$ResourceGroupName - ) - - Get-AzResourceLock -ResourceGroupName $ResourceGroupName -Verbose | Remove-AzResourceLock -Force -verbose -} - -function Remove-AzRecoveryServicesVaultInResourceGroup { - [CmdletBinding()] - param ( - [Parameter(mandatory = $true)] - [string]$ResourceGroupName - ) - - Get-AzRecoveryServicesVault -ResourceGroupName $ResourceGroupName -Verbose | - Clear-AzRecoveryServicesVault | - Remove-AzRecoveryServicesVault -Verbose -} - -function Remove-AzDataProtectionBackupVaultInResourceGroup { - [CmdletBinding()] - param ( - [Parameter(mandatory = $true)] - [string]$ResourceGroupName - ) - - # The Az.DataProtection is not yet included with the rest of the Az module. - if ($null -eq $(Get-Module -ListAvailable Az.DataProtection)) { - Write-Host "Installing Az.DataProtection module..." - Install-Module Az.DataProtection -Force -AllowClobber - } - - $vaults = Get-AzDataProtectionBackupVault -ResourceGroupName $ResourceGroupName - - foreach ($vault in $vaults) { - Write-Host "Removing Backup vault" $vault.name "..." - - $backupInstances = Get-AzDataProtectionBackupInstance -ResourceGroupName $ResourceGroupName -VaultName $vault.Name - foreach ($backupInstance in $backupInstances) { - Write-Host "Removing Backup instance" $backupInstance.Name "..." - Remove-AzDataProtectionBackupInstance -ResourceGroupName $ResourceGroupName -VaultName $vault.Name -Name $backupInstance.Name - } - - $backupPolicies = Get-AzDataProtectionBackupPolicy -ResourceGroupName $ResourceGroupName -VaultName $vault.Name - foreach ($backupPolicy in $backupPolicies) { - Write-Host "Removing Backup policy" $backupPolicy.name "..." - Remove-AzDataProtectionBackupPolicy -ResourceGroupName $ResourceGroupName -VaultName $vault.name -Name $backupPolicy.Name - } - } -} - -function Remove-AzEventHubGeoDRConfigurationInResourceGroup { - [CmdletBinding()] - param ( - [Parameter(mandatory = $true)] - [string]$ResourceGroupName - ) - - $namespaces = Get-AzEventHubNamespace -ResourceGroupName $ResourceGroupName -Verbose - - foreach ($namespace in $namespaces) { - $configurations = Get-AzEventHubGeoDRConfiguration -ResourceGroupName $ResourceGroupName -Namespace $namespace.Name -Verbose - - foreach ($configuration in $configurations) { - # First look at the primary namespaces and break pairing. - if ($configuration.Role.ToString() -eq "Primary") { - Write-Host "Breaking Event Hubs namespace pairing for namespace" $namespace.Name "..." - Set-AzEventHubGeoDRConfigurationBreakPair -ResourceGroupName $ResourceGroupName -Namespace $namespace.Name -Name $configuration.Name - } - - # Now that pairing is removed we can remove primary and secondary configs. - Write-Host "Removing Event Hubs DR configuration" $configuration.Name "..." - Remove-AzEventHubGeoDRConfiguration -ResourceGroupName $ResourceGroupName -Namespace $namespace.Name $configuration.Name -Verbose - } - } -} - -function Remove-AzServiceBusGeoDRConfigurationAndMigrationInResourceGroup { - [CmdletBinding()] - param ( - [Parameter(mandatory = $true)] - [string]$ResourceGroupName - ) - - $namespaces = Get-AzServiceBusNamespace -ResourceGroupName $ResourceGroupName -Verbose - - foreach ($namespace in $namespaces) { - $configurations = Get-AzServiceBusGeoDRConfiguration -ResourceGroupName $ResourceGroupName -Namespace $namespace.Name - - foreach ($configuration in $configurations) { - # First look at the primary namespaces and break pairing. - if ($configuration.Role.ToString() -eq "Primary") { - Write-Host "Breaking Service Bus namespace pairing for namespace" $namespace "..." - Set-AzServiceBusGeoDRConfigurationBreakPair -ResourceGroupName $ResourceGroupName -Namespace $namespace.Name -Name $configuration.Name - } - - # Now that pairing is removed we can remove primary and secondary configs. - Write-Host "Removing Service Bus DR configuration" $configuration.Name "..." - Remove-AzServiceBusGeoDRConfiguration -ResourceGroupName $ResourceGroupName -Namespace $namespace.Name -Name $configuration.Name -Verbose - } - } - - foreach ($namespace in $namespaces) { - # Set ErrorAction on this since it throws if there is no config (unlike the other cmdlets). - $migration = Get-AzServiceBusMigration -ResourceGroupName $ResourceGroupName -Name $namespace.Name -ErrorAction "SilentlyContinue" - - if ($migration) { - Write-Host "Removing Service Bus migration" $migration.Name "..." - Remove-AzServiceBusMigration -ResourceGroupName $ResourceGroupName -Name $namespace.Name -Verbose - } - } -} - -function Remove-AzWebAppSwiftVnetConnectionInResourceGroup { - [CmdletBinding()] - param ( - [Parameter(mandatory = $true)] - [string]$ResourceGroupName - ) - - function Remove-AzWebAppSwiftVnetConnection { - [CmdletBinding()] - param ( - [Parameter(mandatory = $true)] - [Microsoft.Azure.Commands.WebApps.Models.PSSite]$WebAppOrSlot - ) - - process { - # Assumption is that there can only be one connection, but it returns an array so maybe not. - $result = Invoke-AzRestMethod -Method "GET" -Path "$($WebAppOrSlot.Id)/virtualNetworkConnections?api-version=2021-10-01" - - if ($result.StatusCode -eq "200") { - Write-Host "Removing a Swift Virtual Network connection from the Web App: $($WebAppOrSlot.Name)" - # The URI for remove is not the same as the GET URI. - Invoke-AzRestMethod -Method "DELETE" -Path "$($WebAppOrSlot.Id)/networkConfig/virtualNetwork?api-version=2021-10-01" -Verbose - } - } - } - - # Web apps that have a serviceAssociationLink can be deleted even if the link exists and the vnet - # will be bricked (cannot be delete and the serviceAssociation link cannot be removed). - # A funky traversal of 4 resources are needed to discover and remove the link (PUT/GET/DELETE are not symmetrical). - $webApps = Get-AzWebApp -ResourceGroupName $ResourceGroupName -Verbose - - foreach ($webApp in $webApps) { - # Remove the config on the WebApp slots. - Get-AzWebAppSlot -ResourceGroupName $ResourceGroupName -Name $webApp.Name -Verbose | Remove-AzWebAppSwiftVnetConnection - - # Now remove the config on the WebApp itself. - Remove-AzWebAppSwiftVnetConnection -WebAppOrSlot $webApp - } -} - -function Remove-AzRedisCacheLinkInResourceGroup { - [CmdletBinding()] - param ( - [Parameter(mandatory = $true)] - [string]$ResourceGroupName - ) - - $redisCaches = Get-AzRedisCache -ResourceGroupName $ResourceGroupName -Verbose - - foreach ($redisCache in $redisCaches) { - $link = Get-AzRedisCacheLink -Name $redisCache.Name - - if ($link) { - Write-Host "Removing Redis Cache geo-replication link" $link.Name "..." - $link | Remove-AzRedisCacheLink -Verbose - } - } -} - -function Remove-AzSubnetDelegationInResourceGroup { - [CmdletBinding()] - param ( - [Parameter(mandatory = $true)] - [string]$ResourceGroupName - ) - - # ACI create a subnet delegation that must be removed before the vnet can be deleted. - $vnets = Get-AzVirtualNetwork -ResourceGroupName $ResourceGroupName -Verbose - - foreach ($vnet in $vnets) { - foreach ($subnet in $vnet.Subnets) { - $delegations = Get-AzDelegation -Subnet $subnet -Verbose - - foreach ($delegation in $delegations) { - Write-Output "Removing Subnet delegation" $delegation.Name "..." - Remove-AzDelegation -Name $delegation.Name -Subnet $subnet -Verbose - } - } - } -} - -function Remove-AzVirtualHubIPConfigurationInResourceGroup { - [CmdletBinding()] - param ( - [Parameter(mandatory = $true)] - [string]$ResourceGroupName - ) - - # Virtual Hubs can have ipConfigurations that take a few minutes to delete. - # There appears to be no cmdlets or CLI to invoke these APIs. - $virtualHubs = Get-AzVirtualHub -ResourceGroupName $ResourceGroupName -Verbose - - foreach ($virtualHub in $virtualHubs) { - $listResult = Invoke-AzRestMethod -Method "GET" -path "$($virtualHub.Id)/ipConfigurations?api-version=2020-11-01" - $configurations = $($listResult.Content | ConvertFrom-Json -Depth 50).Value - - foreach ($configuration in $configurations) { - Write-Host "Removing Virtual Hub IP configuration" $($configuration.id) "..." - - Write-Host "Sending a DELETE request..." - $deleteResult = Invoke-AzRestMethod -Method "DELETE" -Path "$($configuration.id)?api-version=2020-11-01" - $deleteResult - - if ($deleteResult.StatusCode -like "20*") { - Write-Host "Waiting for the DELETE operation to complte..." - do { - Start-Sleep -Seconds 60 - Write-Host "Making sure GET returns 404..." - $getResult = Invoke-AzRestMethod -Method GET -Path "$($configuration.id)?api-version=2020-11-01" - $getResult - } until ($getResult.StatusCode -eq "404") - } - } - } -} - -function Remove-AzPrivateEndpointConnectionInResourceGroup { - [CmdletBinding()] - param ( - [Parameter(mandatory = $true)] - [string]$ResourceGroupName - ) - - $privateLinkServices = Get-AzPrivateLinkService -ResourceGroupName $ResourceGroupName - - foreach ($privateLinkService in $privateLinkServices) { - $connections = Get-AzPrivateEndpointConnection -ResourceGroupName $ResourceGroupName -ServiceName $privateLinkService.Name - - foreach ($connection in $connections) { - Write-Host "Removing Private Endpoint connection" $connection.Name "..." - Remove-AzPrivateEndpointConnection -ResourceGroupName $ResourceGroupName -ServiceName $privateLinkService.Name -Name $connection.Name -Force - } - } -} - -function Remove-AzKeyVaultInResourceGroup { - [CmdletBinding()] - param ( - [Parameter(mandatory = $true)] - [string]$ResourceGroupName - ) - - $keyVaults = Get-AzKeyVault -ResourceGroupName $ResourceGroupName - - foreach ($keyVault in $keyVaults) { - Write-Host "Removing Key vault" $keyVault.VaultName "..." - Remove-AzKeyVault -VaultName $keyVault.VaultName -ResourceGroupName $ResourceGroupName -Force - - if (-not $keyVault.EnableSoftDelete) { - continue - } - - if ($keyVault.EnablePurgeProtection) { - Write-Warning ('Key vault {0} had purge protection enabled. The retention time is {1} days. Please wait until after this period before re-running the test.' -f $keyVault.VaultName, $keyVault.SoftDeleteRetentionInDays) - } - else { - Wait-Replication { - Write-Host "Waiting for the Key vault deletion operation to complete..." - $null -ne (Get-AzKeyVault -VaultName $keyVault.VaultName -Location $keyVault.Location -InRemovedState) - } - - Write-Host "Purging Key vault" $keyVault.VaultName "..." - Remove-AzKeyVault -VaultName $keyVault.VaultName -Location $keyVault.Location -InRemovedState -Force - } - } -} - -function Remove-AzCognitiveServicesAccountInResourceGroup { - [CmdletBinding()] - param ( - [Parameter(mandatory = $true)] - [string]$ResourceGroupName - ) - - $accounts = Get-AzCognitiveServicesAccount -ResourceGroupName $ResourceGroupName - - foreach ($account in $accounts) { - Write-Host "Removing Cognitive Services account" $account.AccountName "..." - $account | Remove-AzCognitiveServicesAccount -Force - - Wait-Replication { - Write-Host "Waiting for the Cognitive Services account deletion operation to complete..." - $null -ne (Get-AzCognitiveServicesAccount -ResourceGroupName $ResourceGroupName -Name $account.AccountName -Location $account.Location -InRemovedState) - } - - Write-Host "Purging Cognitive Services account" $account.AccountName "..." - $account | Remove-AzCognitiveServicesAccount -Location $account.Location -InRemovedState -Force - } -} - -function Remove-AzApiManagementServiceInResourceGroup { - [CmdletBinding()] - param ( - [Parameter(mandatory = $true)] - [string]$ResourceGroupName - ) - - $context = Get-AzContext - $subscriptionId = $context.Subscription.Id - $services = Get-AzApiManagement -ResourceGroupName $ResourceGroupName - - foreach ($service in $services) { - Write-Host "Removing API Management service" $service.Name "..." - $service | Remove-AzApiManagement - - Write-Host "Waiting for the API Management service deletion operation to complete..." - Start-Sleep 20 - - Write-Host "Purging API Management service" $service.Name "..." - $purgePath = "/subscriptions/{0}/providers/Microsoft.ApiManagement/locations/{1}/deletedservices/{2}?api-version=2020-06-01-preview" -f $subscriptionId, $service.Location, $service.Name - Invoke-AzRestMethod -Method "DELETE" -Path $purgePath - } -} - -function Remove-AzOperationalInsightsWorkspaceInResourceGroup { - [CmdletBinding()] - param ( - [Parameter(mandatory = $true)] - [string]$ResourceGroupName - ) - - $workspaces = Get-AzOperationalInsightsWorkspace -ResourceGroupName $ResourceGroupName - - foreach ($workspace in $workspaces) { - Write-Host "Removing Operational Insights workspace" $workspace.Name "..." - $workspace | Remove-AzOperationalInsightsWorkspace -ForceDelete -Force - } -} - -Export-ModuleMember -Function ` - Wait-Replication, ` - Remove-AzResourceLockInResourceGroup, ` - Remove-AzRecoveryServicesVaultInResourceGroup, ` - Remove-AzDataProtectionBackupVaultInResourceGroup, ` - Remove-AzEventHubGeoDRConfigurationInResourceGroup, ` - Remove-AzServiceBusGeoDRConfigurationAndMigrationInResourceGroup, ` - Remove-AzWebAppSwiftVnetConnectionInResourceGroup, ` - Remove-AzRedisCacheLinkInResourceGroup, ` - Remove-AzSubnetDelegationInResourceGroup, ` - Remove-AzVirtualHubIPConfigurationInResourceGroup, ` - Remove-AzPrivateEndpointConnectionInResourceGroup, ` - Remove-AzKeyVaultInResourceGroup, ` - Remove-AzCognitiveServicesAccountInResourceGroup, ` - Remove-AzApiManagementServiceInResourceGroup, ` - Remove-AzOperationalInsightsWorkspaceInResourceGroup - \ No newline at end of file diff --git a/scripts/github-actions/create-tag.js b/scripts/github-actions/create-tag.js deleted file mode 100644 index fee3b918e9..0000000000 --- a/scripts/github-actions/create-tag.js +++ /dev/null @@ -1,59 +0,0 @@ -/** - * @typedef Params - * @property {typeof require} require - * @property {ReturnType} github - * @property {typeof import("@actions/github").context} context - * @property {typeof import("@actions/core")} core - * @property {string} moduleDir - * @property {string} baseVersion - * @property {string} headVersion - * - * @param {Params} params - */ -async function createTag({ - require, - github, - context, - core, - moduleDir, - baseVersion, - headVersion, -}) { - const semverCompare = require("semver/functions/compare"); - const base = context.payload.before; - const head = context.payload.after; - const compareResult = semverCompare(headVersion, baseVersion); - - if (compareResult < 0) { - core.setFailed( - `The version ${headVersion} calculated at the commit ${head} (head) is smaller than the version ${baseVersion} calculated at the base commit ${base} (base).` - ); - } - - if (compareResult === 0) { - core.info(`No version update detected.`); - return ""; - } - - const red = "\u001b[31m"; - const green = "\u001b[32m"; - const reset = "\u001b[0m"; - core.info( - `Detected version update: ${red}${baseVersion} (old) ${reset}-> ${green}${headVersion} (new).` - ); - - const modulePath = moduleDir.substring(moduleDir.indexOf("/") + 1); - const tag = `${modulePath}/${headVersion}`; - - await github.rest.git.createRef({ - owner: context.repo.owner, - repo: context.repo.repo, - ref: `refs/tags/${tag}`, - sha: context.sha, - }); - - core.info(`Created a new tag: ${tag} (${head}).`); - return tag; -} - -module.exports = createTag; diff --git a/scripts/github-actions/get-changed-module.js b/scripts/github-actions/get-changed-module.js deleted file mode 100644 index 479cb9bdd4..0000000000 --- a/scripts/github-actions/get-changed-module.js +++ /dev/null @@ -1,81 +0,0 @@ -/** - * @typedef Params - * @property {typeof require} require - * @property {ReturnType} github - * @property {typeof import("@actions/github").context} context - * @property {typeof import("@actions/core")} core - * - * @param {Params} params - */ -async function getChangedModule({ require, github, context, core }) { - let base; - let head; - - switch (context.eventName) { - case "pull_request": - base = context.payload.pull_request.base.sha; - head = context.payload.pull_request.head.sha; - break; - case "push": - base = context.payload.before; - head = context.payload.after; - break; - default: - core.setFailed(`Not supported event: ${context.eventName}.`); - } - - const { status, data } = await github.rest.repos.compareCommitsWithBasehead({ - owner: context.repo.owner, - repo: context.repo.repo, - basehead: `${base}...${head}`, - }); - - if (status !== 200) { - core.setFailed( - `Expected github.rest.repos.compareCommitsWithBasehead to return 200, got ${status}.` - ); - } - - if (context.eventName === "push" && data.status !== "ahead") { - core.setFailed( - `The head commit ${head} is not ahead of the base commit ${base}.` - ); - } - - const path = require("path"); - const fs = require("fs"); - const cyan = "\u001b[36;1m"; - - const moduleDirs = [ - ...new Set( - data.files - .filter((file) => file.filename.startsWith("modules/")) - // Do not consider module changed if only the README.md has changed - .filter((file) => !file.filename.endsWith("README.md")) - .map((file) => { - const dir = path.dirname(file.filename); - const segments = dir.split("/"); - // modules/moduleFolder/moduleRoot/* => modules/moduleFolder/moduleRoot - return segments.slice(0, 3).join("/"); - }) - // Ignore removed module directories. - .filter((dir) => fs.existsSync(dir)) - ), - ]; - - switch (moduleDirs.length) { - case 0: - core.info("No changed module found."); - return ""; - case 1: - core.info("Found 1 changed module:"); - core.info(`- ${cyan}${moduleDirs[0]}`); - return moduleDirs[0]; - default: - core.info(`Found ${moduleDirs.length} changed modules:`); - moduleDirs.forEach((dir) => core.info(`- ${cyan}${dir}`)); - core.setFailed("Only one module can be added or updated at a time."); - } -} - -module.exports = getChangedModule; diff --git a/scripts/github-actions/parse-tag.js b/scripts/github-actions/parse-tag.js deleted file mode 100644 index 99f86b1d61..0000000000 --- a/scripts/github-actions/parse-tag.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @typedef Params - * @property {typeof import("@actions/core")} core - * @property {string} tag - * - * @param {Params} params - */ -function parseTag({ core, tag }) { - const segments = tag.split("/"); - - if (segments.length !== 3 || segments.includes("")) { - core.setFailed( - `Invalid tag: "${tag}". A valid tag must be in the format of "//".` - ); - } - - const modulePathSegmentRegex = /^[a-z0-9]+([._-][a-z0-9]+)*$/; - const moduleFolder = segments[0]; - const moduleName = segments[1]; - - if (!modulePathSegmentRegex.test(moduleFolder)) { - core.setFailed( - `The module folder "${moduleFolder}" in the tag "${tag}" is invalid. It must match the regex "${modulePathSegmentRegex}".` - ); - } - - if (!modulePathSegmentRegex.test(moduleName)) { - core.setFailed( - `The module name "${moduleName}" in the tag "${tag}" is invalid. It must match the regex "${modulePathSegmentRegex}".` - ); - } - - const versionRegex = - /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?$/; - const version = segments[2]; - - if (!versionRegex.test(version)) { - core.setFailed( - `The version "${version}" in the tag "${tag}" is invalid. It must match the regex "${versionRegex}".` - ); - } - - core.setOutput("module_path", `${moduleFolder}/${moduleName}`); - core.setOutput("version", version); - - const readmeLink = `https://github.com/Azure/bicep-registry-modules/tree/${tag}/modules/${moduleFolder}/${moduleName}/README.md`; - core.setOutput("documentation_uri", readmeLink); -} - -module.exports = parseTag; diff --git a/scripts/local/approve-autogenerated-prs.js b/scripts/local/approve-autogenerated-prs.js deleted file mode 100644 index 920d11ac1e..0000000000 --- a/scripts/local/approve-autogenerated-prs.js +++ /dev/null @@ -1,55 +0,0 @@ -/* - - This script approves all auto-generated PRs. It will query interactively for each module. - - Usage: - Install gh from https://cli.github.com/ - Log in to gh - cd repos/bicep-registry-modules - npm i - node scripts/local/approve-autogenerated-prs.js - - - -*/ - -const { - runAsync, - queryUserAsync, - queryRunAsync, -} = require("./util/runAsync.js"); -const { clearScreen, green, yellow, red, reset } = require("./util/colors"); - -const { argv } = require("process"); - -function formatPR(pr) { - return `#${pr.number} (${pr.author.login} ${pr.state} ${pr.labels.map( - (l) => l.name - )}) ${yellow}${pr.title}${reset}`; -} - -async function ApprovePRs() { - const prs = JSON.parse( - await runAsync( - `gh pr list --label "Auto-generated" --state open --limit 500 --json number,author,title,state,labels,statusCheckRollup -S "review:required draft:false"` - ) - ); - - console.log(`${yellow}Found these PRs:${reset}`); - for (pr of prs) { - console.log(formatPR(pr)); - } - console.log(); - - for (pr of prs) { - await queryRunAsync( - [ - `gh pr merge --auto --squash ${pr.number}`, - `gh pr review --approve ${pr.number}`, - ], - `Approve the following PR?${reset}\n${formatPR(pr)}` - ); - } -} - -ApprovePRs(); diff --git a/scripts/local/create-prs.js b/scripts/local/create-prs.js deleted file mode 100644 index e448f40988..0000000000 --- a/scripts/local/create-prs.js +++ /dev/null @@ -1,102 +0,0 @@ -/* - - This script creates a PR for each modules on the local disk that has changes. It will query interactively for each module. - - Requires that gh be installed (https://cli.github.com/) - - Usage: - cd repos/bicep-registry-modules - npm i - - - - make sure you're logged in to gh - node scripts/local/create-prs.js - - - -*/ - -const usage = `Usage: see script comments`; - -const { runAsync, queryRunAsync } = require("./util/runAsync.js"); -const { clearScreen, green, yellow, red, reset } = require("./util/colors"); - -const { argv } = require("process"); - -// eslint-disable-next-line prefer-const -let [branchPrefix, commitPrefix] = argv.slice(2); -if (!branchPrefix || !commitPrefix) { - console.error(usage); - process.exit(1); -} - -branchPrefix = branchPrefix.endsWith("/") - ? branchPrefix.slice(0, branchPrefix.length - 1) - : branchPrefix; -console.log(`${green}branch prefix: ${branchPrefix}${reset}`); -console.log(`${green}commit message: ${commitPrefix}${reset}`); - -async function getChangedModulesAsync() { - const changedModules = (await runAsync(`git status modules`)) - .split("\n") - .filter((line) => line.match(/modified/)) - .map((line) => line.replace(/^.*\smodules\/([^/]+\/[^/]+)\/.*$/g, "$1")) - // dedupe the list - .filter((value, index, self) => self.indexOf(value) === index); - - return changedModules; -} - -async function CreatePRAsync(modulePath) { - console.log( - `${clearScreen}${green}=========== Creating PR for ${modulePath}...${reset}` - ); - - const branchName = `${branchPrefix}/auto/${modulePath}`; - await runAsync(`git checkout -b ${branchName}`); - await runAsync(`git add modules/${modulePath}`); - await runAsync(`git diff --cached`); - - const commitMessage = `${commitPrefix} (${modulePath}) (auto)`; - const prTitle = `${commitPrefix} (${modulePath}) (auto-generated)`; - const prBody = `This PR was created by a script. Please review the changes and merge if they look good.`; - const prSubmitted = await queryRunAsync([ - `git commit -m "${commitMessage}"`, - `git push -u origin ${branchName}`, - `gh pr create --title "${prTitle}" --body "${prBody}" --label "Auto-generated"`, - ]); - - // TODO: Changes get lost for a branch if you say no - - await runAsync(`git checkout main`); - if (prSubmitted) { - await runAsync(`git branch -d ${branchName}`); - } else { - console.log( - `${red}Branch ${branchName} contains the unsubmitted changes.${reset}` - ); - } - - console.log(); -} - -async function CreatePRs() { - const changedModules = await getChangedModulesAsync(); - - const currentBranch = await runAsync(`git symbolic-ref --short HEAD`, false); - console.log(`${green}Current branch: ${currentBranch}${reset}`); - - await runAsync(`git checkout main`); - - try { - for (const modulePath of changedModules) { - await CreatePRAsync(modulePath); - } - } finally { - await runAsync(`git checkout ${currentBranch}`, false); - console.log(`${green}Restored branch to ${currentBranch}${reset}`); - } -} - -CreatePRs(); diff --git a/scripts/local/fix-all-readme-examples.js b/scripts/local/fix-all-readme-examples.js deleted file mode 100644 index 742318ee09..0000000000 --- a/scripts/local/fix-all-readme-examples.js +++ /dev/null @@ -1,25 +0,0 @@ -/* - - This script updates the examples in all README.md files to the *current* version. - - Usage: - cd repos/bicep-registry-modules - npm i - node scripts/local/fix-all-readme-examples.js - -*/ - -const { updateReadmeExamples } = require("./util/updateReadmeExamples.js"); -const { - getLatestModuleVersionsAsync, -} = require("./util/getLatestModuleVersionsAsync"); - -async function regenerateAllAsync() { - const modules = await getLatestModuleVersionsAsync(); - - for (const [modulePath, version] of modules) { - updateReadmeExamples(modulePath, version, version); - } -} - -regenerateAllAsync(); diff --git a/scripts/local/regenerate-all.js b/scripts/local/regenerate-all.js deleted file mode 100644 index aaa1630103..0000000000 --- a/scripts/local/regenerate-all.js +++ /dev/null @@ -1,87 +0,0 @@ -/* - - This script is used to regenerate all the modules in the current repo. Also updates the examples - in the README.md to the *next* version of the module (making it ready for checkin). - - Usage: - cd repos/bicep-registry-modules - npm i - node scripts/local/regenerate-all.js - -*/ - -const { resolve } = require("path"); -const { updateReadmeExamples } = require("./util/updateReadmeExamples.js"); -const { runAsync } = require("./util/runAsync.js"); -const { existsSync } = require("fs"); -const { - getLatestModuleVersionsAsync, -} = require("./util/getLatestModuleVersionsAsync.js"); -const { green, reset, yellow } = require("./util/colors"); -const semver = require("semver"); - -let brm = resolve( - `../bicep/src/Bicep.RegistryModuleTool/Bin/Debug/net7.0/Azure.Bicep.RegistryModuleTool` -); -brm = existsSync(brm) ? brm : brm + ".exe"; -brm = existsSync(brm) ? brm : "brm"; - -console.warn(`Using this brm: ${brm}`); - -function getNextVersion(version) { - return semver.inc(version, "patch"); -} - -async function regenerateAllAsync() { - const modules = await getLatestModuleVersionsAsync(); - - for (const [modulePath, version] of modules) { - var currentDir = process.cwd(); - process.chdir(resolve(`modules/${modulePath}`)); - - try { - let needsGenerate = false; - - try { - console.warn(`${yellow}Validating: ${modulePath}${reset}`); - await runAsync(`${brm} validate`); - } catch (err) { - if ( - /Please run "brm generate"/.test(String(err)) || - /The "summary" property in metadata.json does not match/.test( - String(err) - ) - ) { - needsGenerate = true; - } else { - throw err; - } - } - - if (needsGenerate) { - console.error( - `${yellow}Generating: ${modulePath} (version ${version})${reset}` - ); - await runAsync(`${brm} generate`); - - console.error( - `${yellow}Updating README for ${modulePath} (version ${version})${reset}` - ); - process.chdir(resolve(currentDir)); - await updateReadmeExamples( - modulePath, - version, - getNextVersion(version) - ); - } else { - console.error( - `${green}Does not need regeneration: ${modulePath}${reset}` - ); - } - } finally { - process.chdir(resolve(currentDir)); - } - } -} - -regenerateAllAsync(); diff --git a/scripts/local/util/colors.js b/scripts/local/util/colors.js deleted file mode 100644 index ff60da628e..0000000000 --- a/scripts/local/util/colors.js +++ /dev/null @@ -1,6 +0,0 @@ -exports.red = "\u001b[31m"; -exports.green = "\u001b[32m"; -exports.blue = "\u001b[34m"; -exports.yellow = "\u001b[33m"; -exports.reset = "\u001b[0m"; -exports.clearScreen = "\u001b[2J\u001b[0;0H"; diff --git a/scripts/local/util/getLatestModuleVersionsAsync.js b/scripts/local/util/getLatestModuleVersionsAsync.js deleted file mode 100644 index b8309ac35b..0000000000 --- a/scripts/local/util/getLatestModuleVersionsAsync.js +++ /dev/null @@ -1,46 +0,0 @@ -const { runAsync } = require("./runAsync.js"); - -function parseTag(tag) { - const parseTagScript = require("../../github-actions/parse-tag.js"); - - let modulePath, version; - parseTagScript({ - core: { - setOutput: (key, value) => { - if (key === "version") { - version = value; - } else if (key === "module_path") { - modulePath = value; - } - }, - setFailed: (message) => { - throw new Error(message); - }, - }, - tag, - }); - - return { modulePath, version }; -} - -async function getLatestModuleVersionsAsync() { - const tags = (await runAsync(`git tag -l`, false)) - .split("\n") - .filter((tag) => tag !== ""); - const latestModules = new Map(); - for (const tag of tags) { - const { modulePath, version } = parseTag(tag); - if (!latestModules.has(modulePath)) { - latestModules.set(modulePath, version); - } else { - const currentVersion = latestModules.get(modulePath); - if (version > currentVersion) { - latestModules.set(modulePath, version); - } - } - } - - return Array.from(latestModules); -} - -exports.getLatestModuleVersionsAsync = getLatestModuleVersionsAsync; diff --git a/scripts/local/util/runAsync.js b/scripts/local/util/runAsync.js deleted file mode 100644 index b40a6d0540..0000000000 --- a/scripts/local/util/runAsync.js +++ /dev/null @@ -1,72 +0,0 @@ -let runAll = false; - -const { exec } = require("child_process"); -const { promisify } = require("util"); -const { yellow, red, reset } = require("./colors"); - -const execPromise = promisify(exec); - -async function runAsync(cmd, echo = true) { - if (echo) { - console.log(`${yellow}${cmd}${reset}`); - } - - const response = await execPromise(cmd, {}); - if (echo) { - console.log(`> ${response.stdout}`); - } - return response.stdout; -} - -function queryUserAsync(question) { - const readline = require("readline").createInterface({ - input: process.stdin, - output: process.stdout, - }); - - return new Promise((resolve) => { - readline.question(question, (answer) => { - readline.close(); - resolve(answer); - }); - }); -} - -async function queryRunAsync(cmds, optionalFriendlyPrompt) { - cmds = typeof cmds === "string" ? [cmds] : cmds; - let run = runAll === true; - if (!run) { - const prompt = - `${red}` + - (optionalFriendlyPrompt ?? - `Run the following commands?\n${yellow}${cmds.join("\n")}${reset}?`); - const answer = await queryUserAsync( - `${reset}${prompt} ${red}(y/n/a/q)${reset}` - ); - console.log(`answer: ${answer}`); - - if (answer === "y") { - run = true; - } else if (answer === "a") { - runAll = true; - run = true; - } else if (answer === "q") { - throw new Error("User aborted"); - } - } - - if (run) { - for (const cmd of cmds) { - await runAsync(cmd); - } - - return true; - } else { - return false; - } -} - -exports.runAsync = runAsync; -exports.queryRunAsync = queryRunAsync; -exports.queryUserAsync = queryUserAsync; -exports.runAll = runAll; diff --git a/scripts/local/util/updateReadmeExamples.js b/scripts/local/util/updateReadmeExamples.js deleted file mode 100644 index 1f3bf20840..0000000000 --- a/scripts/local/util/updateReadmeExamples.js +++ /dev/null @@ -1,70 +0,0 @@ -const { readFileSync } = require("fs"); - -// Updates the module version references in the README.md file -function updateReadmeExamples( - modulePath, - currentVersion, // what the current version should be - updateToVersion // update all versions to this -) { - const fs = require("fs"); - const path = require("path"); - const red = "\u001b[31m"; - const green = "\u001b[32m"; - const blue = "\u001b[34m"; - const yellow = "\u001b[33m"; - const reset = "\u001b[0m"; - - console.log(`Updating README.md examples for ${modulePath}...`); - - const readmePath = path.join("./modules", modulePath, "README.md"); - const readmeContent = readFileSync(readmePath, "utf8"); - - const currentModulePath = `br/public:${modulePath}:${currentVersion}`; - const nextModulePath = `br/public:${modulePath}:${updateToVersion}`; - - const versionPattern = "[0-9.a-z]+"; - const anyRefPattern = `br/public:${modulePath}:${versionPattern}`; - - // Look for unexpected versions - let versions = Array.from(readmeContent.matchAll(anyRefPattern)); - versions = Array.from(new Set(versions.map((m) => m[0]))); // dedupe - if (versions.length === 0) { - console.warn( - `${yellow}No module references found in ${readmePath}.${reset}` - ); - return false; - } - - const unexpectedVersions = versions.filter( - (m) => m !== currentModulePath && m !== nextModulePath - ); - if (unexpectedVersions.length > 0) { - console.error( - `... ${red}UNEXPECTED VERSIONS FOUND in ${readmePath}: ${unexpectedVersions}${reset}` - ); - console.error( - currentModulePath == nextModulePath - ? `... Expected ${currentModulePath}` - : `... Expected either ${currentModulePath} or ${nextModulePath}${reset}` - ); - } - - const updatedReadmeContent = readmeContent.replace( - new RegExp(anyRefPattern, "g"), - nextModulePath - ); - if (updatedReadmeContent !== readmeContent) { - console.log( - `... ${green}Updated module references in README.md to ${nextModulePath}.${reset}` - ); - fs.writeFileSync(readmePath, updatedReadmeContent, "utf8"); - return true; - } else { - console.log( - `... ${blue}Module references in README.md are up-to-date.${reset}` - ); - return false; - } -} - -exports.updateReadmeExamples = updateReadmeExamples; From f61b688c91d787e47384144e604c1326234c8c38 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Fri, 12 Apr 2024 10:51:50 +0200 Subject: [PATCH 48/55] Updated encr --- .../tests/e2e/encr/dependencies.bicep | 4 +- .../tests/e2e/encr/dependencies.bicep | 2 +- .../tests/e2e/encr/dependencies.bicep | 2 +- .../dependencies.bicep | 2 +- .../dependencies.bicep | 2 +- .../e2e/accessPolicies/dependencies.bicep | 2 +- .../tests/e2e/defaults/dependencies.bicep | 2 +- .../tests/e2e/max/dependencies.bicep | 2 +- .../tests/e2e/waf-aligned/dependencies.bicep | 2 +- .../image/tests/e2e/max/dependencies.bicep | 2 +- .../tests/e2e/waf-aligned/dependencies.bicep | 2 +- .../tests/e2e/linux.ssecmk/dependencies.bicep | 2 +- .../e2e/windows.ssecmk/dependencies.bicep | 2 +- .../tests/e2e/encr/dependencies.bicep | 2 +- .../tests/e2e/encr/dependencies.bicep | 2 +- .../tests/e2e/azure/dependencies.bicep | 2 +- .../tests/e2e/max/dependencies.bicep | 4 +- .../tests/e2e/waf-aligned/dependencies.bicep | 4 +- .../tests/e2e/max/dependencies2.bicep | 8 +-- .../tests/e2e/encr/dependencies.bicep | 63 ++++++++++--------- .../lab/tests/e2e/max/dependencies.bicep | 2 +- .../tests/e2e/encr/dependencies.bicep | 2 +- .../tests/e2e/encr/dependencies.bicep | 2 +- .../tests/e2e/encr/dependencies.bicep | 2 +- .../dependencies.bicep | 7 ++- .../dependencies.bicep | 7 ++- .../tests/e2e/encrwsai/dependencies.bicep | 2 +- .../tests/e2e/encrwuai/dependencies.bicep | 2 +- 28 files changed, 74 insertions(+), 65 deletions(-) diff --git a/avm/res/app-configuration/configuration-store/tests/e2e/encr/dependencies.bicep b/avm/res/app-configuration/configuration-store/tests/e2e/encr/dependencies.bicep index bd17946f56..8e5006c291 100644 --- a/avm/res/app-configuration/configuration-store/tests/e2e/encr/dependencies.bicep +++ b/avm/res/app-configuration/configuration-store/tests/e2e/encr/dependencies.bicep @@ -21,8 +21,8 @@ resource keyVault 'Microsoft.KeyVault/vaults@2023-02-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true - softDeleteRetentionInDays: 90 + enablePurgeProtection: true // Required for encryption to work + softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true enabledForDeployment: true diff --git a/avm/res/automation/automation-account/tests/e2e/encr/dependencies.bicep b/avm/res/automation/automation-account/tests/e2e/encr/dependencies.bicep index 49d0dfa3aa..859e78741b 100644 --- a/avm/res/automation/automation-account/tests/e2e/encr/dependencies.bicep +++ b/avm/res/automation/automation-account/tests/e2e/encr/dependencies.bicep @@ -21,8 +21,8 @@ resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { name: 'standard' } tenantId: tenant().tenantId + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 - enablePurgeProtection: true enabledForTemplateDeployment: true enabledForDiskEncryption: true enabledForDeployment: true diff --git a/avm/res/batch/batch-account/tests/e2e/encr/dependencies.bicep b/avm/res/batch/batch-account/tests/e2e/encr/dependencies.bicep index 7519eccd2b..7d610a83e7 100644 --- a/avm/res/batch/batch-account/tests/e2e/encr/dependencies.bicep +++ b/avm/res/batch/batch-account/tests/e2e/encr/dependencies.bicep @@ -74,7 +74,7 @@ resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true // Required by batch account + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true diff --git a/avm/res/cognitive-services/account/tests/e2e/system-assigned-cmk-encryption/dependencies.bicep b/avm/res/cognitive-services/account/tests/e2e/system-assigned-cmk-encryption/dependencies.bicep index 64f4ad94b8..a9da625760 100644 --- a/avm/res/cognitive-services/account/tests/e2e/system-assigned-cmk-encryption/dependencies.bicep +++ b/avm/res/cognitive-services/account/tests/e2e/system-assigned-cmk-encryption/dependencies.bicep @@ -31,7 +31,7 @@ resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true // Required by batch account + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true diff --git a/avm/res/cognitive-services/account/tests/e2e/user-assigned-cmk-encryption/dependencies.bicep b/avm/res/cognitive-services/account/tests/e2e/user-assigned-cmk-encryption/dependencies.bicep index 1ad042356a..b12458a9b8 100644 --- a/avm/res/cognitive-services/account/tests/e2e/user-assigned-cmk-encryption/dependencies.bicep +++ b/avm/res/cognitive-services/account/tests/e2e/user-assigned-cmk-encryption/dependencies.bicep @@ -21,7 +21,7 @@ resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true // Required by batch account + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true diff --git a/avm/res/compute/disk-encryption-set/tests/e2e/accessPolicies/dependencies.bicep b/avm/res/compute/disk-encryption-set/tests/e2e/accessPolicies/dependencies.bicep index 4bc293926f..810b6e459f 100644 --- a/avm/res/compute/disk-encryption-set/tests/e2e/accessPolicies/dependencies.bicep +++ b/avm/res/compute/disk-encryption-set/tests/e2e/accessPolicies/dependencies.bicep @@ -21,7 +21,7 @@ resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true // Required by disk encryption set + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true diff --git a/avm/res/compute/disk-encryption-set/tests/e2e/defaults/dependencies.bicep b/avm/res/compute/disk-encryption-set/tests/e2e/defaults/dependencies.bicep index a79f18bab3..19eadf3cfc 100644 --- a/avm/res/compute/disk-encryption-set/tests/e2e/defaults/dependencies.bicep +++ b/avm/res/compute/disk-encryption-set/tests/e2e/defaults/dependencies.bicep @@ -13,7 +13,7 @@ resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true // Required by disk encryption set + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true diff --git a/avm/res/compute/disk-encryption-set/tests/e2e/max/dependencies.bicep b/avm/res/compute/disk-encryption-set/tests/e2e/max/dependencies.bicep index e6e79856d7..bf2bbaace8 100644 --- a/avm/res/compute/disk-encryption-set/tests/e2e/max/dependencies.bicep +++ b/avm/res/compute/disk-encryption-set/tests/e2e/max/dependencies.bicep @@ -21,7 +21,7 @@ resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true // Required by disk encryption set + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true diff --git a/avm/res/compute/disk-encryption-set/tests/e2e/waf-aligned/dependencies.bicep b/avm/res/compute/disk-encryption-set/tests/e2e/waf-aligned/dependencies.bicep index 336e29b226..eb651cd09b 100644 --- a/avm/res/compute/disk-encryption-set/tests/e2e/waf-aligned/dependencies.bicep +++ b/avm/res/compute/disk-encryption-set/tests/e2e/waf-aligned/dependencies.bicep @@ -21,7 +21,7 @@ resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true // Required by disk encryption set + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true diff --git a/avm/res/compute/image/tests/e2e/max/dependencies.bicep b/avm/res/compute/image/tests/e2e/max/dependencies.bicep index 6a26edc6cf..229b7d2262 100644 --- a/avm/res/compute/image/tests/e2e/max/dependencies.bicep +++ b/avm/res/compute/image/tests/e2e/max/dependencies.bicep @@ -155,7 +155,7 @@ resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true // Required for encrption to work + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true diff --git a/avm/res/compute/image/tests/e2e/waf-aligned/dependencies.bicep b/avm/res/compute/image/tests/e2e/waf-aligned/dependencies.bicep index 6a26edc6cf..229b7d2262 100644 --- a/avm/res/compute/image/tests/e2e/waf-aligned/dependencies.bicep +++ b/avm/res/compute/image/tests/e2e/waf-aligned/dependencies.bicep @@ -155,7 +155,7 @@ resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true // Required for encrption to work + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true diff --git a/avm/res/compute/virtual-machine-scale-set/tests/e2e/linux.ssecmk/dependencies.bicep b/avm/res/compute/virtual-machine-scale-set/tests/e2e/linux.ssecmk/dependencies.bicep index 324e66e29f..4d041e8ada 100644 --- a/avm/res/compute/virtual-machine-scale-set/tests/e2e/linux.ssecmk/dependencies.bicep +++ b/avm/res/compute/virtual-machine-scale-set/tests/e2e/linux.ssecmk/dependencies.bicep @@ -50,7 +50,7 @@ resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true // Required by disk encryption set + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true diff --git a/avm/res/compute/virtual-machine/tests/e2e/windows.ssecmk/dependencies.bicep b/avm/res/compute/virtual-machine/tests/e2e/windows.ssecmk/dependencies.bicep index 3ae96a4216..bb849994dd 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/windows.ssecmk/dependencies.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/windows.ssecmk/dependencies.bicep @@ -41,7 +41,7 @@ resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true // Required by disk encryption set + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true diff --git a/avm/res/container-instance/container-group/tests/e2e/encr/dependencies.bicep b/avm/res/container-instance/container-group/tests/e2e/encr/dependencies.bicep index b908867ee2..1a2b461308 100644 --- a/avm/res/container-instance/container-group/tests/e2e/encr/dependencies.bicep +++ b/avm/res/container-instance/container-group/tests/e2e/encr/dependencies.bicep @@ -23,7 +23,7 @@ resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true // Required by batch account + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true diff --git a/avm/res/container-registry/registry/tests/e2e/encr/dependencies.bicep b/avm/res/container-registry/registry/tests/e2e/encr/dependencies.bicep index 3d3446c847..ba949b79ea 100644 --- a/avm/res/container-registry/registry/tests/e2e/encr/dependencies.bicep +++ b/avm/res/container-registry/registry/tests/e2e/encr/dependencies.bicep @@ -46,7 +46,7 @@ resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true // Required by batch account + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true diff --git a/avm/res/container-service/managed-cluster/tests/e2e/azure/dependencies.bicep b/avm/res/container-service/managed-cluster/tests/e2e/azure/dependencies.bicep index e2274a7fbb..86b3297af0 100644 --- a/avm/res/container-service/managed-cluster/tests/e2e/azure/dependencies.bicep +++ b/avm/res/container-service/managed-cluster/tests/e2e/azure/dependencies.bicep @@ -67,7 +67,7 @@ resource keyVault 'Microsoft.KeyVault/vaults@2022-11-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true // Required by nodepool vmss + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true diff --git a/avm/res/databricks/workspace/tests/e2e/max/dependencies.bicep b/avm/res/databricks/workspace/tests/e2e/max/dependencies.bicep index 5bf7118978..ea6c34b09e 100644 --- a/avm/res/databricks/workspace/tests/e2e/max/dependencies.bicep +++ b/avm/res/databricks/workspace/tests/e2e/max/dependencies.bicep @@ -47,7 +47,7 @@ resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true // Required by batch account + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true @@ -73,7 +73,7 @@ resource keyVaultDisk 'Microsoft.KeyVault/vaults@2022-07-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true // Required by batch account + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true diff --git a/avm/res/databricks/workspace/tests/e2e/waf-aligned/dependencies.bicep b/avm/res/databricks/workspace/tests/e2e/waf-aligned/dependencies.bicep index f8aa5aab74..689a482cfd 100644 --- a/avm/res/databricks/workspace/tests/e2e/waf-aligned/dependencies.bicep +++ b/avm/res/databricks/workspace/tests/e2e/waf-aligned/dependencies.bicep @@ -47,7 +47,7 @@ resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true // Required by batch account + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true @@ -73,7 +73,7 @@ resource keyVaultDisk 'Microsoft.KeyVault/vaults@2022-07-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true // Required by batch account + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true diff --git a/avm/res/db-for-my-sql/flexible-server/tests/e2e/max/dependencies2.bicep b/avm/res/db-for-my-sql/flexible-server/tests/e2e/max/dependencies2.bicep index 0077f627ce..2966ac2358 100644 --- a/avm/res/db-for-my-sql/flexible-server/tests/e2e/max/dependencies2.bicep +++ b/avm/res/db-for-my-sql/flexible-server/tests/e2e/max/dependencies2.bicep @@ -30,8 +30,8 @@ resource keyVault 'Microsoft.KeyVault/vaults@2023-02-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true - softDeleteRetentionInDays: 90 + enablePurgeProtection: true // Required for encryption to work + softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true enabledForDeployment: true @@ -74,8 +74,8 @@ resource geoBackupKeyVault 'Microsoft.KeyVault/vaults@2023-02-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true - softDeleteRetentionInDays: 90 + enablePurgeProtection: true // Required for encryption to work + softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true enabledForDeployment: true diff --git a/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/encr/dependencies.bicep b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/encr/dependencies.bicep index 52be6351dc..367f400a42 100644 --- a/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/encr/dependencies.bicep +++ b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/encr/dependencies.bicep @@ -8,44 +8,47 @@ param keyVaultName string param managedIdentityName string resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { - name: managedIdentityName - location: location + name: managedIdentityName + location: location } resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = { - name: keyVaultName - location: location - properties: { - sku: { - family: 'A' - name: 'standard' - } - tenantId: tenant().tenantId - enablePurgeProtection: true - softDeleteRetentionInDays: 7 - enabledForTemplateDeployment: true - enabledForDiskEncryption: true - enabledForDeployment: true - enableRbacAuthorization: true - accessPolicies: [] + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' } - - resource key 'keys@2023-07-01' = { - name: 'keyEncryptionKey' - properties: { - kty: 'RSA' - } + tenantId: tenant().tenantId + enablePurgeProtection: true // Required for encryption to work + softDeleteRetentionInDays: 7 + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } + + resource key 'keys@2023-07-01' = { + name: 'keyEncryptionKey' + properties: { + kty: 'RSA' } + } } resource keyPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid('msi-${keyVault::key.id}-${location}-${managedIdentity.id}-Key-Reader-RoleAssignment') - scope: keyVault::key - properties: { - principalId: managedIdentity.properties.principalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424') // Key Vault Crypto User - principalType: 'ServicePrincipal' - } + name: guid('msi-${keyVault::key.id}-${location}-${managedIdentity.id}-Key-Reader-RoleAssignment') + scope: keyVault::key + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '12338af0-0e69-4776-bea7-57ae8d297424' + ) // Key Vault Crypto User + principalType: 'ServicePrincipal' + } } @description('The resource ID of the created Managed Identity.') diff --git a/avm/res/dev-test-lab/lab/tests/e2e/max/dependencies.bicep b/avm/res/dev-test-lab/lab/tests/e2e/max/dependencies.bicep index 376758c41c..5e1c0b1d25 100644 --- a/avm/res/dev-test-lab/lab/tests/e2e/max/dependencies.bicep +++ b/avm/res/dev-test-lab/lab/tests/e2e/max/dependencies.bicep @@ -32,7 +32,7 @@ resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true // Required for encrption to work + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true diff --git a/avm/res/event-hub/namespace/tests/e2e/encr/dependencies.bicep b/avm/res/event-hub/namespace/tests/e2e/encr/dependencies.bicep index 6c4085b1e5..c8d5689b90 100644 --- a/avm/res/event-hub/namespace/tests/e2e/encr/dependencies.bicep +++ b/avm/res/event-hub/namespace/tests/e2e/encr/dependencies.bicep @@ -46,7 +46,7 @@ resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true // Required by event hub namespace + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true diff --git a/avm/res/machine-learning-services/workspace/tests/e2e/encr/dependencies.bicep b/avm/res/machine-learning-services/workspace/tests/e2e/encr/dependencies.bicep index 4e41990054..99e9ed9814 100644 --- a/avm/res/machine-learning-services/workspace/tests/e2e/encr/dependencies.bicep +++ b/avm/res/machine-learning-services/workspace/tests/e2e/encr/dependencies.bicep @@ -24,7 +24,7 @@ resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true // Required for CMK + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true diff --git a/avm/res/service-bus/namespace/tests/e2e/encr/dependencies.bicep b/avm/res/service-bus/namespace/tests/e2e/encr/dependencies.bicep index 5afdae26cd..c8d5689b90 100644 --- a/avm/res/service-bus/namespace/tests/e2e/encr/dependencies.bicep +++ b/avm/res/service-bus/namespace/tests/e2e/encr/dependencies.bicep @@ -46,7 +46,7 @@ resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true // Required by service bus namespace + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true diff --git a/avm/res/storage/storage-account/tests/e2e/system-assigned-cmk-encryption/dependencies.bicep b/avm/res/storage/storage-account/tests/e2e/system-assigned-cmk-encryption/dependencies.bicep index 287edca40f..26d25098d8 100644 --- a/avm/res/storage/storage-account/tests/e2e/system-assigned-cmk-encryption/dependencies.bicep +++ b/avm/res/storage/storage-account/tests/e2e/system-assigned-cmk-encryption/dependencies.bicep @@ -38,7 +38,7 @@ resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true @@ -60,7 +60,10 @@ resource keyPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { scope: keyVault::key properties: { principalId: storageAccount.identity.principalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424') // Key Vault Crypto User + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '12338af0-0e69-4776-bea7-57ae8d297424' + ) // Key Vault Crypto User principalType: 'ServicePrincipal' } } diff --git a/avm/res/storage/storage-account/tests/e2e/user-assigned-cmk-encryption/dependencies.bicep b/avm/res/storage/storage-account/tests/e2e/user-assigned-cmk-encryption/dependencies.bicep index f01760e1ff..a2f946fa9c 100644 --- a/avm/res/storage/storage-account/tests/e2e/user-assigned-cmk-encryption/dependencies.bicep +++ b/avm/res/storage/storage-account/tests/e2e/user-assigned-cmk-encryption/dependencies.bicep @@ -21,7 +21,7 @@ resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true @@ -89,7 +89,10 @@ resource keyPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { scope: keyVault::key properties: { principalId: managedIdentity.properties.principalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424') // Key Vault Crypto User + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '12338af0-0e69-4776-bea7-57ae8d297424' + ) // Key Vault Crypto User principalType: 'ServicePrincipal' } } diff --git a/avm/res/synapse/workspace/tests/e2e/encrwsai/dependencies.bicep b/avm/res/synapse/workspace/tests/e2e/encrwsai/dependencies.bicep index 6d7a736f40..d74453b7c8 100644 --- a/avm/res/synapse/workspace/tests/e2e/encrwsai/dependencies.bicep +++ b/avm/res/synapse/workspace/tests/e2e/encrwsai/dependencies.bicep @@ -16,7 +16,7 @@ resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true diff --git a/avm/res/synapse/workspace/tests/e2e/encrwuai/dependencies.bicep b/avm/res/synapse/workspace/tests/e2e/encrwuai/dependencies.bicep index 04f775602e..487efa3cbe 100644 --- a/avm/res/synapse/workspace/tests/e2e/encrwuai/dependencies.bicep +++ b/avm/res/synapse/workspace/tests/e2e/encrwuai/dependencies.bicep @@ -24,7 +24,7 @@ resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { name: 'standard' } tenantId: tenant().tenantId - enablePurgeProtection: true + enablePurgeProtection: true // Required for encryption to work softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true enabledForDiskEncryption: true From 7ae8786f6dfb9d31f1bfef4ff13c45fd979851e0 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Sat, 20 Apr 2024 09:48:47 +0200 Subject: [PATCH 49/55] Undid changes that should be in branch in main --- ...rule.yml => avm.platform.check.psrule.yml} | 2 +- ...=> avm.platform.manage-workflow-issue.yml} | 0 ...h-tag.yml => avm.platform.publish-tag.yml} | 2 +- ...orm.set-avm-github-issue-owner-config.yml} | 2 +- ...vm.platform.sync-repo-labels-from-csv.yml} | 2 +- ... => avm.platform.toggle-avm-workflows.yml} | 2 +- .../workflows/fork-on-push-brm-generate.yml | 92 +++ .../fork-on-push-format-workflow.yml | 49 ++ .github/workflows/get-changed-module.yml | 26 + ...s.yml => on-pull-request-check-labels.yml} | 2 +- ...yml => on-pull-request-check-pr-title.yml} | 2 +- .github/workflows/on-pull-request.yml | 83 +++ .github/workflows/on-push-main.yml | 63 ++ .github/workflows/publish-module.yml | 126 ++++ .../azure-pipelines/Find-ChangedModule.ps1 | 53 ++ scripts/azure-pipelines/Get-TargetScope.ps1 | 35 + scripts/azure-pipelines/Get-TestFile.ps1 | 21 + .../azure-pipelines/New-TestResourceGroup.ps1 | 51 ++ .../Remove-TestResourceGroup.ps1 | 80 +++ .../utils/AzurePipelinesUtils.psm1 | 33 + .../utils/AzureResourceUtils.psm1 | 596 ++++++++++++++++++ scripts/github-actions/create-tag.js | 59 ++ scripts/github-actions/get-changed-module.js | 81 +++ scripts/github-actions/parse-tag.js | 50 ++ scripts/local/approve-autogenerated-prs.js | 55 ++ scripts/local/create-prs.js | 102 +++ scripts/local/fix-all-readme-examples.js | 25 + scripts/local/regenerate-all.js | 87 +++ scripts/local/util/colors.js | 6 + .../util/getLatestModuleVersionsAsync.js | 46 ++ scripts/local/util/runAsync.js | 72 +++ scripts/local/util/updateReadmeExamples.js | 70 ++ 32 files changed, 1968 insertions(+), 7 deletions(-) rename .github/workflows/{platform.check.psrule.yml => avm.platform.check.psrule.yml} (99%) rename .github/workflows/{platform.manage-workflow-issue.yml => avm.platform.manage-workflow-issue.yml} (100%) rename .github/workflows/{platform.publish-tag.yml => avm.platform.publish-tag.yml} (99%) rename .github/workflows/{platform.set-avm-github-issue-owner-config.yml => avm.platform.set-avm-github-issue-owner-config.yml} (96%) rename .github/workflows/{platform.sync-repo-labels-from-csv.yml => avm.platform.sync-repo-labels-from-csv.yml} (95%) rename .github/workflows/{platform.toggle-avm-workflows.yml => avm.platform.toggle-avm-workflows.yml} (97%) create mode 100644 .github/workflows/fork-on-push-brm-generate.yml create mode 100644 .github/workflows/fork-on-push-format-workflow.yml create mode 100644 .github/workflows/get-changed-module.yml rename .github/workflows/{platform.on-pull-request-check-labels.yml => on-pull-request-check-labels.yml} (95%) rename .github/workflows/{platform.on-pull-request-check-pr-title.yml => on-pull-request-check-pr-title.yml} (88%) create mode 100644 .github/workflows/on-pull-request.yml create mode 100644 .github/workflows/on-push-main.yml create mode 100644 .github/workflows/publish-module.yml create mode 100644 scripts/azure-pipelines/Find-ChangedModule.ps1 create mode 100644 scripts/azure-pipelines/Get-TargetScope.ps1 create mode 100644 scripts/azure-pipelines/Get-TestFile.ps1 create mode 100644 scripts/azure-pipelines/New-TestResourceGroup.ps1 create mode 100644 scripts/azure-pipelines/Remove-TestResourceGroup.ps1 create mode 100644 scripts/azure-pipelines/utils/AzurePipelinesUtils.psm1 create mode 100644 scripts/azure-pipelines/utils/AzureResourceUtils.psm1 create mode 100644 scripts/github-actions/create-tag.js create mode 100644 scripts/github-actions/get-changed-module.js create mode 100644 scripts/github-actions/parse-tag.js create mode 100644 scripts/local/approve-autogenerated-prs.js create mode 100644 scripts/local/create-prs.js create mode 100644 scripts/local/fix-all-readme-examples.js create mode 100644 scripts/local/regenerate-all.js create mode 100644 scripts/local/util/colors.js create mode 100644 scripts/local/util/getLatestModuleVersionsAsync.js create mode 100644 scripts/local/util/runAsync.js create mode 100644 scripts/local/util/updateReadmeExamples.js diff --git a/.github/workflows/platform.check.psrule.yml b/.github/workflows/avm.platform.check.psrule.yml similarity index 99% rename from .github/workflows/platform.check.psrule.yml rename to .github/workflows/avm.platform.check.psrule.yml index 9c60895944..6a61e8bacd 100644 --- a/.github/workflows/platform.check.psrule.yml +++ b/.github/workflows/avm.platform.check.psrule.yml @@ -1,4 +1,4 @@ -name: .Platform - Check PSRule +name: "avm.platform.check.psrule" on: workflow_dispatch: diff --git a/.github/workflows/platform.manage-workflow-issue.yml b/.github/workflows/avm.platform.manage-workflow-issue.yml similarity index 100% rename from .github/workflows/platform.manage-workflow-issue.yml rename to .github/workflows/avm.platform.manage-workflow-issue.yml diff --git a/.github/workflows/platform.publish-tag.yml b/.github/workflows/avm.platform.publish-tag.yml similarity index 99% rename from .github/workflows/platform.publish-tag.yml rename to .github/workflows/avm.platform.publish-tag.yml index 1bde3c4950..194531cad2 100644 --- a/.github/workflows/platform.publish-tag.yml +++ b/.github/workflows/avm.platform.publish-tag.yml @@ -1,4 +1,4 @@ -name: .Platform - Publish tag +name: "avm.platform.publish-tag" on: workflow_dispatch: diff --git a/.github/workflows/platform.set-avm-github-issue-owner-config.yml b/.github/workflows/avm.platform.set-avm-github-issue-owner-config.yml similarity index 96% rename from .github/workflows/platform.set-avm-github-issue-owner-config.yml rename to .github/workflows/avm.platform.set-avm-github-issue-owner-config.yml index 306ced95b9..84f3f7b138 100644 --- a/.github/workflows/platform.set-avm-github-issue-owner-config.yml +++ b/.github/workflows/avm.platform.set-avm-github-issue-owner-config.yml @@ -1,5 +1,5 @@ # Workflow for notifying and assigning issues on creation -name: .Platform - Set GitHub issue owner config +name: .Platform - Set AVM GitHub issue owner config on: issues: diff --git a/.github/workflows/platform.sync-repo-labels-from-csv.yml b/.github/workflows/avm.platform.sync-repo-labels-from-csv.yml similarity index 95% rename from .github/workflows/platform.sync-repo-labels-from-csv.yml rename to .github/workflows/avm.platform.sync-repo-labels-from-csv.yml index 893a9ec3fc..d33fb79970 100644 --- a/.github/workflows/platform.sync-repo-labels-from-csv.yml +++ b/.github/workflows/avm.platform.sync-repo-labels-from-csv.yml @@ -1,5 +1,5 @@ # Workflow for syncing CSV labels to GitHub Labels -name: .Platform - Sync repo labels from CSV +name: avm.platform.sync-repo-labels-from-csv on: schedule: diff --git a/.github/workflows/platform.toggle-avm-workflows.yml b/.github/workflows/avm.platform.toggle-avm-workflows.yml similarity index 97% rename from .github/workflows/platform.toggle-avm-workflows.yml rename to .github/workflows/avm.platform.toggle-avm-workflows.yml index 468f942a5b..04381bea14 100644 --- a/.github/workflows/platform.toggle-avm-workflows.yml +++ b/.github/workflows/avm.platform.toggle-avm-workflows.yml @@ -1,4 +1,4 @@ -name: .Platform - Toggle AVM workflows +name: "avm.platform.toggle-avm-workflows" on: workflow_dispatch: diff --git a/.github/workflows/fork-on-push-brm-generate.yml b/.github/workflows/fork-on-push-brm-generate.yml new file mode 100644 index 0000000000..06a832098c --- /dev/null +++ b/.github/workflows/fork-on-push-brm-generate.yml @@ -0,0 +1,92 @@ +name: On push run brm generate # fork only, optional + +on: + push: + branches-ignore: + - main + paths: + - modules/**/*.bicep + - modules/**/*.sh + - modules/**/metadata.json + +jobs: + check-secret: + runs-on: ubuntu-latest + outputs: + my-key: ${{ steps.my-key.outputs.defined }} + steps: + - id: my-key + if: "${{ env.MY_KEY != '' }}" + run: echo "defined=true" >> $GITHUB_OUTPUT + env: + MY_KEY: ${{ secrets.PAT }} + + get-module-to-validate: + needs: [check-secret] + if: needs.check-secret.outputs.my-key == 'true' + uses: ./.github/workflows/get-changed-module.yml + + push-brm-generate: + runs-on: ubuntu-latest + needs: get-module-to-validate + if: needs.get-module-to-validate.outputs.module_dir + steps: + - uses: actions/checkout@v4 + with: + token: ${{ secrets.PAT }} # A PAT must be used to re-trigger workflows after commit. This PAT should NOT have the workflow scope. + + # Adding a step to explicitly install the latest Bicep CLI because there is + # always a delay in updating Bicep CLI in the job runner environments. + - name: Install the latest Bicep CLI + run: | + curl -Lo bicep https://github.com/Azure/bicep/releases/latest/download/bicep-linux-x64 + chmod +x ./bicep + sudo mv ./bicep /usr/local/bin/bicep + bicep --version + - uses: jungwinter/split@master + id: branch + with: + msg: ${{ needs.get-module-to-validate.outputs.module_dir }} + separator: "/" + maxsplit: -1 + + - name: Bump version and push tag + id: tag_version + uses: mathieudutour/github-tag-action@v6.2 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + tag_prefix: "${{ steps.branch.outputs._1 }}/${{ steps.branch.outputs._2 }}/" + dry_run: true + default_bump: false + + - name: Update Version + if: steps.tag_version.outputs.release_type + shell: bash + env: + OLD_VERSION: ${{ steps.tag_version.outputs.previous_version }} + VERSION: ${{ steps.tag_version.outputs.new_version }} + SAMPLEFOLDER_PATH: ${{ needs.get-module-to-validate.outputs.module_dir }} + MODULE: "${{ steps.branch.outputs._1 }}/${{ steps.branch.outputs._2 }}" + run: | + cd $SAMPLEFOLDER_PATH + NEW_VERSION=${VERSION%%-*} + # The following sed command searches for the specified module in README.md and replaces its version number + # (in formats X.Y.Z, X.Y, X, or a single lowercase letter) or adds a version number if it's not present. + REGEX=$(echo "s|($MODULE:)([0-9]+(\.[0-9]+){0,2})?|\1$NEW_VERSION|") + sed -ri "$REGEX" "README.md" || exit 1 + + - name: Run brm generate + env: + SAMPLEFOLDER_PATH: ${{ needs.get-module-to-validate.outputs.module_dir }} + run: | + dotnet tool install --global Azure.Bicep.RegistryModuleTool + + cd $SAMPLEFOLDER_PATH + brm generate + + - uses: EndBug/add-and-commit@v9 + with: + message: Autogenerate Bicep Files + committer_name: GitHub Actions + committer_email: actions@github.com + add: modules diff --git a/.github/workflows/fork-on-push-format-workflow.yml b/.github/workflows/fork-on-push-format-workflow.yml new file mode 100644 index 0000000000..263a03088f --- /dev/null +++ b/.github/workflows/fork-on-push-format-workflow.yml @@ -0,0 +1,49 @@ +name: On push format workflow files # fork only, optional + +on: + workflow_dispatch: + push: + branches-ignore: + - main + paths: + - .github/** + - CONTRIBUTING.md + +jobs: + check-secret: + runs-on: ubuntu-latest + outputs: + my-key: ${{ steps.my-key.outputs.defined }} + steps: + - id: my-key + if: "${{ env.MY_KEY != '' }}" + run: echo "defined=true" >> $GITHUB_OUTPUT + env: + MY_KEY: ${{ secrets.WORKFLOW_PAT }} + + push-prettier: + runs-on: ubuntu-latest + needs: [check-secret] + if: needs.check-secret.outputs.my-key == 'true' + steps: + - uses: actions/checkout@v4 + with: + token: ${{ secrets.WORKFLOW_PAT }} # A WORKFLOW_PAT must be used to re-trigger workflows after commit. This PAT must have the workflow scope. This is not generally recommended. + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "16" + + - name: Install packages + run: npm ci + + - name: Check formatting + run: npm run prettier --write . + + - uses: EndBug/add-and-commit@v9 + with: + message: Autogenerate Bicep Files + committer_name: GitHub Actions + committer_email: actions@github.com + add: .github CONTRIBUTING.md diff --git a/.github/workflows/get-changed-module.yml b/.github/workflows/get-changed-module.yml new file mode 100644 index 0000000000..696faa3062 --- /dev/null +++ b/.github/workflows/get-changed-module.yml @@ -0,0 +1,26 @@ +name: Get changed module + +on: + workflow_call: + outputs: + module_dir: + description: "The directory of the added or updated module. Empty if no module was changed." + value: ${{ jobs.main.outputs.module_dir }} + +jobs: + main: + runs-on: ubuntu-latest + outputs: + module_dir: ${{ steps.get-changed-module.outputs.result }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Get changed module + uses: actions/github-script@v7 + id: get-changed-module + with: + result-encoding: string + script: | + const script = require("./scripts/github-actions/get-changed-module.js") + return await script({ require, github, context, core }) diff --git a/.github/workflows/platform.on-pull-request-check-labels.yml b/.github/workflows/on-pull-request-check-labels.yml similarity index 95% rename from .github/workflows/platform.on-pull-request-check-labels.yml rename to .github/workflows/on-pull-request-check-labels.yml index 805c215f41..011c0790e6 100644 --- a/.github/workflows/platform.on-pull-request-check-labels.yml +++ b/.github/workflows/on-pull-request-check-labels.yml @@ -1,4 +1,4 @@ -name: .Platform - Check Labels +name: Check Labels on: pull_request_target: diff --git a/.github/workflows/platform.on-pull-request-check-pr-title.yml b/.github/workflows/on-pull-request-check-pr-title.yml similarity index 88% rename from .github/workflows/platform.on-pull-request-check-pr-title.yml rename to .github/workflows/on-pull-request-check-pr-title.yml index ae9b65137f..a5e349f52c 100644 --- a/.github/workflows/platform.on-pull-request-check-pr-title.yml +++ b/.github/workflows/on-pull-request-check-pr-title.yml @@ -1,4 +1,4 @@ -name: .Platform - Semantic PR Check +name: "Semantic PR Check" on: pull_request_target: diff --git a/.github/workflows/on-pull-request.yml b/.github/workflows/on-pull-request.yml new file mode 100644 index 0000000000..588b11f8ea --- /dev/null +++ b/.github/workflows/on-pull-request.yml @@ -0,0 +1,83 @@ +name: On pull request + +on: + pull_request: + branches: + - main + +jobs: + get-module-to-validate: + uses: ./.github/workflows/get-changed-module.yml + + validate-module-files: + runs-on: ubuntu-latest + needs: get-module-to-validate + if: needs.get-module-to-validate.outputs.module_dir + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 7.0.x + + # Adding a step to explicitly install the latest Bicep CLI because there is + # always a delay in updating Bicep CLI in the job runner environments. + - name: Install the latest Bicep CLI + run: | + curl -Lo bicep https://github.com/Azure/bicep/releases/latest/download/bicep-linux-x64 + chmod +x ./bicep + sudo mv ./bicep /usr/local/bin/bicep + bicep --version + + - name: Install Bicep registry module tool + run: dotnet tool install --global Azure.Bicep.RegistryModuleTool + + - name: Validate module files + run: brm validate + working-directory: ${{ needs.get-module-to-validate.outputs.module_dir }} + + - run: mv ${{ needs.get-module-to-validate.outputs.module_dir }}/main.json ${{ needs.get-module-to-validate.outputs.module_dir }}/mainTemplate.json + + - name: Run ARM-TTK (optional) + uses: microsoft/action-armttk@v1 + continue-on-error: true + with: + workdir: "${{ needs.get-module-to-validate.outputs.module_dir }}" + + shellcheck: + name: runner + runs-on: ubuntu-latest + needs: get-module-to-validate + if: needs.get-module-to-validate.outputs.module_dir + steps: + - uses: actions/checkout@v4 + + - name: shellcheck + uses: reviewdog/action-shellcheck@v1 + continue-on-error: true + with: + github_token: ${{ secrets.PAT || github.token }} + reporter: github-pr-review # Change reporter. + path: ${{ needs.get-module-to-validate.outputs.module_dir }} + + validate-non-module-files: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "16" + + - name: Install packages + run: npm ci + + - name: Lint + run: npm run lint + + - name: Check formatting + run: npm run prettier:check diff --git a/.github/workflows/on-push-main.yml b/.github/workflows/on-push-main.yml new file mode 100644 index 0000000000..1e862b6a18 --- /dev/null +++ b/.github/workflows/on-push-main.yml @@ -0,0 +1,63 @@ +name: On push main + +on: + push: + branches: + - main + +jobs: + get-module-to-publish: + uses: ./.github/workflows/get-changed-module.yml + + create-tag: + runs-on: ubuntu-latest + needs: get-module-to-publish + if: ${{ needs.get-module-to-publish.outputs.module_dir }} + outputs: + tag: ${{ steps.create-tag.outputs.result }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install semver + run: npm install semver + + - name: Get base and head versions + id: get-versions + env: + PublicRelease: true + run: | + echo ::set-output name=base_version::$(nbgv get-version ${{ github.event.before }} --format json | jq '.SemVer2') + echo ::set-output name=head_version::$(nbgv get-version ${{ github.event.after }} --format json | jq '.SemVer2') + working-directory: ${{ needs.get-module-to-publish.outputs.module_dir }} + + - name: Create tag + id: create-tag + uses: actions/github-script@v7 + with: + result-encoding: string + script: | + const script = require("./scripts/github-actions/create-tag.js") + return await script({ + require, + github, + context, + core, + moduleDir: "${{ needs.get-module-to-publish.outputs.module_dir }}", + baseVersion: ${{ steps.get-versions.outputs.base_version }}, + headVersion: ${{ steps.get-versions.outputs.head_version }}, + }) + + publish-module: + needs: create-tag + if: needs.create-tag.outputs.tag + uses: ./.github/workflows/publish-module.yml + with: + tag: ${{ needs.create-tag.outputs.tag }} + secrets: + PUBLISH_CLIENT_ID: ${{ secrets.PUBLISH_CLIENT_ID }} + PUBLISH_TENANT_ID: ${{ secrets.PUBLISH_TENANT_ID }} + PUBLISH_SUBSCRIPTION_ID: ${{ secrets.PUBLISH_SUBSCRIPTION_ID }} + PUBLISH_REGISTRY_SERVER: ${{ secrets.PUBLISH_REGISTRY_SERVER }} diff --git a/.github/workflows/publish-module.yml b/.github/workflows/publish-module.yml new file mode 100644 index 0000000000..d573607b20 --- /dev/null +++ b/.github/workflows/publish-module.yml @@ -0,0 +1,126 @@ +name: Publish module + +on: + workflow_call: + inputs: + tag: + description: "The git tag of the module to publish." + required: true + type: string + secrets: + # Secrets must be passed from the caller workflow explicitly. + PUBLISH_CLIENT_ID: + required: true + PUBLISH_TENANT_ID: + required: true + PUBLISH_SUBSCRIPTION_ID: + required: true + PUBLISH_REGISTRY_SERVER: + required: true + workflow_dispatch: + inputs: + tag: + description: "The git tag of the module to publish." + required: true + type: string + +permissions: + id-token: write + contents: read + +jobs: + main: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Parse tag + id: parse-tag + uses: actions/github-script@v7 + with: + result-encoding: string + script: | + const script = require("./scripts/github-actions/parse-tag.js") + const tag = "${{ github.event.inputs.tag || inputs.tag }}" + script({ core, tag }) + + - name: Checkout tag + uses: actions/checkout@v4 + with: + # Input contexts for workflow_dispatch and workflow_call are inconsistent. + # For workflow_dispatch, use ${{ github.event.inputs. }} + # For workflow_call, use ${{ inputs. }} + ref: ${{ github.event.inputs.tag || inputs.tag }} + + - name: Log in to Azure + uses: azure/login@v2 + with: + client-id: ${{ secrets.PUBLISH_CLIENT_ID }} + tenant-id: ${{ secrets.PUBLISH_TENANT_ID }} + subscription-id: ${{ secrets.PUBLISH_SUBSCRIPTION_ID }} + + # Adding a step to explicitly install the latest Bicep CLI because there is + # always a delay in updating Bicep CLI in the job runner environments. + - name: Install the latest Bicep CLI + run: | + curl -Lo bicep https://github.com/Azure/bicep/releases/latest/download/bicep-linux-x64 + chmod +x ./bicep + sudo mv ./bicep /usr/local/bin/bicep + bicep --version + + - name: Publish module + run: bicep publish "modules/${{ steps.parse-tag.outputs.module_path }}/main.bicep" --target "br:${{ secrets.PUBLISH_REGISTRY_SERVER }}/public/bicep/${{ steps.parse-tag.outputs.module_path }}:${{ steps.parse-tag.outputs.version }}" --documentationUri "${{ steps.parse-tag.outputs.documentation_uri }}" --with-source --force + + - name: Validate publish + run: | + Version="${{ steps.parse-tag.outputs.version }}" + ModulePath="${{ steps.parse-tag.outputs.module_path }}" + + time_limit_seconds=3600 + end_time=$((SECONDS+time_limit_seconds)) + retry_seconds=5 + + while true; do + CATALOG=https://mcr.microsoft.com/v2/_catalog + echo curl -sLo catalog $CATALOG + curl -sLo catalog $CATALOG + cat catalog | fgrep "bicep/" > bicepcatalog + echo "Bicep modules found in MCR catalog:" + cat bicepcatalog + + if fgrep -q "\"bicep/$ModulePath\"" catalog; then + echo "Passed: Found module $ModulePath in the MCR catalog" + break + else + echo "Error: Module $ModulePath is not in the MCR catalog. Retrying in $retry_seconds seconds" + sleep $retry_seconds + fi + + if [ $SECONDS -ge $end_time ]; then + echo "Time limit reached. Failed to validate publish within the specified time." + exit 1 + fi + done + + while true; do + TAGS=https://mcr.microsoft.com/v2/bicep/$ModulePath/tags/list + echo curl -sLo tags $TAGS + curl -sLo tags $TAGS + echo "Tags:" + cat tags + + echo + if fgrep -q "$Version" tags; then + echo "Passed: Found new tag $Version for published module" + break + else + echo "Error: Coud not find new tag $Version for published module. Retrying in $retry_seconds seconds" + sleep $retry_seconds + fi + + if [ $SECONDS -ge $end_time ]; then + echo "Time limit reached. Failed to validate publish within the specified time." + exit 1 + fi + done diff --git a/scripts/azure-pipelines/Find-ChangedModule.ps1 b/scripts/azure-pipelines/Find-ChangedModule.ps1 new file mode 100644 index 0000000000..000c25e6c2 --- /dev/null +++ b/scripts/azure-pipelines/Find-ChangedModule.ps1 @@ -0,0 +1,53 @@ +<# +.SYNOPSIS + Finds changed module. + +.DESCRIPTION + The script finds the changed module in the pull request that triggers the pipeline. + +.PARAMETER GitHubToken + The GitHub personal access token to use for authentication. + +.PARAMETER Repository + The Bicep registry module repository name. + +.PARAMETER PullRequestNumber + The pull request number. +#> +param( + # TODO: remove the PAT once the Bicep registry repo goes public. + [Parameter(mandatory = $True)] + [string]$GitHubToken, + + [Parameter(mandatory = $True)] + [string]$Repository, + + [Parameter(mandatory = $True)] + [string]$PullRequestNumber +) + +Import-Module .\scripts\azure-pipelines\utils\AzurePipelinesUtils.psm1 -Force + +$pullRequestFiles = Invoke-RestMethod ` + -Uri "https://api.github.com/repos/$Repository/pulls/$PullRequestNumber/files" ` + -Authentication OAuth ` + -Token (ConvertTo-SecureString $GitHubToken -AsPlainText -Force) + +$separator = [IO.Path]::DirectorySeparatorChar +$changedModuleDirectories = @( + $pullRequestFiles | + Where-Object { $_.filename.StartsWith("modules") } | # Get changed module files. + ForEach-Object { Split-Path $_.filename } | # Get directories of changed module files. + Where-Object { $_.Split($separator).Length -ge 3 } | # Ignore changes outside a module folder, e.g., modules/bicepconfig.json. + ForEach-Object { + $_.Split($separator) | + Select-Object -First 3 | + Join-String -Separator $separator + } | # Get module root directories. + Select-Object -Unique | # Remove duplicates. + Where-Object { Test-Path $_ } # Ignore removed directories. +) + +# If no test file or more than one test file was found, set an empty string to skip the subsequent steps. +$changedModuleDirectory = if ($changedModuleDirectories.Length -eq 1) { $changedModuleDirectories[0] } else { "" } +Set-AzurePipelinesVariable -VariableName "ChangedModuleDirectory" -VariableValue $changedModuleDirectory diff --git a/scripts/azure-pipelines/Get-TargetScope.ps1 b/scripts/azure-pipelines/Get-TargetScope.ps1 new file mode 100644 index 0000000000..52c872c648 --- /dev/null +++ b/scripts/azure-pipelines/Get-TargetScope.ps1 @@ -0,0 +1,35 @@ +<# +.SYNOPSIS + Gets the target scope of the module. + +.DESCRIPTION + The script gets the target scope of the main module file. + +.PARAMETER ChangedModuleDirectory + The directory of the changed module. +#> +param( + [Parameter(mandatory = $True)] + [string]$ChangedModuleDirectory +) + +Import-Module .\scripts\azure-pipelines\utils\AzurePipelinesUtils.psm1 -Force + +$armTemplateFilePath = Join-Path $ChangedModuleDirectory -ChildPath "main.json" +$targetScope = "" + +if (Test-Path $armTemplateFilePath -PathType "Leaf") { + $armTemplateFile = Get-Content -Raw -Path $armTemplateFilePath | ConvertFrom-Json + $armTemplateSchema = $armTemplateFile.'$schema' + $armTemplateSchemaPattern = "https?://schema\.management\.azure\.com/schemas/[0-9a-zA-Z-]+/{0}Template\.json#?" + + $targetScope = switch -Regex ($armTemplateSchema) { + $($armTemplateSchemaPattern -f "deployment") { "resourceGroup" } + $($armTemplateSchemaPattern -f "subscriptionDeployment") { "subscription" } + $($armTemplateSchemaPattern -f "managementGroupDeployment") { "managementGroup" } + $($armTemplateSchemaPattern -f "tenantDeployment") { "tenant" } + default { "" } + } +} + +Set-AzurePipelinesVariable -VariableName "TargetScope" -VariableValue $targetScope diff --git a/scripts/azure-pipelines/Get-TestFile.ps1 b/scripts/azure-pipelines/Get-TestFile.ps1 new file mode 100644 index 0000000000..53ca1ed713 --- /dev/null +++ b/scripts/azure-pipelines/Get-TestFile.ps1 @@ -0,0 +1,21 @@ +<# +.SYNOPSIS + Gets the module test file. + +.DESCRIPTION + The script gets path to the test file in the directory of the changed module. + +.PARAMETER ChangedModuleDirectory + The directory of the changed module. +#> +param( + [Parameter(mandatory = $True)] + [string]$ChangedModuleDirectory +) + +Import-Module .\scripts\azure-pipelines\utils\AzurePipelinesUtils.psm1 -Force + +$testFilePath = Join-Path $ChangedModuleDirectory -ChildPath "test\main.test.bicep" +$testFilePath = if (Test-Path $testFilePath -PathType "Leaf") { $testFilePath } else { "" } + +Set-AzurePipelinesVariable -VariableName "TestFilePath" -VariableValue $testFilePath diff --git a/scripts/azure-pipelines/New-TestResourceGroup.ps1 b/scripts/azure-pipelines/New-TestResourceGroup.ps1 new file mode 100644 index 0000000000..11487fcd3d --- /dev/null +++ b/scripts/azure-pipelines/New-TestResourceGroup.ps1 @@ -0,0 +1,51 @@ +<# +.SYNOPSIS + Creates a test resource group. + +.DESCRIPTION + The script creates a resource group and grants a service principal access to that resource group for deploying the test Bicep file. + +.PARAMETER PrincipalId + The service principal ID (object ID). + +.PARAMETER Location + The Location of the test resource group to create. Defaults to "westus". +#> +Param( + [Parameter(mandatory = $true)] + [string]$PrincipalId, + + [string]$Location = "westus" +) + +Import-Module .\scripts\azure-pipelines\utils\AzurePipelinesUtils.psm1 -Force +Import-Module .\scripts\azure-pipelines\utils\AzureResourceUtils.psm1 -Force + +Invoke-AzurePipelinesTask { + $pullRequestNumber = $env:SYSTEM_PULLREQUEST_PULLREQUESTNUMBER + $commitId = $env:BUILD_SOURCEVERSION.Substring(0, 7) + $timestamp = Get-Date -Format "yyyyMMddHHmmss" -AsUTC + $guid = [GUID]::NewGuid().ToString('N') + $resourceGroupName = "$pullRequestNumber-$commitId-$timestamp-$guid" + + # Create the resource group and wait for replication. + New-AzResourceGroup -Name $resourceGroupName -Location $Location -Verbose + Wait-Replication { (Get-AzResourceGroup -Name $resourceGroupName -Verbose -ErrorAction "SilentlyContinue") -ne $null } + Set-AzurePipelinesVariable -VariableName "ResourceGroupName" -VariableValue $resourceGroupName + + Write-Host "Granting service principal $PrincipalId access to resource group $resourceGroupName..." + + # Can only use -ObjectId instead of -ApplicationId because the connected service principal doesn't have AAD read permision. + $roleAssignment = New-AzRoleAssignment -ResourceGroupName $resourceGroupName -ObjectId $PrincipalId -RoleDefinitionName "Owner" + $roleAssignmentPath = "$($roleAssignment.RoleAssignmentId)?api-version=2021-04-01-preview" + + # Sometimes it takes a while for an RBAC change to propagate. Calling Wait-Replication to ensure + # 6 succesive successful GET operations on the role assignment to reduce the chance of getting + # RBAC errors later due to slow replication. + Wait-Replication { + $getResult = Invoke-AzRestMethod -Method "GET" -Path $roleAssignmentPath + Write-Host $getResult.StatusCode "GET" $roleAssignmentPath + + $getResult.StatusCode -eq 200 + } -SuccessCount 6 -DelayInSeconds 4 +} diff --git a/scripts/azure-pipelines/Remove-TestResourceGroup.ps1 b/scripts/azure-pipelines/Remove-TestResourceGroup.ps1 new file mode 100644 index 0000000000..2874109920 --- /dev/null +++ b/scripts/azure-pipelines/Remove-TestResourceGroup.ps1 @@ -0,0 +1,80 @@ +<# +.SYNOPSIS + Removes a test resource group. + +.DESCRIPTION + This script attempts to remove a resource group. If the resource group cannot be removed, it will try cleaning up all the things + that prevent removing resource groups, such as resource locks, backup protection, geo-pairing, etc. The source code is largely + copied from https://github.com/Azure/azure-quickstart-templates/blob/master/test/ci-scripts/Kill-AzResourceGroup.ps1. + +.PARAMETER ResourceGroupName + The name of the resource group to remove. +#> +param( + [string][Parameter(mandatory = $true)] $ResourceGroupName +) + +Import-Module .\scripts\azure-pipelines\utils\AzurePipelinesUtils.psm1 -Force +Import-Module .\scripts\azure-pipelines\utils\AzureResourceUtils.psm1 -Force + + +Invoke-AzurePipelinesTask { + Write-Host "Removing resource group:" $ResourceGroupName "..." + + # First, try removing and purging soft-delete enabled resources... + Write-Host "Removing soft-delete enabled resources..." + + Write-Host "Checking for Key vaults..." + Remove-AzKeyVaultInResourceGroup -ResourceGroupName $ResourceGroupName + + Write-Host "Checking for Cognitive Services accounts..." + Remove-AzCognitiveServicesAccountInResourceGroup -ResourceGroupName $ResourceGroupName + + Write-Host "Checking for API Management services..." + Remove-AzApiManagementServiceInResourceGroup -ResourceGroupName $ResourceGroupName + + Write-Host "Checking for Operational Insights workspaces..." + Remove-AzOperationalInsightsWorkspaceInResourceGroup -ResourceGroupName $ResourceGroupName + + # Try removing the resource group. + if (Remove-AzResourceGroup -Name $ResourceGroupName -Force -Verbose -ErrorAction "SilentlyContinue") { + exit + } + + # Failed to remove the resource group - try cleaning up resources that can prevent removing resource groups. + Write-Host "Failed to remove the resource group. Try cleaning up resources first..." + + Write-Host "Checking for resource locks..." + Remove-AzResourceLockInResourceGroup -ResourceGroupName $ResourceGroupName + + Write-Host "Checking for Recovery Services vaults..." + Remove-AzRecoveryServicesVaultInResourceGroup -ResourceGroupName $ResourceGroupName + + Write-Host "Checking for Backup vaults..." + Remove-AzDataProtectionBackupVaultInResourceGroup -ResourceGroupName $ResourceGroupName + + Write-Host "Checking for Event Hubs Geo-disaster recovery configurations..." + Remove-AzEventHubGeoDRConfigurationInResourceGroup -ResourceGroupName $ResourceGroupName + + Write-Host "Checking for Service Bus Hubs Geo-disaster recovery configurations and migrations..." + Remove-AzServiceBusGeoDRConfigurationAndMigrationInResourceGroup -ResourceGroupName $ResourceGroupName + + Write-Host "Checking for Web App Swift Virtual Network connections..." + Remove-AzWebAppSwiftVnetConnectionInResourceGroup -ResourceGroupName $ResourceGroupName + + Write-Host "Checking for Redis Cache geo-replication links..." + Remove-AzRedisCacheLinkInResourceGroup -ResourceGroupName $ResourceGroupName + + Write-Host "Checking for Subnet delegations..." + Remove-AzSubnetDelegationInResourceGroup -ResourceGroupName $ResourceGroupName + + Write-Host "Checking for Virtual Hub IP configurations..." + Remove-AzVirtualHubIPConfigurationInResourceGroup -ResourceGroupName $ResourceGroupName + + Write-Host "Checking for Private Endpoint connections..." + Remove-AzPrivateEndpointConnectionInResourceGroup -ResourceGroupName $ResourceGroupName + + # Finally... + Write-Host "Removed resources preventing removing the resource group. Attempting to remove the resource group again..." + Remove-AzResourceGroup -Force -Verbose -Name $ResourceGroupName +} diff --git a/scripts/azure-pipelines/utils/AzurePipelinesUtils.psm1 b/scripts/azure-pipelines/utils/AzurePipelinesUtils.psm1 new file mode 100644 index 0000000000..e9186dd953 --- /dev/null +++ b/scripts/azure-pipelines/utils/AzurePipelinesUtils.psm1 @@ -0,0 +1,33 @@ +function Invoke-AzurePipelinesTask { + [CmdletBinding()] + param ( + [Parameter(mandatory = $true)] + [ScriptBlock]$ScriptBlock + ) + + try { + $ScriptBlock.Invoke(); + } + catch { + Write-Host "##vso[task.logissue type=error;]An error occurred: $_" + Write-Output "##vso[task.complete result=Failed;]" + } + + Exit $LASTEXITCODE +} + +function Set-AzurePipelinesVariable { + [CmdletBinding()] + param ( + [Parameter(mandatory = $true)] + [string]$VariableName, + + [Parameter(mandatory = $true)] + [AllowEmptyString()] + [string]$VariableValue + ) + + Write-Host "##vso[task.setvariable variable=$VariableName;]$VariableValue" +} + +Export-ModuleMember -Function Invoke-AzurePipelinesTask, Set-AzurePipelinesVariable, Set-AzurePipelinesOutputVariable diff --git a/scripts/azure-pipelines/utils/AzureResourceUtils.psm1 b/scripts/azure-pipelines/utils/AzureResourceUtils.psm1 new file mode 100644 index 0000000000..568b9e9fd3 --- /dev/null +++ b/scripts/azure-pipelines/utils/AzureResourceUtils.psm1 @@ -0,0 +1,596 @@ +function Wait-Replication { + [CmdletBinding()] + Param( + [Parameter(mandatory = $true)] + [scriptblock]$ScriptBlock, + + [int]$SuccessCount = 2, + + [int]$DelayInSeconds = 2, + + [int]$MaximumFailureCount = 20 + ) + + Begin { + $successiveSuccessCount = 0 + $failureCount = 0 + } + + Process { + while ($successiveSuccessCount -lt $SuccessCount) { + if ($ScriptBlock.Invoke()) { + $successiveSuccessCount++ + } + else { + $successiveSuccessCount = 0 + $failureCount++ + + if ($failureCount -eq $MaximumFailureCount) { + throw "Reached maximum failure count: $MaximumFailureCount." + } + } + } + + Start-Sleep $DelayInSeconds + } +} + +<# +.SYNOPSIS + Clears a Recovery Services vault. + +.DESCRIPTION + The function removes all backup items and configuration in a Recovery Services vault so it can be removed. + The source code was copied from https://docs.microsoft.com/en-us/azure/backup/scripts/delete-recovery-services-vault. + +.PARAMETER Vault + The vault to clear. +#> +function Clear-AzRecoveryServicesVault { + [CmdletBinding()] + param ( + [Parameter(mandatory = $true, ValueFromPipeline = $true)] + [Microsoft.Azure.Commands.RecoveryServices.ARSVault]$Vault + ) + + process { + Write-Host "Clearing Recovery Services vault" $vault.Name "..." + + Set-AzRecoveryServicesAsrVaultContext -Vault $Vault + Set-AzRecoveryServicesVaultProperty -Vault $Vault.ID -SoftDeleteFeatureState Disable #disable soft delete + Write-Host "Soft delete disabled for the vault" $Vault.Name + + $containerSoftDelete = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureVM -WorkloadType AzureVM -VaultId $Vault.ID | Where-Object { $_.DeleteState -eq "ToBeDeleted" } #fetch backup items in soft delete state + foreach ($softitem in $containerSoftDelete) { + Undo-AzRecoveryServicesBackupItemDeletion -Item $softitem -VaultId $Vault.ID -Force #undelete items in soft delete state + } + #Invoking API to disable enhanced security + $body = @{properties = @{enhancedSecurityState = "Disabled" } } + $vaultPath = $Vault.ID + "/backupconfig/vaultconfig?api-version=2020-05-13" + + Invoke-AzRestMethod -Method "PATCH" -Path $vaultPath -Payload ($body | ConvertTo-JSON -Depth 5) + + #Fetch all protected items and servers + $backupItemsVM = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureVM -WorkloadType AzureVM -VaultId $Vault.ID + $backupItemsSQL = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureWorkload -WorkloadType MSSQL -VaultId $Vault.ID + $backupItemsAFS = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureStorage -WorkloadType AzureFiles -VaultId $Vault.ID + $backupItemsSAP = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureWorkload -WorkloadType SAPHanaDatabase -VaultId $Vault.ID + $backupContainersSQL = Get-AzRecoveryServicesBackupContainer -ContainerType AzureVMAppContainer -Status Registered -VaultId $Vault.ID | Where-Object { $_.ExtendedInfo.WorkloadType -eq "SQL" } + $protectableItemsSQL = Get-AzRecoveryServicesBackupProtectableItem -WorkloadType MSSQL -VaultId $Vault.ID | Where-Object { $_.IsAutoProtected -eq $true } + $backupContainersSAP = Get-AzRecoveryServicesBackupContainer -ContainerType AzureVMAppContainer -Status Registered -VaultId $Vault.ID | Where-Object { $_.ExtendedInfo.WorkloadType -eq "SAPHana" } + $StorageAccounts = Get-AzRecoveryServicesBackupContainer -ContainerType AzureStorage -Status Registered -VaultId $Vault.ID + $backupServersMARS = Get-AzRecoveryServicesBackupContainer -ContainerType "Windows" -BackupManagementType MAB -VaultId $Vault.ID + $backupServersMABS = Get-AzRecoveryServicesBackupManagementServer -VaultId $Vault.ID | Where-Object { $_.BackupManagementType -eq "AzureBackupServer" } + $backupServersDPM = Get-AzRecoveryServicesBackupManagementServer -VaultId $Vault.ID | Where-Object { $_.BackupManagementType -eq "SCDPM" } + $pvtendpoints = Get-AzPrivateEndpointConnection -PrivateLinkResourceId $Vault.ID + + foreach ($item in $backupItemsVM) { + Disable-AzRecoveryServicesBackupProtection -Item $item -VaultId $Vault.ID -RemoveRecoveryPoints -Force #stop backup and delete Azure VM backup items + } + Write-Host "Disabled and deleted Azure VM backup items" + + foreach ($item in $backupItemsSQL) { + Disable-AzRecoveryServicesBackupProtection -Item $item -VaultId $Vault.ID -RemoveRecoveryPoints -Force #stop backup and delete SQL Server in Azure VM backup items + } + Write-Host "Disabled and deleted SQL Server backup items" + + foreach ($item in $protectableItemsSQL) { + Disable-AzRecoveryServicesBackupAutoProtection -BackupManagementType AzureWorkload -WorkloadType MSSQL -InputItem $item -VaultId $Vault.ID #disable auto-protection for SQL + } + Write-Host "Disabled auto-protection and deleted SQL protectable items" + + foreach ($item in $backupContainersSQL) { + Unregister-AzRecoveryServicesBackupContainer -Container $item -Force -VaultId $Vault.ID #unregister SQL Server in Azure VM protected server + } + Write-Host "Deleted SQL Servers in Azure VM containers" + + foreach ($item in $backupItemsSAP) { + Disable-AzRecoveryServicesBackupProtection -Item $item -VaultId $Vault.ID -RemoveRecoveryPoints -Force #stop backup and delete SAP HANA in Azure VM backup items + } + Write-Host "Disabled and deleted SAP HANA backup items" + + foreach ($item in $backupContainersSAP) { + Unregister-AzRecoveryServicesBackupContainer -Container $item -Force -VaultId $Vault.ID #unregister SAP HANA in Azure VM protected server + } + Write-Host "Deleted SAP HANA in Azure VM containers" + + foreach ($item in $backupItemsAFS) { + Disable-AzRecoveryServicesBackupProtection -Item $item -VaultId $Vault.ID -RemoveRecoveryPoints -Force #stop backup and delete Azure File Shares backup items + } + Write-Host "Disabled and deleted Azure File Share backups" + + foreach ($item in $StorageAccounts) { + Unregister-AzRecoveryServicesBackupContainer -container $item -Force -VaultId $Vault.ID #unregister storage accounts + } + Write-Host "Unregistered Storage Accounts" + + foreach ($item in $backupServersMARS) { + Unregister-AzRecoveryServicesBackupContainer -Container $item -Force -VaultId $Vault.ID #unregister MARS servers and delete corresponding backup items + } + Write-Host "Deleted MARS Servers" + + foreach ($item in $backupServersMABS) { + Unregister-AzRecoveryServicesBackupManagementServer -AzureRmBackupManagementServer $item -VaultId $Vault.ID #unregister MABS servers and delete corresponding backup items + } + Write-Host "Deleted MAB Servers" + + foreach ($item in $backupServersDPM) { + Unregister-AzRecoveryServicesBackupManagementServer -AzureRmBackupManagementServer $item -VaultId $Vault.ID #unregister DPM servers and delete corresponding backup items + } + Write-Host "Deleted DPM Servers" + + #Deletion of ASR Items + + $fabricObjects = Get-AzRecoveryServicesAsrFabric + if ($null -ne $fabricObjects) { + # First DisableDR all VMs. + foreach ($fabricObject in $fabricObjects) { + $containerObjects = Get-AzRecoveryServicesAsrProtectionContainer -Fabric $fabricObject + foreach ($containerObject in $containerObjects) { + $protectedItems = Get-AzRecoveryServicesAsrReplicationProtectedItem -ProtectionContainer $containerObject + # DisableDR all protected items + foreach ($protectedItem in $protectedItems) { + Write-Host "Triggering DisableDR(Purge) for item:" $protectedItem.Name + Remove-AzRecoveryServicesAsrReplicationProtectedItem -InputObject $protectedItem -Force + Write-Host "DisableDR(Purge) completed" + } + + $containerMappings = Get-AzRecoveryServicesAsrProtectionContainerMapping ` + -ProtectionContainer $containerObject + # Remove all Container Mappings + foreach ($containerMapping in $containerMappings) { + Write-Host "Triggering Remove Container Mapping: " $containerMapping.Name + Remove-AzRecoveryServicesAsrProtectionContainerMapping -ProtectionContainerMapping $containerMapping -Force + Write-Host "Removed Container Mapping." + } + } + $NetworkObjects = Get-AzRecoveryServicesAsrNetwork -Fabric $fabricObject + foreach ($networkObject in $NetworkObjects) { + #Get the PrimaryNetwork + $PrimaryNetwork = Get-AzRecoveryServicesAsrNetwork -Fabric $fabricObject -FriendlyName $networkObject + $NetworkMappings = Get-AzRecoveryServicesAsrNetworkMapping -Network $PrimaryNetwork + foreach ($networkMappingObject in $NetworkMappings) { + #Get the Neetwork Mappings + $NetworkMapping = Get-AzRecoveryServicesAsrNetworkMapping -Name $networkMappingObject.Name -Network $PrimaryNetwork + Remove-AzRecoveryServicesAsrNetworkMapping -InputObject $NetworkMapping + } + } + # Remove Fabric + Write-Host "Triggering Remove Fabric:" $fabricObject.FriendlyName + Remove-AzRecoveryServicesAsrFabric -InputObject $fabricObject -Force + Write-Host "Removed Fabric." + } + } + + foreach ($item in $pvtendpoints) { + $penamesplit = $item.Name.Split(".") + $pename = $penamesplit[1] + Remove-AzPrivateEndpointConnection -ResourceId $item.PrivateEndpoint.Id -Force #remove private endpoint connections + Remove-AzPrivateEndpoint -Name $pename -ResourceGroupName $Vault.ResourceGroupName -Force #remove private endpoints + } + Write-Host "Removed Private Endpoints" + + #Recheck ASR items in vault + $fabricCount = 1 + $ASRProtectedItems = 1 + $ASRPolicyMappings = 1 + $fabricObjects = Get-AzRecoveryServicesAsrFabric + if ($null -ne $fabricObjects) { + foreach ($fabricObject in $fabricObjects) { + $containerObjects = Get-AzRecoveryServicesAsrProtectionContainer -Fabric $fabricObject + foreach ($containerObject in $containerObjects) { + $protectedItems = Get-AzRecoveryServicesAsrReplicationProtectedItem -ProtectionContainer $containerObject + foreach ($protectedItem in $protectedItems) { + $ASRProtectedItems++ + } + $containerMappings = Get-AzRecoveryServicesAsrProtectionContainerMapping ` + -ProtectionContainer $containerObject + foreach ($containerMapping in $containerMappings) { + $ASRPolicyMappings++ + } + } + $fabricCount++ + } + } + #Recheck presence of backup items in vault + $backupItemsVMFin = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureVM -WorkloadType AzureVM -VaultId $Vault.ID + $backupItemsSQLFin = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureWorkload -WorkloadType MSSQL -VaultId $Vault.ID + $backupContainersSQLFin = Get-AzRecoveryServicesBackupContainer -ContainerType AzureVMAppContainer -Status Registered -VaultId $Vault.ID | Where-Object { $_.ExtendedInfo.WorkloadType -eq "SQL" } + $protectableItemsSQLFin = Get-AzRecoveryServicesBackupProtectableItem -WorkloadType MSSQL -VaultId $Vault.ID | Where-Object { $_.IsAutoProtected -eq $true } + $backupItemsSAPFin = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureWorkload -WorkloadType SAPHanaDatabase -VaultId $Vault.ID + $backupContainersSAPFin = Get-AzRecoveryServicesBackupContainer -ContainerType AzureVMAppContainer -Status Registered -VaultId $Vault.ID | Where-Object { $_.ExtendedInfo.WorkloadType -eq "SAPHana" } + $backupItemsAFSFin = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureStorage -WorkloadType AzureFiles -VaultId $Vault.ID + $StorageAccountsFin = Get-AzRecoveryServicesBackupContainer -ContainerType AzureStorage -Status Registered -VaultId $Vault.ID + $backupServersMARSFin = Get-AzRecoveryServicesBackupContainer -ContainerType "Windows" -BackupManagementType MAB -VaultId $Vault.ID + $backupServersMABSFin = Get-AzRecoveryServicesBackupManagementServer -VaultId $Vault.ID | Where-Object { $_.BackupManagementType -eq "AzureBackupServer" } + $backupServersDPMFin = Get-AzRecoveryServicesBackupManagementServer -VaultId $Vault.ID | Where-Object { $_.BackupManagementType -eq "SCDPM" } + $pvtendpointsFin = Get-AzPrivateEndpointConnection -PrivateLinkResourceId $Vault.ID + Write-Host "Number of backup items left in the vault and which need to be deleted:" $backupItemsVMFin.count "Azure VMs" $backupItemsSQLFin.count "SQL Server Backup Items" $backupContainersSQLFin.count "SQL Server Backup Containers" $protectableItemsSQLFin.count "SQL Server Instances" $backupItemsSAPFin.count "SAP HANA backup items" $backupContainersSAPFin.count "SAP HANA Backup Containers" $backupItemsAFSFin.count "Azure File Shares" $StorageAccountsFin.count "Storage Accounts" $backupServersMARSFin.count "MARS Servers" $backupServersMABSFin.count "MAB Servers" $backupServersDPMFin.count "DPM Servers" $pvtendpointsFin.count "Private endpoints" + Write-Host "Number of ASR items left in the vault and which need to be deleted:" $ASRProtectedItems "ASR protected items" $ASRPolicyMappings "ASR policy mappings" $fabricCount "ASR Fabrics" $pvtendpointsFin.count "Private endpoints. Warning: This script will only remove the replication configuration from Azure Site Recovery and not from the source. Please cleanup the source manually. Visit https://go.microsoft.com/fwlink/?linkid=2182782 to learn more" + + $Vault + } +} + +function Remove-AzResourceLockInResourceGroup { + [CmdletBinding()] + param ( + [Parameter(mandatory = $true)] + [string]$ResourceGroupName + ) + + Get-AzResourceLock -ResourceGroupName $ResourceGroupName -Verbose | Remove-AzResourceLock -Force -verbose +} + +function Remove-AzRecoveryServicesVaultInResourceGroup { + [CmdletBinding()] + param ( + [Parameter(mandatory = $true)] + [string]$ResourceGroupName + ) + + Get-AzRecoveryServicesVault -ResourceGroupName $ResourceGroupName -Verbose | + Clear-AzRecoveryServicesVault | + Remove-AzRecoveryServicesVault -Verbose +} + +function Remove-AzDataProtectionBackupVaultInResourceGroup { + [CmdletBinding()] + param ( + [Parameter(mandatory = $true)] + [string]$ResourceGroupName + ) + + # The Az.DataProtection is not yet included with the rest of the Az module. + if ($null -eq $(Get-Module -ListAvailable Az.DataProtection)) { + Write-Host "Installing Az.DataProtection module..." + Install-Module Az.DataProtection -Force -AllowClobber + } + + $vaults = Get-AzDataProtectionBackupVault -ResourceGroupName $ResourceGroupName + + foreach ($vault in $vaults) { + Write-Host "Removing Backup vault" $vault.name "..." + + $backupInstances = Get-AzDataProtectionBackupInstance -ResourceGroupName $ResourceGroupName -VaultName $vault.Name + foreach ($backupInstance in $backupInstances) { + Write-Host "Removing Backup instance" $backupInstance.Name "..." + Remove-AzDataProtectionBackupInstance -ResourceGroupName $ResourceGroupName -VaultName $vault.Name -Name $backupInstance.Name + } + + $backupPolicies = Get-AzDataProtectionBackupPolicy -ResourceGroupName $ResourceGroupName -VaultName $vault.Name + foreach ($backupPolicy in $backupPolicies) { + Write-Host "Removing Backup policy" $backupPolicy.name "..." + Remove-AzDataProtectionBackupPolicy -ResourceGroupName $ResourceGroupName -VaultName $vault.name -Name $backupPolicy.Name + } + } +} + +function Remove-AzEventHubGeoDRConfigurationInResourceGroup { + [CmdletBinding()] + param ( + [Parameter(mandatory = $true)] + [string]$ResourceGroupName + ) + + $namespaces = Get-AzEventHubNamespace -ResourceGroupName $ResourceGroupName -Verbose + + foreach ($namespace in $namespaces) { + $configurations = Get-AzEventHubGeoDRConfiguration -ResourceGroupName $ResourceGroupName -Namespace $namespace.Name -Verbose + + foreach ($configuration in $configurations) { + # First look at the primary namespaces and break pairing. + if ($configuration.Role.ToString() -eq "Primary") { + Write-Host "Breaking Event Hubs namespace pairing for namespace" $namespace.Name "..." + Set-AzEventHubGeoDRConfigurationBreakPair -ResourceGroupName $ResourceGroupName -Namespace $namespace.Name -Name $configuration.Name + } + + # Now that pairing is removed we can remove primary and secondary configs. + Write-Host "Removing Event Hubs DR configuration" $configuration.Name "..." + Remove-AzEventHubGeoDRConfiguration -ResourceGroupName $ResourceGroupName -Namespace $namespace.Name $configuration.Name -Verbose + } + } +} + +function Remove-AzServiceBusGeoDRConfigurationAndMigrationInResourceGroup { + [CmdletBinding()] + param ( + [Parameter(mandatory = $true)] + [string]$ResourceGroupName + ) + + $namespaces = Get-AzServiceBusNamespace -ResourceGroupName $ResourceGroupName -Verbose + + foreach ($namespace in $namespaces) { + $configurations = Get-AzServiceBusGeoDRConfiguration -ResourceGroupName $ResourceGroupName -Namespace $namespace.Name + + foreach ($configuration in $configurations) { + # First look at the primary namespaces and break pairing. + if ($configuration.Role.ToString() -eq "Primary") { + Write-Host "Breaking Service Bus namespace pairing for namespace" $namespace "..." + Set-AzServiceBusGeoDRConfigurationBreakPair -ResourceGroupName $ResourceGroupName -Namespace $namespace.Name -Name $configuration.Name + } + + # Now that pairing is removed we can remove primary and secondary configs. + Write-Host "Removing Service Bus DR configuration" $configuration.Name "..." + Remove-AzServiceBusGeoDRConfiguration -ResourceGroupName $ResourceGroupName -Namespace $namespace.Name -Name $configuration.Name -Verbose + } + } + + foreach ($namespace in $namespaces) { + # Set ErrorAction on this since it throws if there is no config (unlike the other cmdlets). + $migration = Get-AzServiceBusMigration -ResourceGroupName $ResourceGroupName -Name $namespace.Name -ErrorAction "SilentlyContinue" + + if ($migration) { + Write-Host "Removing Service Bus migration" $migration.Name "..." + Remove-AzServiceBusMigration -ResourceGroupName $ResourceGroupName -Name $namespace.Name -Verbose + } + } +} + +function Remove-AzWebAppSwiftVnetConnectionInResourceGroup { + [CmdletBinding()] + param ( + [Parameter(mandatory = $true)] + [string]$ResourceGroupName + ) + + function Remove-AzWebAppSwiftVnetConnection { + [CmdletBinding()] + param ( + [Parameter(mandatory = $true)] + [Microsoft.Azure.Commands.WebApps.Models.PSSite]$WebAppOrSlot + ) + + process { + # Assumption is that there can only be one connection, but it returns an array so maybe not. + $result = Invoke-AzRestMethod -Method "GET" -Path "$($WebAppOrSlot.Id)/virtualNetworkConnections?api-version=2021-10-01" + + if ($result.StatusCode -eq "200") { + Write-Host "Removing a Swift Virtual Network connection from the Web App: $($WebAppOrSlot.Name)" + # The URI for remove is not the same as the GET URI. + Invoke-AzRestMethod -Method "DELETE" -Path "$($WebAppOrSlot.Id)/networkConfig/virtualNetwork?api-version=2021-10-01" -Verbose + } + } + } + + # Web apps that have a serviceAssociationLink can be deleted even if the link exists and the vnet + # will be bricked (cannot be delete and the serviceAssociation link cannot be removed). + # A funky traversal of 4 resources are needed to discover and remove the link (PUT/GET/DELETE are not symmetrical). + $webApps = Get-AzWebApp -ResourceGroupName $ResourceGroupName -Verbose + + foreach ($webApp in $webApps) { + # Remove the config on the WebApp slots. + Get-AzWebAppSlot -ResourceGroupName $ResourceGroupName -Name $webApp.Name -Verbose | Remove-AzWebAppSwiftVnetConnection + + # Now remove the config on the WebApp itself. + Remove-AzWebAppSwiftVnetConnection -WebAppOrSlot $webApp + } +} + +function Remove-AzRedisCacheLinkInResourceGroup { + [CmdletBinding()] + param ( + [Parameter(mandatory = $true)] + [string]$ResourceGroupName + ) + + $redisCaches = Get-AzRedisCache -ResourceGroupName $ResourceGroupName -Verbose + + foreach ($redisCache in $redisCaches) { + $link = Get-AzRedisCacheLink -Name $redisCache.Name + + if ($link) { + Write-Host "Removing Redis Cache geo-replication link" $link.Name "..." + $link | Remove-AzRedisCacheLink -Verbose + } + } +} + +function Remove-AzSubnetDelegationInResourceGroup { + [CmdletBinding()] + param ( + [Parameter(mandatory = $true)] + [string]$ResourceGroupName + ) + + # ACI create a subnet delegation that must be removed before the vnet can be deleted. + $vnets = Get-AzVirtualNetwork -ResourceGroupName $ResourceGroupName -Verbose + + foreach ($vnet in $vnets) { + foreach ($subnet in $vnet.Subnets) { + $delegations = Get-AzDelegation -Subnet $subnet -Verbose + + foreach ($delegation in $delegations) { + Write-Output "Removing Subnet delegation" $delegation.Name "..." + Remove-AzDelegation -Name $delegation.Name -Subnet $subnet -Verbose + } + } + } +} + +function Remove-AzVirtualHubIPConfigurationInResourceGroup { + [CmdletBinding()] + param ( + [Parameter(mandatory = $true)] + [string]$ResourceGroupName + ) + + # Virtual Hubs can have ipConfigurations that take a few minutes to delete. + # There appears to be no cmdlets or CLI to invoke these APIs. + $virtualHubs = Get-AzVirtualHub -ResourceGroupName $ResourceGroupName -Verbose + + foreach ($virtualHub in $virtualHubs) { + $listResult = Invoke-AzRestMethod -Method "GET" -path "$($virtualHub.Id)/ipConfigurations?api-version=2020-11-01" + $configurations = $($listResult.Content | ConvertFrom-Json -Depth 50).Value + + foreach ($configuration in $configurations) { + Write-Host "Removing Virtual Hub IP configuration" $($configuration.id) "..." + + Write-Host "Sending a DELETE request..." + $deleteResult = Invoke-AzRestMethod -Method "DELETE" -Path "$($configuration.id)?api-version=2020-11-01" + $deleteResult + + if ($deleteResult.StatusCode -like "20*") { + Write-Host "Waiting for the DELETE operation to complte..." + do { + Start-Sleep -Seconds 60 + Write-Host "Making sure GET returns 404..." + $getResult = Invoke-AzRestMethod -Method GET -Path "$($configuration.id)?api-version=2020-11-01" + $getResult + } until ($getResult.StatusCode -eq "404") + } + } + } +} + +function Remove-AzPrivateEndpointConnectionInResourceGroup { + [CmdletBinding()] + param ( + [Parameter(mandatory = $true)] + [string]$ResourceGroupName + ) + + $privateLinkServices = Get-AzPrivateLinkService -ResourceGroupName $ResourceGroupName + + foreach ($privateLinkService in $privateLinkServices) { + $connections = Get-AzPrivateEndpointConnection -ResourceGroupName $ResourceGroupName -ServiceName $privateLinkService.Name + + foreach ($connection in $connections) { + Write-Host "Removing Private Endpoint connection" $connection.Name "..." + Remove-AzPrivateEndpointConnection -ResourceGroupName $ResourceGroupName -ServiceName $privateLinkService.Name -Name $connection.Name -Force + } + } +} + +function Remove-AzKeyVaultInResourceGroup { + [CmdletBinding()] + param ( + [Parameter(mandatory = $true)] + [string]$ResourceGroupName + ) + + $keyVaults = Get-AzKeyVault -ResourceGroupName $ResourceGroupName + + foreach ($keyVault in $keyVaults) { + Write-Host "Removing Key vault" $keyVault.VaultName "..." + Remove-AzKeyVault -VaultName $keyVault.VaultName -ResourceGroupName $ResourceGroupName -Force + + if (-not $keyVault.EnableSoftDelete) { + continue + } + + if ($keyVault.EnablePurgeProtection) { + Write-Warning ('Key vault {0} had purge protection enabled. The retention time is {1} days. Please wait until after this period before re-running the test.' -f $keyVault.VaultName, $keyVault.SoftDeleteRetentionInDays) + } + else { + Wait-Replication { + Write-Host "Waiting for the Key vault deletion operation to complete..." + $null -ne (Get-AzKeyVault -VaultName $keyVault.VaultName -Location $keyVault.Location -InRemovedState) + } + + Write-Host "Purging Key vault" $keyVault.VaultName "..." + Remove-AzKeyVault -VaultName $keyVault.VaultName -Location $keyVault.Location -InRemovedState -Force + } + } +} + +function Remove-AzCognitiveServicesAccountInResourceGroup { + [CmdletBinding()] + param ( + [Parameter(mandatory = $true)] + [string]$ResourceGroupName + ) + + $accounts = Get-AzCognitiveServicesAccount -ResourceGroupName $ResourceGroupName + + foreach ($account in $accounts) { + Write-Host "Removing Cognitive Services account" $account.AccountName "..." + $account | Remove-AzCognitiveServicesAccount -Force + + Wait-Replication { + Write-Host "Waiting for the Cognitive Services account deletion operation to complete..." + $null -ne (Get-AzCognitiveServicesAccount -ResourceGroupName $ResourceGroupName -Name $account.AccountName -Location $account.Location -InRemovedState) + } + + Write-Host "Purging Cognitive Services account" $account.AccountName "..." + $account | Remove-AzCognitiveServicesAccount -Location $account.Location -InRemovedState -Force + } +} + +function Remove-AzApiManagementServiceInResourceGroup { + [CmdletBinding()] + param ( + [Parameter(mandatory = $true)] + [string]$ResourceGroupName + ) + + $context = Get-AzContext + $subscriptionId = $context.Subscription.Id + $services = Get-AzApiManagement -ResourceGroupName $ResourceGroupName + + foreach ($service in $services) { + Write-Host "Removing API Management service" $service.Name "..." + $service | Remove-AzApiManagement + + Write-Host "Waiting for the API Management service deletion operation to complete..." + Start-Sleep 20 + + Write-Host "Purging API Management service" $service.Name "..." + $purgePath = "/subscriptions/{0}/providers/Microsoft.ApiManagement/locations/{1}/deletedservices/{2}?api-version=2020-06-01-preview" -f $subscriptionId, $service.Location, $service.Name + Invoke-AzRestMethod -Method "DELETE" -Path $purgePath + } +} + +function Remove-AzOperationalInsightsWorkspaceInResourceGroup { + [CmdletBinding()] + param ( + [Parameter(mandatory = $true)] + [string]$ResourceGroupName + ) + + $workspaces = Get-AzOperationalInsightsWorkspace -ResourceGroupName $ResourceGroupName + + foreach ($workspace in $workspaces) { + Write-Host "Removing Operational Insights workspace" $workspace.Name "..." + $workspace | Remove-AzOperationalInsightsWorkspace -ForceDelete -Force + } +} + +Export-ModuleMember -Function ` + Wait-Replication, ` + Remove-AzResourceLockInResourceGroup, ` + Remove-AzRecoveryServicesVaultInResourceGroup, ` + Remove-AzDataProtectionBackupVaultInResourceGroup, ` + Remove-AzEventHubGeoDRConfigurationInResourceGroup, ` + Remove-AzServiceBusGeoDRConfigurationAndMigrationInResourceGroup, ` + Remove-AzWebAppSwiftVnetConnectionInResourceGroup, ` + Remove-AzRedisCacheLinkInResourceGroup, ` + Remove-AzSubnetDelegationInResourceGroup, ` + Remove-AzVirtualHubIPConfigurationInResourceGroup, ` + Remove-AzPrivateEndpointConnectionInResourceGroup, ` + Remove-AzKeyVaultInResourceGroup, ` + Remove-AzCognitiveServicesAccountInResourceGroup, ` + Remove-AzApiManagementServiceInResourceGroup, ` + Remove-AzOperationalInsightsWorkspaceInResourceGroup + \ No newline at end of file diff --git a/scripts/github-actions/create-tag.js b/scripts/github-actions/create-tag.js new file mode 100644 index 0000000000..fee3b918e9 --- /dev/null +++ b/scripts/github-actions/create-tag.js @@ -0,0 +1,59 @@ +/** + * @typedef Params + * @property {typeof require} require + * @property {ReturnType} github + * @property {typeof import("@actions/github").context} context + * @property {typeof import("@actions/core")} core + * @property {string} moduleDir + * @property {string} baseVersion + * @property {string} headVersion + * + * @param {Params} params + */ +async function createTag({ + require, + github, + context, + core, + moduleDir, + baseVersion, + headVersion, +}) { + const semverCompare = require("semver/functions/compare"); + const base = context.payload.before; + const head = context.payload.after; + const compareResult = semverCompare(headVersion, baseVersion); + + if (compareResult < 0) { + core.setFailed( + `The version ${headVersion} calculated at the commit ${head} (head) is smaller than the version ${baseVersion} calculated at the base commit ${base} (base).` + ); + } + + if (compareResult === 0) { + core.info(`No version update detected.`); + return ""; + } + + const red = "\u001b[31m"; + const green = "\u001b[32m"; + const reset = "\u001b[0m"; + core.info( + `Detected version update: ${red}${baseVersion} (old) ${reset}-> ${green}${headVersion} (new).` + ); + + const modulePath = moduleDir.substring(moduleDir.indexOf("/") + 1); + const tag = `${modulePath}/${headVersion}`; + + await github.rest.git.createRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: `refs/tags/${tag}`, + sha: context.sha, + }); + + core.info(`Created a new tag: ${tag} (${head}).`); + return tag; +} + +module.exports = createTag; diff --git a/scripts/github-actions/get-changed-module.js b/scripts/github-actions/get-changed-module.js new file mode 100644 index 0000000000..479cb9bdd4 --- /dev/null +++ b/scripts/github-actions/get-changed-module.js @@ -0,0 +1,81 @@ +/** + * @typedef Params + * @property {typeof require} require + * @property {ReturnType} github + * @property {typeof import("@actions/github").context} context + * @property {typeof import("@actions/core")} core + * + * @param {Params} params + */ +async function getChangedModule({ require, github, context, core }) { + let base; + let head; + + switch (context.eventName) { + case "pull_request": + base = context.payload.pull_request.base.sha; + head = context.payload.pull_request.head.sha; + break; + case "push": + base = context.payload.before; + head = context.payload.after; + break; + default: + core.setFailed(`Not supported event: ${context.eventName}.`); + } + + const { status, data } = await github.rest.repos.compareCommitsWithBasehead({ + owner: context.repo.owner, + repo: context.repo.repo, + basehead: `${base}...${head}`, + }); + + if (status !== 200) { + core.setFailed( + `Expected github.rest.repos.compareCommitsWithBasehead to return 200, got ${status}.` + ); + } + + if (context.eventName === "push" && data.status !== "ahead") { + core.setFailed( + `The head commit ${head} is not ahead of the base commit ${base}.` + ); + } + + const path = require("path"); + const fs = require("fs"); + const cyan = "\u001b[36;1m"; + + const moduleDirs = [ + ...new Set( + data.files + .filter((file) => file.filename.startsWith("modules/")) + // Do not consider module changed if only the README.md has changed + .filter((file) => !file.filename.endsWith("README.md")) + .map((file) => { + const dir = path.dirname(file.filename); + const segments = dir.split("/"); + // modules/moduleFolder/moduleRoot/* => modules/moduleFolder/moduleRoot + return segments.slice(0, 3).join("/"); + }) + // Ignore removed module directories. + .filter((dir) => fs.existsSync(dir)) + ), + ]; + + switch (moduleDirs.length) { + case 0: + core.info("No changed module found."); + return ""; + case 1: + core.info("Found 1 changed module:"); + core.info(`- ${cyan}${moduleDirs[0]}`); + return moduleDirs[0]; + default: + core.info(`Found ${moduleDirs.length} changed modules:`); + moduleDirs.forEach((dir) => core.info(`- ${cyan}${dir}`)); + core.setFailed("Only one module can be added or updated at a time."); + } +} + +module.exports = getChangedModule; diff --git a/scripts/github-actions/parse-tag.js b/scripts/github-actions/parse-tag.js new file mode 100644 index 0000000000..99f86b1d61 --- /dev/null +++ b/scripts/github-actions/parse-tag.js @@ -0,0 +1,50 @@ +/** + * @typedef Params + * @property {typeof import("@actions/core")} core + * @property {string} tag + * + * @param {Params} params + */ +function parseTag({ core, tag }) { + const segments = tag.split("/"); + + if (segments.length !== 3 || segments.includes("")) { + core.setFailed( + `Invalid tag: "${tag}". A valid tag must be in the format of "//".` + ); + } + + const modulePathSegmentRegex = /^[a-z0-9]+([._-][a-z0-9]+)*$/; + const moduleFolder = segments[0]; + const moduleName = segments[1]; + + if (!modulePathSegmentRegex.test(moduleFolder)) { + core.setFailed( + `The module folder "${moduleFolder}" in the tag "${tag}" is invalid. It must match the regex "${modulePathSegmentRegex}".` + ); + } + + if (!modulePathSegmentRegex.test(moduleName)) { + core.setFailed( + `The module name "${moduleName}" in the tag "${tag}" is invalid. It must match the regex "${modulePathSegmentRegex}".` + ); + } + + const versionRegex = + /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?$/; + const version = segments[2]; + + if (!versionRegex.test(version)) { + core.setFailed( + `The version "${version}" in the tag "${tag}" is invalid. It must match the regex "${versionRegex}".` + ); + } + + core.setOutput("module_path", `${moduleFolder}/${moduleName}`); + core.setOutput("version", version); + + const readmeLink = `https://github.com/Azure/bicep-registry-modules/tree/${tag}/modules/${moduleFolder}/${moduleName}/README.md`; + core.setOutput("documentation_uri", readmeLink); +} + +module.exports = parseTag; diff --git a/scripts/local/approve-autogenerated-prs.js b/scripts/local/approve-autogenerated-prs.js new file mode 100644 index 0000000000..920d11ac1e --- /dev/null +++ b/scripts/local/approve-autogenerated-prs.js @@ -0,0 +1,55 @@ +/* + + This script approves all auto-generated PRs. It will query interactively for each module. + + Usage: + Install gh from https://cli.github.com/ + Log in to gh + cd repos/bicep-registry-modules + npm i + node scripts/local/approve-autogenerated-prs.js + + + +*/ + +const { + runAsync, + queryUserAsync, + queryRunAsync, +} = require("./util/runAsync.js"); +const { clearScreen, green, yellow, red, reset } = require("./util/colors"); + +const { argv } = require("process"); + +function formatPR(pr) { + return `#${pr.number} (${pr.author.login} ${pr.state} ${pr.labels.map( + (l) => l.name + )}) ${yellow}${pr.title}${reset}`; +} + +async function ApprovePRs() { + const prs = JSON.parse( + await runAsync( + `gh pr list --label "Auto-generated" --state open --limit 500 --json number,author,title,state,labels,statusCheckRollup -S "review:required draft:false"` + ) + ); + + console.log(`${yellow}Found these PRs:${reset}`); + for (pr of prs) { + console.log(formatPR(pr)); + } + console.log(); + + for (pr of prs) { + await queryRunAsync( + [ + `gh pr merge --auto --squash ${pr.number}`, + `gh pr review --approve ${pr.number}`, + ], + `Approve the following PR?${reset}\n${formatPR(pr)}` + ); + } +} + +ApprovePRs(); diff --git a/scripts/local/create-prs.js b/scripts/local/create-prs.js new file mode 100644 index 0000000000..e448f40988 --- /dev/null +++ b/scripts/local/create-prs.js @@ -0,0 +1,102 @@ +/* + + This script creates a PR for each modules on the local disk that has changes. It will query interactively for each module. + + Requires that gh be installed (https://cli.github.com/) + + Usage: + cd repos/bicep-registry-modules + npm i + + + + make sure you're logged in to gh + node scripts/local/create-prs.js + + + +*/ + +const usage = `Usage: see script comments`; + +const { runAsync, queryRunAsync } = require("./util/runAsync.js"); +const { clearScreen, green, yellow, red, reset } = require("./util/colors"); + +const { argv } = require("process"); + +// eslint-disable-next-line prefer-const +let [branchPrefix, commitPrefix] = argv.slice(2); +if (!branchPrefix || !commitPrefix) { + console.error(usage); + process.exit(1); +} + +branchPrefix = branchPrefix.endsWith("/") + ? branchPrefix.slice(0, branchPrefix.length - 1) + : branchPrefix; +console.log(`${green}branch prefix: ${branchPrefix}${reset}`); +console.log(`${green}commit message: ${commitPrefix}${reset}`); + +async function getChangedModulesAsync() { + const changedModules = (await runAsync(`git status modules`)) + .split("\n") + .filter((line) => line.match(/modified/)) + .map((line) => line.replace(/^.*\smodules\/([^/]+\/[^/]+)\/.*$/g, "$1")) + // dedupe the list + .filter((value, index, self) => self.indexOf(value) === index); + + return changedModules; +} + +async function CreatePRAsync(modulePath) { + console.log( + `${clearScreen}${green}=========== Creating PR for ${modulePath}...${reset}` + ); + + const branchName = `${branchPrefix}/auto/${modulePath}`; + await runAsync(`git checkout -b ${branchName}`); + await runAsync(`git add modules/${modulePath}`); + await runAsync(`git diff --cached`); + + const commitMessage = `${commitPrefix} (${modulePath}) (auto)`; + const prTitle = `${commitPrefix} (${modulePath}) (auto-generated)`; + const prBody = `This PR was created by a script. Please review the changes and merge if they look good.`; + const prSubmitted = await queryRunAsync([ + `git commit -m "${commitMessage}"`, + `git push -u origin ${branchName}`, + `gh pr create --title "${prTitle}" --body "${prBody}" --label "Auto-generated"`, + ]); + + // TODO: Changes get lost for a branch if you say no + + await runAsync(`git checkout main`); + if (prSubmitted) { + await runAsync(`git branch -d ${branchName}`); + } else { + console.log( + `${red}Branch ${branchName} contains the unsubmitted changes.${reset}` + ); + } + + console.log(); +} + +async function CreatePRs() { + const changedModules = await getChangedModulesAsync(); + + const currentBranch = await runAsync(`git symbolic-ref --short HEAD`, false); + console.log(`${green}Current branch: ${currentBranch}${reset}`); + + await runAsync(`git checkout main`); + + try { + for (const modulePath of changedModules) { + await CreatePRAsync(modulePath); + } + } finally { + await runAsync(`git checkout ${currentBranch}`, false); + console.log(`${green}Restored branch to ${currentBranch}${reset}`); + } +} + +CreatePRs(); diff --git a/scripts/local/fix-all-readme-examples.js b/scripts/local/fix-all-readme-examples.js new file mode 100644 index 0000000000..742318ee09 --- /dev/null +++ b/scripts/local/fix-all-readme-examples.js @@ -0,0 +1,25 @@ +/* + + This script updates the examples in all README.md files to the *current* version. + + Usage: + cd repos/bicep-registry-modules + npm i + node scripts/local/fix-all-readme-examples.js + +*/ + +const { updateReadmeExamples } = require("./util/updateReadmeExamples.js"); +const { + getLatestModuleVersionsAsync, +} = require("./util/getLatestModuleVersionsAsync"); + +async function regenerateAllAsync() { + const modules = await getLatestModuleVersionsAsync(); + + for (const [modulePath, version] of modules) { + updateReadmeExamples(modulePath, version, version); + } +} + +regenerateAllAsync(); diff --git a/scripts/local/regenerate-all.js b/scripts/local/regenerate-all.js new file mode 100644 index 0000000000..aaa1630103 --- /dev/null +++ b/scripts/local/regenerate-all.js @@ -0,0 +1,87 @@ +/* + + This script is used to regenerate all the modules in the current repo. Also updates the examples + in the README.md to the *next* version of the module (making it ready for checkin). + + Usage: + cd repos/bicep-registry-modules + npm i + node scripts/local/regenerate-all.js + +*/ + +const { resolve } = require("path"); +const { updateReadmeExamples } = require("./util/updateReadmeExamples.js"); +const { runAsync } = require("./util/runAsync.js"); +const { existsSync } = require("fs"); +const { + getLatestModuleVersionsAsync, +} = require("./util/getLatestModuleVersionsAsync.js"); +const { green, reset, yellow } = require("./util/colors"); +const semver = require("semver"); + +let brm = resolve( + `../bicep/src/Bicep.RegistryModuleTool/Bin/Debug/net7.0/Azure.Bicep.RegistryModuleTool` +); +brm = existsSync(brm) ? brm : brm + ".exe"; +brm = existsSync(brm) ? brm : "brm"; + +console.warn(`Using this brm: ${brm}`); + +function getNextVersion(version) { + return semver.inc(version, "patch"); +} + +async function regenerateAllAsync() { + const modules = await getLatestModuleVersionsAsync(); + + for (const [modulePath, version] of modules) { + var currentDir = process.cwd(); + process.chdir(resolve(`modules/${modulePath}`)); + + try { + let needsGenerate = false; + + try { + console.warn(`${yellow}Validating: ${modulePath}${reset}`); + await runAsync(`${brm} validate`); + } catch (err) { + if ( + /Please run "brm generate"/.test(String(err)) || + /The "summary" property in metadata.json does not match/.test( + String(err) + ) + ) { + needsGenerate = true; + } else { + throw err; + } + } + + if (needsGenerate) { + console.error( + `${yellow}Generating: ${modulePath} (version ${version})${reset}` + ); + await runAsync(`${brm} generate`); + + console.error( + `${yellow}Updating README for ${modulePath} (version ${version})${reset}` + ); + process.chdir(resolve(currentDir)); + await updateReadmeExamples( + modulePath, + version, + getNextVersion(version) + ); + } else { + console.error( + `${green}Does not need regeneration: ${modulePath}${reset}` + ); + } + } finally { + process.chdir(resolve(currentDir)); + } + } +} + +regenerateAllAsync(); diff --git a/scripts/local/util/colors.js b/scripts/local/util/colors.js new file mode 100644 index 0000000000..ff60da628e --- /dev/null +++ b/scripts/local/util/colors.js @@ -0,0 +1,6 @@ +exports.red = "\u001b[31m"; +exports.green = "\u001b[32m"; +exports.blue = "\u001b[34m"; +exports.yellow = "\u001b[33m"; +exports.reset = "\u001b[0m"; +exports.clearScreen = "\u001b[2J\u001b[0;0H"; diff --git a/scripts/local/util/getLatestModuleVersionsAsync.js b/scripts/local/util/getLatestModuleVersionsAsync.js new file mode 100644 index 0000000000..b8309ac35b --- /dev/null +++ b/scripts/local/util/getLatestModuleVersionsAsync.js @@ -0,0 +1,46 @@ +const { runAsync } = require("./runAsync.js"); + +function parseTag(tag) { + const parseTagScript = require("../../github-actions/parse-tag.js"); + + let modulePath, version; + parseTagScript({ + core: { + setOutput: (key, value) => { + if (key === "version") { + version = value; + } else if (key === "module_path") { + modulePath = value; + } + }, + setFailed: (message) => { + throw new Error(message); + }, + }, + tag, + }); + + return { modulePath, version }; +} + +async function getLatestModuleVersionsAsync() { + const tags = (await runAsync(`git tag -l`, false)) + .split("\n") + .filter((tag) => tag !== ""); + const latestModules = new Map(); + for (const tag of tags) { + const { modulePath, version } = parseTag(tag); + if (!latestModules.has(modulePath)) { + latestModules.set(modulePath, version); + } else { + const currentVersion = latestModules.get(modulePath); + if (version > currentVersion) { + latestModules.set(modulePath, version); + } + } + } + + return Array.from(latestModules); +} + +exports.getLatestModuleVersionsAsync = getLatestModuleVersionsAsync; diff --git a/scripts/local/util/runAsync.js b/scripts/local/util/runAsync.js new file mode 100644 index 0000000000..b40a6d0540 --- /dev/null +++ b/scripts/local/util/runAsync.js @@ -0,0 +1,72 @@ +let runAll = false; + +const { exec } = require("child_process"); +const { promisify } = require("util"); +const { yellow, red, reset } = require("./colors"); + +const execPromise = promisify(exec); + +async function runAsync(cmd, echo = true) { + if (echo) { + console.log(`${yellow}${cmd}${reset}`); + } + + const response = await execPromise(cmd, {}); + if (echo) { + console.log(`> ${response.stdout}`); + } + return response.stdout; +} + +function queryUserAsync(question) { + const readline = require("readline").createInterface({ + input: process.stdin, + output: process.stdout, + }); + + return new Promise((resolve) => { + readline.question(question, (answer) => { + readline.close(); + resolve(answer); + }); + }); +} + +async function queryRunAsync(cmds, optionalFriendlyPrompt) { + cmds = typeof cmds === "string" ? [cmds] : cmds; + let run = runAll === true; + if (!run) { + const prompt = + `${red}` + + (optionalFriendlyPrompt ?? + `Run the following commands?\n${yellow}${cmds.join("\n")}${reset}?`); + const answer = await queryUserAsync( + `${reset}${prompt} ${red}(y/n/a/q)${reset}` + ); + console.log(`answer: ${answer}`); + + if (answer === "y") { + run = true; + } else if (answer === "a") { + runAll = true; + run = true; + } else if (answer === "q") { + throw new Error("User aborted"); + } + } + + if (run) { + for (const cmd of cmds) { + await runAsync(cmd); + } + + return true; + } else { + return false; + } +} + +exports.runAsync = runAsync; +exports.queryRunAsync = queryRunAsync; +exports.queryUserAsync = queryUserAsync; +exports.runAll = runAll; diff --git a/scripts/local/util/updateReadmeExamples.js b/scripts/local/util/updateReadmeExamples.js new file mode 100644 index 0000000000..1f3bf20840 --- /dev/null +++ b/scripts/local/util/updateReadmeExamples.js @@ -0,0 +1,70 @@ +const { readFileSync } = require("fs"); + +// Updates the module version references in the README.md file +function updateReadmeExamples( + modulePath, + currentVersion, // what the current version should be + updateToVersion // update all versions to this +) { + const fs = require("fs"); + const path = require("path"); + const red = "\u001b[31m"; + const green = "\u001b[32m"; + const blue = "\u001b[34m"; + const yellow = "\u001b[33m"; + const reset = "\u001b[0m"; + + console.log(`Updating README.md examples for ${modulePath}...`); + + const readmePath = path.join("./modules", modulePath, "README.md"); + const readmeContent = readFileSync(readmePath, "utf8"); + + const currentModulePath = `br/public:${modulePath}:${currentVersion}`; + const nextModulePath = `br/public:${modulePath}:${updateToVersion}`; + + const versionPattern = "[0-9.a-z]+"; + const anyRefPattern = `br/public:${modulePath}:${versionPattern}`; + + // Look for unexpected versions + let versions = Array.from(readmeContent.matchAll(anyRefPattern)); + versions = Array.from(new Set(versions.map((m) => m[0]))); // dedupe + if (versions.length === 0) { + console.warn( + `${yellow}No module references found in ${readmePath}.${reset}` + ); + return false; + } + + const unexpectedVersions = versions.filter( + (m) => m !== currentModulePath && m !== nextModulePath + ); + if (unexpectedVersions.length > 0) { + console.error( + `... ${red}UNEXPECTED VERSIONS FOUND in ${readmePath}: ${unexpectedVersions}${reset}` + ); + console.error( + currentModulePath == nextModulePath + ? `... Expected ${currentModulePath}` + : `... Expected either ${currentModulePath} or ${nextModulePath}${reset}` + ); + } + + const updatedReadmeContent = readmeContent.replace( + new RegExp(anyRefPattern, "g"), + nextModulePath + ); + if (updatedReadmeContent !== readmeContent) { + console.log( + `... ${green}Updated module references in README.md to ${nextModulePath}.${reset}` + ); + fs.writeFileSync(readmePath, updatedReadmeContent, "utf8"); + return true; + } else { + console.log( + `... ${blue}Module references in README.md are up-to-date.${reset}` + ); + return false; + } +} + +exports.updateReadmeExamples = updateReadmeExamples; From d20afebd3f7486779747f8651ca98c1e7c3e5c73 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Mon, 29 Apr 2024 17:44:12 +0200 Subject: [PATCH 50/55] Added workflow --- .../platform.deployment.history.cleanup.yml | 126 ++++++++++++++++++ ...Clear-ManagementGroupDeploymentHistory.ps1 | 118 ++++++++++++++++ .../Clear-SubscriptionDeploymentHistory.ps1 | 122 +++++++++++++++++ 3 files changed, 366 insertions(+) create mode 100644 .github/workflows/platform.deployment.history.cleanup.yml create mode 100644 avm/utilities/pipelines/platform/deploymentRemoval/Clear-ManagementGroupDeploymentHistory.ps1 create mode 100644 avm/utilities/pipelines/platform/deploymentRemoval/Clear-SubscriptionDeploymentHistory.ps1 diff --git a/.github/workflows/platform.deployment.history.cleanup.yml b/.github/workflows/platform.deployment.history.cleanup.yml new file mode 100644 index 0000000000..18e9b98278 --- /dev/null +++ b/.github/workflows/platform.deployment.history.cleanup.yml @@ -0,0 +1,126 @@ +name: ".Platform - Clean up deployment history" + +on: + workflow_dispatch: + inputs: + handleSubscriptionScope: + type: boolean + description: "Include Subscription deployments" + required: false + default: true # Note: This requires your service principal to have permissions on the subscription scope. + handleManagementGroupScope: + type: boolean + description: "Include Management Group deployments" + required: false + default: true # Note: This requires your service principal to have permissions on the management group scope. + maxDeploymentRetentionInDays: + type: string + description: "The number of days to keep deployments with status [failed]" # 'Running' are always excluded + required: false + default: "14" + schedule: + - cron: "0 0 * * *" + +env: + workflowPath: ".github/workflows/platform.deployment.history.cleanup.yml" + +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}}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + + ############### + # Removal # + ############### + job_cleanup_subscription_deployments: + runs-on: ubuntu-20.04 + name: "Remove Subscription deployments" + needs: + - job_initialize_pipeline + if: ${{ (fromJson(needs.job_initialize_pipeline.outputs.workflowInput)).handleSubscriptionScope == 'true' }} + steps: + - name: "Checkout" + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Set environment + uses: ./.github/actions/templates/avm-setEnvironment + + - name: Azure Login + uses: azure/login@v1 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + enable-AzPSSession: true + + - name: Remove deployments + uses: azure/powershell@v1 + with: + inlineScript: | + # Load used functions + . (Join-Path $env:GITHUB_WORKSPACE 'avm' 'utilities' 'pipelines' 'platform' 'deploymentRemoval' 'Clear-SubscriptionDeploymentHistory.ps1') + + $functionInput = @{ + SubscriptionId = '${{ secrets.ARM_SUBSCRIPTION_ID }}' + maxDeploymentRetentionInDays = '${{ (fromJson(needs.job_initialize_pipeline.outputs.workflowInput)).maxDeploymentRetentionInDays }}' + } + + Write-Verbose "Invoke task with" -Verbose + Write-Verbose ($functionInput | ConvertTo-Json | Out-String) -Verbose + + Clear-SubscriptionDeploymentHistory @functionInput + azPSVersion: "latest" + + job_cleanup_managementGroup_deployments: + runs-on: ubuntu-20.04 + name: "Remove Management Group deployments" + needs: + - job_initialize_pipeline + if: ${{ (fromJson(needs.job_initialize_pipeline.outputs.workflowInput)).handleManagementGroupScope == 'true' }} + steps: + - name: "Checkout" + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Set environment + uses: ./.github/actions/templates/avm-setEnvironment + + - name: Azure Login + uses: azure/login@v1 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + enable-AzPSSession: true + + - name: Remove deployments + uses: azure/powershell@v1 + with: + inlineScript: | + # Load used functions + . (Join-Path $env:GITHUB_WORKSPACE 'avm' 'utilities' 'pipelines' 'platform' 'deploymentRemoval' 'Clear-ManagementGroupDeploymentHistory.ps1') + + $functionInput = @{ + ManagementGroupId = '${{ secrets.ARM_MGMTGROUP_ID }}' + maxDeploymentRetentionInDays = '${{ (fromJson(needs.job_initialize_pipeline.outputs.workflowInput)).maxDeploymentRetentionInDays }}' + } + + Write-Verbose "Invoke task with" -Verbose + Write-Verbose ($functionInput | ConvertTo-Json | Out-String) -Verbose + + Clear-ManagementGroupDeploymentHistory @functionInput + azPSVersion: "latest" diff --git a/avm/utilities/pipelines/platform/deploymentRemoval/Clear-ManagementGroupDeploymentHistory.ps1 b/avm/utilities/pipelines/platform/deploymentRemoval/Clear-ManagementGroupDeploymentHistory.ps1 new file mode 100644 index 0000000000..050a6ab668 --- /dev/null +++ b/avm/utilities/pipelines/platform/deploymentRemoval/Clear-ManagementGroupDeploymentHistory.ps1 @@ -0,0 +1,118 @@ + +<# +.SYNOPSIS +Bulk delete all deployments on the given management group scope + +.DESCRIPTION +Bulk delete all deployments on the given management group scope + +.PARAMETER ManagementGroupId +Mandatory. The Resource ID of the Management Group to remove the deployments from. + +.PARAMETER DeploymentStatusToExclude +Optional. The status to exlude from removals. Can be multiple. By default, we exclude any deployment that is in state 'running' or 'failed'. + +.PARAMETER maxDeploymentRetentionInDays +Optional. The time to keep deployments with a status to exclude. In other words, if a deployment is in a status to exclude, but older than the threshold, it will be deleted. + +.EXAMPLE +Clear-ManagementGroupDeploymentHistory -ManagementGroupId 'MyManagementGroupId' + +Bulk remove all 'non-running' & 'non-failed' deployments from the Management Group with ID 'MyManagementGroupId' + +.EXAMPLE +Clear-ManagementGroupDeploymentHistory -ManagementGroupId 'MyManagementGroupId' -DeploymentStatusToExclude @('running') + +Bulk remove all 'non-running' deployments from the Management Group with ID 'MyManagementGroupId' +#> +function Clear-ManagementGroupDeploymentHistory { + + + [CmdletBinding(SupportsShouldProcess)] + param ( + [Parameter(Mandatory = $true)] + [string] $ManagementGroupId, + + [Parameter(Mandatory = $false)] + [string[]] $DeploymentStatusToExclude = @('running', 'failed'), + + [Parameter(Mandatory = $false)] + [int] $maxDeploymentRetentionInDays = 14 + ) + + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 # Enables web reponse + $deploymentThreshold = (Get-Date).AddDays(-1 * $maxDeploymentRetentionInDays) + + # Load used functions + . (Join-Path (Split-Path $PSScriptRoot -Parent) 'sharedScripts' 'Split-Array.ps1') + + $getInputObject = @{ + Method = 'GET' + Uri = "https://management.azure.com/providers/Microsoft.Management/managementGroups/$ManagementGroupId/providers/Microsoft.Resources/deployments/?api-version=2021-04-01" + Headers = @{ + Authorization = 'Bearer {0}' -f (Get-AzAccessToken).Token + } + } + $response = Invoke-RestMethod @getInputObject + + if (($response | Get-Member -MemberType 'NoteProperty').Name -notcontains 'value') { + throw ('Fetching deployments failed with error [{0}]' -f ($reponse | Out-String)) + } + + Write-Verbose ('Found [{0}] deployments in management group [{1}]' -f $response.value.Count, $ManagementGroupId) -Verbose + + $relevantDeployments = $response.value | Where-Object { + $_.properties.provisioningState -notin $DeploymentStatusToExclude -or + ([DateTime]$_.properties.timestamp) -lt $deploymentThreshold -and + $_.properties.provisioningState -ne 'running' # we should never delete 'running' deployments + } + + Write-Verbose ('Filtering [{0}] deployments out as they are in state [{1}] or newer than [{2}] days ({3})' -f ($response.value.Count - $relevantDeployments.Count), ($DeploymentStatusToExclude -join '/'), $maxDeploymentRetentionInDays, $deploymentThreshold.ToString('yyyy-MM-dd')) -Verbose + + if (-not $relevantDeployments) { + Write-Verbose 'No deployments found' -Verbose + return + } + + $rawDeploymentChunks = Split-Array -InputArray $relevantDeployments -SplitSize 100 + if ($relevantDeployments.Count -le 100) { + $relevantDeploymentChunks = , $rawDeploymentChunks + } else { + $relevantDeploymentChunks = $rawDeploymentChunks + } + + Write-Verbose ('Triggering the removal of [{0}] deployments from management group [{1}]' -f $relevantDeployments.Count, $ManagementGroupId) -Verbose + + foreach ($deployments in $relevantDeploymentChunks) { + + $requests = $deployments | ForEach-Object { + @{ httpMethod = 'DELETE' + name = (New-Guid).Guid # Each batch request needs a unique ID + requestHeaderDetails = @{ + commandName = 'HubsExtension.Microsoft.Resources/deployments.BulkDelete.execute' + } + url = '/providers/Microsoft.Management/managementGroups/{0}/providers/Microsoft.Resources/deployments/{1}?api-version=2019-08-01' -f $ManagementGroupId, $_.name + } + } + + if ($requests -is [hashtable]) { + $requests = , $requests + } + + $removeInputObject = @{ + Method = 'POST' + Uri = 'https://management.azure.com/batch?api-version=2020-06-01' + Headers = @{ + Authorization = 'Bearer {0}' -f (Get-AzAccessToken).Token + 'Content-Type' = 'application/json' + } + Body = @{ + requests = $requests + } | ConvertTo-Json -Depth 4 + } + if ($PSCmdlet.ShouldProcess(('Removal of [{0}] deployments' -f $requests.Count), 'Request')) { + $null = Invoke-RestMethod @removeInputObject + } + } + Write-Verbose 'Script execution finished. Note that the removal can take a few minutes to propagate.' -Verbose +} diff --git a/avm/utilities/pipelines/platform/deploymentRemoval/Clear-SubscriptionDeploymentHistory.ps1 b/avm/utilities/pipelines/platform/deploymentRemoval/Clear-SubscriptionDeploymentHistory.ps1 new file mode 100644 index 0000000000..c96e3f928b --- /dev/null +++ b/avm/utilities/pipelines/platform/deploymentRemoval/Clear-SubscriptionDeploymentHistory.ps1 @@ -0,0 +1,122 @@ + +<# +.SYNOPSIS +Bulk delete all deployments on the given subscription scope + +.DESCRIPTION +Bulk delete all deployments on the given subscription scope + +.PARAMETER subscriptionId +Optional. The ID of the subscription to remove the deployments from. Defaults to the current context. + +.PARAMETER DeploymentStatusToExclude +Optional. The status to exlude from removals. Can be multiple. By default, we exclude any deployment that is in state 'running' or 'failed'. + +.PARAMETER maxDeploymentRetentionInDays +Optional. The time to keep deployments with a status to exclude. In other words, if a deployment is in a status to exclude, but older than the threshold, it will be deleted. + +.EXAMPLE +Clear-SubscriptionDeploymentHistory -subscriptionId '11111111-1111-1111-1111-111111111111' + +Bulk remove all 'non-running' & 'non-failed' deployments from the subscription with ID '11111111-1111-1111-1111-111111111111' + +.EXAMPLE +Clear-SubscriptionDeploymentHistory -subscriptionId '11111111-1111-1111-1111-111111111111' -DeploymentStatusToExclude @('running') + +Bulk remove all 'non-running' deployments from the subscription with ID '11111111-1111-1111-1111-111111111111' +#> +function Clear-SubscriptionDeploymentHistory { + + + [CmdletBinding(SupportsShouldProcess)] + param ( + [Parameter(Mandatory = $false)] + [string] $subscriptionId = (Get-AzContext).Subscription.Id, + + [Parameter(Mandatory = $false)] + [string[]] $DeploymentStatusToExclude = @('running', 'failed'), + + [Parameter(Mandatory = $false)] + [int] $maxDeploymentRetentionInDays = 14 + ) + + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 # Enables web reponse + $deploymentThreshold = (Get-Date).AddDays(-1 * $maxDeploymentRetentionInDays) + + # Load used functions + . (Join-Path (Split-Path $PSScriptRoot -Parent) 'sharedScripts' 'Split-Array.ps1') + + # Setting context explicitely in case the principal has permissions on multiple + Write-Verbose ('Setting context to subscription [{0}]' -f $subscriptionId) + $null = Set-AzContext -Subscription $subscriptionId + + $getInputObject = @{ + Method = 'GET' + Uri = "https://management.azure.com/subscriptions/$subscriptionId/providers/Microsoft.Resources/deployments?api-version=2020-06-01" + Headers = @{ + Authorization = 'Bearer {0}' -f (Get-AzAccessToken).Token + } + } + $response = Invoke-RestMethod @getInputObject + + if (($response | Get-Member -MemberType 'NoteProperty').Name -notcontains 'value') { + throw ('Fetching deployments failed with error [{0}]' -f ($reponse | Out-String)) + } + + Write-Verbose ('Found [{0}] deployments in subscription [{1}]' -f $response.value.Count, $subscriptionId) -Verbose + + $relevantDeployments = $response.value | Where-Object { + $_.properties.provisioningState -notin $DeploymentStatusToExclude -or + ([DateTime]$_.properties.timestamp) -lt $deploymentThreshold -and + $_.properties.provisioningState -ne 'running' # we should never delete 'running' deployments + } + + Write-Verbose ('Filtering [{0}] deployments out as they are in state [{1}] or newer than [{2}] days ({3})' -f ($response.value.Count - $relevantDeployments.Count), ($DeploymentStatusToExclude -join '/'), $maxDeploymentRetentionInDays, $deploymentThreshold.ToString('yyyy-MM-dd')) -Verbose + + if (-not $relevantDeployments) { + Write-Verbose ('No deployments for subscription [{0}] found' -f $subscriptionId) -Verbose + return + } + + $rawDeploymentChunks = Split-Array -InputArray $relevantDeployments -SplitSize 100 + if ($relevantDeployments.Count -le 100) { + $relevantDeploymentChunks = , $rawDeploymentChunks + } else { + $relevantDeploymentChunks = $rawDeploymentChunks + } + + Write-Verbose ('Triggering the removal of [{0}] deployments from subscription [{1}]' -f $relevantDeployments.Count, $subscriptionId) -Verbose + + foreach ($deployments in $relevantDeploymentChunks) { + + $requests = $deployments | ForEach-Object { + @{ httpMethod = 'DELETE' + name = (New-Guid).Guid # Each batch request needs a unique ID + requestHeaderDetails = @{ + commandName = 'HubsExtension.Microsoft.Resources/deployments.BulkDelete.execute' + } + url = '/subscriptions/{0}/providers/Microsoft.Resources/deployments/{1}?api-version=2019-08-01' -f $subscriptionId, $_.name + } + } + + if ($requests -is [hashtable]) { + $requests = , $requests + } + + $removeInputObject = @{ + Method = 'POST' + Uri = 'https://management.azure.com/batch?api-version=2020-06-01' + Headers = @{ + Authorization = 'Bearer {0}' -f (Get-AzAccessToken).Token + 'Content-Type' = 'application/json' + } + Body = @{ + requests = $requests + } | ConvertTo-Json -Depth 4 -EnumsAsStrings + } + if ($PSCmdlet.ShouldProcess(('Removal of [{0}] deployments' -f $requests.Count), 'Request')) { + $null = Invoke-RestMethod @removeInputObject + } + } + Write-Verbose 'Script execution finished. Note that the removal can take a few minutes to propagate.' -Verbose +} From 2157079ac89f6a65388d07eeb1e621b14b42d77b Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Mon, 29 Apr 2024 17:57:18 +0200 Subject: [PATCH 51/55] Update to latest --- ...Clear-ManagementGroupDeploymentHistory.ps1 | 3 ++ .../Clear-SubscriptionDeploymentHistory.ps1 | 3 ++ .../pipelines/platform/helper/Split-Array.ps1 | 47 +++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 avm/utilities/pipelines/platform/helper/Split-Array.ps1 diff --git a/avm/utilities/pipelines/platform/deploymentRemoval/Clear-ManagementGroupDeploymentHistory.ps1 b/avm/utilities/pipelines/platform/deploymentRemoval/Clear-ManagementGroupDeploymentHistory.ps1 index 050a6ab668..09241272bc 100644 --- a/avm/utilities/pipelines/platform/deploymentRemoval/Clear-ManagementGroupDeploymentHistory.ps1 +++ b/avm/utilities/pipelines/platform/deploymentRemoval/Clear-ManagementGroupDeploymentHistory.ps1 @@ -40,6 +40,9 @@ function Clear-ManagementGroupDeploymentHistory { [int] $maxDeploymentRetentionInDays = 14 ) + # Load helper functions + . (Join-Path (Split-Path $PSScriptRoot) 'helper' 'Split-Array.ps1') + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 # Enables web reponse $deploymentThreshold = (Get-Date).AddDays(-1 * $maxDeploymentRetentionInDays) diff --git a/avm/utilities/pipelines/platform/deploymentRemoval/Clear-SubscriptionDeploymentHistory.ps1 b/avm/utilities/pipelines/platform/deploymentRemoval/Clear-SubscriptionDeploymentHistory.ps1 index c96e3f928b..46df3f960b 100644 --- a/avm/utilities/pipelines/platform/deploymentRemoval/Clear-SubscriptionDeploymentHistory.ps1 +++ b/avm/utilities/pipelines/platform/deploymentRemoval/Clear-SubscriptionDeploymentHistory.ps1 @@ -40,6 +40,9 @@ function Clear-SubscriptionDeploymentHistory { [int] $maxDeploymentRetentionInDays = 14 ) + # Load helper functions + . (Join-Path (Split-Path $PSScriptRoot) 'helper' 'Split-Array.ps1') + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 # Enables web reponse $deploymentThreshold = (Get-Date).AddDays(-1 * $maxDeploymentRetentionInDays) diff --git a/avm/utilities/pipelines/platform/helper/Split-Array.ps1 b/avm/utilities/pipelines/platform/helper/Split-Array.ps1 new file mode 100644 index 0000000000..f886d194f0 --- /dev/null +++ b/avm/utilities/pipelines/platform/helper/Split-Array.ps1 @@ -0,0 +1,47 @@ +<# +.SYNOPSIS +Split a given array evenly into chunks of n-items + +.DESCRIPTION +Split a given array evenly into chunks of n-item + +.PARAMETER InputArray +Mandatory. The array to split + +.PARAMETER SplitSize +Mandatory. The chunk size to split into. + +.EXAMPLE +Split-Array -InputArray @('1','2,'3','4','5') -SplitSize 3 + +Split the given array @('1','2,'3','4','5') into chunks of size '3'. Will return the multi-demensional array @(@('1','2,'3'),@('4','5')) +#> +function Split-Array { + + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [object[]] $InputArray, + + [Parameter(Mandatory = $true)] + [int] $SplitSize + ) + begin { + Write-Debug ('{0} entered' -f $MyInvocation.MyCommand) + } + process { + + if ($splitSize -ge $InputArray.Count) { + return $InputArray + } else { + $res = @() + for ($Index = 0; $Index -lt $InputArray.Count; $Index += $SplitSize) { + $res += , ( $InputArray[$index..($index + $splitSize - 1)] ) + } + return $res + } + } + end { + Write-Debug ('{0} existed' -f $MyInvocation.MyCommand) + } +} From 2bd31295b71b88d670f799febc4d826d87addb3a Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Mon, 29 Apr 2024 18:02:49 +0200 Subject: [PATCH 52/55] Small fix --- .../Clear-ManagementGroupDeploymentHistory.ps1 | 3 --- .../deploymentRemoval/Clear-SubscriptionDeploymentHistory.ps1 | 3 --- 2 files changed, 6 deletions(-) diff --git a/avm/utilities/pipelines/platform/deploymentRemoval/Clear-ManagementGroupDeploymentHistory.ps1 b/avm/utilities/pipelines/platform/deploymentRemoval/Clear-ManagementGroupDeploymentHistory.ps1 index 09241272bc..f84d790395 100644 --- a/avm/utilities/pipelines/platform/deploymentRemoval/Clear-ManagementGroupDeploymentHistory.ps1 +++ b/avm/utilities/pipelines/platform/deploymentRemoval/Clear-ManagementGroupDeploymentHistory.ps1 @@ -46,9 +46,6 @@ function Clear-ManagementGroupDeploymentHistory { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 # Enables web reponse $deploymentThreshold = (Get-Date).AddDays(-1 * $maxDeploymentRetentionInDays) - # Load used functions - . (Join-Path (Split-Path $PSScriptRoot -Parent) 'sharedScripts' 'Split-Array.ps1') - $getInputObject = @{ Method = 'GET' Uri = "https://management.azure.com/providers/Microsoft.Management/managementGroups/$ManagementGroupId/providers/Microsoft.Resources/deployments/?api-version=2021-04-01" diff --git a/avm/utilities/pipelines/platform/deploymentRemoval/Clear-SubscriptionDeploymentHistory.ps1 b/avm/utilities/pipelines/platform/deploymentRemoval/Clear-SubscriptionDeploymentHistory.ps1 index 46df3f960b..234bd4139f 100644 --- a/avm/utilities/pipelines/platform/deploymentRemoval/Clear-SubscriptionDeploymentHistory.ps1 +++ b/avm/utilities/pipelines/platform/deploymentRemoval/Clear-SubscriptionDeploymentHistory.ps1 @@ -46,9 +46,6 @@ function Clear-SubscriptionDeploymentHistory { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 # Enables web reponse $deploymentThreshold = (Get-Date).AddDays(-1 * $maxDeploymentRetentionInDays) - # Load used functions - . (Join-Path (Split-Path $PSScriptRoot -Parent) 'sharedScripts' 'Split-Array.ps1') - # Setting context explicitely in case the principal has permissions on multiple Write-Verbose ('Setting context to subscription [{0}]' -f $subscriptionId) $null = Set-AzContext -Subscription $subscriptionId From 71c34e473fde389fd5dc63be5f4319386b249c30 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Thu, 2 May 2024 17:57:15 +0200 Subject: [PATCH 53/55] Update to latest --- .github/workflows/avm.res.app.job.yml | 86 +++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 .github/workflows/avm.res.app.job.yml diff --git a/.github/workflows/avm.res.app.job.yml b/.github/workflows/avm.res.app.job.yml new file mode 100644 index 0000000000..ac92a6f406 --- /dev/null +++ b/.github/workflows/avm.res.app.job.yml @@ -0,0 +1,86 @@ +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 + 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 From 8a29af8a3e4e10f77629d703b5535f94dc241755 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Fri, 13 Sep 2024 11:58:14 +0200 Subject: [PATCH 54/55] Resolved conflicts & refreshed files --- avm/res/key-vault/vault/README.md | 26 ++++++++++++++++++- .../key-vault/vault/access-policy/main.json | 5 ---- avm/res/key-vault/vault/key/README.md | 5 +--- avm/res/key-vault/vault/key/main.json | 5 ---- avm/res/key-vault/vault/main.json | 20 -------------- avm/res/key-vault/vault/secret/README.md | 6 +---- .../sharedScripts/Set-ModuleReadMe.ps1 | 5 +--- 7 files changed, 28 insertions(+), 44 deletions(-) diff --git a/avm/res/key-vault/vault/README.md b/avm/res/key-vault/vault/README.md index 0c0e96d933..9997df4ed0 100644 --- a/avm/res/key-vault/vault/README.md +++ b/avm/res/key-vault/vault/README.md @@ -1681,6 +1681,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Key Vault Administrator'` + - `'Key Vault Contributor'` + - `'Key Vault Crypto Officer'` + - `'Key Vault Crypto Service Encryption User'` + - `'Key Vault Crypto User'` + - `'Key Vault Reader'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -2365,6 +2377,7 @@ Array of role assignments to create. - `'Contributor'` - `'Key Vault Administrator'` - `'Key Vault Certificates Officer'` + - `'Key Vault Certificate User'` - `'Key Vault Contributor'` - `'Key Vault Crypto Officer'` - `'Key Vault Crypto Service Encryption User'` @@ -2374,7 +2387,7 @@ Array of role assignments to create. - `'Key Vault Secrets User'` - `'Owner'` - `'Reader'` - - `'Role Based Access Control Administrator (Preview)'` + - `'Role Based Access Control Administrator'` - `'User Access Administrator'` **Required parameters** @@ -2553,6 +2566,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Key Vault Administrator'` + - `'Key Vault Contributor'` + - `'Key Vault Reader'` + - `'Key Vault Secrets Officer'` + - `'Key Vault Secrets User'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/key-vault/vault/access-policy/main.json b/avm/res/key-vault/vault/access-policy/main.json index 7edb95c902..ba6a0ab33f 100644 --- a/avm/res/key-vault/vault/access-policy/main.json +++ b/avm/res/key-vault/vault/access-policy/main.json @@ -5,13 +5,8 @@ "metadata": { "_generator": { "name": "bicep", -<<<<<<< users/alsehr/readme_Roles - "version": "0.27.1.19265", - "templateHash": "13379419349517171769" -======= "version": "0.29.47.4906", "templateHash": "7494731697751039419" ->>>>>>> main }, "name": "Key Vault Access Policies", "description": "This module deploys a Key Vault Access Policy.", diff --git a/avm/res/key-vault/vault/key/README.md b/avm/res/key-vault/vault/key/README.md index cdd13cd6c0..a5dfe17fe2 100644 --- a/avm/res/key-vault/vault/key/README.md +++ b/avm/res/key-vault/vault/key/README.md @@ -157,17 +157,14 @@ Array of role assignments to create. - Roles configurable by name: - `'Contributor'` - `'Key Vault Administrator'` - - `'Key Vault Certificates Officer'` - `'Key Vault Contributor'` - `'Key Vault Crypto Officer'` - `'Key Vault Crypto Service Encryption User'` - `'Key Vault Crypto User'` - `'Key Vault Reader'` - - `'Key Vault Secrets Officer'` - - `'Key Vault Secrets User'` - `'Owner'` - `'Reader'` - - `'Role Based Access Control Administrator (Preview)'` + - `'Role Based Access Control Administrator'` - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/key-vault/vault/key/main.json b/avm/res/key-vault/vault/key/main.json index 9ad82a9089..63c2159cb2 100644 --- a/avm/res/key-vault/vault/key/main.json +++ b/avm/res/key-vault/vault/key/main.json @@ -5,13 +5,8 @@ "metadata": { "_generator": { "name": "bicep", -<<<<<<< users/alsehr/readme_Roles - "version": "0.27.1.19265", - "templateHash": "12348300599961129774" -======= "version": "0.29.47.4906", "templateHash": "14269695922191217406" ->>>>>>> main }, "name": "Key Vault Keys", "description": "This module deploys a Key Vault Key.", diff --git a/avm/res/key-vault/vault/main.json b/avm/res/key-vault/vault/main.json index 0785bd9fff..74ea3bdd03 100644 --- a/avm/res/key-vault/vault/main.json +++ b/avm/res/key-vault/vault/main.json @@ -5,13 +5,8 @@ "metadata": { "_generator": { "name": "bicep", -<<<<<<< users/alsehr/readme_Roles - "version": "0.27.1.19265", - "templateHash": "6795174546908413153" -======= "version": "0.29.47.4906", "templateHash": "8938543730613882040" ->>>>>>> main }, "name": "Key Vaults", "description": "This module deploys a Key Vault.", @@ -1229,13 +1224,8 @@ "metadata": { "_generator": { "name": "bicep", -<<<<<<< users/alsehr/readme_Roles - "version": "0.27.1.19265", - "templateHash": "13379419349517171769" -======= "version": "0.29.47.4906", "templateHash": "7494731697751039419" ->>>>>>> main }, "name": "Key Vault Access Policies", "description": "This module deploys a Key Vault Access Policy.", @@ -1503,13 +1493,8 @@ "metadata": { "_generator": { "name": "bicep", -<<<<<<< users/alsehr/readme_Roles - "version": "0.27.1.19265", - "templateHash": "6420465919494344964" -======= "version": "0.29.47.4906", "templateHash": "114626909766354577" ->>>>>>> main }, "name": "Key Vault Secrets", "description": "This module deploys a Key Vault Secret.", @@ -1806,13 +1791,8 @@ "metadata": { "_generator": { "name": "bicep", -<<<<<<< users/alsehr/readme_Roles - "version": "0.27.1.19265", - "templateHash": "12348300599961129774" -======= "version": "0.29.47.4906", "templateHash": "14269695922191217406" ->>>>>>> main }, "name": "Key Vault Keys", "description": "This module deploys a Key Vault Key.", diff --git a/avm/res/key-vault/vault/secret/README.md b/avm/res/key-vault/vault/secret/README.md index f22002ea46..b05c38071f 100644 --- a/avm/res/key-vault/vault/secret/README.md +++ b/avm/res/key-vault/vault/secret/README.md @@ -100,17 +100,13 @@ Array of role assignments to create. - Roles configurable by name: - `'Contributor'` - `'Key Vault Administrator'` - - `'Key Vault Certificates Officer'` - `'Key Vault Contributor'` - - `'Key Vault Crypto Officer'` - - `'Key Vault Crypto Service Encryption User'` - - `'Key Vault Crypto User'` - `'Key Vault Reader'` - `'Key Vault Secrets Officer'` - `'Key Vault Secrets User'` - `'Owner'` - `'Reader'` - - `'Role Based Access Control Administrator (Preview)'` + - `'Role Based Access Control Administrator'` - `'User Access Administrator'` **Required parameters** diff --git a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 index 25b025d04c..09355c6f9d 100644 --- a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 +++ b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 @@ -481,11 +481,8 @@ function Set-DefinitionSection { ('- Type: {0}' -f $type), ((-not [String]::IsNullOrEmpty($formattedDefaultValue)) ? $formattedDefaultValue : $null), ((-not [String]::IsNullOrEmpty($formattedAllowedValues)) ? $formattedAllowedValues : $null), -<<<<<<< users/alsehr/readme_Roles ((-not [String]::IsNullOrEmpty($formattedRoleNames)) ? $formattedRoleNames : $null), -======= - ((-not [String]::IsNullOrEmpty($formattedExample)) ? $formattedExample : $null) ->>>>>>> main + ((-not [String]::IsNullOrEmpty($formattedExample)) ? $formattedExample : $null), '' ) | Where-Object { $null -ne $_ } From 1a6f4383eaf0c8fdd839a5b1591e0e180f6a80cf Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Fri, 13 Sep 2024 14:52:47 +0200 Subject: [PATCH 55/55] Regenerated all docs --- avm/res/aad/domain-service/README.md | 6 + .../alerts-management/action-rule/README.md | 6 + avm/res/analysis-services/server/README.md | 6 + avm/res/api-management/service/README.md | 10 ++ .../configuration-store/README.md | 21 +++ avm/res/app/container-app/README.md | 7 + avm/res/app/job/README.md | 7 + avm/res/app/managed-environment/README.md | 6 + .../automation/automation-account/README.md | 21 +++ avm/res/batch/batch-account/README.md | 2 +- avm/res/cache/redis/README.md | 18 +++ avm/res/cdn/profile/README.md | 10 ++ avm/res/cognitive-services/account/README.md | 41 ++++++ .../communication-service/README.md | 6 + avm/res/communication/email-service/README.md | 6 + .../email-service/domain/README.md | 6 + avm/res/compute/availability-set/README.md | 10 ++ avm/res/compute/disk-encryption-set/README.md | 11 ++ avm/res/compute/disk/README.md | 11 ++ avm/res/compute/gallery/README.md | 7 + avm/res/compute/gallery/application/README.md | 7 + avm/res/compute/gallery/image/README.md | 7 + avm/res/compute/image/README.md | 6 + .../proximity-placement-group/README.md | 6 + avm/res/compute/ssh-public-key/README.md | 6 + .../virtual-machine-scale-set/README.md | 19 +++ avm/res/compute/virtual-machine/README.md | 19 +++ avm/res/container-registry/registry/README.md | 23 +++ .../managed-cluster/README.md | 20 +++ avm/res/data-factory/factory/README.md | 18 +++ .../data-protection/backup-vault/README.md | 9 ++ avm/res/databricks/access-connector/README.md | 6 + avm/res/databricks/workspace/README.md | 12 ++ .../db-for-my-sql/flexible-server/README.md | 7 + .../flexible-server/README.md | 6 + .../application-group/README.md | 23 +++ .../host-pool/README.md | 34 +++++ .../scaling-plan/README.md | 20 +++ .../workspace/README.md | 31 ++++ avm/res/dev-test-lab/lab/README.md | 9 ++ .../digital-twins-instance/README.md | 19 +++ .../document-db/database-account/README.md | 22 +++ avm/res/event-grid/domain/README.md | 21 +++ avm/res/event-grid/namespace/README.md | 25 ++++ .../namespace/topic-space/README.md | 14 ++ avm/res/event-grid/namespace/topic/README.md | 14 ++ .../topic/event-subscription/README.md | 14 ++ avm/res/event-grid/system-topic/README.md | 10 ++ avm/res/event-grid/topic/README.md | 21 +++ avm/res/event-hub/namespace/README.md | 20 +++ .../event-hub/namespace/eventhub/README.md | 9 ++ avm/res/health-bot/health-bot/README.md | 6 + avm/res/healthcare-apis/workspace/README.md | 15 ++ .../workspace/fhirservice/README.md | 15 ++ avm/res/hybrid-compute/machine/README.md | 10 ++ avm/res/insights/action-group/README.md | 6 + avm/res/insights/activity-log-alert/README.md | 6 + avm/res/insights/component/README.md | 10 ++ .../data-collection-endpoint/README.md | 6 + .../insights/data-collection-rule/README.md | 6 + avm/res/insights/metric-alert/README.md | 6 + avm/res/insights/private-link-scope/README.md | 26 ++++ .../insights/scheduled-query-rule/README.md | 6 + avm/res/insights/webtest/README.md | 6 + avm/res/kusto/cluster/README.md | 15 ++ avm/res/load-test-service/load-test/README.md | 6 + avm/res/logic/workflow/README.md | 8 ++ .../workspace/README.md | 21 +++ .../maintenance-configuration/README.md | 7 + .../user-assigned-identity/README.md | 8 ++ avm/res/net-app/net-app-account/README.md | 6 + .../net-app-account/capacity-pool/README.md | 6 + .../capacity-pool/volume/README.md | 6 + avm/res/network/application-gateway/README.md | 17 +++ .../application-security-group/README.md | 6 + avm/res/network/azure-firewall/README.md | 6 + avm/res/network/bastion-host/README.md | 6 + .../network/ddos-protection-plan/README.md | 6 + .../network/dns-forwarding-ruleset/README.md | 9 ++ avm/res/network/dns-resolver/README.md | 11 ++ avm/res/network/dns-zone/README.md | 132 ++++++++++++++++++ avm/res/network/dns-zone/a/README.md | 12 ++ avm/res/network/dns-zone/aaaa/README.md | 12 ++ avm/res/network/dns-zone/caa/README.md | 12 ++ avm/res/network/dns-zone/cname/README.md | 12 ++ avm/res/network/dns-zone/mx/README.md | 12 ++ avm/res/network/dns-zone/ns/README.md | 12 ++ avm/res/network/dns-zone/ptr/README.md | 12 ++ avm/res/network/dns-zone/soa/README.md | 12 ++ avm/res/network/dns-zone/srv/README.md | 12 ++ avm/res/network/dns-zone/txt/README.md | 12 ++ .../network/express-route-circuit/README.md | 7 + .../network/express-route-gateway/README.md | 7 + .../README.md | 6 + avm/res/network/front-door/README.md | 7 + avm/res/network/ip-group/README.md | 7 + avm/res/network/load-balancer/README.md | 7 + .../network/local-network-gateway/README.md | 7 + avm/res/network/nat-gateway/README.md | 7 + avm/res/network/network-interface/README.md | 9 ++ avm/res/network/network-manager/README.md | 10 ++ .../network/network-security-group/README.md | 7 + avm/res/network/network-watcher/README.md | 7 + avm/res/network/private-dns-zone/README.md | 71 ++++++++++ avm/res/network/private-dns-zone/a/README.md | 8 ++ .../network/private-dns-zone/aaaa/README.md | 8 ++ .../network/private-dns-zone/cname/README.md | 8 ++ avm/res/network/private-dns-zone/mx/README.md | 8 ++ .../network/private-dns-zone/ptr/README.md | 8 ++ .../network/private-dns-zone/soa/README.md | 8 ++ .../network/private-dns-zone/srv/README.md | 8 ++ .../network/private-dns-zone/txt/README.md | 8 ++ avm/res/network/private-endpoint/README.md | 11 ++ .../network/private-link-service/README.md | 8 ++ avm/res/network/public-ip-address/README.md | 11 ++ avm/res/network/public-ip-prefix/README.md | 7 + avm/res/network/route-table/README.md | 7 + .../network/service-endpoint-policy/README.md | 7 + .../network/trafficmanagerprofile/README.md | 8 ++ .../network/virtual-network-gateway/README.md | 7 + avm/res/network/virtual-network/README.md | 14 ++ .../network/virtual-network/subnet/README.md | 7 + avm/res/network/virtual-wan/README.md | 7 + avm/res/network/vpn-site/README.md | 7 + .../operational-insights/workspace/README.md | 12 ++ .../workspace/table/README.md | 10 ++ avm/res/portal/dashboard/README.md | 6 + avm/res/power-bi-dedicated/capacity/README.md | 8 ++ avm/res/purview/account/README.md | 18 +++ avm/res/recovery-services/vault/README.md | 23 +++ avm/res/relay/namespace/README.md | 20 +++ .../namespace/hybrid-connection/README.md | 9 ++ avm/res/relay/namespace/wcf-relay/README.md | 9 ++ avm/res/resource-graph/query/README.md | 6 + avm/res/resources/deployment-script/README.md | 6 + avm/res/search/search-service/README.md | 20 +++ avm/res/service-bus/namespace/README.md | 38 +++++ avm/res/service-bus/namespace/queue/README.md | 9 ++ avm/res/service-bus/namespace/topic/README.md | 9 ++ avm/res/service-fabric/cluster/README.md | 6 + avm/res/signal-r-service/signal-r/README.md | 25 ++++ .../signal-r-service/web-pub-sub/README.md | 25 ++++ avm/res/sql/managed-instance/README.md | 13 ++ avm/res/sql/server/README.md | 24 ++++ avm/res/storage/storage-account/README.md | 36 +++++ .../blob-service/container/README.md | 14 ++ .../queue-service/queue/README.md | 14 ++ .../table-service/table/README.md | 12 ++ avm/res/synapse/private-link-hub/README.md | 17 +++ avm/res/synapse/workspace/README.md | 18 +++ .../image-template/README.md | 6 + avm/res/web/connection/README.md | 6 + avm/res/web/hosting-environment/README.md | 6 + avm/res/web/serverfarm/README.md | 8 ++ avm/res/web/site/README.md | 9 ++ avm/res/web/site/slot/README.md | 20 +++ avm/res/web/static-site/README.md | 19 +++ 157 files changed, 2019 insertions(+), 1 deletion(-) diff --git a/avm/res/aad/domain-service/README.md b/avm/res/aad/domain-service/README.md index 9aa32399c5..1a8c5627a8 100644 --- a/avm/res/aad/domain-service/README.md +++ b/avm/res/aad/domain-service/README.md @@ -645,6 +645,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/alerts-management/action-rule/README.md b/avm/res/alerts-management/action-rule/README.md index 72c9e58af6..658f855769 100644 --- a/avm/res/alerts-management/action-rule/README.md +++ b/avm/res/alerts-management/action-rule/README.md @@ -603,6 +603,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/analysis-services/server/README.md b/avm/res/analysis-services/server/README.md index 18ad72dda3..32cb2ff12e 100644 --- a/avm/res/analysis-services/server/README.md +++ b/avm/res/analysis-services/server/README.md @@ -669,6 +669,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/api-management/service/README.md b/avm/res/api-management/service/README.md index fa41e81140..c219b2de19 100644 --- a/avm/res/api-management/service/README.md +++ b/avm/res/api-management/service/README.md @@ -1742,6 +1742,16 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'API Management Developer Portal Content Editor'` + - `'API Management Service Contributor'` + - `'API Management Service Operator Role'` + - `'API Management Service Reader Role'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/app-configuration/configuration-store/README.md b/avm/res/app-configuration/configuration-store/README.md index 06d8a2d62d..62362ac7a1 100644 --- a/avm/res/app-configuration/configuration-store/README.md +++ b/avm/res/app-configuration/configuration-store/README.md @@ -1303,6 +1303,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1435,6 +1446,16 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'App Compliance Automation Administrator'` + - `'App Compliance Automation Reader'` + - `'App Configuration Data Owner'` + - `'App Configuration Data Reader'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/app/container-app/README.md b/avm/res/app/container-app/README.md index 9ac975e122..a032f3411f 100644 --- a/avm/res/app/container-app/README.md +++ b/avm/res/app/container-app/README.md @@ -1409,6 +1409,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'ContainerApp Reader'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/app/job/README.md b/avm/res/app/job/README.md index a0d091b780..792068064b 100644 --- a/avm/res/app/job/README.md +++ b/avm/res/app/job/README.md @@ -1741,6 +1741,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'ContainerApp Reader'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/app/managed-environment/README.md b/avm/res/app/managed-environment/README.md index 66e8fe2364..75b860ddd7 100644 --- a/avm/res/app/managed-environment/README.md +++ b/avm/res/app/managed-environment/README.md @@ -778,6 +778,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/automation/automation-account/README.md b/avm/res/automation/automation-account/README.md index 8aa19e6b65..d6b50e257b 100644 --- a/avm/res/automation/automation-account/README.md +++ b/avm/res/automation/automation-account/README.md @@ -1853,6 +1853,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1973,6 +1984,16 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Automation Contributor'` + - `'Automation Job Operator'` + - `'Automation Operator'` + - `'Automation Runbook Operator'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/batch/batch-account/README.md b/avm/res/batch/batch-account/README.md index 3efdb184f4..788df94957 100644 --- a/avm/res/batch/batch-account/README.md +++ b/avm/res/batch/batch-account/README.md @@ -1542,7 +1542,7 @@ Array of role assignments to create. - `'Contributor'` - `'Owner'` - `'Reader'` - - `'Role Based Access Control Administrator (Preview)'` + - `'Role Based Access Control Administrator'` - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/cache/redis/README.md b/avm/res/cache/redis/README.md index fb766dff67..addd537447 100644 --- a/avm/res/cache/redis/README.md +++ b/avm/res/cache/redis/README.md @@ -1341,6 +1341,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1507,6 +1518,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Redis Cache Contributor'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/cdn/profile/README.md b/avm/res/cdn/profile/README.md index ccaf732ba3..369cadf61b 100644 --- a/avm/res/cdn/profile/README.md +++ b/avm/res/cdn/profile/README.md @@ -740,6 +740,16 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'CDN Endpoint Contributor'` + - `'CDN Endpoint Reader'` + - `'CDN Profile Contributor'` + - `'CDN Profile Reader'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/cognitive-services/account/README.md b/avm/res/cognitive-services/account/README.md index 9838b6a3e6..32e22ce46f 100644 --- a/avm/res/cognitive-services/account/README.md +++ b/avm/res/cognitive-services/account/README.md @@ -1869,6 +1869,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -2010,6 +2021,36 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Cognitive Services Contributor'` + - `'Cognitive Services Custom Vision Contributor'` + - `'Cognitive Services Custom Vision Deployment'` + - `'Cognitive Services Custom Vision Labeler'` + - `'Cognitive Services Custom Vision Reader'` + - `'Cognitive Services Custom Vision Trainer'` + - `'Cognitive Services Data Reader (Preview)'` + - `'Cognitive Services Face Recognizer'` + - `'Cognitive Services Immersive Reader User'` + - `'Cognitive Services Language Owner'` + - `'Cognitive Services Language Reader'` + - `'Cognitive Services Language Writer'` + - `'Cognitive Services LUIS Owner'` + - `'Cognitive Services LUIS Reader'` + - `'Cognitive Services LUIS Writer'` + - `'Cognitive Services Metrics Advisor Administrator'` + - `'Cognitive Services Metrics Advisor User'` + - `'Cognitive Services OpenAI Contributor'` + - `'Cognitive Services OpenAI User'` + - `'Cognitive Services QnA Maker Editor'` + - `'Cognitive Services QnA Maker Reader'` + - `'Cognitive Services Speech Contributor'` + - `'Cognitive Services Speech User'` + - `'Cognitive Services User'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/communication/communication-service/README.md b/avm/res/communication/communication-service/README.md index def24cd565..e1d2bdd046 100644 --- a/avm/res/communication/communication-service/README.md +++ b/avm/res/communication/communication-service/README.md @@ -606,6 +606,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/communication/email-service/README.md b/avm/res/communication/email-service/README.md index 756b60281b..0087caf5ff 100644 --- a/avm/res/communication/email-service/README.md +++ b/avm/res/communication/email-service/README.md @@ -451,6 +451,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/communication/email-service/domain/README.md b/avm/res/communication/email-service/domain/README.md index 20316013ee..e649034df2 100644 --- a/avm/res/communication/email-service/domain/README.md +++ b/avm/res/communication/email-service/domain/README.md @@ -123,6 +123,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/compute/availability-set/README.md b/avm/res/compute/availability-set/README.md index 57229ca6f3..b058766413 100644 --- a/avm/res/compute/availability-set/README.md +++ b/avm/res/compute/availability-set/README.md @@ -377,6 +377,16 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Virtual Machine Administrator Login'` + - `'Virtual Machine Contributor'` + - `'Virtual Machine Data Access Administrator (preview)'` + - `'Virtual Machine User Login'` **Required parameters** diff --git a/avm/res/compute/disk-encryption-set/README.md b/avm/res/compute/disk-encryption-set/README.md index eb3e9b657c..85900913fe 100644 --- a/avm/res/compute/disk-encryption-set/README.md +++ b/avm/res/compute/disk-encryption-set/README.md @@ -585,6 +585,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Data Operator for Managed Disks'` + - `'Disk Backup Reader'` + - `'Disk Pool Operator'` + - `'Disk Restore Operator'` + - `'Disk Snapshot Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/compute/disk/README.md b/avm/res/compute/disk/README.md index be1624c4f6..3a95ddb2ad 100644 --- a/avm/res/compute/disk/README.md +++ b/avm/res/compute/disk/README.md @@ -818,6 +818,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Data Operator for Managed Disks'` + - `'Disk Backup Reader'` + - `'Disk Pool Operator'` + - `'Disk Restore Operator'` + - `'Disk Snapshot Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/compute/gallery/README.md b/avm/res/compute/gallery/README.md index 926c7e1b35..62c4b8041f 100644 --- a/avm/res/compute/gallery/README.md +++ b/avm/res/compute/gallery/README.md @@ -1048,6 +1048,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Compute Gallery Sharing Admin'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/compute/gallery/application/README.md b/avm/res/compute/gallery/application/README.md index be70237005..879fb1c1db 100644 --- a/avm/res/compute/gallery/application/README.md +++ b/avm/res/compute/gallery/application/README.md @@ -129,6 +129,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Compute Gallery Sharing Admin'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/compute/gallery/image/README.md b/avm/res/compute/gallery/image/README.md index 98d3d3ec68..484444ae23 100644 --- a/avm/res/compute/gallery/image/README.md +++ b/avm/res/compute/gallery/image/README.md @@ -321,6 +321,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Compute Gallery Sharing Admin'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/compute/image/README.md b/avm/res/compute/image/README.md index 786bf30b97..58545668c5 100644 --- a/avm/res/compute/image/README.md +++ b/avm/res/compute/image/README.md @@ -476,6 +476,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/compute/proximity-placement-group/README.md b/avm/res/compute/proximity-placement-group/README.md index 849182b03d..7bb3c4a857 100644 --- a/avm/res/compute/proximity-placement-group/README.md +++ b/avm/res/compute/proximity-placement-group/README.md @@ -429,6 +429,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/compute/ssh-public-key/README.md b/avm/res/compute/ssh-public-key/README.md index 6db199cbfd..a4ebea4185 100644 --- a/avm/res/compute/ssh-public-key/README.md +++ b/avm/res/compute/ssh-public-key/README.md @@ -403,6 +403,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/compute/virtual-machine-scale-set/README.md b/avm/res/compute/virtual-machine-scale-set/README.md index 730b23f033..febb8bfea7 100644 --- a/avm/res/compute/virtual-machine-scale-set/README.md +++ b/avm/res/compute/virtual-machine-scale-set/README.md @@ -2450,6 +2450,25 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Data Operator for Managed Disks'` + - `'Desktop Virtualization Power On Contributor'` + - `'Desktop Virtualization Power On Off Contributor'` + - `'Desktop Virtualization Virtual Machine Contributor'` + - `'DevTest Labs User'` + - `'Disk Backup Reader'` + - `'Disk Pool Operator'` + - `'Disk Restore Operator'` + - `'Disk Snapshot Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Virtual Machine Administrator Login'` + - `'Virtual Machine Contributor'` + - `'Virtual Machine User Login'` + - `'VM Scanner Operator'` **Required parameters** diff --git a/avm/res/compute/virtual-machine/README.md b/avm/res/compute/virtual-machine/README.md index f34080a1bc..855f72b4a8 100644 --- a/avm/res/compute/virtual-machine/README.md +++ b/avm/res/compute/virtual-machine/README.md @@ -4210,6 +4210,25 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Data Operator for Managed Disks'` + - `'Desktop Virtualization Power On Contributor'` + - `'Desktop Virtualization Power On Off Contributor'` + - `'Desktop Virtualization Virtual Machine Contributor'` + - `'DevTest Labs User'` + - `'Disk Backup Reader'` + - `'Disk Pool Operator'` + - `'Disk Restore Operator'` + - `'Disk Snapshot Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Virtual Machine Administrator Login'` + - `'Virtual Machine Contributor'` + - `'Virtual Machine User Login'` + - `'VM Scanner Operator'` **Required parameters** diff --git a/avm/res/container-registry/registry/README.md b/avm/res/container-registry/registry/README.md index f81a37d43a..02594a96ff 100644 --- a/avm/res/container-registry/registry/README.md +++ b/avm/res/container-registry/registry/README.md @@ -1526,6 +1526,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1696,6 +1707,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'AcrDelete'` + - `'AcrImageSigner'` + - `'AcrPull'` + - `'AcrPush'` + - `'AcrQuarantineReader'` + - `'AcrQuarantineWriter'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/container-service/managed-cluster/README.md b/avm/res/container-service/managed-cluster/README.md index 44a7b26a1e..2e988e1ca5 100644 --- a/avm/res/container-service/managed-cluster/README.md +++ b/avm/res/container-service/managed-cluster/README.md @@ -3194,6 +3194,26 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Kubernetes Fleet Manager Contributor Role'` + - `'Azure Kubernetes Fleet Manager RBAC Admin'` + - `'Azure Kubernetes Fleet Manager RBAC Cluster Admin'` + - `'Azure Kubernetes Fleet Manager RBAC Reader'` + - `'Azure Kubernetes Fleet Manager RBAC Writer'` + - `'Azure Kubernetes Service Cluster Admin Role'` + - `'Azure Kubernetes Service Cluster Monitoring User'` + - `'Azure Kubernetes Service Cluster User Role'` + - `'Azure Kubernetes Service Contributor Role'` + - `'Azure Kubernetes Service RBAC Admin'` + - `'Azure Kubernetes Service RBAC Cluster Admin'` + - `'Azure Kubernetes Service RBAC Reader'` + - `'Azure Kubernetes Service RBAC Writer'` + - `'Contributor'` + - `'Kubernetes Agentless Operator'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/data-factory/factory/README.md b/avm/res/data-factory/factory/README.md index d4ee7144b0..bd9ec6e1c6 100644 --- a/avm/res/data-factory/factory/README.md +++ b/avm/res/data-factory/factory/README.md @@ -1270,6 +1270,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1397,6 +1408,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Data Factory Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/data-protection/backup-vault/README.md b/avm/res/data-protection/backup-vault/README.md index 5ef4757a5b..77172ba563 100644 --- a/avm/res/data-protection/backup-vault/README.md +++ b/avm/res/data-protection/backup-vault/README.md @@ -693,6 +693,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Backup Contributor'` + - `'Backup Operator'` + - `'Backup Reader'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/databricks/access-connector/README.md b/avm/res/databricks/access-connector/README.md index 5086b63cd6..e825762f75 100644 --- a/avm/res/databricks/access-connector/README.md +++ b/avm/res/databricks/access-connector/README.md @@ -392,6 +392,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/databricks/workspace/README.md b/avm/res/databricks/workspace/README.md index b3084f34a5..5b877cd4ce 100644 --- a/avm/res/databricks/workspace/README.md +++ b/avm/res/databricks/workspace/README.md @@ -1565,6 +1565,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1977,6 +1983,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/db-for-my-sql/flexible-server/README.md b/avm/res/db-for-my-sql/flexible-server/README.md index f915bedd9d..dbe135fbc5 100644 --- a/avm/res/db-for-my-sql/flexible-server/README.md +++ b/avm/res/db-for-my-sql/flexible-server/README.md @@ -1223,6 +1223,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'MySQL Backup And Export Operator'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/db-for-postgre-sql/flexible-server/README.md b/avm/res/db-for-postgre-sql/flexible-server/README.md index 8e84071338..c60b6026b4 100644 --- a/avm/res/db-for-postgre-sql/flexible-server/README.md +++ b/avm/res/db-for-postgre-sql/flexible-server/README.md @@ -1381,6 +1381,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/desktop-virtualization/application-group/README.md b/avm/res/desktop-virtualization/application-group/README.md index 96040b8018..da9a322e54 100644 --- a/avm/res/desktop-virtualization/application-group/README.md +++ b/avm/res/desktop-virtualization/application-group/README.md @@ -608,6 +608,29 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Owner'` + - `'Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Application Group Contributor'` + - `'Desktop Virtualization Application Group Contributor'` + - `'Desktop Virtualization Application Group Reader'` + - `'Desktop Virtualization Contributor'` + - `'Desktop Virtualization Host Pool Contributor'` + - `'Desktop Virtualization Host Pool Reader'` + - `'Desktop Virtualization Power On Off Contributor'` + - `'Desktop Virtualization Reader'` + - `'Desktop Virtualization Session Host Operator'` + - `'Desktop Virtualization User'` + - `'Desktop Virtualization User Session Operator'` + - `'Desktop Virtualization Virtual Machine Contributor'` + - `'Desktop Virtualization Workspace Contributor'` + - `'Desktop Virtualization Workspace Reader'` + - `'Managed Application Contributor Role'` + - `'Managed Application Operator Role'` + - `'Managed Applications Reader'` **Required parameters** diff --git a/avm/res/desktop-virtualization/host-pool/README.md b/avm/res/desktop-virtualization/host-pool/README.md index 2d0ab9b957..886a58e81a 100644 --- a/avm/res/desktop-virtualization/host-pool/README.md +++ b/avm/res/desktop-virtualization/host-pool/README.md @@ -1071,6 +1071,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1207,6 +1218,29 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Owner'` + - `'Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Application Group Contributor'` + - `'Desktop Virtualization Application Group Contributor'` + - `'Desktop Virtualization Application Group Reader'` + - `'Desktop Virtualization Contributor'` + - `'Desktop Virtualization Host Pool Contributor'` + - `'Desktop Virtualization Host Pool Reader'` + - `'Desktop Virtualization Power On Off Contributor'` + - `'Desktop Virtualization Reader'` + - `'Desktop Virtualization Session Host Operator'` + - `'Desktop Virtualization User'` + - `'Desktop Virtualization User Session Operator'` + - `'Desktop Virtualization Virtual Machine Contributor'` + - `'Desktop Virtualization Workspace Contributor'` + - `'Desktop Virtualization Workspace Reader'` + - `'Managed Application Contributor Role'` + - `'Managed Application Operator Role'` + - `'Managed Applications Reader'` **Required parameters** diff --git a/avm/res/desktop-virtualization/scaling-plan/README.md b/avm/res/desktop-virtualization/scaling-plan/README.md index a3860a3213..97207ef73c 100644 --- a/avm/res/desktop-virtualization/scaling-plan/README.md +++ b/avm/res/desktop-virtualization/scaling-plan/README.md @@ -795,6 +795,26 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Owner'` + - `'Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Application Group Contributor'` + - `'Desktop Virtualization Application Group Contributor'` + - `'Desktop Virtualization Application Group Reader'` + - `'Desktop Virtualization Contributor'` + - `'Desktop Virtualization Host Pool Contributor'` + - `'Desktop Virtualization Host Pool Reader'` + - `'Desktop Virtualization Power On Off Contributor'` + - `'Desktop Virtualization Reader'` + - `'Desktop Virtualization Session Host Operator'` + - `'Desktop Virtualization User'` + - `'Desktop Virtualization User Session Operator'` + - `'Desktop Virtualization Virtual Machine Contributor'` + - `'Desktop Virtualization Workspace Contributor'` + - `'Desktop Virtualization Workspace Reader'` **Required parameters** diff --git a/avm/res/desktop-virtualization/workspace/README.md b/avm/res/desktop-virtualization/workspace/README.md index f37ac6ade8..c71da4bcbb 100644 --- a/avm/res/desktop-virtualization/workspace/README.md +++ b/avm/res/desktop-virtualization/workspace/README.md @@ -971,6 +971,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1090,6 +1101,26 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Owner'` + - `'Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Application Group Contributor'` + - `'Desktop Virtualization Application Group Contributor'` + - `'Desktop Virtualization Application Group Reader'` + - `'Desktop Virtualization Contributor'` + - `'Desktop Virtualization Host Pool Contributor'` + - `'Desktop Virtualization Host Pool Reader'` + - `'Desktop Virtualization Power On Off Contributor'` + - `'Desktop Virtualization Reader'` + - `'Desktop Virtualization Session Host Operator'` + - `'Desktop Virtualization User'` + - `'Desktop Virtualization User Session Operator'` + - `'Desktop Virtualization Virtual Machine Contributor'` + - `'Desktop Virtualization Workspace Contributor'` + - `'Desktop Virtualization Workspace Reader'` **Required parameters** diff --git a/avm/res/dev-test-lab/lab/README.md b/avm/res/dev-test-lab/lab/README.md index 22a277da2a..4c3db963d8 100644 --- a/avm/res/dev-test-lab/lab/README.md +++ b/avm/res/dev-test-lab/lab/README.md @@ -1590,6 +1590,15 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DevTest Labs User'` + - `'Owner'` + - `'Reader'` + - `'Resource Policy Contributor'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Virtual Machine Contributor'` **Required parameters** diff --git a/avm/res/digital-twins/digital-twins-instance/README.md b/avm/res/digital-twins/digital-twins-instance/README.md index 8dc8fc0cd8..17f002c774 100644 --- a/avm/res/digital-twins/digital-twins-instance/README.md +++ b/avm/res/digital-twins/digital-twins-instance/README.md @@ -996,6 +996,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1115,6 +1126,14 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' - Required: No - Type: array +- Roles configurable by name: + - `'Azure Digital Twins Data Owner'` + - `'Azure Digital Twins Data Reader'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/document-db/database-account/README.md b/avm/res/document-db/database-account/README.md index 24654fcc7f..e3b1d30fb6 100644 --- a/avm/res/document-db/database-account/README.md +++ b/avm/res/document-db/database-account/README.md @@ -3189,6 +3189,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -3293,6 +3304,17 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Cosmos DB Account Reader Role'` + - `'Cosmos DB Operator'` + - `'CosmosBackupOperator'` + - `'CosmosRestoreOperator'` + - `'DocumentDB Account Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/event-grid/domain/README.md b/avm/res/event-grid/domain/README.md index 7514b32c3d..a9833d9025 100644 --- a/avm/res/event-grid/domain/README.md +++ b/avm/res/event-grid/domain/README.md @@ -1033,6 +1033,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1160,6 +1171,16 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'EventGrid Contributor'` + - `'EventGrid Data Sender'` + - `'EventGrid EventSubscription Contributor'` + - `'EventGrid EventSubscription Reader'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/event-grid/namespace/README.md b/avm/res/event-grid/namespace/README.md index 290a4d6631..7ac321334d 100644 --- a/avm/res/event-grid/namespace/README.md +++ b/avm/res/event-grid/namespace/README.md @@ -2006,6 +2006,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -2132,6 +2143,20 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Resource Notifications System Topics Subscriber'` + - `'Contributor'` + - `'EventGrid Contributor'` + - `'EventGrid Data Contributor'` + - `'EventGrid Data Receiver'` + - `'EventGrid Data Sender'` + - `'EventGrid EventSubscription Contributor'` + - `'EventGrid EventSubscription Reader'` + - `'EventGrid TopicSpaces Publisher'` + - `'EventGrid TopicSpaces Subscriber'` + - `'Owner'` + - `'Reader'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/event-grid/namespace/topic-space/README.md b/avm/res/event-grid/namespace/topic-space/README.md index a931f6ad62..442efe3335 100644 --- a/avm/res/event-grid/namespace/topic-space/README.md +++ b/avm/res/event-grid/namespace/topic-space/README.md @@ -71,6 +71,20 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Resource Notifications System Topics Subscriber'` + - `'Contributor'` + - `'EventGrid Contributor'` + - `'EventGrid Data Contributor'` + - `'EventGrid Data Receiver'` + - `'EventGrid Data Sender'` + - `'EventGrid EventSubscription Contributor'` + - `'EventGrid EventSubscription Reader'` + - `'EventGrid TopicSpaces Publisher'` + - `'EventGrid TopicSpaces Subscriber'` + - `'Owner'` + - `'Reader'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/event-grid/namespace/topic/README.md b/avm/res/event-grid/namespace/topic/README.md index 8b0920ea45..9d831de41c 100644 --- a/avm/res/event-grid/namespace/topic/README.md +++ b/avm/res/event-grid/namespace/topic/README.md @@ -129,6 +129,20 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Resource Notifications System Topics Subscriber'` + - `'Contributor'` + - `'EventGrid Contributor'` + - `'EventGrid Data Contributor'` + - `'EventGrid Data Receiver'` + - `'EventGrid Data Sender'` + - `'EventGrid EventSubscription Contributor'` + - `'EventGrid EventSubscription Reader'` + - `'EventGrid TopicSpaces Publisher'` + - `'EventGrid TopicSpaces Subscriber'` + - `'Owner'` + - `'Reader'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/event-grid/namespace/topic/event-subscription/README.md b/avm/res/event-grid/namespace/topic/event-subscription/README.md index 8b2fcd5527..3efe652422 100644 --- a/avm/res/event-grid/namespace/topic/event-subscription/README.md +++ b/avm/res/event-grid/namespace/topic/event-subscription/README.md @@ -88,6 +88,20 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Resource Notifications System Topics Subscriber'` + - `'Contributor'` + - `'EventGrid Contributor'` + - `'EventGrid Data Contributor'` + - `'EventGrid Data Receiver'` + - `'EventGrid Data Sender'` + - `'EventGrid EventSubscription Contributor'` + - `'EventGrid EventSubscription Reader'` + - `'EventGrid TopicSpaces Publisher'` + - `'EventGrid TopicSpaces Subscriber'` + - `'Owner'` + - `'Reader'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/event-grid/system-topic/README.md b/avm/res/event-grid/system-topic/README.md index eb74e20320..98c9a44742 100644 --- a/avm/res/event-grid/system-topic/README.md +++ b/avm/res/event-grid/system-topic/README.md @@ -732,6 +732,16 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'EventGrid Contributor'` + - `'EventGrid Data Sender'` + - `'EventGrid EventSubscription Contributor'` + - `'EventGrid EventSubscription Reader'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/event-grid/topic/README.md b/avm/res/event-grid/topic/README.md index 56864ec710..bf85377cfe 100644 --- a/avm/res/event-grid/topic/README.md +++ b/avm/res/event-grid/topic/README.md @@ -1127,6 +1127,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1254,6 +1265,16 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'EventGrid Contributor'` + - `'EventGrid Data Sender'` + - `'EventGrid EventSubscription Contributor'` + - `'EventGrid EventSubscription Reader'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/event-hub/namespace/README.md b/avm/res/event-hub/namespace/README.md index aae733f8da..c32df1eeb0 100644 --- a/avm/res/event-hub/namespace/README.md +++ b/avm/res/event-hub/namespace/README.md @@ -1631,6 +1631,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1767,6 +1778,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Event Hubs Data Owner'` + - `'Azure Event Hubs Data Receiver'` + - `'Azure Event Hubs Data Sender'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/event-hub/namespace/eventhub/README.md b/avm/res/event-hub/namespace/eventhub/README.md index 8964602f1b..b10aa5e66f 100644 --- a/avm/res/event-hub/namespace/eventhub/README.md +++ b/avm/res/event-hub/namespace/eventhub/README.md @@ -273,6 +273,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Event Hubs Data Owner'` + - `'Azure Event Hubs Data Receiver'` + - `'Azure Event Hubs Data Sender'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/health-bot/health-bot/README.md b/avm/res/health-bot/health-bot/README.md index 032ebd2d90..b23485fd1c 100644 --- a/avm/res/health-bot/health-bot/README.md +++ b/avm/res/health-bot/health-bot/README.md @@ -407,6 +407,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/healthcare-apis/workspace/README.md b/avm/res/healthcare-apis/workspace/README.md index 3347555bd9..992cee3c23 100644 --- a/avm/res/healthcare-apis/workspace/README.md +++ b/avm/res/healthcare-apis/workspace/README.md @@ -590,6 +590,21 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DICOM Data Owner'` + - `'DICOM Data Reader'` + - `'FHIR Data Contributor'` + - `'FHIR Data Converter'` + - `'FHIR Data Exporter'` + - `'FHIR Data Importer'` + - `'FHIR Data Reader'` + - `'FHIR Data Writer'` + - `'FHIR SMART User'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/healthcare-apis/workspace/fhirservice/README.md b/avm/res/healthcare-apis/workspace/fhirservice/README.md index 0835f81584..ce0990cf46 100644 --- a/avm/res/healthcare-apis/workspace/fhirservice/README.md +++ b/avm/res/healthcare-apis/workspace/fhirservice/README.md @@ -468,6 +468,21 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DICOM Data Owner'` + - `'DICOM Data Reader'` + - `'FHIR Data Contributor'` + - `'FHIR Data Converter'` + - `'FHIR Data Exporter'` + - `'FHIR Data Importer'` + - `'FHIR Data Reader'` + - `'FHIR Data Writer'` + - `'FHIR SMART User'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/hybrid-compute/machine/README.md b/avm/res/hybrid-compute/machine/README.md index 5221e3578b..b7f4fd21ba 100644 --- a/avm/res/hybrid-compute/machine/README.md +++ b/avm/res/hybrid-compute/machine/README.md @@ -509,6 +509,16 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Arc machine Administrator Login'` + - `'Arc machine Contributor'` + - `'Arc machine User Login'` + - `'Windows Admin Center Administrator Login'` **Required parameters** diff --git a/avm/res/insights/action-group/README.md b/avm/res/insights/action-group/README.md index 5ca2f832b8..becc4cda4d 100644 --- a/avm/res/insights/action-group/README.md +++ b/avm/res/insights/action-group/README.md @@ -413,6 +413,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/insights/activity-log-alert/README.md b/avm/res/insights/activity-log-alert/README.md index ab8e82e305..3dc67e6cf2 100644 --- a/avm/res/insights/activity-log-alert/README.md +++ b/avm/res/insights/activity-log-alert/README.md @@ -553,6 +553,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/insights/component/README.md b/avm/res/insights/component/README.md index 458098b208..e4f7b78ac5 100644 --- a/avm/res/insights/component/README.md +++ b/avm/res/insights/component/README.md @@ -645,6 +645,16 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Monitoring Metrics Publisher'` + - `'Application Insights Component Contributor'` + - `'Application Insights Snapshot Debugger'` + - `'Monitoring Contributor'` **Required parameters** diff --git a/avm/res/insights/data-collection-endpoint/README.md b/avm/res/insights/data-collection-endpoint/README.md index a1cd20427a..a2f09497c1 100644 --- a/avm/res/insights/data-collection-endpoint/README.md +++ b/avm/res/insights/data-collection-endpoint/README.md @@ -391,6 +391,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/insights/data-collection-rule/README.md b/avm/res/insights/data-collection-rule/README.md index 6134656d6d..300de97955 100644 --- a/avm/res/insights/data-collection-rule/README.md +++ b/avm/res/insights/data-collection-rule/README.md @@ -2052,6 +2052,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/insights/metric-alert/README.md b/avm/res/insights/metric-alert/README.md index a28a379fae..121b127c85 100644 --- a/avm/res/insights/metric-alert/README.md +++ b/avm/res/insights/metric-alert/README.md @@ -498,6 +498,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/insights/private-link-scope/README.md b/avm/res/insights/private-link-scope/README.md index 9c6f5d5719..4dda77b209 100644 --- a/avm/res/insights/private-link-scope/README.md +++ b/avm/res/insights/private-link-scope/README.md @@ -1221,6 +1221,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1332,6 +1343,21 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Log Analytics Contributor'` + - `'Log Analytics Reader'` + - `'Logic App Contributor'` + - `'Monitoring Contributor'` + - `'Monitoring Metrics Publisher'` + - `'Monitoring Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'Tag Contributor'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/insights/scheduled-query-rule/README.md b/avm/res/insights/scheduled-query-rule/README.md index c0f4c7a979..7497372fa6 100644 --- a/avm/res/insights/scheduled-query-rule/README.md +++ b/avm/res/insights/scheduled-query-rule/README.md @@ -658,6 +658,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/insights/webtest/README.md b/avm/res/insights/webtest/README.md index 2b0ca9def0..ef3bac6253 100644 --- a/avm/res/insights/webtest/README.md +++ b/avm/res/insights/webtest/README.md @@ -529,6 +529,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/kusto/cluster/README.md b/avm/res/kusto/cluster/README.md index 8d94f1f46f..40d7a0e115 100644 --- a/avm/res/kusto/cluster/README.md +++ b/avm/res/kusto/cluster/README.md @@ -1390,6 +1390,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1510,6 +1521,10 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` **Required parameters** diff --git a/avm/res/load-test-service/load-test/README.md b/avm/res/load-test-service/load-test/README.md index 16936f9cdf..687a4e16a1 100644 --- a/avm/res/load-test-service/load-test/README.md +++ b/avm/res/load-test-service/load-test/README.md @@ -509,6 +509,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/logic/workflow/README.md b/avm/res/logic/workflow/README.md index fc08456b5c..a3e33ad480 100644 --- a/avm/res/logic/workflow/README.md +++ b/avm/res/logic/workflow/README.md @@ -805,6 +805,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Logic App Contributor'` + - `'Logic App Operator'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/machine-learning-services/workspace/README.md b/avm/res/machine-learning-services/workspace/README.md index 860f066e50..e8b2aa23b5 100644 --- a/avm/res/machine-learning-services/workspace/README.md +++ b/avm/res/machine-learning-services/workspace/README.md @@ -2035,6 +2035,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -2161,6 +2172,16 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'AzureML Compute Operator'` + - `'AzureML Data Scientist'` + - `'AzureML Metrics Writer (preview)'` + - `'AzureML Registry User'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/maintenance/maintenance-configuration/README.md b/avm/res/maintenance/maintenance-configuration/README.md index b2fe74ff0c..d8187c2a1f 100644 --- a/avm/res/maintenance/maintenance-configuration/README.md +++ b/avm/res/maintenance/maintenance-configuration/README.md @@ -528,6 +528,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'Scheduled Patching Contributor'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/managed-identity/user-assigned-identity/README.md b/avm/res/managed-identity/user-assigned-identity/README.md index 6ab0ca2082..43908d19fe 100644 --- a/avm/res/managed-identity/user-assigned-identity/README.md +++ b/avm/res/managed-identity/user-assigned-identity/README.md @@ -463,6 +463,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Managed Identity Contributor'` + - `'Managed Identity Operator'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/net-app/net-app-account/README.md b/avm/res/net-app/net-app-account/README.md index 7ee4003cbe..13b76bd308 100644 --- a/avm/res/net-app/net-app-account/README.md +++ b/avm/res/net-app/net-app-account/README.md @@ -951,6 +951,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/net-app/net-app-account/capacity-pool/README.md b/avm/res/net-app/net-app-account/capacity-pool/README.md index e8d582aa36..4c95a9ca0b 100644 --- a/avm/res/net-app/net-app-account/capacity-pool/README.md +++ b/avm/res/net-app/net-app-account/capacity-pool/README.md @@ -130,6 +130,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/net-app/net-app-account/capacity-pool/volume/README.md b/avm/res/net-app/net-app-account/capacity-pool/volume/README.md index f7d5472e35..9361b0045e 100644 --- a/avm/res/net-app/net-app-account/capacity-pool/volume/README.md +++ b/avm/res/net-app/net-app-account/capacity-pool/volume/README.md @@ -399,6 +399,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/application-gateway/README.md b/avm/res/network/application-gateway/README.md index b5d206d002..ad061f01d1 100644 --- a/avm/res/network/application-gateway/README.md +++ b/avm/res/network/application-gateway/README.md @@ -2840,6 +2840,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -2984,6 +2995,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/application-security-group/README.md b/avm/res/network/application-security-group/README.md index 227c71bc93..6ef90cc95a 100644 --- a/avm/res/network/application-security-group/README.md +++ b/avm/res/network/application-security-group/README.md @@ -341,6 +341,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/azure-firewall/README.md b/avm/res/network/azure-firewall/README.md index cb38f1c505..ce6a6114ef 100644 --- a/avm/res/network/azure-firewall/README.md +++ b/avm/res/network/azure-firewall/README.md @@ -2079,6 +2079,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/bastion-host/README.md b/avm/res/network/bastion-host/README.md index a7c2f5dd91..fc93544fc5 100644 --- a/avm/res/network/bastion-host/README.md +++ b/avm/res/network/bastion-host/README.md @@ -764,6 +764,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/ddos-protection-plan/README.md b/avm/res/network/ddos-protection-plan/README.md index 5d9187c4d3..6bdd5c6b3c 100644 --- a/avm/res/network/ddos-protection-plan/README.md +++ b/avm/res/network/ddos-protection-plan/README.md @@ -341,6 +341,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/dns-forwarding-ruleset/README.md b/avm/res/network/dns-forwarding-ruleset/README.md index d126a5c2a5..e0d4cf14ae 100644 --- a/avm/res/network/dns-forwarding-ruleset/README.md +++ b/avm/res/network/dns-forwarding-ruleset/README.md @@ -504,6 +504,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` **Required parameters** diff --git a/avm/res/network/dns-resolver/README.md b/avm/res/network/dns-resolver/README.md index 8437207f1f..4642dd8e31 100644 --- a/avm/res/network/dns-resolver/README.md +++ b/avm/res/network/dns-resolver/README.md @@ -542,6 +542,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` **Required parameters** diff --git a/avm/res/network/dns-zone/README.md b/avm/res/network/dns-zone/README.md index 8a4e661ec1..e7a9c463a3 100644 --- a/avm/res/network/dns-zone/README.md +++ b/avm/res/network/dns-zone/README.md @@ -940,6 +940,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1108,6 +1120,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1291,6 +1315,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1452,6 +1488,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1679,6 +1727,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1839,6 +1899,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1999,6 +2071,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -2103,6 +2187,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -2236,6 +2332,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -2444,6 +2552,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -2635,6 +2755,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/dns-zone/a/README.md b/avm/res/network/dns-zone/a/README.md index 8d42ef0747..e93a99ac4a 100644 --- a/avm/res/network/dns-zone/a/README.md +++ b/avm/res/network/dns-zone/a/README.md @@ -73,6 +73,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/dns-zone/aaaa/README.md b/avm/res/network/dns-zone/aaaa/README.md index 93755b92fc..99120461e1 100644 --- a/avm/res/network/dns-zone/aaaa/README.md +++ b/avm/res/network/dns-zone/aaaa/README.md @@ -73,6 +73,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/dns-zone/caa/README.md b/avm/res/network/dns-zone/caa/README.md index 8b433084d9..7d1b1ef225 100644 --- a/avm/res/network/dns-zone/caa/README.md +++ b/avm/res/network/dns-zone/caa/README.md @@ -72,6 +72,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/dns-zone/cname/README.md b/avm/res/network/dns-zone/cname/README.md index 197a33a7fd..7107700e87 100644 --- a/avm/res/network/dns-zone/cname/README.md +++ b/avm/res/network/dns-zone/cname/README.md @@ -73,6 +73,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/dns-zone/mx/README.md b/avm/res/network/dns-zone/mx/README.md index 19577e558e..68615af23c 100644 --- a/avm/res/network/dns-zone/mx/README.md +++ b/avm/res/network/dns-zone/mx/README.md @@ -72,6 +72,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/dns-zone/ns/README.md b/avm/res/network/dns-zone/ns/README.md index bf63641c45..43fd817fe2 100644 --- a/avm/res/network/dns-zone/ns/README.md +++ b/avm/res/network/dns-zone/ns/README.md @@ -72,6 +72,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/dns-zone/ptr/README.md b/avm/res/network/dns-zone/ptr/README.md index d5fffa162b..2dda8e4f59 100644 --- a/avm/res/network/dns-zone/ptr/README.md +++ b/avm/res/network/dns-zone/ptr/README.md @@ -72,6 +72,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/dns-zone/soa/README.md b/avm/res/network/dns-zone/soa/README.md index 3c0227fea8..22832138fb 100644 --- a/avm/res/network/dns-zone/soa/README.md +++ b/avm/res/network/dns-zone/soa/README.md @@ -65,6 +65,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/dns-zone/srv/README.md b/avm/res/network/dns-zone/srv/README.md index 309a786101..c733d69571 100644 --- a/avm/res/network/dns-zone/srv/README.md +++ b/avm/res/network/dns-zone/srv/README.md @@ -65,6 +65,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/dns-zone/txt/README.md b/avm/res/network/dns-zone/txt/README.md index dbc21c21cd..35f4be5c49 100644 --- a/avm/res/network/dns-zone/txt/README.md +++ b/avm/res/network/dns-zone/txt/README.md @@ -65,6 +65,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/express-route-circuit/README.md b/avm/res/network/express-route-circuit/README.md index 578169e9ff..50e00e3bd5 100644 --- a/avm/res/network/express-route-circuit/README.md +++ b/avm/res/network/express-route-circuit/README.md @@ -717,6 +717,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/express-route-gateway/README.md b/avm/res/network/express-route-gateway/README.md index cba6d19ddf..d66a1ef172 100644 --- a/avm/res/network/express-route-gateway/README.md +++ b/avm/res/network/express-route-gateway/README.md @@ -409,6 +409,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/front-door-web-application-firewall-policy/README.md b/avm/res/network/front-door-web-application-firewall-policy/README.md index 02c147d79e..6b4b2dd0df 100644 --- a/avm/res/network/front-door-web-application-firewall-policy/README.md +++ b/avm/res/network/front-door-web-application-firewall-policy/README.md @@ -675,6 +675,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/front-door/README.md b/avm/res/network/front-door/README.md index 1fc4d43721..50e01165f6 100644 --- a/avm/res/network/front-door/README.md +++ b/avm/res/network/front-door/README.md @@ -1157,6 +1157,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/ip-group/README.md b/avm/res/network/ip-group/README.md index 211d8de421..48dcd81c36 100644 --- a/avm/res/network/ip-group/README.md +++ b/avm/res/network/ip-group/README.md @@ -360,6 +360,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'IPAM Pool Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` **Required parameters** diff --git a/avm/res/network/load-balancer/README.md b/avm/res/network/load-balancer/README.md index 2ca817beb0..4b5103926d 100644 --- a/avm/res/network/load-balancer/README.md +++ b/avm/res/network/load-balancer/README.md @@ -1459,6 +1459,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/local-network-gateway/README.md b/avm/res/network/local-network-gateway/README.md index 0e702b10ed..aa324dae8a 100644 --- a/avm/res/network/local-network-gateway/README.md +++ b/avm/res/network/local-network-gateway/README.md @@ -445,6 +445,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/nat-gateway/README.md b/avm/res/network/nat-gateway/README.md index ed01e1d452..8c6358ff0c 100644 --- a/avm/res/network/nat-gateway/README.md +++ b/avm/res/network/nat-gateway/README.md @@ -628,6 +628,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/network-interface/README.md b/avm/res/network/network-interface/README.md index 3e9767ba44..6b6f123af8 100644 --- a/avm/res/network/network-interface/README.md +++ b/avm/res/network/network-interface/README.md @@ -722,6 +722,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` **Required parameters** diff --git a/avm/res/network/network-manager/README.md b/avm/res/network/network-manager/README.md index 99f4273940..ea6a3831c0 100644 --- a/avm/res/network/network-manager/README.md +++ b/avm/res/network/network-manager/README.md @@ -1075,6 +1075,16 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'IPAM Pool Contributor'` + - `'LocalNGFirewallAdministrator role'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Resource Policy Contributor'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/network-security-group/README.md b/avm/res/network/network-security-group/README.md index 15b057b8ce..3de82ead53 100644 --- a/avm/res/network/network-security-group/README.md +++ b/avm/res/network/network-security-group/README.md @@ -693,6 +693,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/network-watcher/README.md b/avm/res/network/network-watcher/README.md index a13c4ae45b..d26f9648ba 100644 --- a/avm/res/network/network-watcher/README.md +++ b/avm/res/network/network-watcher/README.md @@ -605,6 +605,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/private-dns-zone/README.md b/avm/res/network/private-dns-zone/README.md index b9bcac8c5e..bcc558ab55 100644 --- a/avm/res/network/private-dns-zone/README.md +++ b/avm/res/network/private-dns-zone/README.md @@ -823,6 +823,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -983,6 +991,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1143,6 +1159,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1363,6 +1387,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1523,6 +1555,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1627,6 +1667,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` **Required parameters** @@ -1760,6 +1807,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1968,6 +2023,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -2159,6 +2222,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/private-dns-zone/a/README.md b/avm/res/network/private-dns-zone/a/README.md index 1d776a8b07..6584b4966c 100644 --- a/avm/res/network/private-dns-zone/a/README.md +++ b/avm/res/network/private-dns-zone/a/README.md @@ -72,6 +72,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/private-dns-zone/aaaa/README.md b/avm/res/network/private-dns-zone/aaaa/README.md index 8eb2f75a00..01b9ca1fbe 100644 --- a/avm/res/network/private-dns-zone/aaaa/README.md +++ b/avm/res/network/private-dns-zone/aaaa/README.md @@ -72,6 +72,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/private-dns-zone/cname/README.md b/avm/res/network/private-dns-zone/cname/README.md index 0e3cba5ca8..bcabc2f0a8 100644 --- a/avm/res/network/private-dns-zone/cname/README.md +++ b/avm/res/network/private-dns-zone/cname/README.md @@ -72,6 +72,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/private-dns-zone/mx/README.md b/avm/res/network/private-dns-zone/mx/README.md index 3284c3e1e7..721b698ccd 100644 --- a/avm/res/network/private-dns-zone/mx/README.md +++ b/avm/res/network/private-dns-zone/mx/README.md @@ -72,6 +72,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/private-dns-zone/ptr/README.md b/avm/res/network/private-dns-zone/ptr/README.md index 23549d6a1f..0c8d412a53 100644 --- a/avm/res/network/private-dns-zone/ptr/README.md +++ b/avm/res/network/private-dns-zone/ptr/README.md @@ -72,6 +72,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/private-dns-zone/soa/README.md b/avm/res/network/private-dns-zone/soa/README.md index 5936d5e83c..fd6c40a7fb 100644 --- a/avm/res/network/private-dns-zone/soa/README.md +++ b/avm/res/network/private-dns-zone/soa/README.md @@ -65,6 +65,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/private-dns-zone/srv/README.md b/avm/res/network/private-dns-zone/srv/README.md index 01a7f68037..a6047c6bda 100644 --- a/avm/res/network/private-dns-zone/srv/README.md +++ b/avm/res/network/private-dns-zone/srv/README.md @@ -65,6 +65,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/private-dns-zone/txt/README.md b/avm/res/network/private-dns-zone/txt/README.md index 5439d372f2..2121b15b16 100644 --- a/avm/res/network/private-dns-zone/txt/README.md +++ b/avm/res/network/private-dns-zone/txt/README.md @@ -65,6 +65,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/private-endpoint/README.md b/avm/res/network/private-endpoint/README.md index 9aa9d1085e..c063742796 100644 --- a/avm/res/network/private-endpoint/README.md +++ b/avm/res/network/private-endpoint/README.md @@ -942,6 +942,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` **Required parameters** diff --git a/avm/res/network/private-link-service/README.md b/avm/res/network/private-link-service/README.md index 1cf7759826..3df921a3c3 100644 --- a/avm/res/network/private-link-service/README.md +++ b/avm/res/network/private-link-service/README.md @@ -570,6 +570,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/public-ip-address/README.md b/avm/res/network/public-ip-address/README.md index 9f4526d01e..6c71fc4c87 100644 --- a/avm/res/network/public-ip-address/README.md +++ b/avm/res/network/public-ip-address/README.md @@ -810,6 +810,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` **Required parameters** diff --git a/avm/res/network/public-ip-prefix/README.md b/avm/res/network/public-ip-prefix/README.md index 8b70c24c45..22a3790bf4 100644 --- a/avm/res/network/public-ip-prefix/README.md +++ b/avm/res/network/public-ip-prefix/README.md @@ -371,6 +371,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/route-table/README.md b/avm/res/network/route-table/README.md index c93c63b58a..a0a83836fb 100644 --- a/avm/res/network/route-table/README.md +++ b/avm/res/network/route-table/README.md @@ -395,6 +395,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/service-endpoint-policy/README.md b/avm/res/network/service-endpoint-policy/README.md index bc95b35f17..7d1097c4b2 100644 --- a/avm/res/network/service-endpoint-policy/README.md +++ b/avm/res/network/service-endpoint-policy/README.md @@ -240,6 +240,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/trafficmanagerprofile/README.md b/avm/res/network/trafficmanagerprofile/README.md index d7f8192264..c7dfa7d65c 100644 --- a/avm/res/network/trafficmanagerprofile/README.md +++ b/avm/res/network/trafficmanagerprofile/README.md @@ -675,6 +675,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + - `'Traffic Manager Contributor'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/virtual-network-gateway/README.md b/avm/res/network/virtual-network-gateway/README.md index 36648bf55a..83cde965b0 100644 --- a/avm/res/network/virtual-network-gateway/README.md +++ b/avm/res/network/virtual-network-gateway/README.md @@ -1582,6 +1582,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/virtual-network/README.md b/avm/res/network/virtual-network/README.md index 4b6fa95d30..b3f52a10bb 100644 --- a/avm/res/network/virtual-network/README.md +++ b/avm/res/network/virtual-network/README.md @@ -1195,6 +1195,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1415,6 +1422,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/virtual-network/subnet/README.md b/avm/res/network/virtual-network/subnet/README.md index e6269f8046..9a975d39da 100644 --- a/avm/res/network/virtual-network/subnet/README.md +++ b/avm/res/network/virtual-network/subnet/README.md @@ -144,6 +144,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/virtual-wan/README.md b/avm/res/network/virtual-wan/README.md index 18b3f54a3b..418464fd84 100644 --- a/avm/res/network/virtual-wan/README.md +++ b/avm/res/network/virtual-wan/README.md @@ -391,6 +391,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/vpn-site/README.md b/avm/res/network/vpn-site/README.md index 07e306d08b..63156245bb 100644 --- a/avm/res/network/vpn-site/README.md +++ b/avm/res/network/vpn-site/README.md @@ -606,6 +606,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/operational-insights/workspace/README.md b/avm/res/operational-insights/workspace/README.md index 2290266bfb..59a1b53a9a 100644 --- a/avm/res/operational-insights/workspace/README.md +++ b/avm/res/operational-insights/workspace/README.md @@ -2081,6 +2081,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Log Analytics Contributor'` + - `'Log Analytics Reader'` + - `'Monitoring Contributor'` + - `'Monitoring Reader'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'Security Admin'` + - `'Security Reader'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/operational-insights/workspace/table/README.md b/avm/res/operational-insights/workspace/table/README.md index 7313d497ee..dc20f643c0 100644 --- a/avm/res/operational-insights/workspace/table/README.md +++ b/avm/res/operational-insights/workspace/table/README.md @@ -92,6 +92,16 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Log Analytics Contributor'` + - `'Log Analytics Reader'` + - `'Monitoring Contributor'` + - `'Monitoring Reader'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/portal/dashboard/README.md b/avm/res/portal/dashboard/README.md index 0a33b644ff..07b61aa261 100644 --- a/avm/res/portal/dashboard/README.md +++ b/avm/res/portal/dashboard/README.md @@ -796,6 +796,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/power-bi-dedicated/capacity/README.md b/avm/res/power-bi-dedicated/capacity/README.md index 0ef1e8e8f4..b01901daba 100644 --- a/avm/res/power-bi-dedicated/capacity/README.md +++ b/avm/res/power-bi-dedicated/capacity/README.md @@ -478,6 +478,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Log Analytics Contributor'` + - `'Log Analytics Reader'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/purview/account/README.md b/avm/res/purview/account/README.md index 26ccfdb7d2..cc71dad4f6 100644 --- a/avm/res/purview/account/README.md +++ b/avm/res/purview/account/README.md @@ -2165,6 +2165,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -2546,6 +2552,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -2941,6 +2953,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/recovery-services/vault/README.md b/avm/res/recovery-services/vault/README.md index b6ca61f7e5..06c21b10e9 100644 --- a/avm/res/recovery-services/vault/README.md +++ b/avm/res/recovery-services/vault/README.md @@ -2445,6 +2445,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -2603,6 +2614,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Backup Contributor'` + - `'Backup Operator'` + - `'Backup Reader'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'Site Recovery Contributor'` + - `'Site Recovery Operator'` + - `'Site Recovery Reader'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/relay/namespace/README.md b/avm/res/relay/namespace/README.md index 837fa1fa43..06c2c905d1 100644 --- a/avm/res/relay/namespace/README.md +++ b/avm/res/relay/namespace/README.md @@ -1215,6 +1215,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1326,6 +1337,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Relay Listener'` + - `'Azure Relay Owner'` + - `'Azure Relay Sender'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/relay/namespace/hybrid-connection/README.md b/avm/res/relay/namespace/hybrid-connection/README.md index 96212178af..8df88f210d 100644 --- a/avm/res/relay/namespace/hybrid-connection/README.md +++ b/avm/res/relay/namespace/hybrid-connection/README.md @@ -144,6 +144,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Relay Listener'` + - `'Azure Relay Owner'` + - `'Azure Relay Sender'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/relay/namespace/wcf-relay/README.md b/avm/res/relay/namespace/wcf-relay/README.md index abc0f0c610..80caef4d77 100644 --- a/avm/res/relay/namespace/wcf-relay/README.md +++ b/avm/res/relay/namespace/wcf-relay/README.md @@ -161,6 +161,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Relay Listener'` + - `'Azure Relay Owner'` + - `'Azure Relay Sender'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/resource-graph/query/README.md b/avm/res/resource-graph/query/README.md index fd64204c24..316e8d7090 100644 --- a/avm/res/resource-graph/query/README.md +++ b/avm/res/resource-graph/query/README.md @@ -374,6 +374,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/resources/deployment-script/README.md b/avm/res/resources/deployment-script/README.md index 9dac2f308c..a922e8496c 100644 --- a/avm/res/resources/deployment-script/README.md +++ b/avm/res/resources/deployment-script/README.md @@ -1012,6 +1012,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/search/search-service/README.md b/avm/res/search/search-service/README.md index a0de84e740..9001f0359c 100644 --- a/avm/res/search/search-service/README.md +++ b/avm/res/search/search-service/README.md @@ -1236,6 +1236,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1370,6 +1381,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'Search Index Data Contributor'` + - `'Search Index Data Reader'` + - `'Search Service Contributor'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/service-bus/namespace/README.md b/avm/res/service-bus/namespace/README.md index 0e05ec12f1..178f3dd665 100644 --- a/avm/res/service-bus/namespace/README.md +++ b/avm/res/service-bus/namespace/README.md @@ -2000,6 +2000,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -2354,6 +2365,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Service Bus Data Owner'` + - `'Azure Service Bus Data Receiver'` + - `'Azure Service Bus Data Sender'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -2480,6 +2500,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Service Bus Data Owner'` + - `'Azure Service Bus Data Receiver'` + - `'Azure Service Bus Data Sender'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -2764,6 +2793,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Service Bus Data Owner'` + - `'Azure Service Bus Data Receiver'` + - `'Azure Service Bus Data Sender'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/service-bus/namespace/queue/README.md b/avm/res/service-bus/namespace/queue/README.md index cc4a9b560c..0c581d4e73 100644 --- a/avm/res/service-bus/namespace/queue/README.md +++ b/avm/res/service-bus/namespace/queue/README.md @@ -236,6 +236,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Service Bus Data Owner'` + - `'Azure Service Bus Data Receiver'` + - `'Azure Service Bus Data Sender'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/service-bus/namespace/topic/README.md b/avm/res/service-bus/namespace/topic/README.md index 59c7b43e97..7362055d9e 100644 --- a/avm/res/service-bus/namespace/topic/README.md +++ b/avm/res/service-bus/namespace/topic/README.md @@ -201,6 +201,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Service Bus Data Owner'` + - `'Azure Service Bus Data Receiver'` + - `'Azure Service Bus Data Sender'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/service-fabric/cluster/README.md b/avm/res/service-fabric/cluster/README.md index bdeeb3417c..08c89d43fa 100644 --- a/avm/res/service-fabric/cluster/README.md +++ b/avm/res/service-fabric/cluster/README.md @@ -1339,6 +1339,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/signal-r-service/signal-r/README.md b/avm/res/signal-r-service/signal-r/README.md index 35f25de4aa..9d3688a0d3 100644 --- a/avm/res/signal-r-service/signal-r/README.md +++ b/avm/res/signal-r-service/signal-r/README.md @@ -983,6 +983,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1129,6 +1140,20 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'SignalR AccessKey Reader'` + - `'SignalR App Server'` + - `'SignalR REST API Owner'` + - `'SignalR REST API Reader'` + - `'SignalR Service Owner'` + - `'SignalR/Web PubSub Contributor'` + - `'User Access Administrator'` + - `'Web PubSub Service Owner (Preview)'` + - `'Web PubSub Service Reader (Preview)'` **Required parameters** diff --git a/avm/res/signal-r-service/web-pub-sub/README.md b/avm/res/signal-r-service/web-pub-sub/README.md index 46fb8b2483..e255f3e70c 100644 --- a/avm/res/signal-r-service/web-pub-sub/README.md +++ b/avm/res/signal-r-service/web-pub-sub/README.md @@ -952,6 +952,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1098,6 +1109,20 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'SignalR AccessKey Reader'` + - `'SignalR App Server'` + - `'SignalR REST API Owner'` + - `'SignalR REST API Reader'` + - `'SignalR Service Owner'` + - `'SignalR/Web PubSub Contributor'` + - `'User Access Administrator'` + - `'Web PubSub Service Owner (Preview)'` + - `'Web PubSub Service Reader (Preview)'` **Required parameters** diff --git a/avm/res/sql/managed-instance/README.md b/avm/res/sql/managed-instance/README.md index a9394f7cf0..4efc05d72d 100644 --- a/avm/res/sql/managed-instance/README.md +++ b/avm/res/sql/managed-instance/README.md @@ -1286,6 +1286,19 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Reservation Purchaser'` + - `'Role Based Access Control Administrator (Preview)'` + - `'SQL DB Contributor'` + - `'SQL Managed Instance Contributor'` + - `'SQL Security Manager'` + - `'SQL Server Contributor'` + - `'SqlDb Migration Role'` + - `'SqlMI Migration Role'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/sql/server/README.md b/avm/res/sql/server/README.md index e4306982f2..4f73df2fa8 100644 --- a/avm/res/sql/server/README.md +++ b/avm/res/sql/server/README.md @@ -1722,6 +1722,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1865,6 +1876,19 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Reservation Purchaser'` + - `'Role Based Access Control Administrator'` + - `'SQL DB Contributor'` + - `'SQL Managed Instance Contributor'` + - `'SQL Security Manager'` + - `'SQL Server Contributor'` + - `'SqlDb Migration Role'` + - `'SqlMI Migration Role'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/storage/storage-account/README.md b/avm/res/storage/storage-account/README.md index 557a0ff537..bafe70194f 100644 --- a/avm/res/storage/storage-account/README.md +++ b/avm/res/storage/storage-account/README.md @@ -3134,6 +3134,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -3270,6 +3281,31 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Reader and Data Access'` + - `'Role Based Access Control Administrator'` + - `'Storage Account Backup Contributor'` + - `'Storage Account Contributor'` + - `'Storage Account Key Operator Service Role'` + - `'Storage Blob Data Contributor'` + - `'Storage Blob Data Owner'` + - `'Storage Blob Data Reader'` + - `'Storage Blob Delegator'` + - `'Storage File Data Privileged Contributor'` + - `'Storage File Data Privileged Reader'` + - `'Storage File Data SMB Share Contributor'` + - `'Storage File Data SMB Share Elevated Contributor'` + - `'Storage File Data SMB Share Reader'` + - `'Storage Queue Data Contributor'` + - `'Storage Queue Data Message Processor'` + - `'Storage Queue Data Message Sender'` + - `'Storage Queue Data Reader'` + - `'Storage Table Data Contributor'` + - `'Storage Table Data Reader'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/storage/storage-account/blob-service/container/README.md b/avm/res/storage/storage-account/blob-service/container/README.md index 14d00393ef..c66f943899 100644 --- a/avm/res/storage/storage-account/blob-service/container/README.md +++ b/avm/res/storage/storage-account/blob-service/container/README.md @@ -144,6 +144,20 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Reader and Data Access'` + - `'Role Based Access Control Administrator'` + - `'Storage Account Backup Contributor'` + - `'Storage Account Contributor'` + - `'Storage Account Key Operator Service Role'` + - `'Storage Blob Data Contributor'` + - `'Storage Blob Data Owner'` + - `'Storage Blob Data Reader'` + - `'Storage Blob Delegator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/storage/storage-account/queue-service/queue/README.md b/avm/res/storage/storage-account/queue-service/queue/README.md index 508062614a..ccfbd4b635 100644 --- a/avm/res/storage/storage-account/queue-service/queue/README.md +++ b/avm/res/storage/storage-account/queue-service/queue/README.md @@ -64,6 +64,20 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Reader and Data Access'` + - `'Role Based Access Control Administrator'` + - `'Storage Account Backup Contributor'` + - `'Storage Account Contributor'` + - `'Storage Account Key Operator Service Role'` + - `'Storage Queue Data Contributor'` + - `'Storage Queue Data Message Processor'` + - `'Storage Queue Data Message Sender'` + - `'Storage Queue Data Reader'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/storage/storage-account/table-service/table/README.md b/avm/res/storage/storage-account/table-service/table/README.md index dfe48226f8..4009c666b3 100644 --- a/avm/res/storage/storage-account/table-service/table/README.md +++ b/avm/res/storage/storage-account/table-service/table/README.md @@ -55,6 +55,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Reader and Data Access'` + - `'Role Based Access Control Administrator'` + - `'Storage Account Backup Contributor'` + - `'Storage Account Contributor'` + - `'Storage Account Key Operator Service Role'` + - `'Storage Table Data Contributor'` + - `'Storage Table Data Reader'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/synapse/private-link-hub/README.md b/avm/res/synapse/private-link-hub/README.md index 6b406c9bd6..9a2123c05e 100644 --- a/avm/res/synapse/private-link-hub/README.md +++ b/avm/res/synapse/private-link-hub/README.md @@ -708,6 +708,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -819,6 +830,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/synapse/workspace/README.md b/avm/res/synapse/workspace/README.md index d9b6a461a3..45cccee622 100644 --- a/avm/res/synapse/workspace/README.md +++ b/avm/res/synapse/workspace/README.md @@ -1651,6 +1651,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1778,6 +1789,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Resource Policy Contributor'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/virtual-machine-images/image-template/README.md b/avm/res/virtual-machine-images/image-template/README.md index 022c56722c..b40afc22f9 100644 --- a/avm/res/virtual-machine-images/image-template/README.md +++ b/avm/res/virtual-machine-images/image-template/README.md @@ -691,6 +691,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/web/connection/README.md b/avm/res/web/connection/README.md index 8c29f78a19..be084c468f 100644 --- a/avm/res/web/connection/README.md +++ b/avm/res/web/connection/README.md @@ -460,6 +460,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/web/hosting-environment/README.md b/avm/res/web/hosting-environment/README.md index c6aa44fb42..568d1fbb7b 100644 --- a/avm/res/web/hosting-environment/README.md +++ b/avm/res/web/hosting-environment/README.md @@ -797,6 +797,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/web/serverfarm/README.md b/avm/res/web/serverfarm/README.md index 9683316417..0df60a5510 100644 --- a/avm/res/web/serverfarm/README.md +++ b/avm/res/web/serverfarm/README.md @@ -648,6 +648,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Web Plan Contributor'` + - `'Website Contributor'` **Required parameters** diff --git a/avm/res/web/site/README.md b/avm/res/web/site/README.md index 5b72d460f5..bc9c390cb6 100644 --- a/avm/res/web/site/README.md +++ b/avm/res/web/site/README.md @@ -3001,6 +3001,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'App Compliance Automation Administrator'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Web Plan Contributor'` + - `'Website Contributor'` **Required parameters** diff --git a/avm/res/web/site/slot/README.md b/avm/res/web/site/slot/README.md index 063962c630..135fa084b8 100644 --- a/avm/res/web/site/slot/README.md +++ b/avm/res/web/site/slot/README.md @@ -793,6 +793,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -936,6 +947,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'App Compliance Automation Administrator'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Web Plan Contributor'` + - `'Website Contributor'` **Required parameters** diff --git a/avm/res/web/static-site/README.md b/avm/res/web/static-site/README.md index c0b10e3875..e77e8fe0c6 100644 --- a/avm/res/web/static-site/README.md +++ b/avm/res/web/static-site/README.md @@ -940,6 +940,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1073,6 +1084,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Web Plan Contributor'` + - `'Website Contributor'` **Required parameters**