How to write variable type for map of objects in terraform

123 Views Asked by At

I am trying to write a variable type for below configuration

virtual_machines = {
  nodes = {
    app1_node1 = {
      "vm_name" = "app"
      "vm_num"  = "1"
      networks = {
        nic1 = {
          "nic_name" = "app-1"
          "subnet"   = "****"
        },
      }
    },
    service1_node1 = {
      "vm_name" = "service"
      "vm_num"  = "1"
      networks = {
        nic1 = {
          "nic_name" = "service-1"
          "subnet"   = "****"
        },
      }
    },
    db1_node1 = {
      "vm_name" = "db"
      "vm_num"  = "1"
      "as_name" = "app-avset"

      networks = {
        nic1 = {
          "nic_name" = "db-1-1"
          "subnet"   = "****"
        },
        nic2 = {
          "nic_name" = "db-1-2"
          "subnet"   = "/subscriptions/************/resourceGroups/pluto/providers/Microsoft.Network/virtualNetworks/pluto-infra/subnets/db-subnet"
        }
      }
    },
    db2_node2 = {
      "vm_name" = "db"
      "vm_num"  = "2"
      "as_name" = "app-avset"
      networks = {
        nic1 = {
          "nic_name" = "db-2-1"
          "subnet"   = "****"
        },
        nic2 = {
          "nic_name" = "db-2-2"
          "subnet"   = "/subscriptions/************/resourceGroups/pluto/providers/Microsoft.Network/virtualNetworks/pluto-infra/subnets/db-subnet"
        },
      }
    },
  }
}

I have tried with below variable type, however it is not working as expected.

variable "virtual_machines" {
  type = map(object({
    nodes = map(object({
      vm_name = string
      vm_num  = string
      as_name = optional(string)
      networks = map(object({
        nic_name = string
        subnet   = string
      }))
    }))
  }))
  default = {}
}

Error :

│ Error: Invalid value for input variable
│
│   on main.tf line 4, in module "virtualmachine":
│    4:   virtual_machines        = var.virtual_machines
│
│ The given value is not suitable for module.virtualmachine.var.virtual_machines declared at virtualmachine\variables.tf:6,1-28: element "nodes": attribute
│ "nodes" is required.

Could someone assist on how to write the correct type for the given configuration ? Note : The default should be empty if don't have requirement to create virtual machines.

1

There are 1 best solutions below

0
On

I do agree with Olakunle Abiola

The error you encountered was caused by an invalid structure in both tfvars and variable.

Here is the updated terraform code to create VMs using the variable and tfvar file.

terraform.tfvars

virtual_machines = {
  app1_node1 = {
    vm_name = "app"
    vm_num  = "1"
    networks = {
      nic1 = {
        nic_name = "/subscriptions/<sub-id>/resourceGroups/<RG_NAME>/providers/Microsoft.Network/networkInterfaces/NIC-2"
        subnet   = "****"
      }
    }
  },
  service1_node1 = {
    vm_name = "service"
    vm_num  = "1"
    networks = {
      nic1 = {
        nic_name = "/subscriptions/<>sub-id/resourceGroups/<RG_NAMe>/providers/Microsoft.Network/networkInterfaces/venkat-NIC-1"
        subnet   = "****"
      }
    }
  }
}

variables.tf

    variable "virtual_machines" {
      description = "A map of virtual machine configurations"
      type = map(object({
        vm_name  = string
        vm_num   = string
        networks = map(object({
          nic_name = string
          subnet   = string
        }))
      }))
      default = {}
    }

Main.tf

provider "azurerm" {
  features {}
}
data "azurerm_resource_group" "example" {
  name     = "<RG_Name>"
}
resource "azurerm_virtual_machine" "main" {
  for_each = var.virtual_machines
 
  name                  = "${each.value.vm_name}${each.value.vm_num}"
  location              = data.azurerm_resource_group.example.location
  resource_group_name   = data.azurerm_resource_group.example.name
  vm_size               = "Standard_DS1_v2"
 
  network_interface_ids = [for _, nic in each.value.networks : nic.nic_name]
 
  storage_image_reference {
    publisher = "Canonical"
    offer     = "0001-com-ubuntu-server-jammy"
    sku       = "22_04-lts"
    version   = "latest"
  }
 
  storage_os_disk {
    name              = "${each.value.vm_name}${each.value.vm_num}-osdisk"
    caching           = "ReadWrite"
    create_option     = "FromImage"
    managed_disk_type = "Standard_LRS"
  }
 
  os_profile {
    computer_name  = "${each.value.vm_name}${each.value.vm_num}"
    admin_username = "testadmin"
    admin_password = ""
  }
 
  os_profile_linux_config {
    disable_password_authentication = false
  }
 
  tags = {
    environment = "staging"
  }
}

Terraform apply:

enter image description here

After running the code, the VMs were successfully created in the Azure portal

enter image description here