Dynamic appsettings array content in ARM - azure-web-app-service

I have the following simplified ARM template (I left out certain parts to make it more readable). I have a parameter called PrivateKeyCertificateThumbprint. If this parameter is filled in, I want to set the appsetting WEBSITE_LOAD_CERTIFICATES to a certain value. If the parameter is empty, I do not want to set the value. So the elements in the appSettings array are sort of dynamic based on the content of the PrivateKeyCertificateThumbprint parameter.
I do not seem to find a solution for this in ARM. The usecase seems so simple. First I tried to add an additional Microsoft.Web/sites/config/appsettings resource with only the WEBSITE_LOAD_CERTIFICATES key. But doing that removes all the already existing appsettings from the application.
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
...
"PrivateKeyCertificateThumbprint": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "The thumbprint of the client certificate used by the application"
}
}
},
"resources": [
{
"type": "Microsoft.Web/sites",
"apiVersion": "2018-11-01",
"name": "[parameters('AppResourcename')]",
"identity": {
"type": "SystemAssigned"
},
"Location": "[parameters('Location')]",
"kind": "[parameters('SitesKind')]",
"properties": {
"siteConfig": {
"appSettings": [
{
"name": "APPINSIGHTS_INSTRUMENTATIONKEY",
"value": "[if(empty(parameters('AppinsResourceName')), '', reference(resourceId('microsoft.insights/components/', parameters('AppinsResourceName')), '2015-05-01').InstrumentationKey)]"
},
{
"name": "ApplicationInsightsAgent_EXTENSION_VERSION",
"value": "~2"
},
{
"name": "WEBSITE_HEALTHCHECK_MAXPINGFAILURES",
"value": "5"
},
{
"name": "WEBSITE_LOAD_CERTIFICATES",
"value": "[parameters('PrivateKeyCertificateThumbprint')]"
}
],
"healthCheckPath": "[parameters('HealthCheckPath')]"
}
...
}
]
}

For clarity, I used a bicep template.
Here I've defined a variable with default appsettings. Then if the cert thumbprint is not empty, I'm adding the extra app setting:
param PrivateKeyCertificateThumbprint string = ''
param AppResourcename string
param Location string
param SitesKind string
param AppinsResourceName string
// Common app settings
var defaultAppSettings = [
{
name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
value: (empty(AppinsResourceName) ? '' : reference(resourceId('microsoft.insights/components/', AppinsResourceName), '2015-05-01').InstrumentationKey)
}
{
name: 'ApplicationInsightsAgent_EXTENSION_VERSION'
value: '~2'
}
{
name: 'WEBSITE_HEALTHCHECK_MAXPINGFAILURES'
value: '5'
}
]
// if the cert thumbprint is not empty, we add it.
var appSettings = concat(defaultAppSettings, empty(PrivateKeyCertificateThumbprint) ? [] : [
{
name: 'WEBSITE_LOAD_CERTIFICATES'
value: PrivateKeyCertificateThumbprint
}
])
// create the webapp
resource webApp 'Microsoft.Web/sites#2018-11-01' = {
name: AppResourcename
identity: {
type: 'SystemAssigned'
}
location: Location
kind: SitesKind
properties: {
siteConfig: {
appSettings: appSettings
}
}
}
Using Az CLI, you can then generate the ARM temnplate:
az bicep build --file .\main.bicep
the generated ARM template looks like that:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"PrivateKeyCertificateThumbprint": {
"type": "string",
"defaultValue": ""
},
"AppResourcename": {
"type": "string"
},
"Location": {
"type": "string"
},
"SitesKind": {
"type": "string"
},
"AppinsResourceName": {
"type": "string"
}
},
"resources": [
{
"type": "Microsoft.Web/sites",
"apiVersion": "2018-11-01",
"name": "[parameters('AppResourcename')]",
"identity": {
"type": "SystemAssigned"
},
"location": "[parameters('Location')]",
"kind": "[parameters('SitesKind')]",
"properties": {
"siteConfig": {
"appSettings": "[concat(createArray(createObject('name', 'APPINSIGHTS_INSTRUMENTATIONKEY', 'value', if(empty(parameters('AppinsResourceName')), '', reference(resourceId('microsoft.insights/components/', parameters('AppinsResourceName')), '2015-05-01').InstrumentationKey)), createObject('name', 'ApplicationInsightsAgent_EXTENSION_VERSION', 'value', '~2'), createObject('name', 'WEBSITE_HEALTHCHECK_MAXPINGFAILURES', 'value', '5')), if(empty(parameters('PrivateKeyCertificateThumbprint')), createArray(), createArray(createObject('name', 'WEBSITE_LOAD_CERTIFICATES', 'value', parameters('PrivateKeyCertificateThumbprint')))))]"
}
}
}
]
}

I finally managed to get it to work in ARM by using functions. I created 3 functions that created 3 sub arrays with as parameters, values I could only get in the resource itself. I then used a concat in combination with an if, to conditionally add parts to the settings array in the resource.
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters":
// ...
"PrivateKeyCertificateThumbprint": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "The thumbprint of the client certificate used by the application"
}
}
},
"variables": {
// ...
},
"functions": [
{
"namespace": "test",
"members": {
"createAppSettings": {
"parameters": [],
"output": {
"value": [
{
"name": "ApplicationInsightsAgent_EXTENSION_VERSION",
"value": "~2"
},
{
"name": "WEBSITE_HEALTHCHECK_MAXPINGFAILURES",
"value": "5"
}
],
"type": "array"
}
},
"createAppInsightSettings": {
"parameters": [
{
"name": "instrumentationkey",
"type": "string"
}
],
"output": {
"value": [
{
"name": "APPINSIGHTS_INSTRUMENTATIONKEY",
"value": "[parameters('instrumentationkey')]"
}
],
"type": "array"
}
},
"createCertificateAppSettings": {
"parameters": [
{
"name": "certthumbprint",
"type": "string"
}
],
"output": {
"value": [
{
"name": "WEBSITE_LOAD_CERTIFICATES",
"value": "[parameters('certthumbprint')]"
}
],
"type": "array"
}
}
}
}
],
"resources": [
{
"type": "Microsoft.Web/sites",
"apiVersion": "2018-11-01",
"name": "[parameters('AppResourcename')]",
"identity": {
"type": "SystemAssigned"
},
"Location": "[parameters('Location')]",
"kind": "[parameters('SitesKind')]",
"properties": {
"siteConfig": {
"appSettings": "[concat(
test.createAppSettings(),
if(empty(parameters('AppinsResourceName')), createArray(), test.createAppInsightSettings(reference(resourceId('microsoft.insights/components/',parameters('AppinsResourceName')), '2015-05-01').InstrumentationKey)),
if(empty(parameters('PrivateKeyCertificateThumbprint')), createArray(), test.createCertificateAppSettings(parameters('PrivateKeyCertificateThumbprint')))
)]",
"healthCheckPath": "[parameters('HealthCheckPath')]"
}
// ...
}
}
]
}

Related

Default Values in ARM templates when using Template Specs

We have implemented Template Specs for our ARM deployments to Azure a while ago and we drastically decreased the amount of work by doing that. The next thing we're trying to achieve is to start implementing Default Values in template specs, so we do not have to specify all parameters that are the same in all our projects in the parameter files. In case we do want to override the default, we can of course specify the parameter in the parameter file.
We worked with this already in the past with templates and parameter files, but I can't get this to work with Template Specs.
As an example, I'm trying to deploy an App Service Plan like this:
Template Spec:
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"appServicePlanSettings": {
"type": "object",
"defaultValue": {
"isHypervContainerPlan": false
}
},
"resourceNameAndTagSettings": {
"type": "object"
}
},
"variables": {
"appServicePlanName": "[concat('o', parameters('appServicePlanSettings').nameAbbr, parameters('resourceNameAndTagSettings').environmentType, parameters('resourceNameAndTagSettings').resourceGroupNumber, parameters('resourceNameAndTagSettings').solutionNameAbbr, parameters('resourceNameAndTagSettings').locationAbbr)]"
},
"resources": [
{
"comments": "App Service Plans",
"condition": "[parameters('appServicePlanSettings').deploy]",
"apiVersion": "2020-09-01",
"type": "Microsoft.Web/serverfarms",
"name": "[variables('appServicePlanName')]",
"location": "[resourceGroup().location]",
"tags": {
"_Purpose": "[parameters('appServicePlanSettings').tagValuePurpose]",
"CostCenter": "[parameters('resourceNameAndTagSettings').tagValueCostCenter]",
"EnvironmentType": "[parameters('resourceNameAndTagSettings').tagValueEnvironmentType]",
"Owner": "[parameters('resourceNameAndTagSettings').tagValueOwner]"
},
"kind": "[parameters('appServicePlanSettings').kind]",
"sku": {
"name": "[parameters('appServicePlanSettings').sku]",
"size": "[parameters('appServicePlanSettings').sku]",
"tier": "[parameters('appServicePlanSettings').skuTier]"
},
"properties": {
"hyperV": "[parameters('appServicePlanSettings').isHypervContainerPlan]",
"perSiteScaling": "[parameters('appServicePlanSettings').perSiteScaling]",
"reserved": "[parameters('appServicePlanSettings').isLinuxOS]"
},
"dependsOn": []
}
],
"outputs": {}
}
Main Template:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"appServicePlanSettings": {
"type": "array"
},
"dateTime": {
"type": "string",
"defaultValue": "[utcNow()]"
},
"resourceNameAndTagSettings": {
"type": "object"
},
"templateSpecSettings": {
"type": "object"
}
},
"resources": [
{
"comments": "Apps - App Service Plans",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2020-06-01",
"name": "[concat('Deploy-', parameters('appServicePlanSettings')[copyIndex()].nameAbbr, parameters('resourceNameAndTagSettings').environmentType, parameters('resourceNameAndTagSettings').resourceGroupNumber, parameters('resourceNameAndTagSettings').solutionNameAbbr, parameters('resourceNameAndTagSettings').locationAbbr, '-', parameters('dateTime'))]",
"copy": {
"name": "appServicePlanCopy",
"count": "[length(parameters('appServicePlanSettings'))]"
},
"properties": {
"mode": "Incremental",
"templateLink": {
"id": "[concat('/subscriptions/', parameters('templateSpecSettings').templateSpecSubscriptionId, '/resourceGroups/', parameters('templateSpecSettings').templateSpecResourceGroupName, '/providers/Microsoft.Resources/TemplateSpecs/', parameters('templateSpecSettings').appServicePlan.name, '/versions/', parameters('templateSpecSettings').appServicePlan.version)]"
},
"parameters": {
"appServicePlanSettings": {
"value": "[parameters('appServicePlanSettings')[copyIndex()]]"
},
"resourceNameAndTagSettings": {
"value": "[parameters('resourceNameAndTagSettings')]"
}
}
},
"dependsOn": []
}
],
"outputs": {}
}
Parameter File:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"appServicePlanSettings": {
"value": [
{
"comments": "App Service Plan 1",
"deploy": true,
"nameAbbr": "Asp",
"isLinuxOS": false,
"isHypervContainerPlan": false,
"perSiteScaling": false,
"tagValuePurpose": "Test",
"kind": "app",
"sku": "P1v2",
"skuTier": "PremiumV2"
}
]
},
"resourceNameAndTagSettings": {
"value": {
"environmentType": "dev",
"locationAbbr": "europe",
"resourceGroupNumber": "001",
"solutionNameAbbr": "test",
"tagValueCostCenter": "123",
"tagValueEnvironmentType": "Development",
"tagValueOwner": "me"
}
},
"templateSpecSettings": {
"value": {
"templateSpecResourceGroupName": "XXX",
"templateSpecSubscriptionId": "XXX",
"appServicePlan": {
"name": "appServicePlanTest",
"version": "1.2"
}
}
}
}
}
This deploys just fine.
But if I leave out:
"isHypervContainerPlan": false,
in the parameter file, the deployment will fail with this message:
Unable to process template language expressions for resource '...' at
line '24' and column '9'. 'The language expression property
'isHypervContainerPlan' doesn't exist, available properties are
'comments, deploy, nameAbbr, isLinuxOS, perSiteScaling,
tagValuePurpose, kind, sku, skuTier'.
Why would it fail on this error if the defaultValue is set in the Template Spec parameters section?
What am I missing here or are defaultValues not supported with Template Specs?
A defaultValue on a parameter is only used if no value is supplied. Put another way, you can you either use the defaultValue for a parameter or supply a value, not both, nor any combination of the two.
Your templateSpec expects a complex object for the appServicePlanSettings parameter. That object needs to have all of the properties referenced by the serverFarm resource being deployed. You're supplying a value for that param, but you're also omitting one of the properties from that parameter, and that's the property that's being flagged in the error message.
To see this in action in another way, put that property back into your param file and remove a different one, you'll see a similar error... or you could just not supply a param value at all for the ``appServicePlanSettings``` and then the defaultValue will be used.
I've been testing with the 'defaultValue'.
I have also tested with this setup:
Template:
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"appServicePlanSettings": {
"type": "object",
"defaultValue": {
"isHypervContainerPlan": false,
"isLinuxOS": false,
"perSiteScaling": false
}
},
"resourceNameAndTagSettings": {
"type": "object"
}
},
"variables": {
"appServicePlanName": "[concat('o', parameters('appServicePlanSettings').nameAbbr, parameters('resourceNameAndTagSettings').environmentType, parameters('resourceNameAndTagSettings').resourceGroupNumber, parameters('resourceNameAndTagSettings').solutionNameAbbr, parameters('resourceNameAndTagSettings').locationAbbr)]"
},
"resources": [
{
"comments": "App Service Plans",
"condition": "[parameters('appServicePlanSettings').deploy]",
"apiVersion": "2020-09-01",
"type": "Microsoft.Web/serverfarms",
"name": "[variables('appServicePlanName')]",
"location": "[resourceGroup().location]",
"tags": {
"_Purpose": "[parameters('appServicePlanSettings').tagValuePurpose]",
"CostCenter": "[parameters('resourceNameAndTagSettings').tagValueCostCenter]",
"EnvironmentType": "[parameters('resourceNameAndTagSettings').tagValueEnvironmentType]",
"Owner": "[parameters('resourceNameAndTagSettings').tagValueOwner]"
},
"kind": "[parameters('appServicePlanSettings').kind]",
"sku": {
"name": "[parameters('appServicePlanSettings').sku]",
"size": "[parameters('appServicePlanSettings').sku]",
"tier": "[parameters('appServicePlanSettings').skuTier]"
},
"properties": {
"hyperV": "[parameters('appServicePlanSettings').isHypervContainerPlan]",
"perSiteScaling": "[parameters('appServicePlanSettings').perSiteScaling]",
"reserved": "[parameters('appServicePlanSettings').isLinuxOS]"
},
"dependsOn": []
}
],
"outputs": {}
}
Parameters:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"appServicePlanSettings": {
"value": {
"comments": "App Service Plan 1",
"deploy": true,
"nameAbbr": "Asp",
"isLinuxOS": "",
"isHypervContainerPlan": "",
"perSiteScaling": "",
"tagValuePurpose": "Test",
"kind": "app",
"sku": "P1v2",
"skuTier": "PremiumV2"
}
},
"resourceNameAndTagSettings": {
"value": {
"environmentType": "dev",
"locationAbbr": "europe",
"resourceGroupNumber": "001",
"solutionNameAbbr": "test",
"tagValueCostCenter": "123",
"tagValueEnvironmentType": "Development",
"tagValueOwner": "me"
}
},
"templateSpecSettings": {
"value": {
"templateSpecResourceGroupName": "oGen1Weu1PrdMng001",
"templateSpecSubscriptionId": "130176f8-513a-4869-9db3-7c46d0e25159",
"appServicePlan": {
"name": "appServicePlanTest",
"version": "1.2"
}
}
}
}
}
Which also doesn't work when I do not specify "isHypervContainerPlan" in the parameter file, I thought we tested this, but apparently not good enough...
The only thing that works is defining:
"isHypervContainerPlan": "",
in the parameter file, thus not specifying a value. Which is not desirable, because then still all parameters have to be defined, even when I do not want to override the defaults.
So, the solution in the end has become the following (the main template remains the same):
Template Spec:
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"appServicePlanSettings": {
"type": "object"
},
"resourceNameAndTagSettings": {
"type": "object"
}
},
"variables": {
"appServicePlanName": "[concat('o', parameters('appServicePlanSettings').nameAbbr, parameters('resourceNameAndTagSettings').environmentType, parameters('resourceNameAndTagSettings').resourceGroupNumber, parameters('resourceNameAndTagSettings').solutionNameAbbr, parameters('resourceNameAndTagSettings').locationAbbr)]",
"appServicePlanSettings": {
"isHypervContainerPlan": false,
"isLinuxOS": false,
"kind": "app",
"nameAbbr": "Asp",
"perSiteScaling": false
}
},
"resources": [
{
"comments": "App Service Plans",
"condition": "[parameters('appServicePlanSettings').deploy]",
"apiVersion": "2020-09-01",
"type": "Microsoft.Web/serverfarms",
"name": "[variables('appServicePlanName')]",
"location": "[resourceGroup().location]",
"tags": {
"_Purpose": "[parameters('appServicePlanSettings').tagValuePurpose]",
"CostCenter": "[parameters('resourceNameAndTagSettings').tagValueCostCenter]",
"EnvironmentType": "[parameters('resourceNameAndTagSettings').tagValueEnvironmentType]",
"Owner": "[parameters('resourceNameAndTagSettings').tagValueOwner]"
},
"kind": "[if(contains(parameters('appServicePlanSettings'), 'kind'), parameters('appServicePlanSettings').kind, variables('appServicePlanSettings').kind)]",
"sku": {
"name": "[parameters('appServicePlanSettings').sku]",
"size": "[parameters('appServicePlanSettings').sku]",
"tier": "[parameters('appServicePlanSettings').skuTier]"
},
"properties": {
"hyperV": "[if(contains(parameters('appServicePlanSettings'), 'isHypervContainerPlan'), parameters('appServicePlanSettings').isHypervContainerPlan, variables('appServicePlanSettings').isHypervContainerPlan)]",
"perSiteScaling": "[if(contains(parameters('appServicePlanSettings'), 'perSiteScaling'), parameters('appServicePlanSettings').perSiteScaling, variables('appServicePlanSettings').perSiteScaling)]",
"reserved": "[if(contains(parameters('appServicePlanSettings'), 'isLinuxOS'), parameters('appServicePlanSettings').isLinuxOS, variables('appServicePlanSettings').isLinuxOS)]"
},
"dependsOn": []
}
],
"outputs": {}
}
And if I don't specify these values now in the parameter file, the value configured in the variable section will be used:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"appServicePlanSettings": {
"value": [
{
"comments": "App Service Plan 1",
"deploy": true,
"nameAbbr": "Asp",
"tagValuePurpose": "Test",
"kind": "app",
"sku": "P1v2",
"skuTier": "PremiumV2"
}
]
},
"resourceNameAndTagSettings": {
"value": {
"environmentType": "dev",
"locationAbbr": "europe",
"resourceGroupNumber": "001",
"solutionNameAbbr": "test",
"tagValueCostCenter": "123",
"tagValueEnvironmentType": "Development",
"tagValueOwner": "me"
}
},
"templateSpecSettings": {
"value": {
"templateSpecResourceGroupName": "XXX",
"templateSpecSubscriptionId": "XXX",
"appServicePlan": {
"name": "appServicePlanTest",
"version": "1.2"
}
}
}
}
}

ARM Template : Get the SKU of IOT hub

Using the "reference" keyword I am able to access my iot hub and list its properties. However I cannot find any reference to the SKU. How can I list the sku name/tier of an iot hub to output?
If you want to get the iot hub's sku inarm template, you can use the arm template function "reference" :
[reference(resourceId('Microsoft.Devices/IotHubs', 'hubname'),'2018-04-01','Full')]
for example
template
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json",
"contentVersion": "1.0.0.0",
"parameters": {
"hubname": {
"type": "String"
},
"location": {
"type": "String"
},
"sku_name": {
"type": "String"
},
"sku_units": {
"type": "String"
},
"d2c_partitions": {
"type": "String"
},
"features": {
"type": "String"
},
"tags": {
"type": "Object"
},
"cloudEnvironment": {
"defaultValue": "public",
"allowedValues": [
"public",
"china",
"usgov"
],
"type": "String",
"metadata": {
"description": "Cloud environment to deploy (i.e. usgov/china/ ...)"
}
}
},
"resources": [
{
"type": "Microsoft.Devices/IotHubs",
"apiVersion": "2020-07-10-preview",
"name": "[parameters('hubname')]",
"location": "[parameters('location')]",
"tags": "[parameters('tags')]",
"sku": {
"name": "[parameters('sku_name')]",
"capacity": "[parameters('sku_units')]"
},
"properties": {
"eventHubEndpoints": {
"events": {
"retentionTimeInDays": 1,
"partitionCount": "[parameters('d2c_partitions')]"
}
},
"features": "[parameters('features')]"
}
},
{
"type": "Microsoft.Security/IoTSecuritySolutions",
"apiVersion": "2019-08-01",
"name": "[parameters('hubname')]",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.Devices/IotHubs', parameters('hubname'))]"
],
"properties": {
"status": "Enabled",
"unmaskedIpLoggingStatus": "Enabled",
"disabledDataSources": [],
"displayName": "[parameters('hubname')]",
"iotHubs": [
"[resourceId('Microsoft.Devices/IotHubs', parameters('hubname'))]"
],
"recommendationsConfiguration": []
}
}
],
"outputs": {
"iot": {
"type": "Object",
"value": "[reference(resourceId('Microsoft.Devices/IotHubs', parameters('hubname')),'2018-04-01','Full').sku]"
}
}
}
parameter
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"hubname": {
"value": "testiot05"
},
"location": {
"value": "eastasia"
},
"sku_name": {
"value": "S1"
},
"sku_units": {
"value": "1"
},
"d2c_partitions": {
"value": "4"
},
"features": {
"value": "None"
},
"tags": {
"value": {}
},
"cloudEnvironment": {
"value": "public"
}
}
}

Azure ARM Template user defined function

I need to create 8 database and couple of collections though ARM template.I was going through the user defined function here https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/template-user-defined-functions to make the template simpler, Is that something I can achieve instead of copy paste the same scripts? right now, its throwing an error
Template validation failed: Unexpected initial token 'String' when
populating object.
My current Function:
"functions": [
{
"namespace": "contoso",
"members": {
"uniqueName": {
"parameters": [
{
"name": "databaseName",
"type": "string"
}
],
"output": {
"type": "object",
"value": {
"type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases",
"name": "['test', '/', parameters('databaseName'))]",
"apiVersion": "2020-04-01",
"dependsOn": [ "[resourceId('Microsoft.DocumentDB/databaseAccounts/', 'test')]" ],
"properties": {
"resource": {
"id": "[parameters('databaseName')]"
}
}
}
}
}
}
}
],
Is that something we can achieve?
Update: Here is the simplified version
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"accountName": {
"type": "string",
"defaultValue": "test",
"metadata": {
"description": "Cosmos DB account name"
}
},
"databaseName": {
"type": "string",
"metadata": {
"description": "Cosmos DB database name"
}
}
},
"functions": [
{
"namespace": "contoso",
"members": {
"uniqueName": {
"parameters": [
{
"name": "databaseName",
"type": "string"
}
],
"output": {
"type": "object",
"value": {
"type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases",
"name": "[concat('/test', '/', parameters('databaseName'))]",
"apiVersion": "2020-04-01",
"dependsOn": [ "[resourceId('Microsoft.DocumentDB/databaseAccounts/', 'test')]" ],
"properties": {
"resource": {
"id": "[parameters('databaseName')]"
}
}
}
}
}
}
}
],
"resources": [
{
"type": "Microsoft.DocumentDB/databaseAccounts",
"name": "[parameters('accountName')]",
"apiVersion": "2020-04-01",
"location": "central us",
"kind": "MongoDB",
"properties": {
"isVirtualNetworkFilterEnabled": false,
"databaseAccountOfferType": "Standard",
"apiProperties": {
"serverVersion": "3.6"
}
}
},
"[contoso.uniqueName(parameters('databaseName'))]"
]
}
Looks like you're trying to create several mongodbDatabases within the databaseAccounts resource.
I recommend looking at the ARM copy element.
https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/copy-resources#resource-iteration
It would look roughly like:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"accountName": {
"type": "string",
"defaultValue": "test",
"metadata": {
"description": "Cosmos DB account name"
}
},
"databaseNames": {
"type": "array",
"defaultValue": [
"contoso",
"fabrikam",
"coho"
],
"metadata": {
"description": "Cosmos DB database names array"
}
}
},
"resources": [
{
"type": "Microsoft.DocumentDB/databaseAccounts",
"name": "[parameters('accountName')]",
"apiVersion": "2020-04-01",
"location": "central us",
"kind": "MongoDB",
"properties": {
"isVirtualNetworkFilterEnabled": false,
"databaseAccountOfferType": "Standard",
"apiProperties": {
"serverVersion": "3.6"
}
}
},
{
"type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases",
"name": "[concat('/test', '/', parameters('databaseNames')[copyIndex()])]",
"apiVersion": "2020-04-01",
"dependsOn": [ "[resourceId('Microsoft.DocumentDB/databaseAccounts/', 'test')]" ],
"properties": {
"resource": {
"id": "[parameters('databaseNames')[copyIndex()]]"
}
},
"copy": {
"name": "databaseCopy",
"count": "[length(parameters('databaseNames'))]"
}
}
]
}

Parameters as array copy() not working in resource

I am trying to send array of email values as parameters and trying to deploy 'Action group' using 'Copy' in the resource template .My Action group template is getting deployed without errors but email fields are empty. I was passing two email values as parameters. I'm stuck with this for a day. It would be great if someone throw some lights on where i am going wrong.
Template.json:
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"actionGroupName": {
"type": "string",
"defaultValue": "newActionGroup",
"metadata": {
"description": "Unique name (within the Resource Group) for the Action group."
}
},
"actionGroupShortName": {
"type": "string",
"defaultValue": "newActionGroup",
"metadata": {
"description": "Short name (maximum 12 characters) for the Action group."
}
},
"emailReceiverName": {
"type": "array",
"metadata": {
"description": "email receiver service Name."
}
},
"emailReceiverAddress": {
"type": "array",
"metadata": {
"description": "email receiver address."
}
}
},
"variables": {
"customemailReceiverName": "[array(parameters('emailReceiverName'))]",
"customemailReceiverAddress": "[parameters('emailReceiverAddress')]"
},
"resources": [
{
"type": "Microsoft.Insights/actionGroups",
"name": "[parameters('actionGroupName')]",
"apiVersion": "2018-03-01",
"location": "Global",
"properties": {
"groupShortName": "[parameters('actionGroupShortName')]",
"copy": [
{
"name": "counts",
"count": "[length(parameters('emailReceiverName'))]",
"input": {
"emailReceivers": [
{
"name": "[parameters('emailReceiverName')[copyIndex('counts')]",
"emailAddress": "[parameters('emailReceiverAddress')[copyIndex('counts')]]"
}
]
}
}
]
}
}
] }
Parameter.json:
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"actionGroupName": {
"value": "actiongroupslb"
},
"actionGroupShortName": {
"value": "agSLB"
},
"emailReceiverName": {
"value": ["siva","siva1"]
},
"emailReceiverAddress": {
"value": ["siva#gmail.com","svaji#gmail.com"]
}
}
}
Action group created with missing email values
Here's whats working for me:
{
"type": "Microsoft.Insights/actionGroups",
"apiVersion": "2018-03-01",
"name": "[variables('actionGroups')[copyIndex()].Name]",
"copy": {
"name": "ActionGroupCopy",
"count": "[length(parameters('emailReceiverName'))]"
},
"location": "Global",
"properties": {
"groupShortName": "[variables('actionGroups')[copyIndex()].Name]",
"enabled": true,
"emailReceivers": [
{
"name": "[variables('actionGroups')[copyIndex()].EmailName]",
"emailAddress": "[variables('actionGroups')[copyIndex()].EmailAddress]"
}
]
}
},
Here's the variable:
"actionGroups": [
{
"Name": "teamname",
"EmailAddress": "email#domain.com",
"EmailName": "emailname"
},
{
"Name": "teamname1",
"EmailAddress": "email1#domain.com",
"EmailName": "emailname1"
}
],
If you need multiple receivers, use the resource property copy function, not resource:
{
"type": "Microsoft.Insights/actionGroups",
"apiVersion": "2018-03-01",
"name": "name",
"location": "Global",
"properties": {
"groupShortName": "name",
"enabled": true,
"copy": [
{
"name": "emailReceivers",
"count": "[length(parameters('emailReceiverName'))]",
"input": {
"name": "[parameters('emailReceiverName')[copyIndex('emailReceivers')]]",
"emailAddress": "[parameters('emailReceiverAddress')[copyIndex('emailReceivers')]]"
}
}
]
}
},
this is assuming they map 1-to-1

How to print output of linked template using ARM template in Azure

I am using maintemplate and linked template for deployment. I want to print the output of linked template after deployment.
When I deploy the below template. I am getting the below error,
The template output 'vmpublicIPName' is not valid: The language
expression property 'publicIPName' doesn't exist, available properties
are ''.. (Code: DeploymentOutputEvaluationFailed)
How can I print the output of variables present in linked template?
Is there any way to print all the linked template deployment parameters values in main template?
storage.json
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"storageAccountName": {
"type": "string"
},
"storageAccountType": {
"type": "string",
"defaultValue": "Standard_LRS"
}
},
"variables": {
"location": "[resourceGroup().location]",
"resourceGroupName": "[resourceGroup().name]",
"subscriptionId": "[subscription().subscriptionId]"
},
"resources": [
{
"name": "[concat(parameters('storageAccountName'), '1rmtest')]",
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2015-06-15",
"location": "[variables('location')]",
"properties": {
"accountType": "[parameters('storageAccountType')]"
},
"tags": {
"BuildName": "StorageARM"
}
},
{
"apiVersion": "2017-03-01",
"name": "TestTemplate",
"type": "Microsoft.Resources/deployments",
"properties": {
"mode": "incremental",
"templateLink": {
"uri":"https://gist.githubusercontent.com/public-ip-template.json",
"contentVersion":"1.0.0.0"
},
"parameters": {
"publicIpAddressName": {
"value": "public-ip-test"
}
}
}
}
],
"outputs": {
"vmpublicIPName": {
"type": "object",
"value": "[reference('TestTemplate').outputs.publicIPName]"
},
"vmlocation": {
"type": "object",
"value": "[reference('TestTemplate').outputs.location]"
}
}
}
Linked template:-
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"publicIpAddressName": {
"type": "string"
}
},
"variables": {
"location": "[resourceGroup().location]",
"resourceGroupName": "[resourceGroup().name]"
},
"resources": [
{
"name": "[parameters('publicIpAddressName')]",
"type": "Microsoft.Network/publicIpAddresses",
"apiVersion": "2016-09-01",
"location": "[variables('location')]",
"properties": {
"publicIpAllocationMethod": "Static"
}
}
],
"outputs": {
"publicIPName": {
"type": "string",
"value": "[parameters('publicIpAddressName')]"
},
"location": {
"type": "string",
"value": "[variables('location')]"
}
}
}
Do you ensure your linked template URI is correct and accessible? According to this official document
The URI value for the linked parameter file cannot be a local file,
and must include either http or https.
I test in my lab, I only replace your URI such as below:
"templateLink": {
"uri":"https://gist.githubusercontent.com/Walter-Shui/d5387c0fc92f2e8df1c7157a2d5e54aa/raw/722d4a58107b2f617996ae237ceae445ef4342d9/test.json",
"contentVersion":"1.0.0.0"
},
Your template works for me.
How can I print the output of variables present in linked template?
Yes, this is possible. Just like your template.
Is there any way to print all the linked template deployment
parameters values in main template?
You could use Azure cli 2.0 to get linked parameter values.
az group deployment create --name shuitest1 --resource-group shuitest --template-file test.json --parameters '{"storageAccountName":{"value":"shuitest"}}'
{
"id": "/subscriptions/********/resourceGroups/shuitest/providers/Microsoft.Resources/deployments/shuitest1",
"name": "shuitest1",
"properties": {
"correlationId": "dbe16f35-0807-4627-b4b5-86c0a25c49ba",
"debugSetting": null,
"dependencies": [],
"mode": "Incremental",
"outputs": {
"vmlocation": {
"type": "Object",
"value": {
"type": "String",
"value": "centralus"
}
},
"vmpublicIPName": {
"type": "Object",
"value": {
"type": "String",
"value": "public-ip-test"
}
}
},
"parameters": {
"storageAccountName": {
"type": "String",
"value": "shuitest"
},
"storageAccountType": {
"type": "String",
"value": "Standard_LRS"
}
},
"parametersLink": null,
"providers": [
{
"id": null,
"namespace": "Microsoft.Storage",
"registrationState": null,
"resourceTypes": [
{
"aliases": null,
"apiVersions": null,
"locations": [
"centralus"
],
"properties": null,
"resourceType": "storageAccounts"
}
]
},
{
"id": null,
"namespace": "Microsoft.Resources",
"registrationState": null,
"resourceTypes": [
{
"aliases": null,
"apiVersions": null,
"locations": [
null
],
"properties": null,
"resourceType": "deployments"
}
]
}
],
"provisioningState": "Succeeded",
"template": null,
"templateLink": null,
"timestamp": "2017-04-19T02:09:55.064156+00:00"
},
"resourceGroup": "shuitest"
}
"someName": {
"type": "string",
"value": "[variables('somevar')]"
},
The same way you are outputting parameters.
No there is no way of doing that.
So what is the question, your template looks good. I've tested it and it works
ps. the link on your template is wrong, that's the only thing that doesn't work

Resources