alz/azuredevops/pipelines/bicep/templates/helpers/bicep-deploy.yaml (153 lines of code) (raw):
---
parameters:
- name: serviceConnection
type: string
- name: whatIfEnabled
type: boolean
default: true
- name: scriptFiles
type: object
default:
- displayName: "Example Deployment"
templateFilePath: "./infra-as-code/bicep/modules/example/example.bicep"
templateParametersFilePath: "./config/custom-parameters/example.parameters.all.json"
managementGroupId: "00000000-0000-0000-0000-000000000000"
subscriptionId: "00000000-0000-0000-0000-000000000000"
resourceGroupName: "example-rg"
location: "uksouth"
deploymentType: "subscription" # tenant | managementGroup | subscription | resourceGroup
firstRunWhatIf: true
runStep: true
steps:
- task: AzurePowerShell@5
displayName: Check for First Deployment
condition: eq($${{ parameters.whatIfEnabled }}, true)
inputs:
azureSubscription: $${{ parameters.serviceConnection }}
pwsh: true
azurePowerShellVersion: LatestVersion
ScriptType: "InlineScript"
Inline: |
$managementGroupId = $env:MANAGEMENT_GROUP_ID
$managementGroups = Get-AzManagementGroup
$managementGroup = $managementGroups | Where-Object { $_.Name -eq $managementGroupId }
$firstDeployment = $true
if($managementGroup -eq $null) {
Write-Warning "Cannot find the $managementGroupId Management Group, so assuming this is the first deployment. We must skip checking some deployments since their dependent resources do not exist yet."
} else {
Write-Host "Found the $managementGroupId Management Group, so assuming this is not the first deployment."
$firstDeployment = $false
}
Write-Host "##vso[task.setvariable variable=FIRST_DEPLOYMENT;]$firstDeployment"
- $${{ each scriptFile in parameters.scriptFiles }}:
- task: AzurePowerShell@5
displayName: $${{ scriptFile.displayName }}
condition: and(succeeded(), eq($${{ scriptFile.runStep }}, true))
inputs:
azureSubscription: $${{ parameters.serviceConnection }}
pwsh: true
azurePowerShellVersion: LatestVersion
ScriptType: "InlineScript"
Inline: |
$whatIf = [System.Convert]::ToBoolean("$${{ parameters.whatIfEnabled }}")
$firstDeploymentString = $env:FIRST_DEPLOYMENT
$firstDeployment = $true
if($firstDeploymentString -eq "") {
$firstDeployment = $false
} else {
$firstDeployment = [System.Convert]::ToBoolean($firstDeploymentString)
}
$firstRunWhatIf = [System.Convert]::ToBoolean("$${{ scriptFile.firstRunWhatIf }}")
if($whatIf -and $firstDeployment -and !$firstRunWhatIf) {
Write-Warning "Skipping the WhatIf check as the deployment is dependent on resources that do not exist yet..."
exit 0
}
$deploymentType = "$${{ scriptFile.deploymentType }}"
$deploymentPrefix = $env:PREFIX
$deploymentName = "$${{ scriptFile.displayName }}".Replace(" ", "-")
$deploymentTimeStamp = Get-Date -Format 'yyyyMMddHHmmss'
$prefixPostFixAndHythenLength = $deploymentPrefix.Length + $deploymentTimeStamp.Length + 2
$deploymentNameMaxLength = 61 - $prefixPostFixAndHythenLength
if($deploymentName.Length -gt $deploymentNameMaxLength) {
$deploymentName = $deploymentName.Substring(0, $deploymentNameMaxLength)
}
$deploymentName = "$deploymentPrefix-$deploymentName-$deploymentTimeStamp"
Write-Host "Deployment Name: $deploymentName"
$inputObject = @{
TemplateFile = "$${{ scriptFile.templateFilePath }}"
TemplateParameterFile = "$${{ scriptFile.templateParametersFilePath }}"
WhatIf = $whatIf
Verbose = $true
}
$retryCount = 0
$retryMax = 10
$initialRetryDelay = 20
$retryDelayIncrement = 10
$finalSuccess = $false
while ($retryCount -lt $retryMax) {
$retryAttempt = '{0:d2}' -f ($retryCount + 1)
if($retryCount -gt 0) {
$retryDelay = $initialRetryDelay + ($retryCount * $retryDelayIncrement)
Write-Host "Retrying deployment with attempt number $retryAttempt after $retryDelay seconds..." -ForegroundColor Green
Start-Sleep -Seconds $retryDelay
Write-Host "Retrying deployment..." -ForegroundColor Green
}
$inputObject.DeploymentName = "$deploymentName-$retryAttempt"
$result = $null
try {
if ($deploymentType -eq "tenant") {
$inputObject.Location = "$${{ scriptFile.location }}"
$result = New-AzTenantDeployment @inputObject
}
if ($deploymentType -eq "managementGroup") {
$inputObject.Location = "$${{ scriptFile.location }}"
$inputObject.ManagementGroupId = "$${{ scriptFile.managementGroupId }}"
if ($inputObject.ManagementGroupId -eq "") {
$inputObject.ManagementGroupId = (Get-AzContext).Tenant.TenantId
}
$result = New-AzManagementGroupDeployment @inputObject
}
if ($deploymentType -eq "subscription") {
$inputObject.Location = "$${{ scriptFile.location }}"
Select-AzSubscription -SubscriptionId "$${{ scriptFile.subscriptionId }}"
$result = New-AzSubscriptionDeployment @inputObject
}
if ($deploymentType -eq "resourceGroup") {
$inputObject.ResourceGroupName = "$${{ scriptFile.resourceGroupName }}"
Select-AzSubscription -SubscriptionId "$${{ scriptFile.subscriptionId }}"
$result = New-AzResourceGroupDeployment @inputObject
}
} catch {
Write-Host $_ -ForegroundColor Red
Write-Host "Deployment failed with exception, this is likely an intermittent failure so entering retry loop..." -ForegroundColor Red
$retryCount++
continue
}
if ($whatIf) {
$result | Format-List | Out-Host
exit 0
}
$resultId = ""
if($deploymentType -eq "resourceGroup") {
$resultId = "/subscriptions/$${{ scriptFile.subscriptionId }}/resourceGroups/$${{ scriptFile.resourceGroupName }}/providers/Microsoft.Resources/deployments/$deploymentName"
} else {
$resultId = $result.Id
}
$resultIdEscaped = $resultId.Replace("/", "%2F")
$resultUrl = "https://portal.azure.com/#view/HubsExtension/DeploymentDetailsBlade/~/overview/id/$resultIdEscaped"
Write-Host "Deployment Name: $deploymentName"
Write-Host "Deployment ID: $resultId"
Write-Host "Deployment Url: $resultUrl"
$result | Format-List | Out-Host
if($result.ProvisioningState -ne "Succeeded") {
Write-Host "Deployment failed with unsuccessful provisioning state, this is likely an intermittent failure so entering retry loop..." -ForegroundColor Red
$retryCount++
} else {
$finalSuccess = $true
break
}
}
if($finalSuccess -eq $false) {
Write-Error "Deployment failed after $retryMax attempts..."
exit 1
}