Inconsistent syntaxing?

Hello,

I’m working with

# terraform -v                                                                                                                                                                        
Terraform v0.12.24
+ provider.aws v2.56.0
+ provider.random v2.2.1

if i go into the console and do:

> { "a"= "b", "c"= "d"}
{
  "a" = "b"
  "c" = "d"
}

seems to work, but if i do on a tf file:

variable "servers" {
    "ip_address" = "1.2.3.4"
    "hc_port" = "80"
}

I get:
Error: Invalid argument name

  on test.tf line 13, in variable "servers":
  13:     "ip_address" = "1.2.3.4"

Argument names must not be quoted.

And if i unquote them:

Error: Unsupported argument

  on test.tf line 13, in variable "servers":
  13:     ip_address = "1.2.3.4"

An argument named "ip_address" is not expected here.

What is the expected way of creating maps, since “map” is going to be deprecated as per https://www.terraform.io/docs/configuration/functions/map.html ?

Nevermind that, one needs to APPLY in order to get the outputs…

Thanks!

Hi @davidcsi,

The variable block is the declaration of a variable, not the assignment of its value. So inside the variable block Terraform expects a fixed set of arguments like type, description, default, etc.

If you want to declare a map variable and set a default value for it then this would be the syntax for that:

variable "servers" {
  type = map(string)
  default = {
    "ip_address" = "1.2.3.4"
    "hc_port"    = "80"
  }
}
1 Like

Thanks @apparentlymart

I ended up doing

variable "servers" {
    #type = list(map(string))
    default = {
        "fs-1" = {
            ip_address = "1.2.3.4"
            healthcheck_name = "server-1-failure"
            resource_path = "/alive.html"
            resource_port = "80"
        },
        "fs-2" = {
            ip_address = "4.3.2.1"
            healthcheck_name = "server-2-failure"
            resource_path = "/alive.html"
            resource_port = "80"
        },
        "kam" = {
            ip_address = "9.8.7.6"
            healthcheck_name = "server-3"
            resource_path = "/alive.html"
            resource_port = "80"
        }
    }
} 

All of terraform seems so weird to me i had to document it here: https://github.com/davidcsi/terraform/tree/master/healthchecks

I’m starting to play with it.

To your explanation, if the block is only the declaration, then what is the default value for? it’s a way of assigning a value, right? seems to me that yes. I know one can override it, but still.

Anyway, thanks for your help!

Yes, the default argument declares that the variable is optional and that if the caller doesn’t set it then it should be set to the value given as the default.

With that said, it’s unusual to have such a specific value (with particular IP addresses, paths, and port numbers hard-coded) as a default. If you aren’t expecting this value to ever be overridden by setting a value for it, a Local Value might be a better way to express that intent, since that makes it something that is set privately within your module rather than something that the caller is supposed to set:

locals {
  servers = {
    "fs-1" = {
        ip_address = "1.2.3.4"
        healthcheck_name = "server-1-failure"
        resource_path = "/alive.html"
        resource_port = "80"
    },
    "fs-2" = {
        ip_address = "4.3.2.1"
        healthcheck_name = "server-2-failure"
        resource_path = "/alive.html"
        resource_port = "80"
    },
    "kam" = {
        ip_address = "9.8.7.6"
        healthcheck_name = "server-3"
        resource_path = "/alive.html"
        resource_port = "80"
    }
  }
}

You can access that variable then as local.servers rather than var.servers, but the overall result should be the same.


If you are coming from a programming background, it might help to think of variable blocks as being like function arguments, while locals blocks are like declaring local variables within your function. Outputs are like return values from a function. I’ll just choose Python arbitrarily to use as an example here; the difference in meaning between using an input variable vs. a local value here is like the difference between declaring a parameter with a default value, like this:

def example(servers={"fs-1":{...},"fs-2":{...},etc}):
    print(servers)

…vs declaring a function with no parameters that has a local variable, like this:

def example():
  servers = {"fs-1":{...},"fs-2":{...},etc}
  print(servers)

Both of them create a function that you can call with no arguments and get the same result, but the first one invites the caller to potentially override the value to change the outcome, while the second one encapsulates that decision and forces a particular result.

1 Like