Azure / Azure/azure-rest-api-specs
Microsoft.Web/sites/<name> is undocumentedly asynchronous
- Dominant language
- TypeSpec
- Stars
- 3.1k
- Forks
- 5.9k
- Avg merge
- 3d 2h
- Merged PRs (30d)
- 424
Description
When using PUT or PATCH on `https://management.azure.com/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.Web/sites/${functionAppName}`, the response is status code 200, but the operation is not actually complete.
To reproduce:
1. Create a Functions app.
2. Replace the values in the first two lines of the following PowerShell snippet with the resource group name and the app name of the Functions app created in step 1.
3. Run the snippet below (as edited in step 2) using PowerShell Core. You'll need to run `Connect-AzAccount` before running the snippet.
```PowerShell
#PARAMS
$resourceGroupName = 'funcytesty'
$functionAppName = 'funcytesty'
#Execution
$subscriptionId = (Get-AzContext).Subscription.Id
$resourceGroupId = Get-AzResourceGroup -Name $resourceGroupName | Select-Object -ExpandProperty ResourceId
$endpoint = "https://management.azure.com/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.Web/sites/${functionAppName}?api-version=2016-08-01"
$tenantId = (Get-AzSubscription -SubscriptionId $subscriptionId)[0].TenantId
$tokenCache = (Get-AzContext).TokenCache
$accessToken = $tokenCache.ReadItems() `
| Where-Object { $_.TenantId -eq $tenantId -and $_.Resource -eq 'https://management.core.windows.net/' } `
| Sort-Object -Property ExpiresOn -Descending `
| Select-Object -First 1 -ExpandProperty AccessToken
$headers = @{
"Authorization" = "Bearer " + $accessToken;
"Accept" = "application/json" ;
"Content-Type" = "application/json"
}
$identityField = @{
"principalId" = $null;
"tenantId" = $null;
"type" = "SystemAssigned"
}
$requestBody = @{
"identity" = $identityField
}
# This is where we actually call the API
$response = Invoke-WebRequest -Uri $endpoint -Headers $headers -Body ($requestBody | convertto-json ) -Method Patch
echo "Response status code: $($response.StatusCode)"
$principalId = ($response.Content | ConvertFrom-Json).identity.principalId
$applicationId = (Get-AzADServicePrincipal -ObjectId $principalId).ApplicationId
New-AzRoleAssignment -Scope $resourceGroupId -RoleDefinitionName Contributor -ApplicationId $applicationId
```
**Expected behavior:** After the invocation of the API to add an identity, we expect the service principal to have been created.
**Actual behavior:** However, the line `$applicationId = (Get-AzADServicePrincipal -ObjectId $principalId).ApplicationId` actually produces a `$null`. Only seconds later, can the service principal be retrieved with that command.
This is a violation of the API contract, as the status code from the PATCH operation was 200, not 202.
This issue propagates to the actual PowerShell CMDlets that use this API. I discovered the issue when attempting to do the following in PowerShell:
```PowerShell
#Enable MSI
$webApp = Set-AzWebApp -AssignIdentity $true -Name $config.functionAppName -ResourceGroupName $config.functionAppResourceGroup
# Add role to SP
$appServicePrincipal = Get-AzADServicePrincipal -DisplayName $config.functionAppName
New-AzRoleAssignment -Scope $storageAccount.Id -RoleDefinitionName Contributor -ApplicationId $appServicePrincipal.ApplicationId
```
This consistently failed until I put a 10-second sleep timer after the first line.
Contributor guide
Research direction
Start with the Microsoft.Web/sites PUT/PATCH endpoint and reproduce the PowerShell Core request described in the issue. Compare the documented 200 response with the delayed service-principal availability; done means the API contract and observed completion behavior agree, or the asynchronous behavior is explicitly documented.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- azure, powershell
- Domain
- api, backend-api-design
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100