Search code examples
azureterraformazure-cloud-servicesazure-rm

Creating varying number of VM's with unique NIC's using for_each


I'm trying to create varying number of VM's with different configurations. I'm setting for_each on the azurerm_windows_virtual_machine resource and looping through a map set in a tfvars file. The variable is set in the module but defined in the tfvars file.

I want to be able to create x amount of VM's with each one having a unique NIC attached. I am able to create the VM's but provisioning fails because the NIC is not unique. I have tried adding for_each using the same variable but I get the following errors:

Error: Incorrect attribute value type

  on ../modules/compute/windows_vm/windows_vm.tf line 96, in resource "azurerm_network_interface_application_security_group_association" "application_security_group_association":
  96:   network_interface_id          = [azurerm_network_interface.network_interface[each.key].id]

Inappropriate value for attribute "network_interface_id": string required.


Error: Incorrect attribute value type

  on ../modules/compute/windows_vm/windows_vm.tf line 96, in resource "azurerm_network_interface_application_security_group_association" "application_security_group_association":
  96:   network_interface_id          = [azurerm_network_interface.network_interface[each.key].id]

Inappropriate value for attribute "network_interface_id": string required.

This is my code:

# VM Network Interface
resource "azurerm_network_interface" "network_interface" {
  for_each                      = var.servers
  name                          = "nic-${var.environment}-${var.directorate}-${var.business_unit}-${var.vm_identifier}${each.value.name}"
  resource_group_name           = var.resource_group
  location                      = var.location
  enable_ip_forwarding          = "false"
  enable_accelerated_networking = "false"

  ip_configuration {
    name                          = "ipconfig1"
    subnet_id                     = data.azurerm_subnet.subnet.id
    private_ip_address_allocation = "Dynamic"
    primary                       = "true"
  }
  
}

# Application Security Group
resource "azurerm_application_security_group" "application_security_group" {
  name                = "asg-${var.environment}-${var.directorate}-${var.business_unit}-${var.vm_identifier}"
  resource_group_name = var.resource_group
  location            = var.location
}

resource "azurerm_network_interface_application_security_group_association" "application_security_group_association" {
  for_each                      = var.servers
  network_interface_id          = [azurerm_network_interface.network_interface[each.key].id]
  application_security_group_id = azurerm_application_security_group.application_security_group.id
  
}

resource "azurerm_network_interface_security_group_association" "network_security_group_association" {
  for_each                  = var.servers
  network_interface_id      = [azurerm_network_interface.network_interface[each.key].id]
  network_security_group_id = azurerm_network_security_group.network_security_group.id
}

# Azure Virtual Machine
resource "azurerm_windows_virtual_machine" "virtual_machine" {
  for_each                         = var.servers
  name                             = "vm-${var.environment}-${var.vm_identifier}${each.value.name}"
  location                         = var.location
  resource_group_name              = var.resource_group
  zone                             = each.value.zone
  size                             = var.vm_size
  network_interface_ids            = [azurerm_network_interface.network_interface[each.key].id]
  computer_name                    = "${var.vm_identifier}${each.value.name}"
  admin_username                   = xxxx
  admin_password                   = xxxx
  provision_vm_agent               = "true"
  source_image_id                  = data.azurerm_shared_image.shared_image.id


  boot_diagnostics {
    storage_account_uri = data.azurerm_storage_account.diag_storage_account.primary_blob_endpoint
  }

  os_disk {
    name                      = "vm-${var.environment}-${var.directorate}-${var.business_unit}-${var.vm_identifier}-os${each.value.name}"
    caching                   = "ReadWrite"
    storage_account_type      = "Premium_LRS"
  }

  depends_on = [azurerm_network_interface.network_interface]
}

Variable within the root module that is used in the for_each and set in module variables.tf:

variable "servers" {
  description = "Variable for defining each instance"
}

Variables in the module that map to each tfvars per environment:

variable "desktop_servers" {
  description = "Variable for defining each instance"
}

variable "db_servers" {
  description = "Variable for defining each instance"
}

The above are then defined in the tfvars as below:

desktop_servers = {
  "Server_1" = {
    name = 1,
    zone = 1
  }
  "Server_2" = {
    name = 2,
    zone = 2
  }
  "Server_3" = {
    name = 3,
    zone = 3
  }
}

db_servers = {
  "Server_1" = {
    name = 1,
    zone = 1
  }
}

Solution

  • You are assigning a list into network_interface_id, however it should be a string only.

    Thus, instead of:

    network_interface_id          = [azurerm_network_interface.network_interface[each.key].id]
    

    it should be

    network_interface_id          = azurerm_network_interface.network_interface[each.key].id