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 ?
CodePudding user response:
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.
CodePudding user response:
Replicated the same scenario and able to create resources.
Made couple of changes for the existing code base provided
- Added **nic = "nic" value at vms block
- 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 = "Azureuser@123"
}
os_profile_linux_config {
disable_password_authentication = false
}
}
Step2: variable tf file as fallows
variable "allowed_subnet_ids" {
type = list(string)
description = "List of subnet IDs to be allowed to access the ACR"
}
variable "nics" {
type = map
default = {
nic3 = {
name = "ubuntutest3"
}
nic4 = {
name = "ubuntutest4"
}
}
}
variable "vms" {
description = "Virtual Machines"
type = map
default = {
vm3 = {
name = "ubuntutest3"
size = "Standard_DS1_v2"
nic = "nic3"
}
vm4 = {
name = "ubuntutest4"
size = "Standard_DS1_v2"
nic = "nic4"
}
}
}
variable "allowed_ips" {
type = list(string)
description = "White list 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
Here is the output from above code