ARM Template App Service Config - Race Condition / Inconsistent Behavior - azure

Using ARM template below, we enabled diagnostic settings for our app service as well as defining appSettings config under resources element. The issue is that intermittently after deploying our app service from template - the appSettings are not getting assigned, but the diagnostics settings are.
Can someone guide us if there is a better way to define config for logs and appSettings for an app service that provides a more consistent site output? We build and teardown dozens of app services daily for PR builds so this is very apparent.
The appSetting WEBSITE_LOAD_USER_PROFILE will just get randomly dropped when the app service is created. Are we missing a dependsOn or do we need to upgrade apiVersion?
ServerFarm with App Settings + Log Config
{
"$schema": "http://schema.management.azure.com/schemas/2018-05-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"siteName": {
"type": "string"
},
"siteHostingPlanName": {
"type": "string"
},
"resourceLocation": {
"type": "string"
}
},
"resources": [
{
"apiVersion": "2016-09-01",
"name": "[parameters('siteHostingPlanName')]",
"type": "Microsoft.Web/serverfarms",
"location": "[parameters('resourceLocation')]",
"properties": {
"name": "[parameters('siteHostingPlanName')]"
},
"sku": {
"name": "P2V2",
"tier": "PremiumV2",
"capacity": 2
}
},
{
"apiVersion": "2014-11-01",
"name": "[parameters('siteName')]",
"type": "Microsoft.Web/sites",
"location": "[parameters('resourceLocation')]",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', parameters('siteHostingPlanName'))]"
],
"properties": {
"name": "[parameters('siteName')]",
"serverFarm": "[parameters('siteHostingPlanName')]",
"siteConfig": {
"AlwaysOn": true,
"webSocketsEnabled": true,
"http20Enabled": true,
"requestTracingEnabled": true,
"requestTracingExpirationTime": "9999-12-31T23:59:00Z",
"httpLoggingEnabled": true,
"logsDirectorySizeLimit": 100,
"detailedErrorLoggingEnabled": true
}
},
"resources": [
{
"apiVersion": "2014-11-01",
"name": "appsettings",
"type": "config",
"dependsOn": [
"[resourceId('Microsoft.Web/Sites', parameters('siteName'))]"
],
"properties": {
"WEBSITE_LOAD_USER_PROFILE": 1
}
},
{
"apiVersion": "2014-11-01",
"name": "logs",
"type": "config",
"dependsOn": [
"[resourceId('Microsoft.Web/Sites', parameters('siteName'))]"
],
"properties": {
"applicationLogs": {
"fileSystem": {
"level": "Verbose"
}
},
"httpLogs": {
"fileSystem": {
"retentionInMb": 100,
"enabled": true
}
},
"failedRequestsTracing": {
"enabled": true
},
"detailedErrorMessages": {
"enabled": true
}
}
}
]
}
]
}

Instead of defining the settings in a separate resource, you should configure the app settings together with the functionApp Resource. I have used this and defined various app settings and it works fine. Try like the below example.
{
"apiVersion": "[variables('sitesApiVersion')]",
"type": "Microsoft.Web/sites",
"kind": "functionapp",
"location": "[resourceGroup().location]",
"name": "[parameters('functionAppName')]",
"scale": null,
"properties": {
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('functionApp_appServicePlanName'))]",
"siteConfig": {
"appSettings": [
{
"name": "WEBSITE_LOAD_USER_PROFILE",
"value": "1"
}
]
},
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', parameters('functionApp_appServicePlanName'))]",
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
]
}
}

Related

azure ARm Template - Fails to associate AD app registration with function app

Background
I am trying to create an AD app registration for my function app to use for authentication.
I would like it to be for just our tenant, using Azure AD. The app is function app made up of a few endpoints
When I deploy the ARM template below, I don't get any errors, but in poking around and comparing it with what happens when I create authentication manually for my app, i see the following problems:
the application registration is created but there's no Application ID URI specified. When I create this manually via the portal I believe it's auto filled with a value "api://[applicationClientId]"
there are no scopes defined. again, when i create an authentication policy for my app manually via the portal, it does create a user_impersonation scope for me.
When i open up the function app in the portal, under "authentication" this new app registration hasn't been associated with it / or added.
Code
Here's what the ARM template looks like:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"functionAppName": {
"type": "string",
"defaultValue": "[concat('widgets-', uniqueString(resourceGroup().id),'-app')]",
"minLength": 2,
"metadata": {
"description": "my function app"
}
},
"storageAccountName": {
"type": "string",
"defaultValue": "[concat('widgets', uniqueString(resourceGroup().id))]",
"minLength": 2,
"metadata": {
"description": "StorageAccount"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
},
"serviceBusNamespaceName": {
"type": "string",
"defaultValue": "[concat('widgets-', uniqueString(resourceGroup().id),'-bus')]",
"metadata": {
"description": "Name of the Service Bus namespace"
}
},
"serviceBusQueueName": {
"type": "string",
"defaultValue": "workspaces",
"metadata": {
"description": "Name of the Queue"
}
},
"queueAuthorizationRuleName": {
"type": "string",
"defaultValue": "myRule",
"metadata": {
"description": "Name of the Queue AuthorizationRule"
}
},
"aadAppClientId": {
"type": "string"
},
"tenant": {
"type": "string"
}
},
"variables": {
"appServicePlanPortalName": "[concat(parameters('functionAppName'),'servicePlan')]",
"appInsightsName": "[concat(parameters('functionAppName'),'-insights')]",
"identityName": "[concat(parameters('functionAppName'),'-userId')]",
"clientSecret": ""
},
"resources": [
{
"name": "[variables('identityName')]",
"type": "Microsoft.ManagedIdentity/userAssignedIdentities",
"apiVersion": "2018-11-30",
"location": "[parameters('location')]"
},
{
"type": "Microsoft.Storage/storageAccounts",
"name": "[parameters('storageAccountName')]",
"apiVersion": "2019-06-01",
"location": "[parameters('location')]",
"kind": "StorageV2",
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
}
},
{
"type": "Microsoft.Storage/storageAccounts/queueServices",
"apiVersion": "2020-08-01-preview",
"name": "[concat(parameters('storageAccountName'), '/default')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
],
"properties": {
"cors": {
"corsRules": []
}
}
},
{
"type": "Microsoft.Storage/storageAccounts/queueServices/queues",
"apiVersion": "2020-08-01-preview",
"name": "[concat(parameters('storageAccountName'), '/default/workspaces')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
],
"properties": {
"metadata": {}
}
},
{
"type": "Microsoft.Storage/storageAccounts/tableServices/tables",
"apiVersion": "2021-06-01",
"name": "[concat(parameters('storageAccountName'), '/default/provisionedWorkspaces')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
],
"properties": {
"partitionName": "workspaces"
}
},
{
"type": "Microsoft.ServiceBus/namespaces",
"apiVersion": "2017-04-01",
"name": "[parameters('serviceBusNamespaceName')]",
"location": "[parameters('location')]",
"sku": {
"name": "Standard"
},
"properties": {}
},
{
"type": "Microsoft.ServiceBus/namespaces/queues",
"apiVersion": "2017-04-01",
"name": "[format('{0}/{1}', parameters('serviceBusNamespaceName'), parameters('serviceBusQueueName'))]",
"properties": {
"lockDuration": "PT5M",
"maxSizeInMegabytes": 1024,
"requiresDuplicateDetection": false,
"requiresSession": false,
"defaultMessageTimeToLive": "P10675199DT2H48M5.4775807S",
"deadLetteringOnMessageExpiration": false,
"duplicateDetectionHistoryTimeWindow": "PT10M",
"maxDeliveryCount": 10,
"autoDeleteOnIdle": "P10675199DT2H48M5.4775807S",
"enablePartitioning": false,
"enableExpress": false
},
"resources": [
{
"apiVersion": "2017-04-01",
"name": "[parameters('queueAuthorizationRuleName')]",
"type": "AuthorizationRules",
"dependsOn": ["[parameters('serviceBusQueueName')]"],
"properties": {
"rights": ["Listen", "Send", "Manage"]
}
}
],
"dependsOn": [
"[resourceId('Microsoft.ServiceBus/namespaces', parameters('serviceBusNamespaceName'))]"
]
},
{
"apiVersion": "2015-05-01",
"name": "[variables('appInsightsName')]",
"type": "Microsoft.Insights/components",
"kind": "web",
"location": "[parameters('location')]",
"tags": {
"[concat('hidden-link:', resourceGroup().id, '/providers/Microsoft.Web/sites/', parameters('functionAppName'))]": "Resource"
},
"properties": {
"Application_Type": "web",
"ApplicationId": "[variables('appInsightsName')]"
}
},
{
"type": "Microsoft.Web/serverfarms",
"apiVersion": "2020-06-01",
"name": "[variables('appServicePlanPortalName')]",
"location": "[parameters('location')]",
"sku": {
"tier": "Standard",
"name": "S1"
},
"kind": "functionapp,linux",
"properties": {
"name": "[variables('appServicePlanPortalName')]",
"reserved": true
}
},
{
"type": "Microsoft.Web/sites",
"apiVersion": "2020-06-01",
"name": "[parameters('functionAppName')]",
"location": "[parameters('location')]",
"kind": "functionapp,linux",
"identity": {
"type": "UserAssigned",
"userAssignedIdentities": {
"[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName'))]": {}
}
},
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanPortalName'))]",
"[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName'))]"
],
"properties": {
"reserved": true,
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanPortalName'))]",
"siteConfig": {
"linuxFxVersion": "DOTNETCORE|6.0",
"appSettings": [
{
"name": "APPINSIGHTS_INSTRUMENTATIONKEY",
"value": "[reference(resourceId('Microsoft.Insights/components', variables('appInsightsName')), '2015-05-01').InstrumentationKey]"
},
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', parameters('storageAccountName'), ';EndpointSuffix=', environment().suffixes.storage, ';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2019-06-01').keys[0].value)]"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~4"
},
{
"name": "FUNCTIONS_WORKER_RUNTIME",
"value": "dotnet"
}
],
"resources": [
{
"type": "config",
"apiVersion": "2020-12-01",
"name": "authsettingsV2",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.Web/sites/', parameters('functionAppName'))]"
],
"properties": {
"platform": {
"enabled": true,
"runtimeVersion": "~1"
},
"identityProviders": {
"azureActiveDirectory": {
"isAutoProvisioned": false,
"registration": {
"clientId": "[parameters('aadAppClientId')]",
"clientSecret": "[variables('clientSecret')]",
"openIdIssuer": "[concat('https://sts.windows.net/', parameters('tenant'), '/v2.0')]"
},
"validation": {
"allowedAudiences": [
"https://management.core.windows.net/"
]
}
}
}
},
"login": {
"routes": {},
"tokenStore": {
"enabled": true,
"tokenRefreshExtensionHours": 72,
"fileSystem": {},
"azureBlobStorage": {}
},
"preserveUrlFragmentsForLogins": false,
"allowedExternalRedirectUrls": [],
"cookieExpiration": {
"convention": "FixedTime",
"timeToExpiration": "08:00:00"
},
"nonce": {
"validateNonce": true,
"nonceExpirationInterval": "00:05:00"
}
},
"globalValidation": {
"redirectToProvider": "azureactivedirectory",
"unauthenticatedClientAction": "RedirectToLoginPage"
},
"httpSettings": {
"requireHttps": true,
"routes": {
"apiPrefix": "/.auth"
},
"forwardProxy": {
"convention": "NoProxy"
}
}
}
]
}
}
}
]
}
Two comments in case they help / are relevant:
client secret - As you can see I have a variable defined, but its blank. I'm not supplying a client secret value because I was assuming it would auto create for me. But maybe I shouldn't include that parameter at all?
Also, I'm using a linux container for the web app.
Any tips on how to fix these issues would be appreciated.
EDIT 1
I manually created and added an authencation policy and then I've been using resources.azure.com to see what's been created for me. I have two relevant sections under config.
One is called authsettings and looks like this:
And the other is under authsettingsV2 and looks like this:
I'm trying to use the authsettingsV2 for now... but it's not clear where I should paste it into in the ARM template.
Any suggestions?
EDIT 2
Added all the authsettingsv2 stuff under the site resource. No errors. but still the same results.
Found out that I can use the Az Powershell commandlets:
New-AzADApplication
New-AzADAppCredential

Can I conditionally use the Copy function in ARM Template

Our solution is deployed to multiple environments, Dev, Test and Prod. I conditionally deploy Virtual Networks and other beefy network infrastructure for non-dev environments. The struggle I'm having is with applying Access Restrictions to the web config of an App Service, only when a boolean is true (using copyIndex).
The below works for assigning the subnet access restrictions to the App Service:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"location": {
"type": "string",
"defaultValue": "ukwest"
}
},
"variables": {
"networkingRequired": true,
"aspName": "xxxMyAppServicePlan",
"siteName": "xxxMySite1",
"vnetName": "superVnetName",
"subnetNames": [
"subnetone",
"subnettwo",
"subnetthree"
]
},
"resources": [
{
"name": "[variables('aspName')]",
"type": "Microsoft.Web/serverfarms",
"kind": "app",
"apiVersion": "2018-02-01",
"location": "[parameters('location')]",
"properties": {},
"sku": {
"name": "S1",
"capacity": 1
}
},
{
"kind": "app",
"name": "[variables('siteName')]",
"type": "Microsoft.Web/sites",
"apiVersion": "2018-02-01",
"location": "[parameters('location')]",
"identity": {
"type": "SystemAssigned"
},
"properties": {
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('aspName'))]",
"siteConfig": {
"clientAffinityEnabled": false,
"httpsOnly": true,
"alwaysOn": true,
"virtualApplications": [
{
"virtualPath": "/",
"physicalPath": "site\\wwwroot",
"preloadEnabled": true
}
],
"copy": [
{
"name": "ipSecurityRestrictions",
"count": "[length(variables('subnetNames'))]",
"input": {
"vnetSubnetResourceId": "[resourceId(resourceGroup().name, 'Microsoft.Network/virtualNetworks/subnets', variables('vnetName'), variables('subnetNames')[copyIndex('ipSecurityRestrictions')])]",
"action": "Allow",
"priority": "1",
"name": "[variables('subnetNames')[copyIndex('ipSecurityRestrictions')]]",
"description": "[concat(variables('subnetNames')[copyIndex('ipSecurityRestrictions')], ' subnet')]"
}
}
]
}
},
"dependsOn": [
"[variables('aspName')]"
]
}
]
}
So what I now need to do is have it respect the variable 'networkingRequired' and only do the "copy" for ipSecurityRestrictions when networking is true.
easiest way of doing this - move the copy to the variables section and use an expression to define the value of ipSecurityRestrictions "on the fly".
"variables": {
"empty": [],
"copy": [you copy goes here]
},
...
"ipSecurityRestrictions": "[if(variables('networkingRequired'), variables('ipSecurityRestrictions'), variables('empty'))]"

Deploy Azure Function with ARM template

I am trying to deploy Azure Function with ARM template , but I am not able to create the function itself. Is it possible to create the actual function using ARM template?
I have zipped the source code for the function and placed it in a public location, I have added the MSBuild section to the template and although the deployment finished successfully - the App function was created but not the function itself
here is the template
{
"parameters": {
"name": {
"type": "string"
},
"storageName": {
"type": "string"
},
"location": {
"type": "string"
},
"subscriptionId": {
"type": "string"
},
"storage_account_endpoint": {
"type": "string"
}
},
"resources": [
{
"apiVersion": "2016-03-01",
"name": "[parameters('name')]",
"type": "Microsoft.Web/sites",
"properties": {
"name": "[parameters('name')]",
"siteConfig": {
"appSettings": [
{
"name": "FUNCTIONS_WORKER_RUNTIME",
"value": "node"
},
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=',parameters('storageName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), '2015-05-01-preview').key1)]"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~2"
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=',parameters('storageName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), '2015-05-01-preview').key1)]"
},
{
"name": "WEBSITE_CONTENTSHARE",
"value": "[concat(toLower(parameters('name')), 'bd58')]"
},
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "8.11.1"
},
{
"name": "storage_account_connection",
"value": "[parameters('storage_account_endpoint')]"
}
]
},
"clientAffinityEnabled": false,
"reserved": false
},
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageName'))]"
],
"resources": [
{
"name": "MSDeploy",
"type": "Extensions",
"apiVersion": "2015-02-01",
"dependsOn": [
"[resourceId('Microsoft.Web/Sites', parameters('name'))]"
],
"properties": {
"packageUri": "<URL to zip>"
}
}
],
"location": "[parameters('location')]",
"identity": {
"type": "SystemAssigned"
},
"kind": "functionapp"
},
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Storage/storageAccounts",
"name": "[parameters('storageName')]",
"location": "[parameters('location')]",
"properties": {
"accountType": "Standard_LRS"
}
}
],
"$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json#",
"contentVersion": "1.0.0.0"
}
In short No - ARM can only create the infrastructure for you but not deploy the code (**see comment).
But as always there is a way. A while back MS release a new feature 'Run from ZIP' on web apps (including Function Apps). All you need is the actual project (code published as ZIP) to be in a location where the function app can access it.
We use VSTS (Azure Dev Ops) for CI/CD. So we build the solution add the ZIP to the artifact. Then in the Release we copy the ZIP to blob storage, create a SAS Token and pass the location of the blob Container with the SAS Token to ARM. In the ARM template we build the connection string to the ZIP, using input parameter. As soon as ARM is done then the Function is up and running.
Eg.
{
"parameters": {
"name": {
"type": "string"
},
"storageName": {
"type": "string"
},
"location": {
"type": "string"
},
"subscriptionId": {
"type": "string"
},
"storage_account_endpoint": {
"type": "string"
},
"artifactsUri": {
"type": "string"
},
"artifactsBlobContainer": {
"type": "string"
},
"artifactsLocationSasToken": {
"type": "string"
}
},
"resources": [
{
"apiVersion": "2016-03-01",
"name": "[parameters('name')]",
"type": "Microsoft.Web/sites",
"properties": {
"name": "[parameters('name')]",
"siteConfig": {
"appSettings": [
{
"name": "FUNCTIONS_WORKER_RUNTIME",
"value": "node"
},
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=',parameters('storageName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), '2015-05-01-preview').key1)]"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~2"
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=',parameters('storageName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), '2015-05-01-preview').key1)]"
},
{
"name": "WEBSITE_CONTENTSHARE",
"value": "[concat(toLower(parameters('name')), 'bd58')]"
},
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "8.11.1"
},
{
"name": "storage_account_connection",
"value": "[parameters('storage_account_endpoint')]"
},
{
"name": "WEBSITE_RUN_FROM_ZIP",
"value": "[concat(parameters('artifactsUri'), '/', parameters('artifactsBlobContainer'),'/','blahbla.FA.zip',parameters('artifactsLocationSasToken'))]"
}
]
},
"clientAffinityEnabled": false,
"reserved": false
},
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageName'))]"
],
"resources": [
{
"name": "MSDeploy",
"type": "Extensions",
"apiVersion": "2015-02-01",
"dependsOn": [
"[resourceId('Microsoft.Web/Sites', parameters('name'))]"
],
"properties": {
"packageUri": "<URL to zip>"
}
}
],
"location": "[parameters('location')]",
"identity": {
"type": "SystemAssigned"
},
"kind": "functionapp"
},
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Storage/storageAccounts",
"name": "[parameters('storageName')]",
"location": "[parameters('location')]",
"properties": {
"accountType": "Standard_LRS"
}
}
],
"$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json#",
"contentVersion": "1.0.0.0"
}
'Run from ZIP' is achieved with the 'WEBSITE_RUN_FROM_ZIP' app setting.
Hope this helps
I just use this FunctionWebDeploy.json template. I download the app content(zip file)from the existing function app and upload it to the public address. Finally I can deploy function app including code.
Go to Azure portal portal.azure.com, and create a new Azure Function.
2.Go to Resource Group.
3.Go to Export template.
4.You will see something like this.
This is the ARM Template for all resources/componets.

ARM Template containing config settings for web app

I am encountering strange behavior when deploying an ARM template.
I have the following template: (Note that sasUrl value 'xxx' has a real, working value in my file)
{
"name": "[variables('webAppServiceName')]",
"type": "Microsoft.Web/sites",
"location": "[resourceGroup().location]",
"apiVersion": "2016-08-01",
"dependsOn": [
"[concat('Microsoft.Web/serverfarms/', variables('appServicePlanName'))]"
],
"tags": {
"[concat('hidden-related:', resourceGroup().id, '/providers/Microsoft.Web/serverfarms/', variables('appServicePlanName'))]": "Resource",
"displayName": "[variables('webAppServiceName')]"
},
"properties": {
"name": "[variables('webAppServiceName')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]"
},
"resources": [
{
"apiVersion": "2014-11-01",
"name": "appsettings",
"type": "config",
"dependsOn": [
"[concat('Microsoft.Web/sites/', variables('webAppServiceName'))]",
"[concat('Microsoft.Web/certificates/', variables('certificateName'))]"
],
"tags": {
"displayName": "WebAppSettings"
},
"properties": {
"WEBSITE_LOAD_CERTIFICATES": "[reference(resourceId('Microsoft.Web/certificates', variables('certificateName')), providers('Microsoft.Web', 'certificates').apiVersions[0]).thumbprint]"
}
},
{
"apiVersion": "2016-08-01",
"name": "Microsoft.ApplicationInsights.Profiler.AzureWebApps",
"type": "siteextensions",
"dependsOn": [
"[resourceId('Microsoft.Web/Sites', variables('webAppServiceName'))]"
],
"properties": {}
},
{
"apiVersion": "2015-08-01",
"name": "logs",
"type": "config",
"dependsOn": [
"[resourceId('Microsoft.Web/Sites', variables('webAppServiceName'))]"
],
"properties": {
"applicationLogs": {
"fileSystem": {
"level": "Off"
},
"azureTableStorage": {
"level": "Off"
},
"azureBlobStorage": {
"level": "[parameters('applicationLogLevel')]",
"sasUrl": "xxx"
}
},
"httpLogs": {
"fileSystem": {
"enabled": false
},
"azureBlobStorage": {
"enabled": true,
"sasUrl": "xxx"
}
},
"failedRequestsTracing": {
"enabled": "[parameters('enableFailedRequestTracing')]"
},
"detailedErrorMessages": {
"enabled": "[parameters('enableDetailedErrorMessages')]"
}
}
}
]
}
When deploying this template without modifying anything, the config section 'logs' is not deployed correctly +- 1 on 2 times. I have just tested the ARM template again, and the first deployment, the web app had not the correct settings for diagnostics logging. The second time neither, but the third time they were ok. But the fourth time, the settings were not correct anymore. It looks like this part of the template has no consistent behavior.
Am I overseeing something?
I try to create WebApp with the appsetting and logs, it works correctly for me. I created the project using Visual Studio. The following is my detail steps.
1.Create the Azure Resource Project
2.Select the WebApp template
3.Click the deploy file then right click and remove the unnecessary resource
4.Add the Appsetting Resource for the WebApp
5.Add the logs code for the Azure WebApp
{
"apiVersion": "2015-08-01",
"name": "logs",
"type": "config",
"dependsOn": [
"[resourceId('Microsoft.Web/Sites', variables('webSiteName'))]"
],
"properties": {
"applicationLogs": {
"fileSystem": {
"level": "Off"
},
"azureTableStorage": {
"level": "Off"
},
"azureBlobStorage": {
"level": "[variables('Level')]",
"sasUrl": "xxxx"
}
},
"httpLogs": {
"fileSystem": {
"enabled": false
},
"azureBlobStorage": {
"enabled": true,
"sasUrl": "xxxxxx"
}
},
"failedRequestsTracing": {
"enabled": "[parameters('enableFailedRequestTracing')]"
},
"detailedErrorMessages": {
"enabled": "[parameters('enableDetailedErrorMessages')]"
}
}
}
6.Right click the project and select the deploy
7.Check the result from the Output and Azure portal
The whole arm template:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"hostingPlanName": {
"type": "string",
"minLength": 1
},
"enableFailedRequestTracing": {
"type": "bool"
},
"enableDetailedErrorMessages": {
"type": "bool"
},
"skuName": {
"type": "string",
"defaultValue": "F1",
"allowedValues": [
"F1",
"D1",
"B1",
"B2",
"B3",
"S1",
"S2",
"S3",
"P1",
"P2",
"P3",
"P4"
],
"metadata": {
"description": "Describes plan's pricing tier and capacity. Check details at https://azure.microsoft.com/en-us/pricing/details/app-service/"
}
},
"skuCapacity": {
"type": "int",
"defaultValue": 1,
"minValue": 1,
"metadata": {
"description": "Describes plan's instance count"
}
}
},
"variables": {
"webSiteName": "[concat('webSite', uniqueString(resourceGroup().id))]",
"Level": "Error"
},
"resources": [
{
"apiVersion": "2015-08-01",
"name": "[parameters('hostingPlanName')]",
"type": "Microsoft.Web/serverfarms",
"location": "[resourceGroup().location]",
"tags": {
"displayName": "HostingPlan"
},
"sku": {
"name": "[parameters('skuName')]",
"capacity": "[parameters('skuCapacity')]"
},
"properties": {
"name": "[parameters('hostingPlanName')]"
}
},
{
"apiVersion": "2015-08-01",
"name": "[variables('webSiteName')]",
"type": "Microsoft.Web/sites",
"location": "[resourceGroup().location]",
"tags": {
"[concat('hidden-related:', resourceGroup().id, '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]": "Resource",
"displayName": "Website"
},
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]"
],
"properties": {
"name": "[variables('webSiteName')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('hostingPlanName'))]"
},
"resources": [
{
"name": "appsettings",
"type": "config",
"apiVersion": "2015-08-01",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', variables('webSiteName'))]"
],
"tags": {
"displayName": "appsettings"
},
"properties": {
"key1": "value1",
"key2": "value2"
}
},
{
"apiVersion": "2015-08-01",
"name": "logs",
"type": "config",
"dependsOn": [
"[resourceId('Microsoft.Web/Sites', variables('webSiteName'))]"
],
"properties": {
"applicationLogs": {
"fileSystem": {
"level": "Off"
},
"azureTableStorage": {
"level": "Off"
},
"azureBlobStorage": {
"level": "[variables('Level')]",
"sasUrl": "xxxxx"
}
},
"httpLogs": {
"fileSystem": {
"enabled": false
},
"azureBlobStorage": {
"enabled": true,
"sasUrl": "xxxx"
}
},
"failedRequestsTracing": {
"enabled": "[parameters('enableFailedRequestTracing')]"
},
"detailedErrorMessages": {
"enabled": "[parameters('enableDetailedErrorMessages')]"
}
}
}
]
}
]
}
I have experienced similar issues. We fixed this using dependsOn rules.
You should add dependsOn rules to split the processing of each config section.
It seems like otherwise there can occur problems, for instance ...missing settings.
Arm snippet:
{
"name": "[variables('ExampleAppName')]",
"type": "Microsoft.Web/sites",
"location": "[resourceGroup().location]",
"apiVersion": "2015-08-01",
"kind": "api",
"dependsOn": ["[resourceId('Microsoft.Web/serverfarms', variables('applicationPlanName'))]"],
"tags": {
"displayName": "Example App"
},
"properties": {
"name": "[variables('ExampleAppName')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms/', variables('applicationPlanName'))]",
"clientAffinityEnabled": "false"
},
"resources": [{
"name": "web",
"type": "config",
"apiVersion": "2015-08-01",
"dependsOn": ["[resourceId('Microsoft.Web/sites', variables('ExampleAppName'))]"],
"tags": {
"displayName": "webconfig Example App"
},
"properties": {
"alwaysOn": "true"
}
},
{
"apiVersion": "2015-08-01",
"name": "appsettings",
"type": "config",
"dependsOn": ["[resourceId('Microsoft.Web/sites', variables('ExampleAppName'))]",
"[resourceId('Microsoft.Web/sites/config', variables('ExampleAppName'), 'web')]"],
"tags": {
"displayName": "appsettings Example App"
},
"properties": {
"EXAMPLE1": "[parameters('EXAMPLE1')]",
"EXAMPLE2": "[parameters('EXAMPLE2')]"
}
},
{
"name": "logs",
"type": "config",
"apiVersion": "2015-08-01",
"dependsOn": ["[concat('Microsoft.Web/sites/', variables('ExampleAppName'))]",
"[resourceId('Microsoft.Web/sites/config', variables('ExampleAppName'), 'appsettings')]"],
"tags": {
"displayName": "logs Example App"
},
"properties": {
"applicationLogs": {
"fileSystem": {
"level": "Warning"
}
},
"httpLogs": {
"fileSystem": {
"retentionInMb": "35",
"enabled": true
}
},
"detailedErrorMessages": {
"enabled": false
}
}
}]
}
For additional information you can read my post:
Click here!

Attach an existing Web Service plan to a new Website using Azure Resource Manager templates

I am trying to automate website deployment using the Azure Resource Manager. Website creation and code deployment is working fine, but I am unable to attach the new site to an existing Web Hosting plan.
I am using the 2015-08-01 API and from different examples I think that this template should work (it does not...):
The deployment fails at "Microsoft.Web/sites/config" and the site is beeing assigned a new default free hosting plan.
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"siteName": {
"type": "string"
},
"subscriptionId": {
"type": "string"
},
"setting1": {
"type": "string"
},
"setting2": {
"type": "string"
}
},
"resources": [
{
"apiVersion": "2015-08-01",
"type": "Microsoft.Web/sites",
"name": "[parameters('siteName')]",
"location": "[resourceGroup().location]",
"properties": {
"serverFarmId ": "/subscriptions/xxxxxx/resourceGroups/xxxxxx/providers/Microsoft.Web/serverfarms/xxxxxx"
},
"resources": [
{
"apiVersion": "2015-08-01",
"name": "web",
"type": "config",
"dependsOn": [
"[resourceId('Microsoft.Web/Sites', parameters('siteName'))]"
],
"properties": {
"phpVersion": "off",
"netFrameworkVersion": "v4.6",
"use32BitWorkerProcess": false,
"webSocketsEnabled": true,
"alwaysOn": true,
"requestTracingEnabled": false,
"httpLoggingEnabled": false,
"logsDirectorySizeLimit": 40,
"detailedErrorLoggingEnabled": false,
"appSettings": [
{
"Name": "setting1",
"Value": "Value1"
},
{
"Name": "setting2",
"Value": "Value2"
}
]
}
},
{
"apiVersion": "2015-08-01",
"type": "extensions",
"name": "MSDeploy",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', parameters('siteName'))]"
],
"properties": {
"packageUri": "xxxxxxxx",
"dbType": "None",
"connectionString": ""
}
}
]
}
],
"outputs": {
"siteUri": {
"type": "string",
"value": "[concat('http://',reference(resourceId('Microsoft.Web/sites', parameters('siteName'))).hostNames[0])]"
}
}
}
I ended up falling back to the 2014-06-01 API and with some adjustments to the script, was able to do what I wanted.
Providing the script for future references.
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"siteName": {
"type": "string"
},
"subscriptionId": {
"type": "string"
},
"hostingPlanName": {
"type": "string"
},
"setting1": {
"type": "string"
},
"setting2": {
"type": "string"
}
},
"resources": [
{
"apiVersion": "2014-06-01",
"type": "Microsoft.Web/sites",
"name": "[parameters('siteName')]",
"location": "[resourceGroup().location]",
"dependsOn": [
],
"properties": {
"name": "[parameters('siteName')]",
"serverFarm": "[parameters('hostingPlanName')]"
},
"resources": [
{
"apiVersion": "2014-06-01",
"name": "web",
"type": "config",
"dependsOn": [
"[resourceId('Microsoft.Web/Sites', parameters('siteName'))]",
"[concat('Microsoft.Web/Sites/', parameters('siteName'), '/Extensions/MSDeploy')]"
],
"properties": {
"phpVersion": "off",
"netFrameworkVersion": "v4.6",
"use32BitWorkerProcess": false,
"webSocketsEnabled": true,
"alwaysOn": true,
"requestTracingEnabled": false,
"httpLoggingEnabled": false,
"logsDirectorySizeLimit": 40,
"detailedErrorLoggingEnabled": false
}
},
{
"apiVersion": "2014-11-01",
"name": "appsettings",
"type": "config",
"dependsOn": [
"[resourceId('Microsoft.Web/Sites', parameters('siteName'))]",
"[concat('Microsoft.Web/Sites/', parameters('siteName'), '/Extensions/MSDeploy')]"
],
"properties": {
"Setting1": "[parameters('setting1')]",
"Setting2": "[parameters('setting2')]"
}
},
{
"apiVersion": "2015-08-01",
"type": "extensions",
"name": "MSDeploy",
"dependsOn": [
"[resourceId('Microsoft.Web/Sites', parameters('siteName'))]"
],
"properties": {
"packageUri": "https://xxxxx.zip",
"dbType": "None",
"connectionString": ""
}
}
]
}
]
}

Resources