11

My terraform snippet:

variable "machine_details" {
  type = object({
    name              = string
    size = string
    username               = string
    password = string
  })

  default = [
    {
      name              = "example-vm"
      size = "Standard_F2"
      username               = "adminuser"
      password = "Notallowed1!"
    }
  ]
}

I am getting error as below.

    Error: Invalid default value for variable
    │
    │   on variables.tf line 38, in variable "machine_details":
    │   38:   default = [
    │   39:     {
    │   40:       name              = "example-vm"
    │   41:       size = "Standard_F2"
    │   42:       username               = "adminuser"
    │   43:       password = "Notallowed1!"
    │   44:     }
    │   45:   ]
This default value is not compatible with the variable's type constraint: object required.

I tried map(string) but didn't work too.

similary list(string) also.

I am trying the latest azurerm provider.

Also, in the gcp, we have option to provide count(for instances), so if I provide 2, two instances will be created.

How to do the same with azure and aws?

How to resolve this?

6
  • 2
    Why is the default value a list? Commented Jan 13, 2022 at 9:56
  • Because we want to keep all the data related to the azure instance resource in a single place. Commented Jan 13, 2022 at 10:12
  • 3
    That is not what I meant: you specify the type to be an object but you provide a list as default, those two types do not match up. Either the type needs to be list(object(...)) or the default must not be a list. Commented Jan 13, 2022 at 10:13
  • Can you share a sample code on how to pass the values here Commented Jan 13, 2022 at 10:29
  • 1
    Well, he did, just enclose the object with list(). Commented Jan 13, 2022 at 13:01

4 Answers 4

16

it is working this way.

variable "machine_details" {
  type = object({
    name = string
    size = string
    username = string
    password = string
  })

  default = {
      name = "example-vm"
      size = "Standard_F2"
      username  = "adminuser"
      password = "Notallowed1!"
    }
  
}

And can refer like this : var.machine_details.name

Sign up to request clarification or add additional context in comments.

Comments

9

I am using Terraform 1.3.0, this can be done using the optional function.
I changed your example to demonstrate some more functionalities

variable machine_details {
  description = "Example using optional values"
  type        = object({
    id        = string
    name      = optional(string,"defalt_name") 
    size      = optional(number, 500)
    username  = optional(string,"defalt_username")
    password  = optional(string)
  })
}

Creating an object id is mandatory, password is null by default


machine_details = {
  id  = "id-example-1"
}

result

 { 
  id  = "id-example-1",
  username ="defalt_name",
  size = 500,
  username ="defalt_username",
  password = null
}

Creating object overriding default username and setting password

machine_details = {
  id  = "id-example-2",
  username ="my_name",
  password = "secret" 
}

result

 { 
  id  = "id-example-1",
  name ="defalt_name",
  size = 500,
  username ="my_name",
  password = "secret" 
}

see also Optional with defaults

Comments

3

As Marko E and luk2302 have mentioned , You have to declare and pass the variable as below :

variable "machine_details" {
  type = list(object({
    name = string
    size = string
    username = string
    password = string
  }))

  default = [
    {
      name = "example-vm"
      size = "Standard_F2"
      username = "adminuser"
      password = "Notallowed1!"
    },
    {
      name = "example2-vm"
      size = "Standard_F2"
      username = "adminuser1"
      password = "Notallowed2!"
    }
  ]
}

So that if you want to use count then you can use something like below :

provider "azurerm" {
  features{}
}

data "azurerm_resource_group" "example" {
  name     = "ansumantest"
}

resource "azurerm_virtual_network" "example" {
  name                = "example-network"
  address_space       = ["10.0.0.0/16"]
  location            = data.azurerm_resource_group.example.location
  resource_group_name = data.azurerm_resource_group.example.name
}

resource "azurerm_subnet" "example" {
  name                 = "internal"
  resource_group_name  = data.azurerm_resource_group.example.name
  virtual_network_name = azurerm_virtual_network.example.name
  address_prefixes     = ["10.0.2.0/24"]
}
resource "azurerm_public_ip" "example" {
  count = length(var.machine_details)
  name                = "aks-nfs-public-ip${count.index}"
  location            = data.azurerm_resource_group.example.location
  resource_group_name = data.azurerm_resource_group.example.name
  allocation_method   = "Dynamic"

  tags = {
    environment = "Production"
  }
}

resource "azurerm_network_interface" "example" {
  count = length(var.machine_details)
  name                = "example-nic-${count.index}"
  location            = data.azurerm_resource_group.example.location
  resource_group_name = data.azurerm_resource_group.example.name

  ip_configuration {
    name                          = "internal"
    subnet_id                     = azurerm_subnet.example.id
    public_ip_address_id = "${element(azurerm_public_ip.example.*.id, count.index)}"
    private_ip_address_allocation = "Dynamic"
  }
}

resource "azurerm_ssh_public_key" "example" {
  name                = "ansuman-sshkey"
  resource_group_name = data.azurerm_resource_group.example.name
  location            = data.azurerm_resource_group.example.location
  public_key          = file("~/.ssh/id_rsa.pub")
}

resource "azurerm_linux_virtual_machine" "example" {
  count = length(var.machine_details)
  name                = var.machine_details[count.index].name
  resource_group_name = data.azurerm_resource_group.example.name
  location            = data.azurerm_resource_group.example.location
  size                = var.machine_details[count.index].size
  admin_username      = var.machine_details[count.index].username
  admin_password      = var.machine_details[count.index].password
  disable_password_authentication = true
  network_interface_ids = ["${element(azurerm_network_interface.example.*.id, count.index)}"]

  admin_ssh_key {
    username   = var.machine_details[count.index].username
    public_key = azurerm_ssh_public_key.example.public_key
  }

  os_disk {
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
  }

  source_image_reference {
    publisher = "Canonical"
    offer     = "UbuntuServer"
    sku       = "16.04-LTS"
    version   = "latest"
  }
}

Output:

enter image description here

Comments

1

You can use optional object type attributes

https://developer.hashicorp.com/terraform/language/expressions/type-constraints

variable "with_optional_attribute" {
  type = object({
    a = string                # a required attribute
    b = optional(string)      # an optional attribute
    c = optional(number, 127) # an optional attribute with default value
  })
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.