Open fawohlsc opened 4 years ago
Hi @fawohlsc ,
We currently have technical difficulties to support waiting LRO as job for Invoke-AzRestMethod
,
for now I think you have to write a loop to get response from "Azure-AsyncOperation"
@VeryEarly thanks for the prompt and insightful answer. Some cmdlets like Start-AzPolicyRemediation
and Start-AzPolicyComplianceScan
awaiting LRO with the -AsJob
parameter. Without it, they just continue without awaiting the operation. Is this generally best practise across Azure PowerShell, so if you want to await LRO use -AsJob
? Suggestion is to keep this issue open until Invoke-AzRestMethod
supports LRO with -AsJob
parameter.
@VeryEarly - Below stating a workaround until Invoke-AzRestMethod
supports awaiting async operations:
# Remove-AzRouteConfig will issue a PUT request for routeTables and hence the route will be appended by policy.
# In order to remove the route, directly call the REST API by issuing a DELETE request for route.
$httpResponse = Invoke-AzRestMethod `
-ResourceGroupName $RouteTable.ResourceGroupName `
-ResourceProviderName "Microsoft.Network" `
-ResourceType @("routeTables", "routes") `
-Name @($RouteTable.Name, $route.Name) `
-ApiVersion "2020-05-01" `
-Method "DELETE"
# Handling the HTTP status codes returned by the DELETE request for route
# See also: https://docs.microsoft.com/en-us/rest/api/virtualnetwork/routes/delete
# Accepted
if ($httpResponse.StatusCode -eq 200) {
# All good, do nothing
}
# Accepted and the operation will complete asynchronously
elseif ($httpResponse.StatusCode -eq 202) {
# Invoke-AzRestMethod currently does not support awaiting asynchronous operations
# See also: https://github.com/Azure/azure-powershell/issues/13293
$asyncOperation = $httpResponse | Wait-AsyncOperation
if ($asyncOperation.Status -ne "Succeeded") {
throw "Route '$($route.Name)' could not be removed from route table '$($RouteTable.Name)'."
}
}
# Route was deleted or not found
elseif ($httpResponse.StatusCode -eq 204) {
# All good, do nothing
}
# Error response describing why the operation failed
else {
throw "Route '$($route.Name)' could not be removed from route table '$($RouteTable.Name)'."
}
function Wait-AsyncOperation {
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[ValidateNotNull()]
[Microsoft.Azure.Commands.Profile.Models.PSHttpResponse]$HttpResponse,
[Parameter()]
[ValidateRange(1, [int]::MaxValue)]
[int]$MaxRetries = 100
)
# Asynchronous operations either return HTTP status code 201 (Created) or 202 (Accepted)
# See also: https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/async-operations#status-codes-for-asynchronous-operations
if ($HttpResponse.StatusCode -notin @(201, 202)) {
throw "HTTP response status code must be either '201' or '202' to indicate an asynchronous operation."
}
# Extracting retry after from HTTP Response Headers
# See also: https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/async-operations#url-to-monitor-status
$retryAfter = $HttpResponse
| Get-HttpResponseHeaderValues -HeaderName "Retry-After"
| Select-Object -First 1
# Extracting status URL from HTTP Response Headers
$statusUrl = $HttpResponse
| Get-HttpResponseHeaderValues -HeaderName "Azure-AsyncOperation"
| Select-Object -First 1
if ($null -eq $statusUrl) {
$statusUrl = $HttpResponse
| Get-HttpResponseHeaderValues -HeaderName "Location"
| Select-Object -First 1
}
if ($null -eq $statusUrl) {
throw "HTTP response does not contain any header 'Azure-AsyncOperation' or 'Location' containing the URL to monitor the status of the asynchronous operation."
}
# Convert status URL to path
$statusPath = $statusUrl.Replace("https://management.azure.com", "")
# Monitor status of asynchronous operation
$httpResponse = $null
$stopMonitoring = $false
$retries = 0
do {
Start-Sleep -Second $retryAfter
$retries++
$asyncOperation = Invoke-AzRestMethod -Path $statusPath -Method "GET"
| Select-Object -ExpandProperty Content
| ConvertFrom-Json
if ($asyncOperation.Status -in @("Succeeded", "Failed", "Canceled")) {
$stopMonitoring = $true
}
} until (($stopMonitoring -eq $true) -or ($retries -ge $MaxRetries))
if ($retries -ge $MaxRetries) {
throw "Maximum retries of $($MaxRetries) reached for monitoring the status of the asynchronous operation."
}
return $asyncOperation
}
function Get-HttpResponseHeaderValues {
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[ValidateNotNull()]
[Microsoft.Azure.Commands.Profile.Models.PSHttpResponse]$HttpResponse,
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string]$HeaderName
)
$headerValues = New-Object System.Collections.Generic.List[string]
$httpResponse.Headers.TryGetValues($HeaderName, [ref] $headerValues) > $null
return $headerValues
}
@VeryEarly thanks for the prompt and insightful answer. Some cmdlets like
Start-AzPolicyRemediation
andStart-AzPolicyComplianceScan
awaiting LRO with the-AsJob
parameter. Without it, they just continue without awaiting the operation. Is this generally best practise across Azure PowerShell, so if you want to await LRO use-AsJob
? Suggestion is to keep this issue open untilInvoke-AzRestMethod
supports LRO with-AsJob
parameter.
Sorry for the delay response.
-AsJob is a way for you to wait the job and get the output after it was finished without blocking the current process. It really depends on do you have to wait for the LRO to be finished.
Thank you @VeryEarly and no worries regarding delay. In my case, I want to wait for the LRO to finish.
Hi, I am struggling to use Invoke-AzRestMethod to call SendGrid api post method for sending mails. Please suggest how can we use that in place of Invoke-RestMethod,or Its not possible to use Invoke-AzRestMethod with Post method to call sendgrid api
Description
Invoke-AzRestMethod with -AsJob seems to not await asynchronous operations to complete. The Azure REST API, returns a HTTP status code 201 or 202 for asynchronous operations and a status URL to monitor the operation. In order to await the asynchronous operation to complete, the status URL can be periodically called using busy waiting (See Track asynchronous Azure operations). When using
Invoke-AzRestMethod
with the parameter -AsJob, it seems to not await the asynchronous operation since it still returns 202 instead of 200/204, which would indicate the operation is complete. Expectation is thatInvoke-AzRestMethod
with the parameter -AsJob actually awaits for the asynchronous operations to complete. This seems to be currently not handled in the source code.Steps to reproduce
Environment data
Module versions