I am trying to modify an ARM template that I have which deploys some VMs and defines some autoscale rules (you can see the full template at https://gist.github.com/jinky32/d80e0ab2137236ff262484193f93c946, it is based on the template at https://github.com/gbowerman/azure-myriad/tree/master/vmss-ubuntu-scale).
I am trying to add in some load balancer rules so that traffic is spread across the new VMs as they are generated in reponse to the autoscale rules that are defined.
When I run this template via Azure CLI I get no errors in terminal but the deployment fails. Digging into the error events I see two:
statusCode:BadRequest serviceRequestId:ef42ec66-600e-4fb9-b4e2-dc2c06dda79c statusMessage:{"error":{"code":"InvalidRequestFormat","message":"Cannot parse the request.","details":[{"code":"InvalidJsonReferenceFormat","message":"Reference Id cc2bepool is not formatted correctly. The Id is expected to reference resources of type loadBalancers/backendAddressPools. Path properties.loadBalancingRules[0].properties.backendAddressPool."}]}} responseBody:{"error":{"code":"InvalidRequestFormat","message":"Cannot parse the request.","details":[{"code":"InvalidJsonReferenceFormat","message":"Reference Id cc2bepool is not formatted correctly. The Id is expected to reference resources of type loadBalancers/backendAddressPools. Path properties.loadBalancingRules[0].properties.backendAddressPool."}]}}
and
statusCode:BadRequest statusMessage:{"error":{"code":"InvalidRequestFormat","message":"Cannot parse the request.","details":[{"code":"InvalidJsonReferenceFormat","message":"Reference Id cc2bepool is not formatted correctly. The Id is expected to reference resources of type loadBalancers/backendAddressPools. Path properties.loadBalancingRules[0].properties.backendAddressPool."}]}}
I've put some of the relevant variables below and have also included my loadbalancer object but I believe that the issue is related to how I am referencing backendAddressPool:
"loadBalancingRules": [
{
"name": "LBRule",
"properties": {
"frontendIPConfiguration": {
"id": "[variables('frontEndIPConfigID')]"
},
"backendAddressPool": {
"id": "[variables('bePoolName')]"
},
but I'm confused because I refer to it the same way elsewhere. Any advice on how to do this correctly much appreciated.
"variables": {
....
"loadBalancerName": "[concat(parameters('vmssName'), 'lb')]",
"lbProbeID": "[concat(variables('lbID'),'/probes/tcpProbe')]",
"publicIPAddressID": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]",
"lbID": "[resourceId('Microsoft.Network/loadBalancers',variables('loadBalancerName'))]",
"natPoolName": "[concat(parameters('vmssName'), 'natpool')]",
"bePoolName": "[concat(parameters('vmssName'), 'bepool')]",
....
....
}
.....
.....
{
"type": "Microsoft.Network/loadBalancers",
"name": "[variables('loadBalancerName')]",
"location": "[variables('location')]",
"apiVersion": "[variables('networkApiVersion')]",
"dependsOn": [
"[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]"
],
"properties": {
"frontendIPConfigurations": [
....
],
"backendAddressPools": [
{
"name": "[variables('bePoolName')]"
}
],
"inboundNatPools": [
{
"name": "[variables('natPoolName')]",
...
},
{
"name": "natpooltileserver",
....
},
{
"name": "natpool2",
....
],
"loadBalancingRules": [
{
"name": "LBRule",
"properties": {
"frontendIPConfiguration": {
"id": "[variables('frontEndIPConfigID')]"
},
"backendAddressPool": {
"id": "[variables('bePoolName')]"
},
"protocol": "tcp",
"frontendPort": 80,
"backendPort": 80,
"enableFloatingIP": false,
"idleTimeoutInMinutes": 5,
"probe": {
"id": "[variables('lbProbeID')]"
}
}
}
],
"probes": [
{
"name": "tcpProbe",
"properties": {
"protocol": "tcp",
"port": 80,
"intervalInSeconds": 5,
"numberOfProbes": 2
}
}
]
}
},
please go to the portal and open a support request to see what's wrong with your template edits.
Related
I'm deploying an application gateway with ARM Template and wants to loop through the creation of listeners.
This is how far I got:
"copy": [
{
"name": "httpListeners",
"count": "[length(parameters('APPLICATIONS'))]",
"input": {
"name": "[concat(parameters('APPLICATIONS')[copyIndex('httpListeners')].site,'-',parameters('APPLICATIONS')[copyIndex('httpListeners')].protocol,'listener')]",
"properties": {
"FrontendIPConfiguration": {
"Id": "[concat(variables('applicationGatewayID'), '/frontendIPConfigurations/', variables('frontendIpConfigName'))]"
},
"FrontendPort": {
"Id": "[concat(variables('applicationGatewayID'), '/frontendPorts/', variables('frontendPortName443'))]"
},
"Protocol": "[parameters('APPLICATIONS')[copyIndex('httpListeners')].protocol]",
"SslCertificate": {
"Id": "[parameters('APPLICATIONS')[copyIndex('httpListeners')].cert]"
},
"HostName": "[parameters('APPLICATIONS')[copyIndex('httpListeners')].site]",
"RequireServerNameIndication": "[if(equals(parameters('APPLICATIONS')[copyIndex('httpListeners')].protocol, 'HTTPS'), json('true'), json('false'))]"
}
}
}
]
It works well as long as I only create HTTPS listeners, but when I create a HTTP listener I want to get rid of this part:
"SslCertificate": {
"Id": "[parameters('APPLICATIONS')[copyIndex('httpListeners')].cert]"
}
Just setting the parameter parameters('APPLICATIONS')[copyIndex('httpListeners')].cert to null doesn't help.
Any suggestions?
I started Infrastructure as Code with ARM Template and previously all my deployment was made with Powershell. Hope you can help me to fix this issue.
I would like to deploy {2 app services + Azure FrontDoor]. In FrontDoor-Backendpool I want to define the 2 appservices. Below my code:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"location": {
"type": "array",
"metadata": {
"description": "array of region"
},
"defaultValue": [
"centralus",
"eastus"
]
},
"Stage": {
"type": "string",
"metadata": {
"description": "Stage dev, prod"
},
"allowedValues": [
"Dev",
"Prod"
],
"defaultValue": "Dev"
}
},
"functions": [],
"variables": {
"appServicePlanName": "[concat('AppServicePlan-', parameters('Stage'),'-')]",
"appServiceName": "[concat('AppService-', parameters('Stage'), '-')]",
"frontDoorName": "[concat('FrontDoor-', parameters('Stage'), uniqueString(resourceGroup().id))]"
},
"resources": [
{ // App Service Plan
"type": "Microsoft.Web/serverfarms",
"name": "[concat(variables('appServicePlanName'),parameters('location')[copyIndex()])]",
"apiVersion": "2018-02-01",
"copy": {
"count": "[length(parameters('location'))]",
"name": "copy multiple"
},
"location": "[parameters('location')[copyIndex()]]",
"sku": {
"name": "F1",
"capacity": 1
},
"tags": {
"cost": "[parameters('Stage')]"
},
"properties": {
"name": "[concat(variables('appServicePlanName'),parameters('location')[copyIndex()])]"
}
},
{ // App Services
"type": "Microsoft.Web/sites",
"name": "[concat(variables('appServiceName'), parameters('location')[copyIndex()])]",
"apiVersion": "2018-11-01",
"copy": {
"name": "Copy website",
"count": "[length(parameters('location'))]"
},
"location": "[parameters('location')[copyIndex()]]",
"tags": {
"cost": "[parameters('Stage')]"
},
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', concat(variables('appServicePlanName'),parameters('location')[copyIndex()]))]"
],
"properties": {
"name": "[concat(variables('appServiceName'), parameters('location')[copyIndex()])]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', concat(variables('appServicePlanName'),parameters('location')[copyIndex()]))]"
}
},
{ // Front Door
"type": "Microsoft.Network/frontDoors",
"apiVersion": "2020-05-01",
"name": "[variables('frontDoorName')]",
"location": "global",
"properties": {
"routingRules": [
{
"name": "routingRule1",
"properties": {
"frontendEndpoints": [
{
"id": "[resourceId('Microsoft.Network/frontDoors/frontendEndpoints', variables('frontDoorName'), 'frontendEndpoint1')]"
}
],
"acceptedProtocols": [
"Http",
"Https"
],
"patternsToMatch": [
"/*"
],
"routeConfiguration": {
"#odata.type": "#Microsoft.Azure.FrontDoor.Models.FrontdoorForwardingConfiguration",
"forwardingProtocol": "MatchRequest",
"backendPool": {
"id": "[resourceId('Microsoft.Network/frontDoors/backendPools', variables('frontDoorName'), 'backendPool1')]"
}
},
"enabledState": "Enabled"
}
}
],
"healthProbeSettings": [
{
"name": "healthProbeSettings1",
"properties": {
"path": "/",
"protocol": "Http",
"intervalInSeconds": 120
}
}
],
"loadBalancingSettings": [
{
"name": "loadBalancingSettings1",
"properties": {
"sampleSize": 4,
"successfulSamplesRequired": 2
}
}
],
"backendPools": [
{
"id": "backendPool1",
"name": "backendPool1",
"properties": {
"copy": [
{
"name": "backends",
"count": "[length(parameters('location'))]",
"input": {
"address": "[concat(variables('appServiceName'), parameters('location')[copyIndex()], '.azurewebsites.net') ]",
"httpPort": 80,
"httpsPort": 443,
"weight": 50,
"priority": 1,
"enabledState": "Enabled"
}
}
],
"loadBalancingSettings": {
"id": "[resourceId('Microsoft.Network/frontDoors/loadBalancingSettings', variables('frontDoorName'), 'loadBalancingSettings1')]"
},
"healthProbeSettings": {
"id": "[resourceId('Microsoft.Network/frontDoors/healthProbeSettings', variables('frontDoorName'), 'healthProbeSettings1')]"
}
}
}
],
"frontendEndpoints": [
{
"name": "frontendEndpoint1",
"properties": {
"hostName": "[concat(variables('frontDoorName'), '.azurefd.net')]",
"sessionAffinityEnabledState": "Enabled"
}
}
],
"enabledState": "Enabled"
}
}
],
"outputs": {}
}
As you can see i iterate on paramater location to create my AppService Plan and AppService and it worked well. So I thought to do same for BackEndpool.
Here part of code which break my head
address": "[concat(variables('appServiceName'), parameters('location')[copyIndex()], '.azurewebsites.net') ]",
Something is wrong inside but I have no idea why.
Error retuned is:
Error: Code=InvalidTemplate; Message=Deployment template language expression evaluation
failed: 'The template language function 'copyIndex' has an invalid argument. The provided copy name '' doesn't exist in the resource.
Please see https://aka.ms/arm-copy for usage details.'. Please see https://aka.ms/arm-template-expressions for usage details.
I take my inspiration from official MS documentation link from MS
Any idea on how I can fix it ?
Thx
You need to include the copy name property in the call to copyIndex in the backendPools part. That is why is says "The provided copy name '' doesn't exist". The property copy is treated a little differently than the resource copy.
"The loopName property enables you to specify whether copyIndex is referring to a resource iteration or property iteration. If no value is provided for loopName, the current resource type iteration is used. Provide a value for loopName when iterating on a property."
Source: https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/template-functions-numeric#copyindex
parameters('location')[copyIndex('backends')]
I'm creating an ARM template that has rules for FTP traffic. I'd like to use the copy command within the probes property of the load balancer to create probes for a range of ports, but I also have other probes that do not need to be repeated (fall outside of the copy). When I try to add both, the ARM template says it's invalid because the probes property is already present. Is it possible to use the "copy" syntax in addition to other value or must the "copy" be the only ARM syntax that builds the entire list of array values?
{
"type": "Microsoft.Network/loadBalancers",
"sku": {
"name": "Standard",
"tier": "Regional"
},
"name": "[variables('lb-csl-private.name')]",
"apiVersion": "2018-10-01",
"location": "[resourceGroup().location]",
"scale": null,
"properties": {
"frontendIPConfigurations": [
{
"name": "LoadBalancerFrontEnd",
"properties": {
"privateIPAddress": "[variables('ip-lb-csl-private')]",
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('vnet-csl.name'), variables('vnet-csl.subnets.loadBalancerName'))]"
}
}
}
],
"copy": [
{
"name": "probes",
"count": 10,
"input": {
"name": "[concat('probe-CSL-PASV-', copyIndex('probes'))]",
"properties": {
"protocol": "Tcp",
"port": "[copyIndex('probes')]",
"inervalInSeconds": 5,
"numberOfProbes": 2
}
}
}
],
"probes": [
{
"name": "probe-CSL-FTP",
"properties": {
"protocol": "Tcp",
"port": 21,
"intervalInSeconds": 5,
"numberOfProbes": 2
}
}
],
"inboundNatRules": [],
"outboundRules": [],
"inboundNatPools": []
}
}
it is possible to do that using variables:
"variables": {
"copy": [
{
"name": "probes",
"count": 10,
"input": {
"name": "[concat('probe-CSL-PASV-', copyIndex('probes'))]",
"properties": {
"protocol": "Tcp",
"port": "[copyIndex('probes')]",
"inervalInSeconds": 5,
"numberOfProbes": 2
}
}
}
],
"otherProbes": [
{
probe1
},
{
probe2
},
etc
]
}
and then, in your load balancer:
"probes": "[concat(variables('probes'), variables('otherProbes'))]"
I want to create 2 edge nodes in HDI cluster using ARM template. I need to have Edge node 2 is depends on Edge node 1
Here is my ARM template for Edge node:-
{
"name": "[concat(parameters('clusterName'),'/', parameters('TestEdgenodeName1'))]",
"type": "Microsoft.HDInsight/clusters/applications",
"apiVersion": "2015-03-01-preview",
"dependsOn": [
"[concat('Microsoft.HDInsight/clusters/', parameters('clusterName'))]"
],
"properties": {
"marketPlaceIdentifier": "TestEdgeNode1",
"computeProfile": {
"roles": [{
"name": "edgenode",
"targetInstanceCount": 1,
"hardwareProfile": {
"vmSize": "[parameters('EdgenodeSize1')]"
}
}]
},
"installScriptActions": [{
"name": "[concat('node','-' ,uniquestring(parameters('TestEdgenodeName1')))]",
"uri": "[variables('InstallationScript1')]",
"parameters": "",
"roles": ["edgenode"]
}],
"uninstallScriptActions": [],
"httpsEndpoints": [],
"applicationType": "CustomApplication"
}
}
"name": "[concat(parameters('clusterName'),'/', parameters('TestEdgenodeName2'))]",
"type": "Microsoft.HDInsight/clusters/applications",
"apiVersion": "2015-03-01-preview",
"dependsOn": [
"[concat('Microsoft.HDInsight/clusters/applications/', parameters('clusterName'), '/', parameters('TestEdgenodeName1'))]"
],
"properties": {
"marketPlaceIdentifier": "TestEdgeNode2",
"computeProfile": {
"roles": [{
"name": "edgenode",
"targetInstanceCount": 1,
"hardwareProfile": {
"vmSize": "[parameters('EdgenodeSize2')]"
}
}]
},
"installScriptActions": [{
"name": "[concat('node','-' ,uniquestring(parameters('TestEdgenodeName2')))]",
"uri": "[variables('installationScript2')]",
"parameters": "",
"roles": ["edgenode"]
}],
"uninstallScriptActions": [],
"httpsEndpoints": [],
"applicationType": "CustomApplication"
}
}
I am getting the below error when deploying ARM template.
InvalidTemplate : Deployment template validation failed: 'The resource 'Microsoft.HDInsight/clusters/applications/test-cluster/test-edgenode' is not defined in the template.
HDInsight supports single edge node at this time.
I am able to solve the issue by using the below on second edge node.
"dependsOn": [
"[resourceId('Microsoft.HDInsight/clusters/applications', parameters('clusterName'), parameters('TestEdgenodeName1'))]"
],
I have an ARM template where I set up a load balancer and I want to add a number of port openings by adding rules and probes to the LB.
This is the template I have so far:
{
"type": "Microsoft.Network/loadBalancers",
"name": "LB-front",
"apiVersion": "2016-03-30",
"location": "westeurope",
"tags": { },
"properties": {
"frontendIPConfigurations": [
{
"name": "LoadBalancerIPConfig",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddresses_lbipdev_0_name'))]"
}
}
}
],
"backendAddressPools": [
{
"name": "LoadBalancerBEAddressPool"
}
],
"loadBalancingRules": [
{
"name": "AppPortLBRule1",
"properties": {
"frontendIPConfiguration": {
"id": "[parameters('loadBalancers_LB_dev_id_6')]"
},
"frontendPort": 80,
"backendPort": 80,
"enableFloatingIP": false,
"idleTimeoutInMinutes": 5,
"protocol": "Tcp",
"loadDistribution": "Default",
"backendAddressPool": {
"id": "[parameters('loadBalancers_LB_dev_id_7')]"
},
"probe": {
"id": "[parameters('loadBalancers_LB_dev_id_8')]"
}
}
},
{
"name": "AppPortLBRule2",
"properties": {
"frontendIPConfiguration": {
"id": "[parameters('loadBalancers_LB_dev_id_9')]"
},
"frontendPort": 81,
"backendPort": 81,
"enableFloatingIP": false,
"idleTimeoutInMinutes": 5,
"protocol": "Tcp",
"loadDistribution": "Default",
"backendAddressPool": {
"id": "[parameters('loadBalancers_LB_dev_id_10')]"
},
"probe": {
"id": "[parameters('loadBalancers_LB_dev_id_11')]"
}
}
},
{
"name": "AppPortLBRule3",
"properties": {
"frontendIPConfiguration": {
"id": "[parameters('loadBalancers_LB_dev_id_12')]"
},
"frontendPort": 82,
"backendPort": 82,
"enableFloatingIP": false,
"idleTimeoutInMinutes": 5,
"protocol": "Tcp",
"loadDistribution": "Default",
"backendAddressPool": {
"id": "[parameters('loadBalancers_LB_dev_id_13')]"
},
"probe": {
"id": "[parameters('loadBalancers_LB_dev_id_14')]"
}
}
}
],
"probes": [
{
"name": "AppPortProbe1",
"properties": {
"protocol": "Tcp",
"port": 80,
"intervalInSeconds": 5,
"numberOfProbes": 2
}
},
{
"name": "AppPortProbe2",
"properties": {
"protocol": "Tcp",
"port": 81,
"intervalInSeconds": 5,
"numberOfProbes": 2
}
},
{
"name": "AppPortProbe3",
"properties": {
"protocol": "Tcp",
"port": 82,
"intervalInSeconds": 5,
"numberOfProbes": 2
}
}
],
"inboundNatRules": [],
"outboundNatRules": [],
"inboundNatPools": []
},
"resources": [],
"dependsOn": [
"[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddresses_lbipdev_1_name'))]"
]
},
(some details omitted)
What I would like to do is to have an array of the port numbers I want to create rules and probes for and loop over those instead of explicitly having to write each rule and probe as a property for the resource.
Basically I would like a parameter or variable in my template like this:
"ports": [ 80, 81, 82, ...]
and that I could loop over this similar to this: https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-multiple.
Indeed you can! Copy does work with properties!
Create a parameter or variable like this (this example will use parameter array):
"lbRules": {
"type": "array",
"defaultValue": [
{
"name": "httpPort",
"frontendPort": "80",
"backendPort": "80",
"protocol": "tcp"
},
{
"name": "customAppPort",
"frontendPort": "8080",
"backendPort": "8888",
"protocol": "tcp"
},
{
"name": "httpsPort",
"frontendPort": "443",
"backendPort": "443",
"protocol": "tcp"
}
]
}
Use this parameter in the Loadbalancer resource using copy like this that will create that many probes and rules that you defined in your parameter array:
{
"apiVersion": "[variables('lbApiVersion')]",
"type": "Microsoft.Network/loadBalancers",
"name": "[parameters('myLoadBalancer')]",
"location": "[parameters('computeLocation')]",
"dependsOn": [
"[concat('Microsoft.Network/publicIPAddresses/',concat(parameters('lbIPName'),'-','0'))]"
],
"properties": {
"frontendIPConfigurations": [
{
"name": "LoadBalancerIPConfig",
"properties": {
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses',concat(parameters('lbIPName'),'-','0'))]"
}
}
}
],
"backendAddressPools": [
{
"name": "LoadBalancerBEAddressPool",
"properties": {}
}
],
"copy": [
{
"name": "probes",
"count": "[length(parameters('lbRules'))]",
"input": {
"name": "[concat(parameters('lbRules')[copyIndex('probes')].name,'Probe')]",
"properties": {
"intervalInSeconds": 5,
"numberOfProbes": 2,
"port": "[parameters('lbRules')[copyIndex('probes')].backendPort]",
"protocol": "[parameters('lbRules')[copyIndex('probes')].protocol]"
}
}
},
{
"name": "loadBalancingRules",
"count": "[length(parameters('lbRules'))]",
"input": {
"name": "[parameters('lbRules')[copyIndex('loadBalancingRules')].name]",
"properties": {
"frontendIPConfiguration": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers', parameters('myLoadBalancer')),'/frontendIPConfigurations/LoadBalancerIPConfig')]"
},
"frontendport": "[parameters('lbRules')[copyIndex('loadBalancingRules')].frontendport]",
"backendport": "[parameters('lbRules')[copyIndex('loadBalancingRules')].backendport]",
"enableFloatingIP": false,
"idleTimeoutInMinutes": "5",
"protocol": "[parameters('lbRules')[copyIndex('loadBalancingRules')].protocol]",
"backendAddressPool": {
"id": "[concat(resourceId('Microsoft.Network/loadBalancers', parameters('myLoadBalancer')),'/backendAddressPools/LoadBalancerBEAddressPool')]"
},
"probe": {
"id": "[concat(variables('lbID0'),'/probes/', parameters('lbRules')[copyIndex('loadBalancingRules')].name,'Probe')]"
}
}
}
}
],
"inboundNatPools": []
},
}
}
More info can be found here:
https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-multiple#property-iteration
https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/copy-properties
You can only apply the copy object to a top-level resource.
You cannot apply it to a property on a resource type, or to a child resource.
"resources": [
{
"type": "{provider-namespace-and-type}",
"name": "parentResource",
"copy": {
/* yes, copy can be applied here */
},
"properties": {
"exampleProperty": {
/* no, copy cannot be applied here */
}
},
"resources": [
{
"type": "{provider-type}",
"name": "childResource",
/* copy can be applied if resource is promoted to top level */
}
]
}
]
Source of Quotation: Deploy multiple instances of resources in Azure Resource Manager templates
You can loop over properties in ARM Template ONLY IF the copy object is applied to a top-level resource, which is in your case the "Microsoft.Network/loadBalancers", but that will also create multiple copy of the said resource.
If this is not what you want to achieve, I would recommend you to keep your existing way until ARM Template support copy object to property on a resource type in the future.
It is now possible to loop on properties or on child resources as stated in https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-multiple#property-iteration or in
https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-multiple#create-multiple-instances-of-a-child-resource
You can a child resource extension (e.g. WebSite/Extension) as a top-level resource by following the format for the type:
{resource-provider-namespace}/{parent-resource-type}/{child-resource-type}.
For instance
Microsoft.Web/sites/siteextensions
You have also to reference the parent resource in the child resource by a concat. For instance:
"name": "[concat('mywebsite', '/', 'myextension', copyIndex())]"
What you want to achieve is possible with the take function.
You linked the proper documentation site yourself. Go to the link you posted and check out the section "Create multiple instances when copy won't work".
in your case this would look like this:
"variables": {
"probeArray": [
{
"name": "AppPortProbe1",
"properties": {
"protocol": "Tcp",
"port": 80,
"intervalInSeconds": 5,
"numberOfProbes": 2
}
},
{
"name": "AppPortProbe2",
"properties": {
"protocol": "Tcp",
"port": 81,
"intervalInSeconds": 5,
"numberOfProbes": 2
}
},
{
"name": "AppPortProbe3",
"properties": {
"protocol": "Tcp",
"port": 82,
"intervalInSeconds": 5,
"numberOfProbes": 2
}
}
],
You then create an parameter specifying how many probes you want
"parameters": {
...
"numProbes": {
"type": "int",
"maxValue": 3,
"metadata": {
"description": "This parameter allows you to select the number of probes you want"
}
}
Finally you use take inside the resource:
"resources": [
...
{
"type": "Microsoft.Network/loadBalancers",
"properties": {
...
"probes": "[take(variables('probeArray'),parameters('numProbes'))]"
},
...
}
...
}
]
If you continue the through the documentation you will see that you can get even more crazy and combine copy and take with linked templates.