skip to Main Content

I’m trying to create multiplane vms using for each function in terraform.

Resource Group

resource "azurerm_resource_group" "rg" {
  name     = "${var.prefix}-rg"
  location = "east us 2"
  tags = var.tags
}

VNET

resource "azurerm_virtual_network" "vnet" {
  name                = "${var.prefix}-network-1"
  address_space       = ["10.0.0.0/16"]
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  tags = var.tags
}

Subnet

resource "azurerm_subnet" "subnet" {
  name                 = "${var.prefix}-network-subnet-1"
  resource_group_name  = azurerm_resource_group.rg.name
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefixes     = ["10.0.2.0/24"]
}

Variables for NICS

variable "nics" {
  type = map
  default = {
    
  nic3 = {
        name = "ubuntu-test-3"
  }

  nic4 = {
        name = "ubuntu-test-4"
  }
 }
}

NICS

resource "azurerm_network_interface" "nics" {
  for_each            = var.nics
  name                = each.value.name
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name

  ip_configuration {
    name                          = "${each.value.name}-conf-1"
    subnet_id                     = azurerm_subnet.subnet.id
    private_ip_address_allocation = "Dynamic"
  }

  tags = var.tags
}

Variables for VMS

variable "vms" {
  description = "Virtual Machines"
  type = map
  default = {
  vm3 = {
        name            = "ubuntu-test-3"
        size            = "Standard_DS1_v2"
    }
  vm4 = {
        name            = "ubuntu-test-4"
        size            = "Standard_DS1_v2"
  }
 }

}

and the block for the VM ( not completed – i wrote only the section that i have issue with )

resource "azurerm_virtual_machine" "vms" {
  for_each            = var.vms
  name                = each.value.name
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location
  vm_size                = each.value.size
  tags = var.tags
  network_interface_ids = [
    azurerm_network_interface.nics[each.value].id,
  ]

The issue is with this section

network_interface_ids = [
        azurerm_network_interface.nics[each.value].id,
      ]

I’m getting ERROR

│ Error: Invalid index
│
│   on main.tf line 247, in resource "azurerm_virtual_machine" "vms":
│  247:     azurerm_network_interface.nics[each.value].id,
│     ├────────────────
│     │ azurerm_network_interface.nics is object with 2 attributes
│     │ each.value is object with 2 attributes
│
│ The given key does not identify an element in this collection value: string required.

Also tried with

network_interface_ids = [
        azurerm_network_interface.nics[each.key].id,
      ]

and got ERROR

│ Error: Invalid index
│
│   on main.tf line 249, in resource "azurerm_virtual_machine" "vms":
│  249:     azurerm_network_interface.nics[each.key].id,
│     ├────────────────
│     │ azurerm_network_interface.nics is object with 2 attributes
│     │ each.key is "vm3"
│
│ The given key does not identify an element in this collection value.
╵
╷
│ Error: Invalid index
│
│   on main.tf line 249, in resource "azurerm_virtual_machine" "vms":
│  249:     azurerm_network_interface.nics[each.key].id,
│     ├────────────────
│     │ azurerm_network_interface.nics is object with 2 attributes
│     │ each.key is "vm4"
│
│ The given key does not identify an element in this collection value

What I’m doing wrong ?

2

Answers


  1. In order for this to work, you would need to modify the variable for VMs slightly:

    variable "vms" {
      description = "Virtual Machines"
      type = map
      default = {
      vm3 = {
            name            = "ubuntu-test-3"
            size            = "Standard_DS1_v2"
            nic             = "nic3"
        }
      vm4 = {
            name            = "ubuntu-test-4"
            size            = "Standard_DS1_v2"
            nic             = "nic4"
      }
     }
    }
    

    Then, in the VM resource block:

    resource "azurerm_virtual_machine" "vms" {
      for_each            = var.vms
      name                = each.value.name
      resource_group_name = azurerm_resource_group.rg.name
      location            = azurerm_resource_group.rg.location
      vm_size             = each.value.size
      tags = var.tags
      network_interface_ids = [
        azurerm_network_interface.nics[each.value.nic].id,
      ]
    }
    

    Alternatively, you could try with resource chaining with for_each [1], but then you would have to refactor the resource block a bit:

    resource "azurerm_virtual_machine" "vms" {
      for_each            = azurerm_network_interface.nics
      name                = each.value.name
      resource_group_name = azurerm_resource_group.rg.name
      location            = azurerm_resource_group.rg.location
      vm_size             = var.vm_size # or set it to be equal to "Standard_DS1_v2"
      tags = var.tags
      network_interface_ids = [
        each.value.id,
      ]
    }
    

    Then, you would also have to define a new variable called vm_size:

    variable "vm_size" {
      type        = string
      description = "VM size."
    
      default = "Standard_DS1_v2"
    }
    

    In the second case, you could remove the variable vms completely.


    [1] https://developer.hashicorp.com/terraform/language/meta-arguments/for_each#chaining-for_each-between-resources

    Login or Signup to reply.
  2. Replicated the same scenario and able to create resources.

    Made couple of changes for the existing code base provided

    1. Added **nic = "nic" value at vms block
    2. Updated network_interface_ids = [azurerm_network_interface.nics[each.value.nic].id,]

    Here is the code snippet.
    Step1:
    Main tf code as below

            provider "azurerm" {
     features {}
     }
    variable "prefix" {
      default = "rg_swarna"
    }
    
    resource "azurerm_resource_group" "rg" {
      name     = "${var.prefix}-rg"
      location = "West US"
     // tags = var.tags
    }
    resource "azurerm_virtual_network" "vnet" {
      name                = "${var.prefix}-network-1"
      address_space       = ["10.0.0.0/16"]
      location            = azurerm_resource_group.rg.location
      resource_group_name = azurerm_resource_group.rg.name
     // tags = var.tags
    }
    resource "azurerm_subnet" "subnet" {
      name                 = "${var.prefix}-network-subnet-1"
      resource_group_name  = azurerm_resource_group.rg.name
      virtual_network_name = azurerm_virtual_network.vnet.name
      address_prefixes     = ["10.0.2.0/24"]
    }
    resource "azurerm_network_interface" "nics" {
      for_each            = var.nics
      name                = each.value.name
      location            = azurerm_resource_group.rg.location
      resource_group_name = azurerm_resource_group.rg.name
    
      ip_configuration {
        name                          = "${each.value.name}-conf-1"
        subnet_id                     = azurerm_subnet.subnet.id
        private_ip_address_allocation = "Dynamic"
      }
    
      //tags = var.tags
    }
    resource "azurerm_virtual_machine" "vms" {
      for_each            = var.vms
      name                = each.value.name
      vm_size                = "Standard_DS1_v2"
      resource_group_name = azurerm_resource_group.rg.name
      location            = azurerm_resource_group.rg.location
      network_interface_ids =  [azurerm_network_interface.nics[each.value.nic].id,]
       storage_os_disk {
        name              = "myosdisk${each.value.name}"
        caching           = "ReadWrite"
        create_option     = "FromImage"
        managed_disk_type = "Standard_LRS"
      }
      storage_image_reference {
        publisher = "Canonical"
        offer     = "UbuntuServer"
        sku       = "16.04-LTS"
        version   = "latest"
      }
      os_profile {
        computer_name  = "TestDemo"
        admin_username = "azureuser"
        admin_password = "*****@123"
      }
       os_profile_linux_config {
        disable_password_authentication = false
      }
    }
    

    Step2:
    variable tf file

    variable "allowed_subnet_ids" {
      type        = list(string)
      description = "access"
    }
    variable "nics" {
      type = map
      default = {
        
      nic3 = {
            name = "ubun3"
      }
    
      nic4 = {
            name = "ubun4"
      }
     }
    }
    variable "vms" {
      description = "VM"
      type = map
      default = {
      vm3 = {
            name            = "ubun3"
            size            = "Standard_DS1_v2"
             nic             = "nic3"
        }
      vm4 = {
            name            = "ubuntu4"
            size            = "Standard_DS1_v2"
            nic             = "nic4"
       }
     }
    }
    variable "allowed_ips" {
      type        = list(string)
      description = "IP addresses"
    }
    
    variable "sku" {
      type        = string
      description = "SKU"
    }
    variable "resource_group_name" {
      type        = string
      description = "resource_group_name"
    }
    variable "location" {
      type        = string
      description = "location"
    }    
    

    Step3:

    terraform plan
    terraform apply -auto-approve
    

    Here are the reference screenshots
    enter image description here

    Here is the output from above code

    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search