Azure Arm template copy function for VM and Datadisks - azure

I am using copy to create multiple VM's and want to have multiple datadisks for each vm.
I know i can do it this way:
{
"name": "[concat('dataDisk-',parameters('vm-name'),'-0',copyIndex(1))]",
"diskSizeGB": "[parameters('dataDisksize')]",
"lun": 0,
"createOption": "Empty"
},
{
"name": "[concat('dataDisk1-',parameters('vm-name'),'-0',copyIndex(1))]",
"diskSizeGB": "[parameters('dataDisksize')]",
"lun": 1,
"createOption": "Empty"
}
Now I have to create 20 disks with the same name and this doesn't seem to be good workaround. Getting issue with disk name while using copy. For my case i can use the same disksize for all 20 disks

You can use the copy element to repeat properties:
"copy": [
{
"name": "dataDisks",
"count": "[parameters('numberOfDataDisks')]",
"input": {
"lun": "[copyIndex('dataDisks')]",
"createOption": "Empty",
"diskSizeGB": 1023
}
}
]
More information here: https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/copy-properties

Now I have to create 20 disks with the same name and this doesn't seem
to be good workaround. Getting issue with disk name while using copy.
Creating multiple disks using same name is impossible. you need concat either copyindex values to disk name or the VMnames to the Names of the disk..
In our template we have used the copy function block in the below manner to deploy multiple disks for a single virtual Machine & we have tested this in our local environment which is working fine.
Here is the ARM template that we have created :
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"dataDiskCount": {
"type": "int","minvalue" : 1,"maxValue" :20,"defaultValue" : 4,
"metadata": {
"description": "number of data disks."
}
}
},
"variables": {}
"resources": [
{
"copy": [
{
"name": "dataDisks",
"count": "[parameters('dataDiskCount')]",
"input": {
"diskSizeGB": "20",
"lun": "[copyIndex('dataDisks')]",
"createOption": "Empty",
"name":"[concat('disk',copyIndex('dataDisks'),'dk')]"
}
}
},
"outputs": {}
}
Here is the sample output screen shot for reference:

Related

ARM Template for VM Having Statically and Dynamically Defined Disks

I am trying to create an ARM template for a VM to deploy a custom application.
VM is based on this ARM template quickstart for a SQL Server VM:
https://azure.microsoft.com/en-us/resources/templates/101-sql-vm-new-storage/
I need to create one disk first for my application, followed by the "copy" function to define the remaining disks.
This is how the quickstart originally defines the disks: (the createOption in the variables is "empty")
"copy": [
{
"name": "dataDisks",
"count": "[add(parameters('sqlDataDisksCount'), parameters('sqlLogDisksCount'))]",
"input": {
"lun": "[copyIndex('dataDisks')]",
"createOption": "[variables('dataDisks').createOption]",
"caching": "[if(greaterOrEquals(copyIndex('dataDisks'), parameters('sqlDataDisksCount')) ,'None', variables('dataDisks').caching )]",
"writeAcceleratorEnabled": "[variables('dataDisks').writeAcceleratorEnabled]",
"diskSizeGB": "[variables('dataDisks').diskSizeGB]",
"managedDisk": {
"storageAccountType": "[variables('dataDisks').storageAccountType]"
}
}
}
]
As I need an extra 512 GB disk for the application that I want to place at the beginning, I modified my template as follows:
"copy": [
{
"name": "dataDisks",
"count": "[add(1, add(parameters('sqlDataDisksCount'), parameters('sqlLogDisksCount')))]",
"input": {
"lun": "[copyIndex('dataDisks')]",
"createOption": "[variables('dataDisks').createOption]",
"caching": "[if(greaterOrEquals(copyIndex('dataDisks'), add(1, parameters('sqlDataDisksCount'))) ,'None', variables('dataDisks').caching )]",
"writeAcceleratorEnabled": "[variables('dataDisks').writeAcceleratorEnabled]",
"diskSizeGB": "[if(equals(copyIndex('dataDisks'), 0), 512, variables('dataDisks').diskSizeGB)]",
"managedDisk": {
"storageAccountType": "[variables('dataDisks').storageAccountType]"
}
}
}
]
When the VM is created my desired disk is unallocated, it does not appear as a usable disk.
I tried changing the createOption configuration to be:
"createOption": "[if(equals(copyIndex('dataDisks'), 0), 'attach', variables('dataDisks').createOption)]"
But that throws an error of
18:58:27 - New-AzureRmResourceGroupDeployment : 6:58:27 PM - Resource Microsoft.Compute/virtualMachines 'myVM' failed with
18:58:27 - message '{
18:58:27 - "error": {
18:58:27 - "code": "InvalidParameter",
18:58:27 - "message": "Required parameter 'dataDisk.managedDisk.id' is missing (null).",
18:58:27 - "target": "dataDisk.managedDisk.id"
18:58:27 - }
18:58:27 - }'
I also tried to define the other disk outside the copy loop but that did not work either.
Not sure how I should go about this. Help??

Azure ARM - Microsoft.Resources/deploymentScripts

I am going to configure created azure VM (for example, install role, initialize new hdd disk etc). I see that there is a new feature Microsoft.Resources/deploymentScripts in azure ARM. As per documantation I created Managed Identity in my subscription, give Contributor permissions to newly created Managed Identity, on Subscription level. then I developed below ARM template using Microsoft.Resources/deploymentScripts feature. code pasted below. I want to paste this code into my ARM template for VM deployment.Question is if I will be able to use this approach to perform scripts like: installing role on the OS level, like IIS or WSUS, configure HDD etc...
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"name": {
"type": "string",
"defaultValue": "'John Dole'"
},
"utcValue": {
"type": "string",
"defaultValue": "[utcNow()]"
}
},
"resources": [
{
"type": "Microsoft.Resources/deploymentScripts",
"apiVersion": "2019-10-01-preview",
"name": "runPowerShellInlineWithOutput",
"location": "westeurope",
"kind": "AzurePowerShell",
"identity": {
"type": "userAssigned",
"userAssignedIdentities": {
"/subscriptions/SubID/resourceGroups/RGname/providers/Microsoft.ManagedIdentity/userAssignedIdentities/MI-ARMdeployment": {}
}
},
"properties": {
"forceUpdateTag": "[parameters('utcValue')]",
"azPowerShellVersion": "3.0",
"scriptContent": "
$output = 'hello'
Write-Output $output",
"arguments": "",
"timeout": "PT1H",
"cleanupPreference": "OnSuccess",
"retentionInterval": "P1D"
}
}
]
}
Well, yes (with some hacks), but its not meant for that. Its meant for provisioning\configuring Azure level resources, not things inside of the VM.
You have DSC extension and script extension for that (available for both windows\linux).

Identify resources associated with VM deallocated

During the cleanup process of Azure VM. I am trying to identify all resources associated with Deallocated VM, Like network, storage and nic.
I ran below query to get details, but unable to write a query to get other details in the same query parameter to get a result of nic, storge in table format.
az vm list -d --query "[?powerState=='VM deallocated']" -o table
qa-automation-10 TEST-QA-AUTOMATION
qa-automation-11 TEST-QA-AUTOMATION
qa-automation-12 TEST-QA-AUTOMATION
qa-automation-13 TEST-QA-AUTOMATION
qa-automation-14 TEST-QA-AUTOMATIO
Any help will be appreciable, I am especially looking for az client query. As VM deallocated list is big so I will run through gitlab pipeline.
},
"id": "/subscriptions/xxxxxxxx/resourceGroups/xxxx/providers/Microsoft.Compute/virtualMachines/x023901",
"identity": null,
"licenseType": null,
"location": "x",
"macAddresses": "",
"name": "x023901",
"networkProfile": {
"networkInterfaces": [
{
"id": "/subscriptions/x/resourceGroups/rGroup-ENV0239/providers/Microsoft.Network/networkInterfaces/x023901nic",
"primary": null,
"resourceGroup": "rGroup-ENV0239"
}
]
},
"osProfile": null,
"plan": null,
"powerState": "VM deallocated",
"privateIps": "x.x.x.x",
"provisioningState": "Succeeded",
"publicIps": "",
"resourceGroup": "RGROUP-ENV0239",
"resources": [
{
"autoUpgradeMinorVersion": true,
"forceUpdateTag": null,
"id": "/subscriptions/xxxxxxx/resourceGroups/RGROUP-ENV0239/providers/Microsoft.Compute/virtualMachines/x023901/extensions/OmsAgentForLinux",
"instanceView": null,
"location": "x",
"name": "OmsAgentForLinux",
"protectedSettings": null,
"provisioningState": "Succeeded",
"publisher": "Microsoft.EnterpriseCloud.Monitoring",
"resourceGroup": "RGROUP-ENV0239",
"settings": {
"stopOnMultipleConnections": true,
"workspaceId": "xx"
},
"tags": null,
"type": "Microsoft.Compute/virtualMachines/extensions",
"typeHandlerVersion": "1.0",
"virtualMachineExtensionType": "OmsAgentForLinux"
}
],
"storageProfile": {
"dataDisks": [
{
"caching": "None",
"createOption": "Attach",
"diskSizeGb": 20,
"image": null,
"lun": 0,
"managedDisk": null,
"name": "x-data1.vhd",
"vhd": {
"uri": "https://x.core.windows.net/vhds/x-data1.vhd"
},
"writeAcceleratorEnabled": null
}
],
"imageReference": null,
"osDisk": {
"caching": "ReadWrite",
"createOption": "Attach",
"diffDiskSettings": null,
"diskSizeGb": 30,
"encryptionSettings": null,
"image": null,
"managedDisk": null,
"name": "xosDisk",
"osType": "Linux",
"vhd": {
"uri": "https://xblob.core.windows.net/vhds/x.vhd"
},
"writeAcceleratorEnabled": null
}
},
"tags": null,
"type": "Microsoft.Compute/virtualMachines",
"vmId": "x",
"zones": null
},
The VMs in Azure has two types, one is the managed VM while the other is unmanaged VM. When you want to show the details of all the VMs, you should pay attention to this.
In addition, there no property about the storage account. You can store the files in the storage account and do not associate to the VM. So you just get a little info about the storage account if the VM is unmanaged.
Get a list of the VM with some resources just like vmName, NIC, osDisk or osDiskURI, the CLI command here:
az vm list --query "[].{VMName:name, nicId:networkProfile.networkInterfaces[0].id, managedDiskId:storageProfile.osDisk.managedDisk.id, UnmanagedDiskURL:storageProfile.osDisk.vhd.uri}" -o table
You can change the info that you want if you can find it in the VM details through the CLI command az vm show. Hope this will help. Any more question you can give me the message.
You will need to use a query like below:
az vm show -g RG-DemoAutomation -n DemoVM101 --query "{VMName:name, admin:osProfile.adminUsername,nicId:networkProfile.networkInterfaces[0].id, osDiskId:storageProfile.osDisk.managedDisk.id}" -o table
As you mentioned you will need to iterate through the output of the az vm list and then for each VM you will need to run az vm show as I showed in the sample above.
You can have filter and data selection in one query as "[?query here].{customColName1:value1, customColName2:value2}" but the problem is that az vm list does not have the details that you are looking for. That detail is available with az vm show command.
For values in the above syntax, the query uses JMESPATH and you can find the exact value by using a neat utility available here: JMESPath Terminal
Also, try using the output as json (-o json) as that will be much more readable unless you want to dump the output into an excel sheet.

Deployment Agents in Azure VM Scale Set

I am currently deploying a VM Scale Set (VMSS) using an ARM template which has a resource inside VMSS to install Azure extension for Azure DevOps (ADO) Deployment Agent. All is deployed successfully and a node is registered in ADO with all details as are in the ARM template. However the problem is that it installs the agent only on first node and (as far as I see) ignores the rest of the nodes. I've tested this with multiple nodes during creation of the scale set and with auto-scale as well. Both scenarios result in only first agent registered.
This is the code layout I'm using (I've removed the VMSS bits to reduce the template length here, there are of course OS, storage and network settings inside):
{
"type": "Microsoft.Compute/virtualMachineScaleSets",
"name": "[parameters('VMSSName')]",
"apiVersion": "2018-10-01",
"location": "[resourceGroup().location]",
"sku": {
"name": "[parameters('VMSSSize')]",
"capacity": "[parameters('VMSSCount')]",
"tier": "Standard"
},
"dependsOn": [],
"properties": {
"overprovision": "[variables('overProvision')]",
"upgradePolicy": {
"mode": "Automatic"
},
"virtualMachineProfile": {},
"storageProfile": {},
"networkProfile": {},
"extensionProfile": {
"extensions": [
{
"type": "Microsoft.Compute/virtualMachineScaleSets/extensions",
"name": "VMSS-NetworkWatcher",
"location": "[resourceGroup().location]",
"properties": {
"publisher": "Microsoft.Azure.NetworkWatcher",
"type": "[if(equals(parameters('Platform'), 'Windows'), 'NetworkWatcherAgentWindows', 'NetworkWatcherAgentLinux')]",
"typeHandlerVersion": "1.4",
"autoUpgradeMinorVersion": true
}
},
{
"type": "Microsoft.Compute/virtualMachineScaleSets/extensions",
"name": "VMSS-TeamServicesAgent",
"location": "[resourceGroup().location]",
"properties": {
"publisher": "Microsoft.VisualStudio.Services",
"type": "[if(equals(parameters('Platform'), 'Windows'), 'TeamServicesAgent', 'TeamServicesAgentLinux')]",
"typeHandlerVersion": "1.0",
"autoUpgradeMinorVersion": true,
"settings": {
"VSTSAccountName": "[parameters('VSTSAccountName')]",
"TeamProject": "[parameters('VSTSTeamProjectName')]",
"DeploymentGroup": "[parameters('VSTSDeploymentGroupName')]",
"AgentName": "[concat(parameters('VMSSName'),'-DG')]",
"Tags": "[parameters('VSTSDeploymentAgentTags')]"
},
"protectedSettings": {
"PATToken": "[parameters('VSTSPATToken')]"
}
}
}
]
}
}
}
}
Now the desired state, of course, is that all nodes will have agent installed so that I can use the Deployment Group inside Release pipeline.
your problem is in the fact that all agents have the same AgentName, so it effectively overwrites the agent and only the latest one "survives". I dont think there is anything you can do, unless you just amend the AgentName and it auto assigns based on computer name.
You can convert this to a script\dsc extension, that way you can calculate everything on the fly.

Create ARM parameter names dynamically

I have a scenario where i need to generate the parameters names dynamically. Like certificate1, certificate2, certificate3 .. so on. Currently all these parameters should be defined in Main template. Can we use copy to iterate and define parameter Names dynamically in Main/Parent template? Or is there a way in ARM templates by which this can be accomplished?
you can use copy construct in variables section or in resource definition\resource properties. and then you can use concat() together with copyIndex() function to create names.
example:
[concat('something-', copyIndex())]
this will give you names like something-0, something-1, something-2 etc. (copyIndex starts at 0). you can also choose to offset copyIndex by giving it an offset number:
[concat('something-', copyIndex(10))]
this will give you name like something-10, something-11, something-12 etc.
copy in variables\properties:
"copy": [
{
"name": "nameOfThePropertyOrVariableYouWantToIterateOver",
"count": 3,
"input": {
"name": "[concat('something-', copyIndex('nameOfThePropertyOrVariableYouWantToIterateOver', 1))]"
}
}
]
here you need to specify which loop are you referring to with copyIndex function and you can use offset as well
You can use the copy function in Azure Template to generate the name of the resource, just like certificate1, certificate2, certificate3 .. so on.
Example below:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"apiVersion": "2016-01-01",
"type": "Microsoft.Storage/storageAccounts",
"name": "[concat('storage',copyIndex())]",
"location": "[resourceGroup().location]",
"sku": {
"name": "Standard_LRS"
},
"kind": "Storage",
"properties": {},
"copy": {
"name": "storagecopy",
"count": 3
}
}
],
"outputs": {}
}
And the storage name will like these:
storage0
storage1
storage2
For more details, see Deploy multiple instances of a resource or property in Azure Resource Manager Templates.

Resources