ARM - Add multiple VM to Recovery Services Vault (

2019-08-02 15:06发布

问题:

I'm trying to use the Recovery Services where I can automatically add a VM to Azure Backup via ARM template. I have successfully done this on a single machine deploy, but I'm trying to import it for when multiple VMs are deployed.

Here is where I had help from: https://www.francoisdelport.com/2017/03/automating-azure-vm-backups-using-arm-templates/

and

Azure ARM JSON template - Add VM to Recovery Services Vault in different Resource Group

Here is a snippet from a single deploy I had working

{
  "apiVersion": "2017-05-10",
  "name": "nestedTemplate",
  "type": "Microsoft.Resources/deployments",
  "resourceGroup": "Env1",
  "dependsOn": [
    "[concat('Microsoft.Compute/virtualMachines/', variables('vmName'))]"
  ],
  "properties": {
    "mode": "Incremental",
    "template": {
      "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
      "contentVersion": "1.0.0.0",
      "parameters": {},
      "variables": {},
      "resources": [
        {
          "apiVersion": "2016-06-01",
          "name": "[concat( parameters('recoveryVault'), '/Azure/', 'iaasvmcontainer;iaasvmcontainerv2;', parameters('vmRsg') , ';', parameters('vmPrefix'), '/vm;iaasvmcontainerv2;', parameters('vmRsg'),';', parameters('vmPrefix'))]",
          "location": "[resourceGroup().location]",
          "type": "Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems",
          "properties": {
            "protectedItemType": "Microsoft.Compute/virtualMachines",
            "policyId": "[resourceId('Microsoft.RecoveryServices/vaults/backupPolicies', parameters('recoveryVault'), parameters('recoveryPolicy'))]",
            "sourceResourceId": "[resourceId(subscription().subscriptionId, parameters('vmRsg'), 'Microsoft.Compute/virtualMachines', parameters('vmPrefix'))]"
          }
        }
      ]
    }
  }
}

Now I'm trying to use that in a copyIndex form for VM deploy, and here is the code I've been testing with:

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "adminUsername": {
      "type": "string",
      "minLength": 1,
      "metadata": {
        "description": "Username for the Virtual Machine."
      }
    },
    "adminPassword": {
      "type": "securestring",
      "metadata": {
        "description": "Password for the Virtual Machine."
      }
    },
    "dnsNameForPublicIP": {
      "type": "string",
      "minLength": 1,
      "metadata": {
        "description": "Globally unique DNS Name for the Public IP used to access the Virtual Machine."
      }
    },
    "windowsOSVersion": {
      "type": "string",
      "defaultValue": "2012-R2-Datacenter",
      "allowedValues": [
        "2008-R2-SP1",
        "2012-Datacenter",
        "2012-R2-Datacenter"
      ],
      "metadata": {
        "description": "The Windows version for the VM. This will pick a fully patched image of this given Windows version. Allowed values: 2008-R2-SP1, 2012-Datacenter, 2012-R2-Datacenter."
      }
    },
    "vmCount": {
      "type": "int",
      "defaultValue": 1
    },
    "virtualNetworkName": {
      "type": "string"
    },
    "dataDiskCount": {
      "type": "int",
      "defaultValue": 1
    },
    "recoveryVault": {
      "type": "string",
      "metadata": {
        "description": "Backup vault name"
      }
    },
    "recoveryPolicy": {
      "type": "string",
      "metadata": {
        "description": "Backcup policy name"
      }
    },
    "vmPrefix": {
      "type": "string",
      "metadata": {
        "description": "Prefix for VM names, used with vmCount to build the VM names"
      }
    },
    "vmRsg": {
      "type": "string",
      "metadata": {
        "description": "Resource group where VMs reside"
      }
    }
  },
  "variables": {
    "imagePublisher": "MicrosoftWindowsServer",
    "imageOffer": "WindowsServer",
    "OSDiskName": "osdiskforwindowssimple",
    "nicName": "myVMNic",
    "subnetName": "Subnet",
    "vhdStorageType": "Standard_LRS",
    "publicIPAddressName": "myPublicIP",
    "publicIPAddressType": "Dynamic",
    "vhdStorageContainerName": "vhds",
    "vmName": "MWindowsVM",
    "vmSize": "Standard_A2",
    "virtualNetworkName": "MyVNET",
    "vnetId": "[resourceId(resourceGroup().name, 'Microsoft.Network/virtualNetworks', parameters('virtualNetworkName'))]",
    "subnetRef": "[concat(variables('vnetId'), '/subnets/', variables('subnetName'))]"
  },
  "resources": [
    {
      "apiVersion": "2016-03-30",
      "type": "Microsoft.Network/publicIPAddresses",
      "name": "[concat(variables('publicIPAddressName'), copyIndex(1))]",
      "location": "[resourceGroup().location]",
      "tags": {
        "displayName": "PublicIPAddress"
      },
      "properties": {
        "publicIPAllocationMethod": "[variables('publicIPAddressType')]",
        "dnsSettings": {
          "domainNameLabel": "[concat(parameters('dnsNameForPublicIP'), copyIndex(1))]"
        }
      },
      "copy": {
        "name": "publicIpCopy",
        "count": "[parameters('vmCount')]"
      }
    },
    {
      "apiVersion": "2016-03-30",
      "type": "Microsoft.Network/networkInterfaces",
      "name": "[concat(variables('nicName'), copyIndex(1))]",
      "location": "[resourceGroup().location]",
      "tags": {
        "displayName": "NetworkInterface"
      },
      "dependsOn": [
        "[concat('Microsoft.Network/publicIPAddresses/', concat(variables('publicIPAddressName'), copyIndex(1)))]"
      ],
      "properties": {
        "ipConfigurations": [
          {
            "name": "[concat('ipconfig', copyIndex(1))]",
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "publicIPAddress": {
                "id": "[resourceId('Microsoft.Network/publicIPAddresses', concat(variables('publicIPAddressName'), copyIndex(1)))]"
              },
              "subnet": {
                "id": "[variables('subnetRef')]"
              }
            }
          }
        ]
      },
      "copy": {
        "name": "nicCopy",
        "count": "[parameters('vmCount')]"
      }
    },
    {
      "apiVersion": "2017-03-30",
      "copy": {
        "name": "nodeCopy",
        "count": "[parameters('vmCount')]"
      },
      "type": "Microsoft.Compute/virtualMachines",
      "name": "[concat(variables('vmName'), copyIndex(1))]",
      "location": "[resourceGroup().location]",
      "tags": {
        "displayName": "VirtualMachine"
      },
      "dependsOn": [
        "[resourceId('Microsoft.Network/networkInterfaces/', concat(variables('nicName'), copyIndex(1)))]"
      ],
      "properties": {
        "hardwareProfile": {
          "vmSize": "[variables('vmSize')]"
        },
        "osProfile": {
          "computerName": "[concat(variables('vmName'), copyIndex(1))]",
          "adminUsername": "[parameters('adminUsername')]",
          "adminPassword": "[parameters('adminPassword')]"
        },
        "storageProfile": {
          "imageReference": {
            "publisher": "[variables('imagePublisher')]",
            "offer": "[variables('imageOffer')]",
            "sku": "[parameters('windowsOSVersion')]",
            "version": "latest"
          },
          "osDisk": {
            "createOption": "FromImage"
          },
          "copy": [
            {
              "name": "dataDisks",
              "count": "[parameters('dataDiskCount')]",
              "input": {
                "diskSizeGB": 1023,
                "lun": "[copyIndex('dataDisks')]",
                "createOption": "Empty"
              }
            }
          ]
        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[resourceId('Microsoft.Network/networkInterfaces', concat(variables('nicName'), copyIndex(1)))]"
            }
          ]
        }
      }
    },
    {
      "apiVersion": "2017-05-10",
      "name": "nestedTemplate",
      "type": "Microsoft.Resources/deployments",
      "resourceGroup": "Env1",
      "dependsOn": [
        "[concat('Microsoft.Compute/virtualMachines/', concat(variables('vmName'), copyIndex(1)))]"
      ],
      "properties": {
        "mode": "Incremental",
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "parameters": {},
          "variables": {},
          "resources": [
            {
              "copy": {
                "name": "protectedItemsCopy",
                "count": "[parameters('vmCount')]"
              },
              "apiVersion": "2017-03-30",
              "name": "[concat( parameters('recoveryVault'), '/Azure/', 'iaasvmcontainer;iaasvmcontainerv2;', parameters('vmRsg') , ';', parameters('vmPrefix'), copyIndex(1), '/vm;iaasvmcontainerv2;', parameters('vmRsg'),';', parameters('vmPrefix'), copyIndex(1))]",
              "location": "[resourceGroup().location]",
              "type": "Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems",
              "properties": {
                "protectedItemType": "Microsoft.Compute/virtualMachines",
                "policyId": "[resourceId('Microsoft.RecoveryServices/vaults/backupPolicies', parameters('recoveryVault'), parameters('recoveryPolicy'))]",
                "sourceResourceId": "[resourceId(subscription().subscriptionId ,parameters('vmRsg'),'Microsoft.Compute/virtualMachines', concat(parameters('vmPrefix'), copyIndex(1)) )]"
              }
            }
          ]
        }
      }
    }
  ]
}

Sadly it reports an error when trying to deploy, which I can't figure out why because it seems to be correct.

Error: Code=InvalidTemplate; Message=Deployment template validation failed: 'The template resource 'nestedTemplate' at line '198' and column '10' is not valid: The template function 'copyIndex' is not expected at this location. The function can only be used in a resource with copy specified. Please see https://aka.ms/arm-copy for usage details.. Please see https://aka.ms/arm-template-expressions for usage details.'.
The deployment validation failed

FYI, line 198 is "name": "nestedTemplate",

Any ideas, please?

回答1:

So what its telling you that you are not supposed to use copyIndex() function in that place. Now why exactly this is happening I don't know, but I do know that inline templates are a mess (for instance they use parent template paremeters, not nested template), I'm pretty sure if you convert that template to a real nested template (so a linked template, completely separate file) the above syntax will work.

Also, I'm handling this in a separate manner. I'm using 1 single nested deployment for each VM I have, so I'm using copy on the deployment resource, not backup resource.



回答2:

To expand upon @4c74356b41 answer I was missing the all important "index":{ "value": "[copyIndex()]" within "Microsoft.Resources/deployments" on the parent template.

For those wanting to know more, have a look at: https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-multiple

Ensure you have the ('index') parameter next to those items which need to be duplicated, such as "[concat(parameters('WHATEVER'), parameters('index'))]"

I also ended up having a nested source within my linked template for the overall design I was looking for.

So my parent template had a linked (child) template (to another file) with:

name": "[concat('nestings', copyIndex(1))]",
"type": "Microsoft.Resources/deployments", ...

My child template had all the usual buildings of a VM with the parameters ('index') to ensure the items which are duplicated are named correctly.

And finally at the bottom of the child template I had a nested template source so I could back the VM up to another resource group (had to be nested, otherwise you can't do multiple resource groups), which looked like this:

{
      "apiVersion": "2017-05-10",
      "name": "[concat('nestedTemplate', parameters('index'))]",
      "type": "Microsoft.Resources/deployments",
      "resourceGroup": "Env1",
      "dependsOn": [
        "[concat('Microsoft.Compute/virtualMachines/', concat(variables('vmName'), parameters('index')))]"
      ],
      "properties": {
        "mode": "Incremental",
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "parameters": {},
          "variables": {},
          "resources": [
            {
              "apiVersion": "2016-06-01",
              "name": "[concat( parameters('recoveryVault'), '/Azure/', 'iaasvmcontainer;iaasvmcontainerv2;', parameters('vmRsg') , ';', concat(parameters('vmPrefix'), parameters('index')), '/vm;iaasvmcontainerv2;', parameters('vmRsg'),';', concat(parameters('vmPrefix'), parameters('index')))]",
              "location": "[resourceGroup().location]",
              "type": "Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems",
              "properties": {
                "protectedItemType": "Microsoft.Compute/virtualMachines",
                "policyId": "[resourceId('Microsoft.RecoveryServices/vaults/backupPolicies', parameters('recoveryVault'), parameters('recoveryPolicy'))]",
                "sourceResourceId": "[resourceId(subscription().subscriptionId, parameters('vmRsg'), 'Microsoft.Compute/virtualMachines', concat(parameters('vmPrefix'), parameters('index')))]"
              }
            }
          ]
        }
      }
    }