0
votes

I have a request to create multiple VMs for different servers, for example:

{
  "type"   = "ansibleserver"
  "size"   = "Standard_DC2s"
  "count" = 2
},
{
  "type"   = "frontendserver"
  "size"   = "Standard_DC2s"
  "count" = 2
},
{
  "type"   = "backendserver"
  "size"   = "Standard_L8s_v2"
  "count" = 3
}

For all the 3 kinds of servers, I have to create them in different sizes and counts, for now I can only do it in a pretty bad way:

resource "azurerm_virtual_machine" "ansibleserver" {
  count = "${lookup(var.ansibleserver, "count")}"

  name  = 
  ......
}

resource "azurerm_virtual_machine" "frontendserver" {
  count = "${lookup(var.frontendserver, "count")}"

  name  = 
  ......
}

Then if any new requirements coming in, I not only need to change the variables but also the script, it is too complicated. Is there any way to change the whole creation process in a more decent way, such as for-loop in code?

2
What version of Terraform?Matt Schuchard

2 Answers

5
votes

Refer to the suggestion mentioned in the link and let me know the status

This GitHub article should help you

For more information you may refer to the suggestion mentioned in this link.

Something like this are you looking out:

resource "azurerm_virtual_machine" "server" {
  name                  = "server-${count.index}"
  count                 = "${var.instance_count}"
  …
  storage_os_disk {
    name              = "server-${count.index}-os"
    caching           = "ReadWrite"
    create_option     = "FromImage"
    managed_disk_type = "Standard_LRS"
  }
} 

Additional information : azurerm_virtual_machine

Need to create multile vms in azure through terraform

Kindly let us know if the above helps or you need further assistance on this issue.

2
votes

The first task here is to flatten your inputs into a collection where each element corresponds to just one virtual machine:

locals {
  servers_flat = flatten([
    for s in var.servers : [
      for n in range(s.count) : {
        type  = s.type
        size  = s.size
        index = n
      }
    ]
  ])
}

Once you've done this, you can use for_each to create one instance of a resource for each element of the collection.

resource "azurerm_virtual_machine" "ansibleserver" {
  for_each = { for s in var.servers_flat : format("%s%02d", s.name, s.index) => s }

  name = each.key # a string like "ansibleserver01"
  size = each.value.size
}

We must give each element a unique key by converting to a map, so here I assumed that the "type" should be unique in the input list and thus it's sufficient to combine that with the index to produce a unique key. If that's not true, you might need to include the size string in the key too, by adjusting the key expression in the for_each.

The result of this will be instances with addresses like azurerm_virtual_machine.ansibleserver["ansibleserver01"], so that when you add or remove elements to your list in future Terraform will be able to correlate with existing instances to figure out what it needs to create or destroy, without disturbing unrelated instances.