Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I have an ARM template resource with a COPY array of 0 to N

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.

like image 514
Christopher G. Lewis Avatar asked Aug 28 '17 16:08

Christopher G. Lewis


3 Answers

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

like image 140
4c74356b41 Avatar answered Oct 24 '22 02:10

4c74356b41


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

  1. The section that I'm interested in (dataDisks) is surrounded by a bunch of other json that doesn't change leaving me to the same crappy issue of having to manually sync code between two files.
  2. I now have to not only maintain two json files for the nested resources, but I have to publish them via a publicly accessible URL.

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.

like image 33
Christopher G. Lewis Avatar answered Oct 24 '22 01:10

Christopher G. Lewis


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": {
    }
}
like image 3
Klaas Avatar answered Oct 24 '22 01:10

Klaas