2

We could create multiple azure vms in a availability set using "count" loop.

How can we create the same using "for_each" loop where the hostname and network interfaceid will be dynamic and looped over. (in terrraform > 0.12.6)

resource "azurerm_virtual_machine" "test" {

 # user provides inputs only for the number of vms to be created in the Azure avaialibility set

 count                 = var.count 
 name                  = "acctvm${count.index}"
 location              = azurerm_resource_group.test.location
 availability_set_id   = azurerm_availability_set.avset.id
 resource_group_name   = azurerm_resource_group.test.name
 network_interface_ids = [element(azurerm_network_interface.test.*.id, count.index)]
 vm_size               = "Standard_DS1_v2"
 tags                  = var.tags
user6041236
  • 35
  • 1
  • 6

2 Answers2

1

You can specify the VM properties required in an object list, and then use a for_each loop like so:

variable "VirtualMachines" {
  type = list(object({
    hostname= string
    interfaceid = string 
  }))
  default = [
    {
        hostname= "VM01",
        interfaceid = "01"
    },
     {
        hostname= "VM02",
        interfaceid = "02"
    }
  ]
}
    
resource "azurerm_virtual_machine" "test" {

  for_each = {for vm in var.VirtualMachines: vm.hostname => vm}

  name =  each.value.hostname
  location = azurerm_resource_group.test.location
  availability_set_id = azurerm_availability_set.avset.id
  resource_group_name = azurerm_resource_group.test.name
  network_interface_ids = [each.value.interfaceid]
  vm_size = "Standard_DS1_v2"
  tags = var.tags
}
CMills
  • 26
  • 3
  • 1
    Is there a way how to use for_each also for NIC creation and then use this resources as input for VM creation? If I need to create dozens of instance I would prefer not to pre-create NIC for them. – 32cupo Apr 01 '22 at 04:58
0

For-each needs a set to loop over. I assume you use a variable as an input, so

variable "vms" {
  type = list(string)
  default = ["alpha", "beta"]
}

variable "vms_data" {
  type = map(map(string))
  default = {
    alpha = {
      hostname = "alpha"
      interfaceid = "01"
    }
    alpha = {
      hostname = "beta"
      interfaceid = "02"
    }
  }
}

resource "azurerm_virtual_machine" "test" {
  for_each = toset(var.vms)

  name = var.vms_data[each.value].hostname
  location = azurerm_resource_group.test.location
  availability_set_id = azurerm_availability_set.avset.id
  resource_group_name = azurerm_resource_group.test.name
  network_interface_ids = [
    element(azurerm_network_interface.test.*.id, var.vms_data[each.value].interfaceid)]
  vm_size = "Standard_DS1_v2"
  tags = var.tags
}

But it has not been realised for Azure yet (v. 12.23). I got an error The name "for_each" is reserved for use in a future version of Terraform.

Dmitry Grebenyuk
  • 471
  • 1
  • 5
  • 7
  • Thanks for your response @Dmitry Please advise... -> how about there are no default in the variable for vms.. ? variable "vms" { type = list(string) } I am generating the names of the vm dynamically based the inputs given by the end user. – user6041236 Mar 21 '20 at 01:00