I recently had an issue deploying an App Gateway Blueprint using this Blueprints pipeline tasks extension...
Tricky to explain this as it's part of a big deployment but here we go...
It had been working fine with an App Gateway with multiple Listeners, HTTP Settings, Routing Rules and Health Probes until one day I added a Rewrite ruleset which was necessary to change the response HTTP headers from an internal only App Service (*.azurewebsites.net) to the external domain suffix, e.g. contoso.com.
I could deploy the content of the Blueprint ARM template using Visual Studio Deploy method and it worked fine - not a perfect test of the Blueprint but the content in the JSON was correct and it worked to create, successfully, the Rewrite ruleset. Unfortunately when getting the creation to go through Azure DevOps it fails.
Azure DevOps initially calls the Create Blueprint task and successfully creates the Blueprint - no problem.
It then later has a pipeline to assign the Blueprint in order to deploy the App Gateway - that fails.
The failure is:
"properties": {
"statusCode": "BadRequest",
"statusMessage": "{\"error\":{\"code\":\"InvalidRequestFormat\",\"message\":\"Cannot parse the request.\",\"details\":[{\"code\":\"InvalidJson\",\"message\":\"Unexpected initial token 'String' when populating object. Expected JSON object or array. Path 'properties.rewriteRuleSets[0].properties.rewriteRules[0].actionSet.responseHeaderConfigurations[0]', line 1, position 9748.\"},{\"code\":\"InvalidJson\",\"message\":\"Unexpected initial token 'String' when populating object. Expected JSON object or array. Path 'properties.rewriteRuleSets[1].properties.rewriteRules[0].actionSet.responseHeaderConfigurations[0]', line 1, position 10202.\"},{\"code\":\"InvalidJson\",\"message\":\"Unexpected initial token 'String' when populating object. Expected JSON object or array. Path 'properties.rewriteRuleSets[2].properties.rewriteRules[0].actionSet.responseHeaderConfigurations[0]', line 1, position 10645.\"}]}}",
An example of the Rewrite ruleset is discussed here.
The section of ARM that has been added for my rewrite ruleset is like this (redacted for domain/server/name only):
"g_appGatewayRewriteRuleSets": {
"value": [
{
"name": "my1-lsnr",
"properties": {
"rewriteRules": [
{
"ruleSequence": 100,
"conditions": [
{
"variable": "http_resp_Location",
"pattern": "(https?):\\/\\/.*azurewebsites\\.net(.*)$",
"ignoreCase": true,
"negate": false
}
],
"name": "ConvertToASCGroup",
"actionSet": {
"requestHeaderConfigurations": [],
"responseHeaderConfigurations": [
{
"headerName": "Location",
"headerValue": "{http_resp_Location_1}://my1-server.contoso.com{http_resp_Location_2}"
}
]
}
}
]
}
},
... 2 more rules follow for my2-lsnr and my3-lsnr similarly coded.
If I try to Assign the Blueprint manually in Portal, I can see that the value of the g_appGatewayRewriteRuleSets parameter is being assigned this - which is what was sent in from the last Azure DevOps deployment with the Blueprint Assign task:
[{"name":"my1-lsnr","properties":{"rewriteRules":[{"ruleSequence":100,"conditions":[{"variable":"http_resp_Location","pattern":"(https?):\/\/.azurewebsites\.net(.)$","ignoreCase":true,"negate":false}],"name":"ConvertToASCGroup","actionSet":{"requestHeaderConfigurations":[],"responseHeaderConfigurations":["@{headerName=Location; headerValue={http_resp_Location_1}://my-server1.contoso.com{http_resp_Location_2}}"]}}]}},{"name":"my2-lsnr","properties":{"rewriteRules":[{"ruleSequence":100,"conditions":[{"variable":"http_resp_Location","pattern":"(https?):\/\/.azurewebsites\.net(.)$","ignoreCase":true,"negate":false}],"name":"ConvertToASCGroup","actionSet":{"requestHeaderConfigurations":[],"responseHeaderConfigurations":["@{headerName=Location; headerValue={http_resp_Location_1}://my-server2.contoso.com{http_resp_Location_2}}"]}}]}},{"name":"my3-lsnr","properties":{"rewriteRules":[{"ruleSequence":100,"conditions":[{"variable":"http_resp_Location","pattern":"(https?):\/\/.azurewebsites\.net(.)$","ignoreCase":true,"negate":false}],"name":"ConvertToASCGroup","actionSet":{"requestHeaderConfigurations":[],"responseHeaderConfigurations":["@{headerName=Location; headerValue={http_resp_Location_1}://my-server3.contoso.com{http_resp_Location_2}}"]}}]}}]
That is wrong and should be:
[{"name":"my1-lsnr","properties":{"rewriteRules":[{"ruleSequence":100,"conditions":[{"variable":"http_resp_Location","pattern":"(https?):\/\/.azurewebsites\.net(.)$","ignoreCase": true,"negate": false}],"name": "ConvertToASCGroup","actionSet": {"requestHeaderConfigurations": [],"responseHeaderConfigurations": [{"headerName": "Location","headerValue": "{http_resp_Location_1}://my1-server.contoso.com{http_resp_Location_2}"}]}}]}},{"name": "my2-lsnr","properties": {"rewriteRules": [{"ruleSequence": 100,"conditions": [{"variable": "http_resp_Location","pattern": "(https?):\/\/.azurewebsites\.net(.)$","ignoreCase": true,"negate": false}],"name": "ConvertToASCGroup","actionSet": {"requestHeaderConfigurations": [],"responseHeaderConfigurations": [{"headerName": "Location","headerValue": "{http_resp_Location_1}://my2-server.contoso.com{http_resp_Location_2}"}]}}]}},{"name": "my3-lsnr","properties": {"rewriteRules": [{"ruleSequence": 100,"conditions": [{"variable": "http_resp_Location","pattern": "(https?):\/\/.azurewebsites\.net(.)$","ignoreCase": true,"negate": false}],"name": "ConvertToASCGroup","actionSet": {"requestHeaderConfigurations": [],"responseHeaderConfigurations": [{"headerName": "Location","headerValue": "{http_resp_Location_1}://my3-server.contoso.com{http_resp_Location_2}"}]}}]}}]
...which if I paste in, works.
There are some subtle differences around the responseHeaderConfigurations area - in the failing JSON parameter value you can see an @ symbol...but that isn't in the ARM JSON and isn't in the working parameter text either.
To get around this I disabled use of the blueprint assignment task and simply added a Powershell task that did this, i.e. uses the PS commands to do the assignment using the successfully deployed Blueprint and the incoming ARM Blueprint assignment file that I'm asking the original Assignment to use:
Install-Module -Name Az.Blueprint -Force
$subscriptionID = Get-AzSubscription | Where-Object -Property Name -eq "My-sub"
$bpDefinition = Get-AzBlueprint -SubscriptionId $subscriptionID -Name 'My-AppGateway-bp' -LatestPublished
$bpAssignment = Set-AzBlueprintAssignment -Name 'My-AppGateway-Assignment-bp' -Blueprint $bpDefinition -SubscriptionId $subscriptionID -AssignmentFile '$(System.DefaultWorkingDirectory)_Blueprint-AppGateway\code\blueprint\assign-My-ag.json'
Any ideas would be appreciated as I'd obviously like to go back to being consistently using the task rather than the PS to deploy this one. I've tons of other resources being deployed across the estate using these tasks without issue so it's working great apart from this one esoteric issue.
Thanks
Jeff