Nested ARM template and dependsOn in another Resource Group - azure

I am trying to create a Function App with VNET Integration in ARM. I have made all that work just fine in one main template.
Now I have a new requirement where the VNET needs to be in another RG and thus seperate from the Func App RG, but the Func App still needs to have VNET integration to the VNET in the other RG.
I'm struggling how to define the ARM template, so that I deploy the Func App in one RG and VNET in another. The hard part is how to define this so that the Func App integrates into a VNET in another RG in the same ARM template using nested template.
Here is my ARM template:
"resources": [{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2019-10-01",
"name": "nestedTemplate",
"resourceGroup": "[parameters('VNETPeered_RG_Name')]",
"subscriptionId": "0a2009c0-e2ae-4991-aa0e-5c34c141e4cb",
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"variables": {},
"resources": [{
"comments": "Virtual Network for VNET integration feature in the Premium Plan for the Function App",
"type": "Microsoft.Network/virtualNetworks",
"apiVersion": "2019-11-01",
"name": "[variables('virtual_network_name')]",
"location": "[resourceGroup().location]",
"properties": {
"addressSpace": {
"addressPrefixes": [
"[parameters('vnetAddressPrefix')]"
]
},
"subnets": [{
"name": "[variables('subnet_name')]",
"properties": {
"addressPrefix": "[parameters('subnet1Prefix')]",
"serviceEndpoints": [{
"service": "Microsoft.Storage",
"locations": [
"[resourceGroup().location]"
]
}
}
}]
}
}]
}
}
},
{
"comments": "Function App to host the functions themselves. Integrates into a VNET and makes use of Azure DNS Private Zones.",
"type": "Microsoft.Web/sites",
"apiVersion": "2019-08-01",
"name": "[variables('function_app_name')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"nestedTemplate",
"[resourceId('Microsoft.Storage/storageAccounts', variables('storage_account_name'))]",
"[resourceId('Microsoft.Web/serverfarms', variables('app_service_plan_name'))]"
],
"kind": "functionapp",
"identity": {
"type": "SystemAssigned"
},
"properties": {
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('app_service_plan_name'))]",
"siteConfig": {
"appSettings": [{
"name": "APPINSIGHTS_INSTRUMENTATIONKEY",
"value": "[reference(variables('application_insights_resourceId'), '2018-05-01-preview').InstrumentationKey]"
}]
},
"clientAffinityEnabled": true
},
"resources": [{
"type": "networkConfig",
"apiVersion": "2019-08-01",
"name": "virtualNetwork",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', variables('function_app_name'))]"
],
"properties": {
"subnetResourceId": "[reference(resourceId('RG-FunctionsGroup','Microsoft.Network/virtualNetworks/subnets', 'vn-MY-VNET', 'sn-MY-SUBNET'),'2020-05-01')]",
"isSwift": true
}
}]
]
}
On this I get the following error when I try to deploy it with az deployment group command from az cli:
Deployment failed. Correlation ID: 39b0173b-8a51-42c5-a796-1d3427556194. {
"error": {
"code": "InternalServerError",
"message": "There was an unexpected InternalServerError. Please try again later. x-ms-correlation-request-id: 844e9f35-2e9c-411a-817d-9045511558cb"
}
}

reference() will work but TLDR; it's a little heavyweight
https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/template-functions-resource#resourceid
is all you need in this case. To "reference" any resource in ARM you'll use the resourceId - there are a handful of functions to help but it really helps if you understand the basics of the resourceId, which is summarized here:
https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/template-functions-resource#return-value-6
When you want a resourceId to a resource in the same deployment (which is not the same as the same template) you can use the shorthand version
resourceId({namespace/resourceType}, {resourceName})
If it's in a different RG, you need to add the RG param, and if it's in a different sub you need to add that too. I can't tell for certain with your snippet, but it looks like all you need in your case is this (assuming the vnet and fn app are in the same subscription):
"subnetResourceId": "[resourceId(parameters('VNETPeered_RG_Name'), 'Microsoft.Network/virtualNetworks/subnets', variables('virtual_network_name'), variables('subnet_name'))]"
That help?

Your problem is in this part of code:
"properties": {
"subnetResourceId": "[reference(resourceId('RG-FunctionsGroup','Microsoft.Network/virtualNetworks/subnets', 'vn-MY-VNET', 'sn-MY-SUBNET'),'2020-05-01')]",
"isSwift": true
}
You are pointing the subnet with the wrong resource group. Change the resource group where the vnet and the subnet is deployed.
"properties": {
"subnetResourceId": "[reference(resourceId(parameters('VNETPeered_RG_Name'),'Microsoft.Network/virtualNetworks/subnets', variables('virtual_network_name'), variables('subnet_name')),'2020-05-01')]",
"isSwift": true
}

Related

How can I set dependencies on child resources in nested ARM template?

I am trying to use nested templates to deploy a resource group and multiple resources within it on subscription level.
Microsoft documentation has an example of deploying resource group and storage account that I'm trying to follow. I am trying to create another inner level of dependency between a Storage Account resource and a Container resource. That is, the container should only be deployed after the deployment of the storage account is finished. Here is simplified version of my template:
{
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"rgName": {
"type": "string"
},
"rgLocation": {
"type": "string"
},
"storagePrefix": {
"type": "string",
"maxLength": 11
},
"containerName": {
"type": "string"
}
},
"variables": {
"storageName": "[concat(parameters('storagePrefix'), uniqueString(subscription().id, parameters('rgName')))]"
},
"resources": [
{
"type": "Microsoft.Resources/resourceGroups",
"apiVersion": "2021-04-01",
"name": "[parameters('rgName')]",
"location": "[parameters('rgLocation')]",
"properties": {}
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2021-04-01",
"name": "storageDeployment",
"resourceGroup": "[parameters('rgName')]",
"dependsOn": [
"[resourceId('Microsoft.Resources/resourceGroups/', parameters('rgName'))]"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"variables": {},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2021-04-01",
"name": "[variables('storageName')]",
"location": "[parameters('rgLocation')]",
"sku": {
"name": "Standard_LRS"
},
"kind": "StorageV2"
},
{
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
"apiVersion": "2021-06-01",
"name": "[format('{0}/default/{1}', variables('storageName'), parameters('containerName'))]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageName'))]"
]
}
],
"outputs": {}
}
}
}
],
"outputs": {}
}
When I try to deploy this template using PowerShell script New-AzSubscriptionDeployment, I get the following error:
| InvalidTemplate - Long running operation failed with status 'Failed'. Additional Info:'Deployment template validation failed: 'The resource 'Microsoft.Storage/storageAccounts/myStorageAccount' is not defined in the template. Please see https://aka.ms/arm-template for usage details.'.'
I kind of know it has to do with the dependsOn part of the container resource. But how can I resolve this problem?
EDIT: The selected answer solves the problem with dependencies, however the issue still persists in cases where a value needs to be called using concat or listKeys expressions. Here's an example where setting the value for AzureWebJobsStorage throws an error in a nested template:
{
"type": "Microsoft.Web/sites",
[ ... ]
"dependsOn": [
"[variables('hostingPlanName')]",
"[variables('functionAppStorageAccountName')]"
],
"properties": {
"serverFarmId": "[variables('hostingPlanName')]",
"siteConfig": {
"appSettings": [
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('functionAppstorageAccountName'), ';EndpointSuffix=', environment().suffixes.storage, ';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('functionAppstorageAccountName')), '2021-04-01').keys[0].value)]"
}
[ ... ]
]
}
The value for AzureWebJobsStorage causes the deployment to fail with the following error:
`Status Message: The Resource 'Microsoft.Storage/storageAccounts/stfuncaedotestfeb16g' under resource group '<null>' was not found. For more details
| please go to https://aka.ms/ARMResourceNotFoundFix (Code:ResourceNotFound) CorrelationId: 55942377-6d0f-40ec-9733-33b9c3ea13de
I tried being more verbose by using resource group name (and then subscription ID), but that didn't solve the problem.
You should be able to use:
"dependsOn": [
"[variables('storageName')]"
]
Note that will only work if there is no other resource in the template with the same name - otherwise you have to manually construct the full resourceId, like:
[format('{0}/resourceGroups/{1}/providers/Microsoft.Storage/storageAccounts/{2}', subscription().id, parameters('rgName'), variables('storageName'))]
The latter form will always work, just a bit more verbose.
A bit more detail is that the resourceId function doesn't work as you would expect at subscription scope.

ARM template storage account not found while creating Azure Function App

I have an ARM template which creates a Storage Account, App Service Plan, Application Insights and a Function App. In the dependsOn section of the Function App, I configured it to be depending on the other three resources. But when I deploy the template, it fails with the following error:
Status Message: The Resource 'Microsoft.Storage/storageAccounts/dummystorage' under resource group 'dummy-rg' was not found.
I see that the Storage Account, ASP and App Insights are being created first, followed by the Function App. So it seems the dependency is being honored. It's almost like the Storage Account provisioning is not completely finished when the Function App is being created. As you can see in the template below, the Function App resource uses the listKeys to get the Storage Account keys as part of the provisioning.
Does anybody have any idea how I can prevent this from happening? I've read everything in the docs regarding dependencies, and I believe this should just work.
One remark is that the storage account is being deployed based on a condition. I can't imagine it has something to do with my issue, but I just wanted to mention it.
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"functionAppName": {
"type": "string"
},
"appServicePlanName": {
"type": "string"
},
"appInsightsName": {
"type": "string"
},
"deployStorage": {
"type": "bool",
"defaultValue": true
},
"storageAccountName": {
"type": "string"
},
"utcDateTime": {
"type": "string",
"defaultValue": "[utcNow()]"
}
},
"variables": {
"storageAccountDeploymentName": "[concat('storageDeploy-', parameters('utcDateTime'))]",
},
"resources": [
{
"name": "[parameters('functionAppName')]",
"apiVersion": "2018-11-01",
"type": "Microsoft.Web/sites",
"kind": "functionapp",
"location": "[parameters('location')]",
"tags": "[parameters('tags')]",
"dependsOn": [
"[parameters('appInsightsName')]",
"[parameters('appServicePlanName')]",
"[resourceId('Microsoft.Resources/deployments', variables('storageAccountDeploymentName'))]"
],
"properties": {
"name": "[parameters('functionAppName')]",
"siteConfig": {
"appSettings": [
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~3"
},
{
"name": "FUNCTIONS_WORKER_RUNTIME",
"value": "powershell"
},
{
"name": "APPINSIGHTS_INSTRUMENTATIONKEY",
"value": "[reference(concat('Microsoft.Insights/components/', parameters('appInsightsName')), '2015-05-01').InstrumentationKey]"
},
{
"name": "APPLICATIONINSIGHTS_CONNECTION_STRING",
"value": "[reference(concat('Microsoft.Insights/components/', parameters('appInsightsName')), '2015-05-01').ConnectionString]"
},
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=',parameters('storageAccountName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2019-06-01').keys[0].value,';EndpointSuffix=','core.windows.net')]"
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=',parameters('storageAccountName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2019-06-01').keys[0].value,';EndpointSuffix=','core.windows.net')]"
},
{
"name": "WEBSITE_CONTENTSHARE",
"value": "[concat(toLower(parameters('functionAppName')), '813b')]"
}
],
"use32BitWorkerProcess": false,
"powerShellVersion": "[variables('powerShellVersion')]"
},
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]",
"clientAffinityEnabled": true
}
},
{
"name": "[parameters('appServicePlanName')]",
"apiVersion": "2018-11-01",
"type": "Microsoft.Web/serverfarms",
"location": "[parameters('location')]",
"tags": "[parameters('tags')]"
// snip
},
{
"name": "[parameters('appInsightsName')]",
"apiVersion": "2020-02-02-preview",
"type": "microsoft.insights/components",
"location": "[parameters('location')]",
"tags": "[parameters('tags')]",
// snip
},
{
"name": "[variables('storageAccountDeploymentName')]",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2019-10-01",
"condition": "[parameters('deployStorage')]",
"properties": {
"expressionEvaluationOptions": {
"scope": "outer"
},
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"name": "[parameters('storageAccountName')]",
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-06-01",
"tags": "[parameters('tags')]",
"location": "[parameters('location')]",
// snip
}
]
}
}
}
]
}
I think you're running into this: https://bmoore-msft.blog/2020/07/26/resource-not-found-dependson-is-not-working/
TLDR;
listKeys is called in a separate job in the deployment engine and gets called early if that resource (i.e. your storage) is not in the same deployment.
you don't need to nest your storageAccount deployment, doesn't hurt but doesn't help. If your storageAccount deployment is unconditional, then it will help because ARM will wait before running listKeys.
if you need the condition, the only fix is to nest the function app deployment and set a dependency on the conditional storageAccount (the dependency need not be conditional ARM will handle that). You need to set the evaluation scope to "inner" on that nested deployment.
That help?
I noticed your dependsOn for Storage looks like this:
"dependsOn": [
"[parameters('appInsightsName')]",
"[parameters('appServicePlanName')]",
"[resourceId('Microsoft.Resources/deployments', variables('storageAccountDeploymentName'))]"
Whereas my despendsOn for Storage Account and Blob Container looks like this... could that be the reason it's not working? I have never used Microsoft.Resources/deployments (FYI my ARM Template deployment is working)
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', variables('StorageAccountName'), 'default', variables('BlobContainerName2'))]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('StorageAccountName'))]"
Alternatively:
You could drop the conditional and deploy the Storage Account each time. If it exists no change, if it doesn't exist then it's created.
The only caveat to this is if you change something on the storage account post-deployment or if the Storage account has a dynamically set name based on Timestamp or GUID etc.
I realize this is a work around, but it should solve your problem barring the caveat above.

Creating storage queue subscription to custom Event Grid Topic via ARM

I'm trying to set up an Event Grid subscription to my Storage Queue from a custom topic.
This is easy to do when navigating in the portal, but I'm failing to create the appropriate ARM template for this. After having searched and tried out a lot, I've come up with the following piece of template.
{
"name": "MyCustomTopicName/Microsoft.EventGrid/MySubscriptionName",
"type": "Microsoft.EventGrid/topics/providers/eventSubscriptions",
"location": "[resourceGroup().location]",
"apiVersion": "2019-06-01",
"properties": {
"destination": {
"endpointType": "StorageQueue",
"properties": {
"resourceId": "[resourceId('Microsoft.Storage/storageAccounts', variables('theNameOfMyStorageAccount'))]",
"queueName": "[variables('theNameOfMyQueue')]"
}
},
"filter": {
"advancedFilters": []
},
"labels": [],
"eventDeliverySchema": "EventGridSchema"
}
}
This looks rather OK to me but fails because the Event Grid topic isn't in the resource group to which I'm deploying the template.
Deployment failed. Correlation ID: [guid]. {
"error": {
"code": "ResourceNotFound",
"message": "The Resource 'Microsoft.EventGrid/topics/MyCustomTopicName' under resource group 'TheResourceGroupTheStorageAccountIsIn' was not found."
}
}
I'm deploying the complete ARM template to TheResourceGroupTheStorageAccountIsIn.
The MyCustomTopicName topic is in a resource group where we place the custom topics, so all services can use it.
I've tried using the full identifier (resource id) of the custom topic, but this isn't valid. Ideas?
PS: I'm using a similar template for creating a subscription to an Azure Function, which does work properly. The main difference over there is the destination block, which makes sense.
If I'm reading this right you just need to use a nested deployment and target the resource group where the topic is in:
{
"apiVersion": "2017-05-10",
"name": "nestedTemplate",
"type": "Microsoft.Resources/deployments",
"resourceGroup": "your_topic_resource_roup",
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"variables": {},
"resources": [
{
"name": "MyCustomTopicName/Microsoft.EventGrid/MySubscriptionName",
"type": "Microsoft.EventGrid/topics/providers/eventSubscriptions",
"location": "[resourceGroup().location]",
"apiVersion": "2019-06-01",
"properties": {
"destination": {
"endpointType": "StorageQueue",
"properties": {
"resourceId": "[resourceId('Microsoft.Storage/storageAccounts', variables('theNameOfMyStorageAccount'))]",
"queueName": "[variables('theNameOfMyQueue')]"
}
},
"filter": {
"advancedFilters": []
},
"labels": [],
"eventDeliverySchema": "EventGridSchema"
}
}
]
}
}
},

ARM nested template ‘Invalid Template could not find template resource’

I'm deploying arm template to create an SSL certificate to existing traffic managers and to bind the certificates to the app services.
Since the app services in one resource group and the traffic manager and certificate in a different resource group - I use nested template.
i got an error with my certificate SSL:
Deployment template validation failed: 'The template reference
'blabla-ssl1' is not valid: could not find template resource or
resource copy with this name
"comments": "Get the Traffic Manager SSL cert that will be binded to the app",
"copy": {
"name": "loop",
"count": "[length(variables('locations'))]"
},
"type": "Microsoft.Web/certificates",
"name": "[concat(variables('tmsslcert')['secretname'], copyIndex())]",
"apiVersion": "2016-03-01",
"location": "[variables('locations')[copyIndex()]]",
"dependsOn": [
"[variables('TMName')]"
],
"properties": {
"keyVaultId": "[variables('tmsslcert')['KeyVaultId']]",
"secretname": "[variables('tmsslcert')['secretname']]"
}
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2018-05-01",
"resourceGroup": "[variables('webappResourceGroup')]",
"name": "[concat('AddTMSSLCert_',variables('locations')[copyIndex()],'_nestedTemplate')]",
"copy": {
"name": "endpointloop",
"count": "[length(variables('locations'))]"
},
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"comments": "app hostname binding of TM CNAME",
"type": "Microsoft.Web/sites/hostNameBindings",
"name": "[concat(variables('webappDNSNamePrefix'), '-', variables('locations')[copyIndex()], '/', variables('tmcname'))]",
"apiVersion": "2016-08-01",
"location": "[variables('locations')[copyIndex()]]",
"scale": null,
"properties": {
"siteName": "variables('webappDNSNamePrefix'), '-', variables('locations')[copyIndex()]",
"sslState": "SniEnabled",
"thumbprint": "[reference(resourceId(variables('webappResourceGroup'),'Microsoft.Web/certificates', concat(variables('tmsslcert')['secretname'], copyIndex())),'2016-03-01').Thumbprint]"
},
"dependsOn": [
"[concat(variables('tmsslcert')['secretname'], copyIndex())]",
//"[concat('Microsoft.Web/certificates/', variables('tmsslcert')['secretname'], copyIndex())]"
]
}
]
}
}
}
its impossible to tell where the error is exactly (given the data you provided), but this means either your references or dependsOn are trying to reach the resource that's either not created or in a different resource group. One thing that looks specifically wrong is this:
"dependsOn": [
"[concat(variables('tmsslcert')['secretname'], copyIndex())]",
//"[concat('Microsoft.Web/certificates/', variables('tmsslcert')['secretname'], copyIndex())]"
]
this would not work, because it will work in the context of the nested deployment, so in a different resource group

Azure - Set WebSocket On from ARM json template

I'm trying to turn WebSockets On for an Azure WebApp from an Azure ARM json template that deploys my whole infrastructure.
Here is an extract with regards to the Azure Web App. It doesn't work, i.e the WebSockets are still Off. I unsuccessfully tried different spelling: webSocketsEnabled or WebSockets.
"resources":[
{
"name": "[variables('MyApp')]",
"type": "Microsoft.Web/sites",
"location": "Brazil South",
"apiVersion": "2016-08-01",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', variables('MyAppPlanBrazil'))]"
],
"tags": {
"[concat('hidden-related:', resourceId('Microsoft.Web/serverfarms', variables('MyAppPlanBrazil')))]": "Resource",
"displayName": "MyAppAppBrazil"
},
"properties": {
"name": "[variables('MyAppPlanBrazil')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('MyAppPlanBrazil'))]",
"siteConfig": {
"AlwaysOn": true,
"webSocketsEnabled": true,
"connectionStrings": [
{
...
},
{
...
},
]
}
}
]
UPDATE
As suggested in answer below I updated the apiVersion to "2016-08-01" but this still doesn't work.
Also note that while my schema is the one described here, apiVersion is squiggled in VS and it says the authorized value is "2015-08-01" only.
UPDATE2
I tried the solutions below. They work for their authors but not for me. I guess the problem is elsewhere. My infrastructure is already deployed and I try to update it with webSocketsEnabled. Whereas in the solution below I imagine the authors directly create the web app with webSocketsEnabled.
Also, I coupled webSocketsEnabled with alwaysOn whereas the pricing tier of my webapp doesn't allow "AlwaysOn" (as it says in the portal I need to upgrade to use that feature) so I'll try without alwaysOn.
UPDATE3
At the end, the above template worked when I removed AlwaysOn.
Thank you to those who tried to help me.
Set your api version to this: "2016-08-01"
Use
"webSocketsEnabled": true
This is from the Microsoft.Web/sites template reference:
https://learn.microsoft.com/en-us/azure/templates/microsoft.web/sites
The api version you are using (2015-08-01) from:
https://github.com/Azure/azure-resource-manager-schemas/blob/master/schemas/2015-08-01/Microsoft.Web.json
Doesn't have web sockets in it, but the later one:
https://github.com/Azure/azure-resource-manager-schemas/blob/master/schemas/2016-08-01/Microsoft.Web.json
Does have webSocketsEnabled.
Please have a try to use the following code. It works correctly on my side.
Updated: add whole test arm template and you could have a try to use the following code with your service plan name and resource group name
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"serverFarmName": {
"type": "string",
"defaultValue": "YourPlan"
},
"serverFarmResourceGroup": {
"type": "string",
"defaultValue": "ResourceGroupName"
}},
"variables": {
"ARMtemplateTestName": "[concat('ARMtemplateTest', uniqueString(resourceGroup().id))]"},
"resources": [
{
"name": "[variables('ARMtemplateTestName')]",
"type": "Microsoft.Web/sites",
"location": "southcentralus",
"apiVersion": "2015-08-01",
"dependsOn": [ ],
"tags": {
"[concat('hidden-related:', resourceId(parameters('serverFarmResourceGroup'), 'Microsoft.Web/serverFarms', parameters('serverFarmName')))]": "Resource",
"displayName": "ARMtemplateTest"
},
"properties": {
"name": "[variables('ARMtemplateTestName')]",
"serverFarmId": "[resourceId(parameters('serverFarmResourceGroup'), 'Microsoft.Web/serverFarms', parameters('serverFarmName'))]"
},
"resources": [
{
"name": "web",
"type": "config",
"apiVersion": "2015-08-01",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', variables('ARMtemplateTestName'))]"
],
"tags": {
"displayName": "enableWebSocket"
},
"properties": {
"webSocketsEnabled": true,
"alwaysOn": true
}
},
{
"apiVersion": "2015-08-01",
"name": "connectionstrings",
"type": "config",
"dependsOn": [
"[resourceId('Microsoft.Web/Sites', variables('ARMtemplateTestName'))]"
],
"properties": {
"ConnString1": {
"value": "My custom connection string",
"type": "custom"
},
"ConnString2": {
"value": "My SQL connection string",
"type": "SQLAzure"
}
}
},
{
"name": "appsettings",
"type": "config",
"apiVersion": "2015-08-01",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', variables('ARMtemplateTestName'))]"
],
"tags": {
"displayName": "Appsetting"
},
"properties": {
"key1": "value1",
"key2": "value2"
}
}
]
}],
"outputs": {}
}
Test Result:
All the above solution should work.
My initial snippet worked as well ... as soon as I removed alwaysOn.
Indeed, I was using a free tiers App Service Plan for which alwaysOn is not available. While there was no errors or anything else indicating something wrong, I could not set webSocketEnabled and alwaysOn at the same time in that case.

Resources