I've written up the script below to do the following:
The problem lies in the setting of the app settings in the function app, when I'm setting up the AzureWebJobsStorage. The resourceId function fails to resolve the storage account. When looking at the documention for the resourceId function, it states:
When used with a subscription-level deployment, the resourceId() function can only retrieve the ID of resources deployed at that level. [docs]
But now I don't know how to resolve this!
Template:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"resourceGroupName": {
"type": "string"
},
"functionName": {
"type": "string"
},
"storageAccName": {
"type": "string"
},
"namingPrefix": {
"type": "string"
}
},
"variables": {
"resourceGroupLocation": "North Europe",
"planName": "[replace(concat(variables('resourceGroupLocation'), 'Plan'),' ','')]",
"resourceGroupName": "[concat(parameters('namingPrefix'), '-', parameters('resourceGroupName'))]",
"functionName": "[concat(parameters('namingPrefix'), '-', parameters('functionName'))]",
"storageAccName": "[toLower(concat(parameters('namingPrefix'), parameters('storageAccName')))]"
},
"resources": [
{
"type": "Microsoft.Resources/resourceGroups",
"apiVersion": "2018-05-01",
"location": "[variables('resourceGroupLocation')]",
"name": "[variables('resourceGroupName')]",
"properties": {}
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2019-05-01",
"name": "NestedTemplate",
"resourceGroup": "[variables('resourceGroupName')]",
"dependsOn": [
"[variables('resourceGroupName')]"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-04-01",
"name": "[variables('storageAccName')]",
"location": "[variables('resourceGroupLocation')]",
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"kind": "Storage",
"properties": {
"networkAcls": {
"bypass": "AzureServices",
"virtualNetworkRules": [],
"ipRules": [],
"defaultAction": "Allow"
},
"supportsHttpsTrafficOnly": true,
"encryption": {
"services": {
"file": {
"enabled": true
},
"blob": {
"enabled": true
}
},
"keySource": "Microsoft.Storage"
}
}
},
{
"type": "Microsoft.Web/serverfarms",
"apiVersion": "2016-09-01",
"name": "[variables('planName')]",
"location": "[variables('resourceGroupLocation')]",
"sku": {
"name": "Y1",
"tier": "Dynamic",
"size": "Y1",
"family": "Y",
"capacity": 0
},
"kind": "functionapp",
"properties": {
"name": "[variables('planName')]",
"computeMode": "Dynamic",
"perSiteScaling": false,
"reserved": false,
"targetWorkerCount": 0,
"targetWorkerSizeId": 0
}
},
{
"type": "Microsoft.Web/sites",
"apiVersion": "2016-08-01",
"name": "[variables('functionName')]",
"location": "[variables('resourceGroupLocation')]",
"dependsOn": [
"[variables('planName')]",
"[variables('appInsightsName')]",
"[variables('storageAccName')]"
],
"kind": "functionapp",
"identity": {
"type": "SystemAssigned"
},
"properties": {
"enabled": true,
"hostNameSslStates": [
{
"name": "[concat(variables('functionName'), '.azurewebsites.net')]",
"sslState": "Disabled",
"hostType": "Standard"
},
{
"name": "[concat(variables('functionName'), '.scm.azurewebsites.net')]",
"sslState": "Disabled",
"hostType": "Repository"
}
],
"siteConfig": {
"appSettings": [
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccName')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).key1)]"
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccName')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).key1)]"
},
{
"name": "WEBSITE_CONTENTSHARE",
"value": "[variables('functionName')]"
},
{
"name": "FUNCTIONS_WORKER_RUNTIME",
"value": "node"
},
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "10.14.1"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~2"
}
]
},
"serverFarmId": "[variables('planName')]",
"reserved": false
}
}
]
}
}
}
]
}
Executed using following line:
New-AzDeployment -Location "North Europe" -TemplateFile $TemplateFilePath -TemplateParameterFile $ParametersFilePath -namingPrefix $namingPrefix;
Output
Resource Microsoft.Storage/storageAccounts 'testStorageAccount' failed with message '{
"error": {
"code": "ResourceNotFound",
"message": "The Resource 'Microsoft.Storage/storageAccounts/testStorageAccount' under resource group '<null>'
was not found."
}
}'
For anyone who runs into this issue at a later date (probably myself) I was forced to create the resource group in my powershell script, and then use new-AzResourceGroupDeployment instead.
To accommodate this, the changes to the deployment template were minimal (I remove the resource group and brought the nested template one level up). However, I was also accessing the storage account key incorrectly. This has been updated in the code below.
$resourceGroup = Get-AzResourceGroup -Name $resourceGroupName -ErrorAction SilentlyContinue
if(!$resourceGroup)
{
Write-Host "Creating resource group '$resourceGroupName' in location '$resourceGroupLocation'";
New-AzResourceGroup -Name $resourceGroupName -Location $resourceGroupLocation
}
else{
Write-Host "Using existing resource group '$resourceGroupName'";
}
# Start the deployment
Write-Host "Starting deployment...";
if(Test-Path $parametersFilePath) {
New-AzResourceGroupDeployment -ResourceGroupName $resourceGroupName -TemplateFile $TemplateFilePath -TemplateParameterFile $parametersFilePath;
}
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"resourceGroupName": {
"type": "string"
},
"functionName": {
"type": "string"
},
"storageAccName": {
"type": "string"
},
"namingPrefix": {
"type": "string"
}
},
"variables": {
"resourceGroupLocation": "North Europe",
"planName": "[replace(concat(variables('resourceGroupLocation'), 'Plan'),' ','')]",
"resourceGroupName": "[concat(parameters('namingPrefix'), '-', parameters('resourceGroupName'))]",
"functionName": "[concat(parameters('namingPrefix'), '-', parameters('functionName'))]",
"storageAccName": "[toLower(concat(parameters('namingPrefix'), parameters('storageAccName')))]"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-04-01",
"name": "[variables('storageAccName')]",
"location": "[variables('resourceGroupLocation')]",
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"kind": "Storage",
"properties": {
"networkAcls": {
"bypass": "AzureServices",
"virtualNetworkRules": [],
"ipRules": [],
"defaultAction": "Allow"
},
"supportsHttpsTrafficOnly": true,
"encryption": {
"services": {
"file": {
"enabled": true
},
"blob": {
"enabled": true
}
},
"keySource": "Microsoft.Storage"
}
}
},
{
"type": "Microsoft.Web/serverfarms",
"apiVersion": "2016-09-01",
"name": "[variables('planName')]",
"location": "[variables('resourceGroupLocation')]",
"sku": {
"name": "Y1",
"tier": "Dynamic",
"size": "Y1",
"family": "Y",
"capacity": 0
},
"kind": "functionapp",
"properties": {
"name": "[variables('planName')]",
"computeMode": "Dynamic",
"perSiteScaling": false,
"reserved": false,
"targetWorkerCount": 0,
"targetWorkerSizeId": 0
}
},
{
"type": "Microsoft.Web/sites",
"apiVersion": "2016-08-01",
"name": "[variables('functionName')]",
"location": "[variables('resourceGroupLocation')]",
"dependsOn": [
"[variables('planName')]",
"[variables('appInsightsName')]",
"[variables('storageAccName')]"
],
"kind": "functionapp",
"identity": {
"type": "SystemAssigned"
},
"properties": {
"enabled": true,
"hostNameSslStates": [
{
"name": "[concat(variables('functionName'), '.azurewebsites.net')]",
"sslState": "Disabled",
"hostType": "Standard"
},
{
"name": "[concat(variables('functionName'), '.scm.azurewebsites.net')]",
"sslState": "Disabled",
"hostType": "Repository"
}
],
"siteConfig": {
"appSettings": [
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccName')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value)]"
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccName')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value)]"
},
{
"name": "WEBSITE_CONTENTSHARE",
"value": "[variables('functionName')]"
},
{
"name": "FUNCTIONS_WORKER_RUNTIME",
"value": "node"
},
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "10.14.1"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~2"
}
]
},
"serverFarmId": "[variables('planName')]",
"reserved": false
}
}
]
}