Having an issue trying to build multiple vms that could have different source image references

So When i try and build multiple virtual machines using my tfvars i get the following error

Error: Too many source_image_reference blocks

│ on main.tf line 104, in resource “azurerm_windows_virtual_machine” “main”:
│ 104: content {

│ No more than 1 “source_image_reference” blocks are allowed


│ Error: Too many source_image_reference blocks

│ on main.tf line 104, in resource “azurerm_windows_virtual_machine” “main”:
│ 104: content {

│ No more than 1 “source_image_reference” blocks are allowed


│ Error: Too many os_disk blocks

│ on main.tf line 116, in resource “azurerm_windows_virtual_machine” “main”:
│ 116: content {

│ No more than 1 “os_disk” blocks are allowed


│ Error: Too many os_disk blocks

│ on main.tf line 116, in resource “azurerm_windows_virtual_machine” “main”:
│ 116: content {

│ No more than 1 “os_disk” blocks are allowed

This will only work if i run one virtual machine. This is my tfvars file here. I would just add another section below the kevintest part to create another vm

subscription_id              = "" 
virtual_machines = {
    ###kevintest###
    kevintest  = {
    virtual_machine_name = "kevintest"
    virtual_machine_size = "Standard_B4ms"
    azurerm_resource_group      = "bastiontest"  
    azurerm_virtual_network_rg  = "bastiontest" 
    azurerm_virtual_network     = "bastionvnet"   
    azurerm_subnet              = "subnet1"      
    resource_created_by         = "Kevin Sims"   
    virtual_machine_purpose     = "kevin test"          
    virtual_machine_environment = "sbx"        
    virtual_machine_region      = "centralus"    
    azurerm_managed_disk_size    = "10" 
    storage_account_type         = "StandardSSD_LRS"
    admin_password = "" 
    source_image_reference = {
                      publisher = "MicrosoftWindowsServer"
                      offer     = "WindowsServer"
                      sku       = "2019-Datacenter"
                      version   = "latest"
    }
    os_disk = {
      caching = "ReadWrite"
      storage_account_type = "StandardSSD_LRS"
    }
    
  }
  ###kevintest###

}

Here is my variable


###Connection Informatoin
variable "client_secret" {}
variable "subscription_id" {}
variable "client_id" { default = "" }
variable "tenant_id" { default = "" }
###Connection Informatoin

variable "virtual_machines" {
  type = map(object({
    virtual_machine_size = string
    virtual_machine_name = string
    azurerm_resource_group      = string   #what resouce group the vm will be created in
    azurerm_virtual_network_rg  = string #the resource group that the virtual network lives in
    azurerm_virtual_network     = string   #the virtual network the vm will live in
    azurerm_subnet              = string       # the subnet the vm will live in
    resource_created_by         = string    #who created the vm
    storage_account_type = string
    /*virtual_machine_purpose     = string          #one word pupose for this vm
    virtual_machine_environment = string        #environment vm will live in
    virtual_machine_region      = string */    #region that the vm will live in
    azurerm_managed_disk_size   = number 
    admin_password = string
    source_image_reference = object({
      publisher = string
      offer = string
      sku = string
      version = string
    })
    os_disk = map(any)

  }))
  
}

Here is the code

resource "azurerm_windows_virtual_machine" "main" {
  for_each                 = var.virtual_machines
  name                     = each.value.virtual_machine_name
  resource_group_name      = data.azurerm_resource_group.main[each.key].name
  location                 = data.azurerm_resource_group.main[each.key].location
  size                     = each.value.virtual_machine_size
  admin_username           = "${each.value.virtual_machine_name}-adm"
  admin_password           = each.value.admin_password
  network_interface_ids    = [azurerm_network_interface.main[each.key].id]
  enable_automatic_updates = false
  patch_mode               = "Manual"

  lifecycle {
    ignore_changes = [
      admin_password
    ]
  }

  dynamic "source_image_reference" {
    for_each = var.virtual_machines

    content {
      publisher = each.value.source_image_reference.publisher
      offer     = each.value.source_image_reference.offer
      sku       = each.value.source_image_reference.sku
      version   = each.value.source_image_reference.version
    }

  }

  dynamic "os_disk" {
    for_each = var.virtual_machines

    content {
      caching              = each.value.os_disk.caching
      storage_account_type = each.value.os_disk.storage_account_type
    }
  }
}

Suppose var.virtual_machines defines 3 VMs.

Written this way, you’ve just told Terraform to build 3 VMs, and attach 3 source_image_references and 3 os_disks to each of the 3 VMs.

Stop using dynamic blocks here, just write an ordinary single block.

But then how would I pass in multiple vms in my tfvars that may have different image types.

Your object includes the source_image_reference within the definition of each VM.

A dynamic block is only needed if you might have a differing number of instances of a block. In this case you are always going to have exactly one instance of each of the “source_image_reference” and “os_disk” blocks, so dynamic is not needed.