使用部署指令碼檢查資源屬性

本文說明如何使用 Bicep 和部署腳本暫停部署,直到資源屬性回傳特定值。 你可以用這個技術確保部署成功,如果已部署的資源向 Azure Resource Manager 報告已準備好,但底層資源還沒準備好。 在這種情況下,已部署的資源尚未準備好與其餘部署互動,這意味著需要暫停。

本文使用了一個 Azure Virtual WAN 情境來示範這項技術。 以下檔案包含資源檢查與暫停實作:

您可以調整檔案以供部署使用。 為了幫助你,azResourceStateCheck.bicep 模組有參數化。 dependsOn此屬性在 orchestration.bicep 中被用來確保 vwanvhcs.bicep 模組部署依賴於 azResourceStateCheck.bicep 模組部署。

Architecture

顯示 Bicep 和部署腳本架構的圖表。

下載此架構的 Visio 檔案

檢閱並下載 GitHub 中的程式碼範例 ,以取得此架構。

  1. 請將 orchestration.bicep 檔案提交以供部署到 Resource Manager 的訂閱範圍。

    Note

    你可以從 infra/samples/deployment-scripts-property-check 目錄取得這個Bicep檔案和其他用於此範例的檔案。 架構圖的右側顯示了倉庫中部分檔案的檔案架構。

  2. orchestration.bicep 檔案會在訂用帳戶範圍建立資源群組。

  3. orchestration.bicep 檔案部署虛擬 WAN 和輻射形虛擬網路。

    • Orchestration.BICEP 部署 vwan.bicep模組,該模組在資源群組範圍內部署Virtual WAN。

    • Orchestration.BICEP 部署 vnet.bicep模組,該模組在資源群組範圍內部署虛擬網路。

    Virtual WAN 與輻射式虛擬網路是並行部署的,因為 Bicep 視它們為獨立的。 相依性會決定 Bicep 中的部署順序。 在任何依賴資源的其他資源之前,都會先部署該資源。 如需 Bicep 中資源相依性的詳細資訊,包括明確和隱含相依性,請參閱 Bicep 中的資源相依性

  4. orchestration.bicep 檔案部署 vwanhub.bicep 模組,該模組部署於資源群組層級的虛擬 WAN 集線器。 集線器隱含依賴於 Virtual WAN,意即集線器部署僅在 Virtual WAN 部署完成後進行。

  5. orchestration.bicep 檔案部署 azResourceStateCheck.bicep 模組,該模組建立使用者指派的管理身份,並將 Azure 角色基礎存取控制(RBAC)讀取器角色指派給資源群組。

  6. azResourceStateCheck.bicep 模組會部署 部署腳本資源

  7. 部署腳本資源使用使用者指派的管理身份來進行 Resource Manager 認證。 資源接著執行 PowerShell 部署腳本 Invoke-AzResourceStateCheck.ps1。 如需部署腳本的詳細資訊,請參閱 在 Bicep 中使用部署腳本

    腳本會輪詢 Virtual WAN hub routingState 屬性,以判斷值是否為 Provisioned

    1. 如果屬性值與 Provisioned 不相等,腳本會暫停一段由 orchestration.bicep 檔案中參數設定並傳入 azResourceStateCheck.bicep 模組的時間。 腳本接著會再次檢查 routingState 屬性值。

      腳本會重複暫停與檢查的循環。 orchestration.bicep 檔案中的一個參數決定了最大迭代次數。 如果屬性值在最大迭代次數後未達到 Provisioned,腳本會產生例外並退出,導致剩餘的Bicep部署停止並失敗。

    2. 若屬性值為 Provisioned,部署腳本將以成功碼 (0)退出。

  8. 若部署腳本成功,orchestration.bicep 檔案會部署 vwanvhcs.bicep 模組,這會在分支虛擬網路與 Virtual WAN 集線器之間建立連接。

    在 orchestration.bicep 中 vwanvhcs.bicep 模組的定義中,有一個 dependsOn 子句讓 vwanvhcs.bicep 明確依賴於 azResourceStateCheck.bicep 模組的成功完成。 因此,只有當性質 routingStateProvisioned時,才會建立連結。

    vwanvhcs.bicep 模組是依序部署 Virtual WAN 集線器的連線,而非平行部署,因為單一 Virtual WAN 集線器不支援平行部署。 若要將批次大小設為 1,模組會使用 Bicep batchSize 裝飾器 @batchSize(1)。 這位裝飾師確保連接線一次部署一條。

案例詳細資料

此架構的關鍵部分是 azResourceStateCheck.bicep 模組,負責部署腳本資源,以及相關的部署腳本 Invoke-AzResourceStateCheck.ps1,這是一個 PowerShell 檔案。 模組會使用部署腳本來檢查資源屬性的值。 在此範例中,資源是虛擬 WAN 中樞。

你可以用 dependsOn 讓一個模組明確依賴另一個模組,因為這個環境是從一個使用Bicep模組的單一檔案部署出來的。 在此範例中, dependsOn vwanvhcs.bicep 模組依賴 azResourceStateCheck.bicep 模組。

以下是 orchestration.bicep 的 dependsOn 使用情況摘錄:

@description('The API version of the Azure Resource you need to use to check the state of a property.')
param parAzResourceApiVersion string = '2022-01-01'

@description('The property of the resource that you need to check. This is a property inside the `properties` bag of the resource that's captured from a GET call to the Resource ID.')
param parAzResourcePropertyToCheck string = 'routingState'

@description('The value of the property of the resource that you need to check.')
param parAzResourceDesiredState string = 'Provisioned'

@description('The duration that the deployment script waits between check or polling requests to check the property and its state, if it is not in its desired state. The duration defaults to `30` seconds.')
param parWaitInSecondsBetweenIterations int = 30

module modVWANHub 'modules/vwanHub.bicep' = {
  scope: rsg
  name: 'deployVWANHub'
  params: {
    region: region
    regionNamePrefix: regionNamePrefix
    defaultTags: defaultTags
    vwanHubCIDR: vwanHubCIDR
    vwanName: modVWAN.outputs.vwanName
  }
}

module modVWANHubRouterCheckerDeploymentScript 'modules/azResourceStateCheck.bicep' = {
  scope: rsg
  name: 'deployVWANHubRouterChecker'
  params: {
    parLocation: region
    parAzResourceId: modVWANHub.outputs.outVwanVHubId
    parAzResourceApiVersion: parAzResourceApiVersion
    parAzResourcePropertyToCheck: parAzResourcePropertyToCheck
    parAzResourceDesiredState: parAzResourceDesiredState
    parMaxIterations: parMaxIterations
    parWaitInSecondsBetweenIterations: parWaitInSecondsBetweenIterations
  }
}

module modVWanVhubVnetConnections 'modules/vwanVhcs.bicep' = {
  dependsOn: [
    modVWANHubRouterCheckerDeploymentScript
  ]
  scope: rsg
  name: 'deployConnectVnetsToVWANVHub'
  params: {
    vnets: vnets
    regionNamePrefix: regionNamePrefix
  }
}

資源檢查是必要的,因為部署的Virtual WAN樞紐要等到 routingState 屬性達到 Provisioned 值時才準備好使用。 Virtual WAN 集線器會向 Resource Manager 報告成功部署,以便部署引擎繼續部署。 當Virtual WAN集線器路由器被配置到已建立的集線器後,Virtual WAN集線器會開始運作。 這個過程大約需要15分鐘。 此行為可在以下新 Virtual WAN 集線器的截圖中看到。 截圖顯示 hub 狀態是 , Succeeded 但路由狀態是 Provisioning

新部署Virtual WAN集線器的截圖。樞紐狀態為成功,路由狀態為 Provisioning.

如果你嘗試在 值 routingStateProvisioned之前部署 vwanvhcs.bicep 模組,連線建立會失敗,整體部署也會失敗。 在路由器配置完成前,重新部署嘗試也會失敗。

以下截圖展示了部署腳本在Virtual WAN樞紐routingState檢查期間的日誌範例。 日誌顯示對該屬性的反覆檢查,回傳的值非 Provisioned

截圖顯示部署腳本輪詢 Virtual WAN 中心的 routingState 屬性。

以下截圖顯示值會變為 Provisioned

截圖顯示當 Virtual WAN 樞紐 routingState 屬性變更為 Provisioned 時,部署腳本已完成的情況。

如果在最大迭代次數後,值仍未變為 Provisioned,腳本會產生例外,這表示腳本資源失敗Resource Manager。 Resource Manager 部署引擎失敗並停止部署,因為例外顯示 Azure 資源有問題,需要進行故障排除。 欲了解更多資訊,請參閱以下 Invoke-AzResourceStateCheck.ps1 腳本。

[CmdletBinding()]
param (
  [string]
  $azResourceResourceId,

  [string]
  $apiVersion = "2022-05-01",

  [string]
  $azResourcePropertyToCheck = "provisioningState",

  [string]
  $azResourceDesiredState = "Provisioned",

  [int]
  $waitInSecondsBetweenIterations = 30,

  [int]
  $maxIterations = 30
)

$totalTimeoutCalculation = $waitInSecondsBetweenIterations * $maxIterations

$azResourcePropertyExistenceCheck = Invoke-AzRestMethod -Method GET -Path "$($azResourceResourceId)?api-version=$($apiVersion)"

if ($azResourcePropertyExistenceCheck.StatusCode -ne "200") {
  $DeploymentScriptOutputs["azResourcePropertyState"] = "Not Found"
  throw "Unable to get Azure Resource - $($azResourceResourceId). Likely it doesn't exist. Status code: $($azResourcePropertyExistenceCheck.StatusCode) Error: $($azResourcePropertyExistenceCheck.Content)"
}

$azResourcePropertyStateResult = "Unknown"
$iterationCount = 0

do {
  $azResourcePropertyStateGet = Invoke-AzRestMethod -Method GET -Path "$($azResourceResourceId)?api-version=$($apiVersion)"
  $azResourcePropertyStateJsonConverted = $azResourcePropertyStateGet.Content | ConvertFrom-Json -Depth 10
  $azResourcePropertyStateResult = $azResourcePropertyStateJsonConverted.properties.$($azResourcePropertyToCheck)

  if ($azResourcePropertyStateResult -ne $azResourceDesiredState) {
    Write-Host "Azure Resource Property ($($azResourcePropertyToCheck)) is not in $($azResourceDesiredState) state. Waiting $($waitInSecondsBetweenIterations) seconds before checking again. Iteration count: $($iterationCount)"
    Start-Sleep -Seconds $waitInSecondsBetweenIterations
    $iterationCount++
  }
} while (
  $azResourcePropertyStateResult -ne $azResourceDesiredState -and $iterationCount -ne $maxIterations
)

if ($azResourcePropertyStateResult -eq $azResourceDesiredState) {
  Write-Host "Azure Resource Property ($($azResourcePropertyToCheck)) is now in $($azResourceDesiredState) state."
  $DeploymentScriptOutputs["azResourcePropertyState"] = "$($azResourceDesiredState)"
}

if ($iterationCount -eq $maxIterations -and $azResourcePropertyStateResult -ne $azResourceDesiredState) {
  $DeploymentScriptOutputs["azResourcePropertyState"] = "Azure Resource Property ($($azResourcePropertyToCheck)) is still not in desired state of $($azResourceDesiredState). Timeout reached of $($totalTimeoutCalculation) seconds."
  throw "Azure Resource Property ($($azResourcePropertyToCheck)) is still not in $($azResourceDesiredState) state after $($totalTimeoutCalculation) seconds."
}

參與者

本文由 Microsoft 維護。 以下貢獻者撰寫了這篇文章。

主要作者:

其他參與者:

若要查看非公開的 LinkedIn 個人檔案,請登入 LinkedIn。

下一步