I'm deploying an ARM template that uses a copy resource block to deploy 1 or more data disks to a VM. What I'd like to do is change this to 0 or more.
The parameter I use is
"VirtualMachineDiskSizeArray": {
"type": "array",
"defaultValue": [ "100" ]
},
Which is then called in a resource:
"resources": [
{
"name": "[parameters('virtualMachineName')]",
"type": "Microsoft.Compute/virtualMachines",
"apiVersion": "2016-04-30-preview",
"location": "[parameters('rgLocation')]",
"dependsOn": [
"[concat('Microsoft.Storage/storageAccounts/', parameters('rgStorageAccountName'))]"
],
"properties": {
"osProfile": { ... },
"hardwareProfile": { ... },
"storageProfile": {
"imageReference": { ... },
"osDisk": { ... },
"copy": [
{
"name": "dataDisks",
"count": "[length(parameters('VirtualMachineDiskSizeArray'))]",
"input": {
"lun": "[copyIndex('dataDisks')]",
"name": "[concat(parameters('vmDataDiskNameStub'), add(copyIndex('dataDisks'),1), '.vhd')]",
"diskSizeGB": "[parameters('VirtualMachineDiskSizeArray')[copyIndex('dataDisks')]]",
"createOption": "Empty",
"vhd": {
"uri": "[concat(concat(reference(resourceId(parameters('rgName'), 'Microsoft.Storage/storageAccounts', parameters('rgStorageAccountName')), '2015-06-15').primaryEndpoints['blob'], 'vhds/'), concat(parameters('vmDataDiskNameStub'), add(copyIndex('dataDisks'),1), '.vhd') )]"
}
}
}
]
}
}
},
However, when I pass in an array of data disks with 0 elements, I get this error, as expected:
Validation returned the following errors:
: Deployment template validation failed: 'The template 'copy' definition at line '0' and column '0' has an invalid copy count. The co
py count must be a postive integer value and cannot exceed '800'. Please see https://aka.ms/arm-copy for usage details.'.
Template is invalid.
I would like to try to work around this somehow - I tried adding a condition on the copy:
"condition": "[ greater(length(parameters('VirtualMachineDiskSizeArray')), 0)]",
But that returned the same error.
I'm researching nested templates, but that doesn't look good for a section of a resource.
The easiest way to work around that is using this:
{
"condition": "[if(equals(parameters('numberOfDataDisks'), 0), bool('false'), bool('true'))]",
"apiVersion": "2017-03-30",
"type": "Microsoft.Compute/virtualMachines",
"name": "[variables('vmName')]",
"location": "[resourceGroup().location]",
"properties": {
"storageProfile": {
"imageReference": { xxx },
"osDisk": { xxx },
"copy": [
{
"name": "dataDisks",
"count": "[if(equals(parameters('numberOfDataDisks'), 0), 1, parameters('numberOfDataDisks'))]",
"input": {
"diskSizeGB": "1023",
"lun": "[copyIndex('dataDisks')]",
"createOption": "Empty"
}
}
]
}
}
}
this will work around the fact that you are passing 0 data disks and at the same time wont deploy this vm. all you need to do is add another vm resource. But it has to be with a different name (else template will fail) or you can use nested template to deploy a vm with the same name.
this can be improved with recent fixes to if()
function, you can always work around by using nested deployments as well
I'm going to use this answer to use a reference on my research into nested templates.
Looking at here I can see an approach that would have two nested templates, one like this:
"resources": [
{
"name": "MultiDataDisk",
"type": "Microsoft.Compute/virtualMachines",
"apiVersion": "2016-04-30-preview",
"location": "[parameters('rgLocation')]",
"dependsOn": [
"[concat('Microsoft.Storage/storageAccounts/', parameters('rgStorageAccountName'))]"
],
"properties": {
"osProfile": { ... },
"hardwareProfile": { ... },
"storageProfile": {
"imageReference": { ... },
"osDisk": { ... },
"copy": [
{
"name": "dataDisks",
"count": "[length(parameters('VirtualMachineDiskSizeArray'))]",
"input": {
"lun": "[copyIndex('dataDisks')]",
"name": "[concat(parameters('vmDataDiskNameStub'), add(copyIndex('dataDisks'),1), '.vhd')]",
"diskSizeGB": "[parameters('VirtualMachineDiskSizeArray')[copyIndex('dataDisks')]]",
"createOption": "Empty",
"vhd": {
"uri": "[concat(concat(reference(resourceId(parameters('rgName'), 'Microsoft.Storage/storageAccounts', parameters('rgStorageAccountName')), '2015-06-15').primaryEndpoints['blob'], 'vhds/'), concat(parameters('vmDataDiskNameStub'), add(copyIndex('dataDisks'),1), '.vhd') )]"
}
}
}
]
}
}
}
]
and one like this:
"resources": [
{
"name": "ZeroDataDisk",
"type": "Microsoft.Compute/virtualMachines",
"apiVersion": "2016-04-30-preview",
"location": "[parameters('rgLocation')]",
"dependsOn": [
"[concat('Microsoft.Storage/storageAccounts/', parameters('rgStorageAccountName'))]"
],
"properties": {
"osProfile": { ... },
"hardwareProfile": { ... },
"storageProfile": {
"imageReference": { ... },
"osDisk": { ... },
"dataDisks": []
}
}
}
]
And reference them from a parent template:
"parameters": {
"nestedType": {
"type": "string",
"defaultValue": "ZeroDataDisk",
"allowedValues": [
"ZeroDataDisk",
"MultiDataDisk"
],
}
},
"resources": [
{
"name": "[concat("nested-",parameters('virtualMachineName')]",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2015-01-01",
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat('https://someplace.on.the.internet/nested/',parameter('nestedType'),".json")],
"contentVersion": "1.0.0.0"
},
"parameters": {
"rgStorageAccountName": {
"value": "[parameters(rgStorageAccountName)]"
},
"OtherParms": {
"value": "[parameters('otherParms')]"
}
. . .
}
}
]
}
However, I don't believe this is better/easier than what I did in my "Interest of Time" answer because
So basically, unless I can have a copy of 0-N of a section (rather than 1-N) or nest just a section, my two file hack with the powershell switch seems to be the least overhead.
I would like to share our solution based many of the answers already here. This is a simple example to have an input array of disks - values being their sizes - and create with those with your vm. works from 0-n. n needs to be smaller than supported disks of your VM size and other azure limits :) This should also help with this comment
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
[...]
"dataDiskArray": {
"type": "array",
"defaultValue": [
"100",
"50"
]
}
},
"variables": {
"copy": [
{
"name": "dataDisks",
"count": "[if(equals(length(parameters('dataDiskArray')),0),1, length(parameters('dataDiskArray')))]",
"input": {
"lun": "[if(equals(length(parameters('dataDiskArray')),0),0, copyIndex('dataDisks'))]",
"createOption": "Empty",
"diskSizeGB": "[if(equals(length(parameters('dataDiskArray')),0),10,parameters('dataDiskArray')[copyIndex('dataDisks')])]"
}
}
]
},
"resources": [
{
"name": "[parameters('virtualMachineName')]",
"type": "Microsoft.Compute/virtualMachines",
[...]
"properties": {
[...]
"storageProfile": {
[...]
"dataDisks": "[if(equals(length(parameters('dataDiskArray')),0),json('null'),variables('dataDisks'))]"
},
[...]
}
}
],
"outputs": {
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With