There is ARM template for provisioning two Azure Search services
"resources": [
{
"type": "Microsoft.Search/searchServices",
"name": "[parameters('serviceName')]",
"apiVersion": "[parameters('serviceApiVersion')]",
"location": "[parameters('location')]",
"properties": {
"sku": {
"name": "[parameters('sku')]"
},
"replicaCount": 1,
"partitionCount": 1,
"hostingMode": "[parameters('hostingMode')]"
}
},
{
"type": "Microsoft.Search/searchServices",
"name": "[concat(parameters('serviceName'), 'secondary')]",
"apiVersion": "[parameters('serviceApiVersion')]",
"location": "[parameters('location')]",
"properties": {
"sku": {
"name": "[parameters('sku')]"
},
"replicaCount": 1,
"partitionCount": 1,
"hostingMode": "[parameters('hostingMode')]"
}
}]
Deployment of ARM Template provisions one search service and fails another with response:
{
"error": {
"code": "Unknown",
"message": "There was a conflicting update. No change was made to the resource from this request. RequestId: b65a51b5-cd87-4dc5-82d9-9041ddd1c2dc",
"target": null,
"details": null
}
}
Does anyone face issue like that?
Perhaps search services cannot be concurrently provisioned in the same resource group. Try adding a "dependsOn" property to the second search service.
The issue
The search services don't rely on another, so a dependsOn property wouldn't be required.
I think the problem is that your arm syntax is invalid.
I don't know which apiVersion you are using, but I cannot find any that has the same syntax...
(it resembles 2015-02-28 the most, but the hostingMode field is not allowed there).
Solution
Either use apiVersion 2015-02-28 without hostingmode or (if you need that field) use a newer apiVersion where "sku" is taken outside the "properties". The following works for me!
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.Search/searchServices",
"name": "parameters('serviceName')",
"apiVersion": "2015-08-19",
"location": "parameters('location')",
"properties": {
"replicaCount": 1,
"partitionCount": 1,
"hostingMode": "default"
},
"sku": {
"name": "basic"
}
},
{
"type": "Microsoft.Search/searchServices",
"name": "[concat(parameters('serviceName'), 'secondary')]"
"apiVersion": "2015-08-19",
"location": "parameters('location')",
"properties": {
"replicaCount": 1,
"partitionCount": 1,
"hostingMode": "default"
},
"sku": {
"name": "basic"
}
}]
}
Related
I am using output from a linked template in my ARM template for deployment below are my templates :
Link template :
"resources": [
{
"name": "[variables('clusterName')]",
"type": "Microsoft.Kusto/clusters",
"sku": {
"name": "Standard_D13_v2",
"tier": "Standard",
"capacity": 2
},
"apiVersion": "2020-09-18",
"location": "[parameters('location')]",
"properties": {
"trustedExternalTenants": [],
"optimizedAutoscale": {
"version": 1,
"isEnabled": true,
"minimum": 2,
"maximum": 10
},
"enableDiskEncryption": false,
"enableStreamingIngest": true,
"enablePurge": false,
"enableDoubleEncryption": false,
"engineType": "V3"
}
}
],
"outputs": {
"clusterNameResult": {
"type": "string",
"value": "[variables('clusterName')]"
}
}
Template using this linked template:
"resources": [
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2021-04-01",
"name": "linkedTemplate",
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(uri(deployment().properties.templateLink.uri, 'Dataexplorer_Deployment_Template.json'))]",
"contentVersion": "1.0.0.0"
}
},
"copy": {
"name": "databasecopy",
"count": "[length(parameters('databaseNameList'))]"
}
},
{
"type": "Microsoft.Kusto/Clusters/Databases",
"apiVersion": "2020-09-18",
"name": "[variables('databaseNameList').databaseNames[copyIndex()]]",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.Kusto/Clusters', reference('linkedTemplate').outputs['clusterNameResult'].value)]"
],
"kind": "ReadWrite",
"properties": {
"softDeletePeriod": "P5D",
"hotCachePeriod": "P1D"
},
"copy": {
"name": "databasecopy",
"count": "[length(parameters('databaseNameList'))]"
}
},
{
"type": "Microsoft.Kusto/Clusters/Databases/PrincipalAssignments",
"apiVersion": "2020-09-18",
"name": "[variables('databaseNameList').databaseNames[copyIndex()]]",
"dependsOn": [
"[resourceId('Microsoft.Kusto/Clusters/Databases', variables('databaseNameList').databaseNames[copyIndex()])]",
"[resourceId('Microsoft.Kusto/Clusters', reference('linkedTemplate').outputs['clusterNameResult'].value)]"
],
"properties": {
"principalId": "abc.def#gmail.com",
"role": "Viewer",
"principalType": "User",
"tenantId": "523547f7-9d12-45c5-9g15-2ysb44a3r2m4"
},
"copy": {
"name": "databasecopy",
"count": "[length(parameters('databaseNameList'))]"
}
}
]
I am refering to the cluster name deployed through template 1 in template 2 , specified at "dependsOn" but it fails with error The template resource 'adx-jtcjiot-dev-sea-adxdb001' at line '84' and column '9' is not valid: The template function 'reference' is not expected at this location.
Has anyone used reference functions for deployment like this, I want to keep cluster and database deployment separately as database creation might occur often at the same time i don't want to hardcode the clustername in the database template. Is there any other way to do it or to resolve this error.
Thanks in advance!
I'm not sure I understand why you want to keep those separate in the first place.
What about simply putting them together as in the example here: https://learn.microsoft.com/en-us/azure/data-explorer/automated-deploy-overview#step-3-create-an-arm-template-to-deploy-the-cluster?
Ultimately, dependsOn doesn't accept reference functions as appeared in the error message. My second thought was to find out resource name using resourceID function, but apparently that's not supported. So, instead I have defined the server name in variables and used it for database "name field"
Because you're depending on a resource being deployed in the same deployment, you don't need to define a resource id, or use a reference. You can just use the name of the resource deployment (as defined in the arm template), like this:
{
"type": "Microsoft.Resources/deployments",
"name": "linkedTemplate",
etc
},
{
"type": "Microsoft.Kusto/Clusters/Databases",
etc
"dependsOn": [
"linkedTemplate"
]
}
That will ensure that the deployment of the database will not start until the deployment of the Kusto cluster has been completed.
I am attempting to deploy an Azure Firewall with a Policy, a Rule and a set of IPGroups. When I deploy the ARM templates to start everything works.. Later If I want to change something in one of the IPGroups, and I try to deploy that IPGroup change, the Azure Deployment fails with a Status: Conflict with message:
{
"status": "Failed",
"error": {
"code": "ResourceDeploymentFailure",
"message": "The resource operation completed with terminal provisioning state 'Failed'."
}
}
I've attempted to both manage the IPGroups distinctly in their own ARM Template, and place them in with the Azure Policy Rule Collection ARM Template with a DependsOn to see if deploying them all together would help, but either way we just get "Conflict".. I Guess I am wondering what is the appropriate way to update an IPGroup that is a part of a Firewall Network rule? If I can't simply update the IPGroup?
Here is an example of my full ARM Template for my Policy with the IPGroups..
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"firewallPolicyName": {
"defaultValue": "[concat('onelucki-fw-parent-policy', uniqueString(resourceGroup().id))]",
"type": "String"
},
"DevSubnets": {
"defaultValue": "DevSubnets",
"type": "String"
},
"AzureSubnets": {
"defaultValue": "AzureSubnets",
"type": "String"
}
},
"variables": {
"fwPolicyName": "[parameters('firewallPolicyName')]"
},
"resources": [
{
"type": "Microsoft.Network/ipGroups",
"apiVersion": "2020-05-01",
"name": "AzureSubnets",
"location": "centralus",
"tags": { "Zone": "MixedZones" },
"properties": {
"ipAddresses": [
"10.99.1.1"
]
}
},
{
"type": "Microsoft.Network/ipGroups",
"apiVersion": "2020-05-01",
"name": "DevSubnets",
"location": "centralus",
"tags": { "Zone": "Dev" },
"properties": {
"ipAddresses": [
"10.99.2.2"
]
}
},
{
"type": "Microsoft.Network/firewallPolicies",
"apiVersion": "2020-11-01",
"name": "[parameters('firewallPolicyName')]",
"location": "centralus",
"properties": {
"sku": {
"tier": "Standard"
},
"threatIntelMode": "Alert"
}
},
{
"type": "Microsoft.Network/firewallPolicies/ruleCollectionGroups",
"apiVersion": "2020-11-01",
"name": "[concat(parameters('firewallPolicyName'), '/DefaultNetworkRuleCollectionGroup')]",
"location": "westus",
"dependsOn": [
"[resourceId('Microsoft.Network/ipGroups', parameters('AzureSubnets'))]",
"[resourceId('Microsoft.Network/ipGroups', parameters('DevSubnets'))]",
"[resourceId('Microsoft.Network/firewallPolicies', parameters('firewallPolicyName'))]"
],
"properties": {
"priority": 200,
"ruleCollections": [
{
"ruleCollectionType": "FirewallPolicyFilterRuleCollection",
"action": {
"type": "Allow"
},
"rules": [
{
"ruleType": "NetworkRule",
"name": "DemoRule",
"ipProtocols": [
"TCP"
],
"sourceAddresses": [],
"sourceIpGroups": [
"/subscriptions/<subscriptionIDHere>/resourceGroups/onelucki-fw/providers/Microsoft.Network/ipGroups/DevSubnets"
],
"destinationAddresses": [],
"destinationIpGroups": [
"/subscriptions/<subscriptionIDHere>/resourceGroups/onelucki-fw/providers/Microsoft.Network/ipGroups/AzureSubnets"
],
"destinationFqdns": [],
"destinationPorts": [
"135",
"445"
]
}
],
"name": "DemoDeployRuleCollection",
"priority": 1300
}
]
}
}
]
}
IP groups need to be deployed one at a time. Also the firewall policy needs a depends on the IP groups being used despite it not having them listed.
The deploy of the IP groups seems to do some validation/update on the firewall policy during deploy.
Deploy nested resources in Azure using DependsOn
I am trying to deploy app services but I keep getting deployment failure Microsoft.Web/sites/hostNameBindings
Message: Cannot modify this site because another operation is in progress. OperationName: RegisterTrafficManagerProfile, CreatedTime: 5/14/2021 12:03:05 AM, , EntityType: 1.
I get this error intermittently.
I read one of the stack overflow answers that it seems Traffic Manager causes a problem with the asynchronous hostNameBindings iteration operation.
Which can be resolved by specifying a synchronous copy using "mode": "serial" mode with "batchsize": 1,
I tried this solution but I still get this conflict error, not sure why? anyone ran into same issue where after synchronising the copy getting above error?
Recently we had changes to our template to deploy traffic manager endpoints as separate resource which caused the process to take longer, Does increase in process time can cause conflict? what can be other reasons for this failure?
Any insights into this will be helpful. I am quite new to working on app service arm template
EDIT My current arm template I am just showing hostname bindings and traffic manager profiles
{
"type": "Microsoft.Web/sites/hostNameBindings",
"apiVersion": "2016-03-01",
"copy": {
"name": "hostNameBindingLoop",
"mode": "serial",
"batchSize": 1,
"count": "[length(variables('appServicePlanLocations'))]"
},
"name": "[concat(variables('websiteName') [copyIndex()], '/', parameters('cName'))]",
"location": "[vaiables('appServicePlanLocations')[copyIndex()]]",
"properties": {
"sslState": "SniEnabled",
"thumbprint": "[reference(resourceId('Microsoft.Web/certificates', variables('xyzCertName')[copyIndex()])).Thumbprint]"
},
"dependsOn": [
"[concat('Microsoft.Web/certificates/',variables('xyzCertName'[copyIndex()])]",
],
},
{
"type": "Microsoft.Network/trafficManagerProfiles",
"apiVersion": "2018-08-01",
"name": "[parameters('trafficManagerName')]",
"location": "global",
"properties": {
"profileStatus": "Enabled",
"trafficRoutingMethod": "Performance",
"dnsConfig": {
"relativeName": "[parameters('uniqueDnsName')]",
"ttl": 300
},
"monitorConfig": {
"protocol": "HTTPS",
"port": 443,
"path": "/"
}
"endpoints": [],
"trafficViewEnrollmentStatus": "Disabled
}
},
{
"type": "Microsoft.Network/trafficManagerProfiles/azureEndpoints",
"apiVersion": "2018-08-01",
"name": "[concat(variables('trafficManager'),'/',variables('websiteName'), copyIndex(1))]",
"location": "global",
"dependsOn": [
"[concat('Microsoft.Network/trafficManagerProfiles/', variables('trafficManager'))]"
],
"properties": {
"targetResourceId": "[concat('Microsoft.Web/sites/',variables('websiteName')[copyIndex()])]",'
"endpointStatus": "Enabled",
"endpointLocation": "[vaiables('appServicePlanLocations')[copyIndex()]]"
},
"copy": {
"name": "trafficManagerEndPointLoop",
"mode": "serial",
"batchSize": 1,
"count": "[length(variables('appServicePlanLocations'))]"
}
}
I assume that you would like to create an Azure Traffic Manager profile with an App Service Behind It. Here is a template for your reference. This automatically provisions a custom domain xxxx.trafficmanager.net in the custom domains settings of your Azure app service.
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"uniqueDnsName": {
"type": "string",
"metadata": {
"description": "Relative DNS name for the traffic manager profile, resulting FQDN will be <uniqueDnsName>.trafficmanager.net, must be globally unique."
}
},
"uniqueDnsNameForWebApp": {
"type": "string",
"metadata": {
"description": "Relative DNS name for the WebApps, must be globally unique. An index will be appended for each Web App."
}
},
"webServerName": {
"type": "string",
"metadata": {
"description": "Name of the App Service Plan that is being created"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]"
},
"trafficManagerName": {
"type": "string",
"metadata": {
"description": "Name of the trafficManager being created"
}
}
},
"variables": {},
"resources": [
{
"type": "Microsoft.Web/serverfarms",
"apiVersion": "2019-08-01",
"name": "[parameters('webServerName')]",
"location": "[parameters('location')]",
"sku": {
"name": "S1",
"tier": "Standard"
}
},
{
"type": "Microsoft.Web/sites",
"apiVersion": "2019-08-01",
"name": "[parameters('uniqueDnsNameForWebApp')]",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms/',parameters('webServerName'))]"
],
"properties": {
"serverFarmId": "[parameters('webServerName')]"
}
},
{
"type": "Microsoft.Network/trafficManagerProfiles",
"apiVersion": "2018-08-01",
"name": "[parameters('trafficManagerName')]",
"location": "global",
"properties": {
"profileStatus": "Enabled",
"trafficRoutingMethod": "Priority",
"dnsConfig": {
"relativeName": "[parameters('uniqueDnsName')]",
"ttl": 30
},
"monitorConfig": {
"protocol": "HTTPS",
"port": 443,
"path": "/"
}
}
},
{
"type": "Microsoft.Network/trafficManagerProfiles/azureEndpoints",
"apiVersion": "2018-08-01",
"name": "[concat(parameters('trafficManagerName'),'/',parameters('uniqueDnsNameForWebApp'))]",
"location": "global",
"dependsOn": [
"[resourceId('Microsoft.Network/trafficManagerProfiles/',parameters('trafficManagerName'))]",
"[resourceId('Microsoft.Web/sites/',parameters('uniqueDnsNameForWebApp'))]"
],
"properties": {
"targetResourceId": "[resourceId('Microsoft.Web/sites/', parameters('uniqueDnsNameForWebApp'))]",
"endpointStatus": "Enabled"
}
}
]
}
I have an ARM template which conditionally creates a resource:
{
"type": "Microsoft.Storage/storageAccounts",
"sku": {
"name": "Standard_GRS",
"tier": "Standard"
},
"kind": "BlobStorage",
"name": "[variables('storageAccounts_name')]",
"condition": "[equals(parameters('is_Not_Development'), 'True')]",
"apiVersion": "2017-06-01",
"location": "[resourceGroup().location]",
"scale": null,
"properties": {
"accessTier": "Hot"
},
"dependsOn": []
},
In my output parameters I have the following which causes an error if the resource is not created:
"storageAccountConnectionString": {
"type": "string",
"value": "[Concat('DefaultEndpointsProtocol=https;AccountName=',variables('StorageAccounts_name'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('StorageAccounts_name')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value)]"
},
I have tried this:
"storageAccountConnectionString": {
"type": "string",
"condition": "[equals(parameters('is_Not_Development'), 'True')]",
"value": "[Concat('DefaultEndpointsProtocol=https;AccountName=',variables('StorageAccounts_name'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('StorageAccounts_name')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value)]"
},
with the condition clause but this is not recognised. How can I make the output parameter conditional?
UPDATE:
I have tried the following:
"storageAccountConnectionString": {
"type": "string",
"value": "[if(equals(parameters('is_Not_Development'),'False'),'null',Concat('DefaultEndpointsProtocol=https;AccountName=',variables('StorageAccounts_name'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('StorageAccounts_name')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value))]"
},
but it gives me the same error message, it must be evaluating both true and false conditions.
There is a trick to solve this issue and we use it successfully.
Let's see for example how the following template returns a value only if the corresponding resource has been deployed.
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"appInsightsLocation": {
"type": "string",
"defaultValue": "",
"allowedValues": [
"",
"northeurope",
"westeurope"
]
}
},
"variables": {
"appInsightsName": "exampleAppInsights",
"planName": "example-plan",
"appInsightsEnabled": "[if(greater(length(parameters('appInsightsLocation')), 0), 'true', 'false')]",
"appInsightsOrPlanResource": "[if(bool(variables('appInsightsEnabled')), concat('Microsoft.Insights/components/', variables('appInsightsName')), concat('Microsoft.Web/serverFarms/', variables('planName')))]",
"appInsightsKeyOrPlanName": "[if(bool(variables('appInsightsEnabled')), 'InstrumentationKey', 'name')]"
},
"resources": [
{
"comments": "The example service plan",
"apiVersion": "2015-08-01",
"type": "Microsoft.Web/serverfarms",
"location": "[resourceGroup().location]",
"name": "[variables('planName')]",
"sku": {
"name": "B1",
"capacity": 1
},
"properties": {
"numberOfWorkers": 1,
"name": "[variables('planName')]"
}
},
{
"comments": "The application insights instance",
"apiVersion": "2014-04-01",
"condition": "[bool(variables('appInsightsEnabled'))]",
"type": "Microsoft.Insights/components",
"location": "[parameters('appInsightsLocation')]",
"name": "[variables('appInsightsName')]",
"properties": {}
}
],
"outputs": {
"appInsightsKey": {
"value": "[if(bool(variables('appInsightsEnabled')), reference(variables('appInsightsOrPlanResource'))[variables('appInsightsKeyOrPlanName')], '')]",
"type": "string"
}
}
The template declares two resources. One app service plan and one Application Insights instance. The AppInsights instance is deployed only if the location parameter is not empty string. So the instrumentation key of this instance is also returned only if it has been created.
To achieve this we also need a resource that is always present. In our case this is the service plan. We use this resource to get the reference when AppInsights is not deployed. This could be any azure resource of course.
The trick happens on the two variables appInsightsOrPlanResource and appInsightsKeyOrPlanName we declare. When appInsightsLocation is provided then those two variables end up referencing the key of the instance which is returned from the output.
When appInsightsLocation is not provided on the other hand those two variables contain a valid reference to the service plan that is not used but it's valid. We need to do this one because if function evaluates always both sides. An empty string is returned from the output in this case though.
I know this is an old question, but in case anyone arrives here, it looks like MSFT has fixed this in two ways now.
In Feb 2019 they fixed the 'if' evaluation to only evaluate the true side.
https://feedback.azure.com/forums/281804-azure-resource-manager/suggestions/31538470-arm-template-if-function-should-not-evaluate-both
In August 2019 they added support for condition: in the outputs.
https://feedback.azure.com/forums/281804-azure-resource-manager/suggestions/19492006-conditional-output-from-arm-template
https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-authoring-templates#outputs
Looks like as long as you're at Azure CLI version 2.0.72 you'll have access to these changes. I just tested both on 2.0.76 and they appear to work.
I'm trying to provision the following API Management via ARM, with the following template (note specifically the apiVersion date of 2016-07-07). This results in the error:
Invalid parameter: Value cannot be null.\r\nParameter name: skuproperties
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"apimSettings": {
"type": "object",
"defaultValue": {
"sku": "Developer",
"skuCount": "1",
"publisherName": "",
"publisherEmail": ""
}
}
},
"variables": {
"apiManagementServiceName": "[concat('apim', uniqueString(resourceGroup().id))]"
},
"resources": [{
"apiVersion": "2016-07-07",
"name": "[variables('apiManagementServiceName')]",
"type": "Microsoft.ApiManagement/service",
"location": "[resourceGroup().location]",
"properties": {
"sku": {
"name": "[parameters('apimSettings').sku]",
"capacity": "[parameters('apimSettings').skuCount]"
},
"publisherEmail": "[parameters('apimSettings').publisherEmail]",
"publisherName": "[parameters('apimSettings').publisherName]"
}
}],
"outputs": {
"apimUri" : {
"type": "object",
"value": "[reference(variables('apiManagementServiceName'))]"
}
}
}
The schema for that version of API Management doesn't show 'skuProperties'. Note, the deployment works if I use the old version 2014-02-14. I also noted that the deployment template schema refers to the newer API Management schema.
Clearly it wants "skuproperties" but how would I know what to provide there?
this is how you use it:
{
"type": "Microsoft.ApiManagement/service",
"sku": {
"name": "Developer",
"capacity": 1
},
"name": "[parameters('name')]",
"apiVersion": "2016-10-10",
"location": "[parameters('location')]",
"properties": {
"publisherEmail": "[parameters('adminEmail')]",
"publisherName": "[parameters('orgName')]"
}
}
This is the description of the API Management API model. As you can see it uses 2016-10-10 and the object similar to what I've described. That's why its working that way.