Azure ARM templates with Storage and Cosmos Db connection strings - azure

I hope someone knows how to do this.
I have setup an ARM template which creates my resources when I do CI/CD which is great.
I have even managed to set up a connection string:
"ConnectionStrings:ConnectionString": "[concat('Data Source=tcp:', reference(concat('Microsoft.Sql/servers/', variables('name'))).fullyQualifiedDomainName, ',1433;Initial Catalog=', variables('sqlMasterName'), ';User Id=', variables('sqlServerUser'), '#', reference(concat('Microsoft.Sql/servers/', variables('name'))).fullyQualifiedDomainName, ';Password=', variables('sqlServerPassword'), ';')]",
the variable sqlServerPassword is randomly generated by this:
"sqlServerPassword": "[concat('P', uniqueString(resourceGroup().id, '224F5A8B-51DB-46A3-A7C8-59B0DD584A41'), 'x', '!')]",
With that in mind does anyone know how I can do the same for the storage account and for an azure cosmos db?
It doesn't seem to be the same.
My template for creating my storage account looks like this:
{
"apiVersion": "2018-11-01",
"type": "Microsoft.Storage/storageAccounts",
"name": "[variables('name')]",
"location": "[variables('location')]",
"tags": {
"displayName": "SXP storage"
},
"kind": "Storage",
"sku": {
"name": "Standard_LRS"
}
},
Which doesn't mention a password, etc.
Also, for my CosmosDb I have the same issue:
{
"name": "[variables('name')]",
"type": "Microsoft.DocumentDB/databaseAccounts",
"apiVersion": "2015-04-08",
"location": "[variables('location')]",
"tags": {
"displayName": "Cosmos DB Account"
},
"properties": {
"locations": "[variables('locations')]",
"databaseAccountOfferType": "Standard"
}
},
{
"name": "[concat(variables('name'), '/sql/', variables('cosmosMasterName'))]",
"type": "Microsoft.DocumentDB/databaseAccounts/apis/databases",
"apiVersion": "2016-03-31",
"dependsOn": [
"[resourceId('Microsoft.DocumentDB/databaseAccounts/', variables('name'))]"
],
"properties": {
"resource": {
"id": "[variables('cosmosMasterName')]"
},
"options": { "throughput": "[variables('cosmosMasterThroughPut')]" }
}
},
{
"name": "[concat(variables('name'), '/sql/', variables('cosmosMasterName'), '/', variables('cosmosContainerName'))]",
"type": "Microsoft.DocumentDb/databaseAccounts/apis/databases/containers",
"apiVersion": "2016-03-31",
"dependsOn": [ "[resourceId('Microsoft.DocumentDB/databaseAccounts/apis/databases', variables('name'), 'sql', variables('cosmosMasterName'))]" ],
"properties": {
"resource": {
"id": "[variables('cosmosContainerName')]",
"partitionKey": {
"paths": [
"/gtin"
],
"kind": "Hash"
},
"indexingPolicy": {
"indexingMode": "consistent",
"includedPaths": [
{
"path": "/*"
}
]
}
}
}
},
{
"name": "[concat(variables('name'), '/sql/', variables('cosmosDevelopName'))]",
"type": "Microsoft.DocumentDB/databaseAccounts/apis/databases",
"apiVersion": "2016-03-31",
"dependsOn": [
"[resourceId('Microsoft.DocumentDB/databaseAccounts/', variables('name'))]"
],
"properties": {
"resource": {
"id": "[variables('cosmosDevelopName')]"
},
"options": { "throughput": "[variables('cosmosDevelopThroughPut')]" }
}
},
{
"name": "[concat(variables('name'), '/sql/', variables('cosmosDevelopName'), '/', variables('cosmosContainerName'))]",
"type": "Microsoft.DocumentDb/databaseAccounts/apis/databases/containers",
"apiVersion": "2016-03-31",
"dependsOn": [ "[resourceId('Microsoft.DocumentDB/databaseAccounts/apis/databases', variables('name'), 'sql', variables('cosmosDevelopName'))]" ],
"properties": {
"resource": {
"id": "[variables('cosmosContainerName')]",
"partitionKey": {
"paths": [
"/gtin"
],
"kind": "Hash"
},
"indexingPolicy": {
"indexingMode": "consistent",
"includedPaths": [
{
"path": "/*"
}
]
}
}
}
}
If anyone can help, that would be great.

David Makogon is spot on, but there is a way to retrieve the Storage Account and CosmosDB generated keys and connection strings within an ARM template. Use the ARM ListKeys function.
Here's an example from one of my own ARM templates. This is an app setting in an Azure Function where I reference a storage account's generated key:
{
"name": "StorageConnectionString",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId(variables('InfrastructureResourceGroupName'), 'Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1)]"
},
Note that if your storage account is in the same resource group, I believe you can omit the first argument to ListKeys.
It's very similar for getting the key to a CosmosDB database. If you get stuck, let me know and I'll dig up that example too.

With the Cosmos DB 2019-08-01 template listKeys returns an object like this;
{
"primaryMasterKey": "...==",
"secondaryMasterKey": "...==",
"primaryReadonlyMasterKey": "...==",
"secondaryReadonlyMasterKey": "...=="
}
This gives the option of a read-only or a read/write connection. You can build a connection like this;
{
"name": "DatabaseConnectionString",
"value": "[concat('AccountEndpoint=https://', variables('accountName'),'.documents.azure.com:443/;AccountKey=', listKeys(resourceId('Microsoft.DocumentDB/databaseAccounts', variables('accountName')), '2019-08-01').primaryMasterKey, ';')]"
},

Related

How to create CosmosDB SQL API serverless account with ARM template?

I am trying to create a serverless account with Cosmosdb sql api and i have not found any samples given here
I have tried with the following ARM template and it's not creating a serverless account
"resources" : [
{
"type": "Microsoft.DocumentDB/databaseAccounts",
"apiVersion": "2020-04-01",
"kind": "Serverless",
"name": "[parameters('accountName')]",
"location": "[parameters('location')]",
"properties": {
"enableFreeTier": false,
"databaseAccountOfferType": "Standard",
"consistencyPolicy": {
"defaultConsistencyLevel": "Session"
},
"locations": [
{
"locationName": "[parameters('location')]"
}
]
}
},
{
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases",
"apiVersion": "2020-04-01",
"name": "[format('{0}/{1}', parameters('accountName'), parameters('databaseName'))]",
"properties": {
"resource": {
"id": "[parameters('databaseName')]"
},
"options": {}
},
"dependsOn": [
"[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('accountName'))]"
]
}
]
throwing an error "
"message": "Resource kind Serverless is unknown\r\nActivityId: 0c86f162-3386-49e1-b354-57ba309bb44f, Microsoft.Azure.Documents.Common/2.14.0""
The error is valid, below are the possible values available for the databaseAccount kind
'GlobalDocumentDB'
'MongoDB'
'Parse'
To create a serverless account, you need to pass the capabilities parameter as below under properties
"properties": {
"enableFreeTier": false,
"capabilities": [
{
"name": "EnableServerless"
}
],
"databaseAccountOfferType": "Standard",
"consistencyPolicy": {
"defaultConsistencyLevel": "Session"
},
"locations": [
{
"locationName": "[parameters('location')]"
}
]
}

Strange error when deploying ARM templates using DevOps

I have an arm template which creates 2 document db servers.
The section of the ARM template looks like this:
{
"name": "[variables('sqlServerName')]",
"type": "Microsoft.DocumentDB/databaseAccounts",
"apiVersion": "2019-12-12",
"location": "[parameters('location')]",
"tags": {
"name": "Cosmos DB Account"
},
"properties": {
"locations": "[variables('locations')]",
"databaseAccountOfferType": "Standard"
}
},
{
"name": "[variables('sqlServerDevelopmentName')]",
"type": "Microsoft.DocumentDB/databaseAccounts",
"apiVersion": "2019-12-12",
"location": "[parameters('location')]",
"tags": {
"name": "Cosmos Development DB Account"
},
"properties": {
"locations": "[variables('locations')]",
"databaseAccountOfferType": "Standard"
}
},
{
"type": "Microsoft.DocumentDB/databaseAccounts/apis/databases",
"name": "[concat(variables('sqlServerName'), '/sql/', variables('name'))]",
"apiVersion": "2016-03-31",
"dependsOn": ["[resourceId('Microsoft.DocumentDB/databaseAccounts/', variables('sqlServerName'))]"],
"properties": {
"resource": {
"name": "[variables('liveName')]"
},
"options": {
"throughput": "[variables('cosmosThroughPut')]"
}
}
},
{
"type": "Microsoft.DocumentDB/databaseAccounts/apis/databases",
"name": "[concat(variables('sqlServerDevelopmentName'), '/sql/', variables('name'))]",
"apiVersion": "2016-03-31",
"dependsOn": ["[resourceId('Microsoft.DocumentDB/databaseAccounts/', variables('sqlServerDevelopmentName'))]"],
"properties": {
"resource": {
"name": "[variables('developmentName')]"
},
"options": {
"throughput": "[variables('cosmosDevelopThroughPut')]"
}
}
},
{
"name": "[concat(variables('sqlServerName'), '/sql/', variables('name'), '/', variables('cosmosContainerName'))]",
"type": "Microsoft.DocumentDb/databaseAccounts/apis/databases/containers",
"apiVersion": "2016-03-31",
"dependsOn": ["[resourceId('Microsoft.DocumentDB/databaseAccounts/apis/databases', variables('sqlServerName'), 'sql', variables('name'))]"],
"properties": {
"resource": {
"name": "[variables('cosmosContainerName')]",
"partitionKey": {
"paths": [
"/categoryId"
],
"kind": "Hash"
},
"indexingPolicy": {
"indexingMode": "consistent",
"includedPaths": [{
"path": "/*"
}]
}
}
}
},
{
"name": "[concat(variables('sqlServerDevelopmentName'), '/sql/', variables('name'), '/', variables('cosmosContainerName'))]",
"type": "Microsoft.DocumentDb/databaseAccounts/apis/databases/containers",
"apiVersion": "2016-03-31",
"dependsOn": ["[resourceId('Microsoft.DocumentDB/databaseAccounts/apis/databases', variables('sqlServerDevelopmentName'), 'sql', variables('name'))]"],
"properties": {
"resource": {
"name": "[variables('cosmosContainerName')]",
"partitionKey": {
"paths": [
"/categoryId"
],
"kind": "Hash"
},
"indexingPolicy": {
"indexingMode": "consistent",
"includedPaths": [{
"path": "/*"
}]
}
}
}
}
And the variables look like this:
"name": "sxp",
"sqlServerName": "[variables('liveName')]",
"sqlServerDevelopmentName": "[variables('developmentName')]",
"sxpDatabaseName": "[variables('name')]",
"cosmosContainerName": "products",
"cosmosThroughPut": "400",
"cosmosDevelopThroughPut": "400",
When I run my release I get this error (for both DocumentDb servers):
{
"status": "Failed",
"error": {
"code": "ResourceDeploymentFailure",
"message": "The resource operation completed with terminal provisioning state 'Failed'.",
"details": [
{
"code": "BadRequest",
"message": "Message: {\"code\":\"BadRequest\",\"message\":\"Message: {\\\"partitionCount\\\":1}\\r\\nActivityId: b0751976-2076-4f29-93ab-b3d5849390b8, Request URI: /apps/0ccd856f-da7a-4ff9-a530-88ce0dbfd50c/services/b3350877-fd5e-4ea1-b6ee-41ecb9fb2540/partitions/14300278-223a-4614-afca-48f66e186695/replicas/132272757678585484p, RequestStats: , SDK: Microsoft.Azure.Documents.Common/2.9.2\"}, Request URI: /dbs, RequestStats: , SDK: Microsoft.Azure.Documents.Common/2.9.2, Microsoft.Azure.Documents.Common/2.9.2, Microsoft.Azure.Documents.Common/2.9.2, Microsoft.Azure.Documents.Common/2.9.2, Microsoft.Azure.Documents.Common/2.9.2, Microsoft.Azure.Documents.Common/2.9.2, Microsoft.Azure.Documents.Common/2.9.2, Microsoft.Azure.Documents.Common/2.9.2, Microsoft.Azure.Documents.Common/2.9.2"
}
]
}
}
Which means absolutely nothing to me. I have tried googling it, but I can't find any reference to the error. The strange thing is, it creates the resources and they are usable, but the deployment says it has failed.
Has anyone seen this issue before?
I have figured this out.
It's to do with the id property. You must have one. If you use the arm-ttk-master it will tell you that not using the resourceId function is not valid, but in the case for cosmos databases and containers, it is wrong.....
So, it should look like this:
{
"type": "Microsoft.DocumentDB/databaseAccounts/apis/databases",
"name": "[concat(variables('sqlServerDevelopmentName'), '/sql/', variables('name'))]",
"apiVersion": "2016-03-31",
"dependsOn": [
"[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('sqlServerDevelopmentName'))]"
],
"properties": {
"resource": {
"id": "[variables('name')]"
},
"options": {
"throughput": "[variables('cosmosDevelopThroughPut')]"
}
}
},
{
"name": "[concat(variables('sqlServerName'), '/sql/', variables('name'), '/', variables('cosmosContainerName'))]",
"type": "Microsoft.DocumentDb/databaseAccounts/apis/databases/containers",
"apiVersion": "2016-03-31",
"dependsOn": [
"[resourceId('Microsoft.DocumentDB/databaseAccounts/apis/databases', variables('sqlServerName'), 'sql', variables('name'))]"
],
"properties": {
"resource": {
"id": "[variables('cosmosContainerName')]",
"partitionKey": {
"paths": [
"/categoryId"
],
"kind": "Hash"
},
"indexingPolicy": {
"indexingMode": "consistent",
"includedPaths": [{
"path": "/*"
}]
}
}
}
},
take note of the id properties:
"id": "[variables('cosmosContainerName')]",

Getting issue The request to create role assignment 'xxxx--x-x-x--x-x-x-xxxxxxx' is not valid. Role assignment scope must match the scope specified

I am trying to create storage account, blob storage and then trying to create role on storage account. Below is the code storagedeploy.json:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"Project": {
"type": "string",
"metadata": {
"description": "Project name"
}
},
"Environment": {
"type": "string",
"metadata": {
"description": "Project name"
}
},
"location": {
"type": "string",
"metadata": {
"description": "Location for all resources."
}
}
},
"variables": {
"storageAccountName": "[toLower(concat(parameters('Project'), parameters('Environment'), uniqueString(resourceGroup().id)))]"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-04-01",
"name": "[variables('storageAccountName')]",
"location": "[parameters('location')]",
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"kind": "StorageV2",
"properties": {
"networkAcls": {
"bypass": "AzureServices",
"virtualNetworkRules": [],
"ipRules": [],
"defaultAction": "Allow"
},
"supportsHttpsTrafficOnly": true,
"encryption": {
"services": {
"file": {
"enabled": true
},
"blob": {
"enabled": true
}
},
"keySource": "Microsoft.Storage"
},
"accessTier": "Hot"
}
},
{
"type": "Microsoft.Storage/storageAccounts/blobServices",
"apiVersion": "2019-04-01",
"name": "[concat(variables('storageAccountName'), '/default')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
],
"properties": {
"cors": {
"corsRules": []
},
"deleteRetentionPolicy": {
"enabled": false
}
}
},
{
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
"apiVersion": "2019-04-01",
"name": "[concat(variables('storageAccountName'), '/default/mycompany-project123-dev-data-store-ue1')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('storageAccountName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
],
"properties": {
"publicAccess": "None"
}
},
{
"type": "Microsoft.Authorization/roleAssignments",
"name": "[guid(resourceGroup().id)]",
"apiVersion": "2019-04-01-preview",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('storageAccountName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
],
"properties": {
"roleDefinitionId": "[concat(subscription().id, '/providers/Microsoft.Authorization/roleDefinitions/17d1049b-9a84-46fb-8f53-869881c3d3ab')]",
"principalId": "xxxxxxx-xxxxxxxx-xxxxxxxx-xxxxxxx",
"scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
}
}
]
}
on execution, i am getting below issue:
PS C:\work\azure\azure-devops\resourcetemplates\staticresources> az group deployment create --resource-group myproject-devops --template-file .\storagedeploy.json
Please provide string value for 'Project' (? for help): ert
Please provide string value for 'Environment' (? for help): fds
Please provide string value for 'location' (? for help): eastus2
Deployment failed. Correlation ID: xxxx-x-x-x-x--x-xxxxxxx. {
"error": {
"code": "InvalidCreateRoleAssignmentRequest",
"message": "The request to create role assignment 'xxxx--x-x-x--x-x-x-sxxssxxx' is not valid. Role assignment scope '/subscriptions/xxxxxxxx3-xxxxxxxd-xxxxxxxd-xxe-xxxxxxxx2/resourceGroups/myproject-devops/providers/Microsoft.Storage/storageAccounts/ertfds5h4nafspjqzii' must match the scope specified on the URI '/subscriptions/xxxxxxxx3-xxxxxxxd-xxxxxxxd-xxe-xxxxxxxx2/resourcegroups/myproject-devops'."
}
}
I tried to google, but getting different solutions. Where exactly i am missing. I tried to follow this issue on stack-overflow
Also, i am trying to assign permission to particular resource like:
To assign to storage, below is code which is working fine:
{
"type": "Microsoft.Storage/storageAccounts/providers/roleAssignments",
"name": "[concat(variables('storageAccountName'),'/Microsoft.Authorization/',guid(subscription().subscriptionId))]",
"apiVersion": "2019-04-01-preview",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('storageAccountName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
],
"properties": {
"roleDefinitionId": "[concat(resourceGroup().id, '/providers/Microsoft.Authorization/roleDefinitions/17d1049b-9a84-46fb-8f53-869881c3d3ab')]",
"principalId": "[parameters('principalId')]",
"scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
}
}
But same i need to do with cosmosDB, redis cache, key vault, but its not working, any idea where i am missing. Below are codes:
For cosmosDB::
{
"type": "Microsoft.DocumentDB/databaseAccounts/providers/roleAssignments",
"name": "[concat(variables('cosmosDBAccountName'),'/Microsoft.Authorization/',guid(subscription().subscriptionId))]",
"apiVersion": "2019-04-01-preview",
"dependsOn": [
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', variables('cosmosDBAccountName'), parameters('Project'))]",
"[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosDBAccountName'))]"
],
"properties": {
"roleDefinitionId": "[concat(resourceGroup().id, '/providers/Microsoft.Authorization/roleDefinitions/5bd9cd88-fe45-4216-938b-f97437e15450')]",
"principalId": "[parameters('principalId')]",
"scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosDBAccountName'))]"
}
}
For Redis cache::
{
"type": "Microsoft.Cache/Redis/providers/roleAssignments",
"name": "[concat(variables('redisCacheName'),'/Microsoft.Authorization/',guid(subscription().subscriptionId))]",
"apiVersion": "2019-04-01-preview",
"dependsOn": [
"[resourceId('Microsoft.Cache/Redis', variables('redisCacheName'))]"
],
"properties": {
"roleDefinitionId": "[concat(resourceGroup().id, '/providers/Microsoft.Authorization/roleDefinitions/e0f68234-74aa-48ed-b826-c38b57376e17')]",
"principalId": "[parameters('principalId')]",
"scope": "[resourceId('Microsoft.Cache/Redis', variables('redisCacheName'))]"
}
}
For Key vault:
{
"type": "Microsoft.KeyVault/vaults/providers/roleAssignments",
"name": "[concat(variables('keyVaultName'),'/Microsoft.Authorization/',guid(subscription().subscriptionId))]",
"apiVersion": "2019-04-01-preview",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]"
],
"properties": {
"roleDefinitionId": "[concat(resourceGroup().id, '/providers/Microsoft.Authorization/roleDefinitions/f25e0fa2-a7c8-4377-a976-54943a77a395')]",
"principalId": "[parameters('principalId')]",
"scope": "[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]"
}
}
this means the role you are trying to assign cannot be assigned to that scope. you should either alter the role to allow it to be assigned to that scope or you should use another role\create a new custom role.
https://learn.microsoft.com/en-us/azure/role-based-access-control/role-definitions#assignablescopes
Made some changes into your json, and it worked on my side now:
{....
.......
......
{
"type": "Microsoft.Authorization/roleAssignments",
"name": "[guid(resourceGroup().id)]",
"apiVersion": "2019-04-01-preview",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('storageAccountName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
],
"properties": {
"roleDefinitionId": "[concat(resourceGroup().id, '/providers/Microsoft.Authorization/roleDefinitions/17d1049b-9a84-46fb-8f53-869881c3d3ab')]",
"principalId": "xxxxxxxxxxxxxxxxxxxxxxxxxx",
"scope": "[resourceGroup().Id]"
}
}
]
}
As the error said, here you should let your roleassignment scope same with your resource group.

Azure function staging slot swap bug when deployed via ARM template

I have created an Azure function app(consumption plan) using ARM template.
After i deploy code and perform a swap operation(VSTS task) both the production and staging slot have the new code. But i expected the staging slot to have the old code after the swap operation, is this a known bug in Azure functions ? Or do i have to do anything extra
"resources": [
{
"name": "CampaignSyncJob",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2016-09-01",
"dependsOn": [],
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(parameters('artifactsLocation'), '/', variables('linkedTemplateFolderName'), '/', variables('webAppTemplateFileName'), parameters('artifactsLocationSasToken'))]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"appServicePlanName": {
"value": "[reference('ReleaseParams').outputs.webApp.value.appServicePlanName]"
},
"appServiceName": {
"value": "[reference('ReleaseParams').outputs.webApp.value.appServiceName]"
},
"artifactsLocation": {
"value": "[parameters('artifactsLocation')]"
},
"artifactsLocationSasToken": {
"value": "[parameters('artifactsLocationSasToken')]"
},
"packageFolder": {
"value": "CampaignSyncJob"
},
"packageFileName": {
"value": "package.zip"
},
"appSettings": {
"value": {
"AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountid'),'2015-05-01-preview').key1)]",
"WEBSITE_CONTENTAZUREFILECONNECTIONSTRING": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountid'),'2015-05-01-preview').key1)]",
"WEBSITE_CONTENTSHARE": "[toLower(variables('appServiceName'))]",
"FUNCTIONS_EXTENSION_VERSION": "~2",
"WEBSITE_NODE_DEFAULT_VERSION": "6.5.0",
"MSDEPLOY_RENAME_LOCKED_FILES": "1",
"AppInsights_InstrumentationKey": "[variables('appInsightsInstrumentationKey')]",
"StickySetting": "StuckToProduction1"
}
},
"slotAppSettings": {
"value": {
"AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountid'),'2015-05-01-preview').key1)]",
"WEBSITE_CONTENTAZUREFILECONNECTIONSTRING": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountid'),'2015-05-01-preview').key1)]",
"WEBSITE_CONTENTSHARE": "[toLower(variables('appServiceName'))]",
"FUNCTIONS_EXTENSION_VERSION": "~2",
"WEBSITE_NODE_DEFAULT_VERSION": "6.5.0",
"MSDEPLOY_RENAME_LOCKED_FILES": "1",
"AppInsights_InstrumentationKey": "[variables('appInsightsInstrumentationKey')]",
"StickySetting": "StuckToStaging1"
}
},
"slotName": {
"value": "[reference('ReleaseParams').outputs.webApp.value.appServiceSlotName]"
},
"appServiceLocation": {
"value": "[reference('ReleaseParams').outputs.common.value.location]"
},
"slotSpecificAppSettingKeys": {
"value": [
"StickySetting"
]
}
}
}
},
Linked template which deploys the function app
{
"condition": "[parameters('deployOnStagingSlot')]",
"apiVersion": "2015-08-01",
"name": "[concat(parameters('appServiceName'), '/', parameters('slotName'))]",
"type": "Microsoft.Web/sites/slots",
"location": "[parameters('appServiceLocation')]",
"properties": {
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('appServicePlanName'))]"
},
"dependsOn": [
],
"resources": [
{
"condition": "[parameters('deployOnStagingSlot')]",
"name": "appsettings",
"type": "config",
"apiVersion": "2015-08-01",
"dependsOn": [
"[concat('Microsoft.Web/sites/', parameters('appServiceName'), '/slots/', parameters('slotName'))]",
"[concat('Microsoft.Web/sites/', parameters('appServiceName'), '/slots/', parameters('slotName'), '/Extensions/MSdeploy')]"
],
"properties": "[parameters('slotAppSettings')]"
},
{
"condition": "[parameters('deployOnStagingSlot')]",
"name": "MSDeploy",
"type": "extensions",
"location": "[parameters('appServiceLocation')]",
"apiVersion": "2015-08-01",
"dependsOn": [
"[concat('Microsoft.Web/sites/', parameters('appServiceName'), '/slots/', parameters('slotName'))]"
],
"properties": {
"packageUri": "[concat(parameters('artifactsLocation'), '/', parameters('packageFolder'), '/', parameters('packageFileName'), parameters('artifactsLocationSasToken'))]",
"setParameters": {
"IIS Web Application Name": "[parameters('slotName')]"
}
}
}
]
}
Hmm, I know that for swapping slots within a functions app it is required to change app setting WEBSITE_CONTENTSHARE to a slot specific setting.
For this solution and other ARM issues regarding multiple slots, check out the blog of Gary Lumsden

ARM - Deploy storage account only if not exists

Is there a way, using Azure Resource Manager (ARM) templates, to deploy a storage account only if that storage account does not exist?
The below template will create:
App Insights resource (shared)
Storage Account (shared)
App Plan
App instance with configuration containing the App Insights Instrumentation Key and the Storage Account Connection String.
I would like the first two steps to be optional meaning if they already exist, just use them.
Only thing I have found so far is the pattern of newOrExisting, but that just does not make any sense. The script should be able to tell if those resource already exist and simply skip creation.
The same App Insights and Storage Account will be used by other deployment scripts so it would be nice if the template could just figure it out.
Thanks for any help!
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"environmentName": {
"type": "string",
"defaultValue": "Dev",
"allowedValues": [
"Dev",
"Test",
"Prod"
]
}
},
"variables": {
"rgLocation": "[resourceGroup().location]",
"insightsName": "[concat('Insights-', parameters('environmentName'))]",
"appName": "[concat('MyAppName-', parameters('environmentName'))]",
"genStorageName": "[concat('blgenstorage', parameters('environmentName'))]"
},
{
"comments": "Creates a general storage account that is used to save various data, including configurations.",
"name": "[variables('genStorageName')]",
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2017-06-01",
"sku": {
"name": "Standard_LRS"
},
"kind": "Storage",
"location": "[variables('rgLocation')]",
"tags": {},
"properties": {}
},
{
"comments": "Creates the service plan under which the web app will live.",
"name": "[concat('ServicePlan-MyApp-', parameters('environment'))]",
"type": "Microsoft.Web/serverfarms",
"apiVersion": "2016-09-01",
"kind": "app",
"location": "[variables('rgLocation')]",
"tags": {},
"properties": {
"name": "[concat('ServicePlan-MyApp-', parameters('environmentName'))]",
"perSiteScaling": "false",
"reserved": "false"
},
"sku": {
"name": "S1",
"tier": "Standard",
"size": "S1",
"family": "S",
"capacity": 1
}
},
{
"comments": "Primary web app deployment.",
"name": "[variables('appName')]",
"type": "Microsoft.Web/sites",
"apiVersion": "2016-08-01",
"kind": "app",
"location": "[variables('rgLocation')]",
"tags": {},
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', concat('ServicePlan-MyApp-', variables('envShortName')))]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('genStorageName'))]",
"[resourceId('microsoft.insights/components', variables('insightsName'))]"
],
"properties": {
"enabled": true,
"hostNameSslStates": [
{
"name": "[concat(variables('appName'), '.azurewebsites.net')]",
"sslState": "Disabled"
},
{
"name": "[concat(variables('appName'), '.scm.azurewebsites.net')]",
"sslState": "Disabled"
}
],
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', concat('ServicePlan-MyApp-', parameters('environmentName')))]",
"siteConfig": {
"numberOfWorkers": 1,
"defaultDocuments": [
"Default.htm",
"Default.html",
"Default.asp",
"index.htm",
"index.html",
"iisstart.htm",
"default.aspx",
"index.php",
"hostingstart.html"
],
"netFrameworkVersion": "v4.6",
"appSettings": [
{
"name": "AppInsightsInstrumentationKey",
"value": "[reference(resourceId('Microsoft.Insights/components', variables('insightsName')), '2015-05-01').InstrumentationKey]"
}
],
"connectionStrings": [
{
"name": "AzureStorage",
"connectionString": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('genStorageName')), '2017-06-01').keys[0].value]",
"type": "Custom"
}
],
"alwaysOn": true,
"managedPipelineMode": "Integrated",
"virtualApplications": [
{
"virtualPath": "/",
"physicalPath": "site\\wwwroot",
"preloadEnabled": false
}
],
"autoHealEnabled": false,
"vnetName": ""
},
"microService": "WebSites",
"clientAffinityEnabled": false,
"clientCertEnabled": false,
"hostNamesDisabled": false
}
}
How would you create a storage account if it exists?
Basically if an ARM Template encounters a resource its trying to deploy it will update it if the properties do not match. In your case it won't do anything (it will skip it).

Resources