Terraform CLI decides how to interpret your -var arguments (and also the similar TF_VAR_-prefixed environment variables) based on the type constraint you specified for the input variable.
Because root module input variables are most commonly strings, by default Terraform CLI will just treat the value as a raw string to make it easier to set those without needing to include extra quotes escaped by the shell.
If you change your variable block to declare the variable as expecting a map or list type then Terraform CLI will instead parse the string you provided as Terraform expression syntax, which I think will achieve the result you wanted:
variable "mylist" {
type = list(string)
}
variable "mymap" {
type = map(string)
}
This is a special rule just for root module input variables set directly on the command line and in environment variables, because in this case thereβs some ambiguity about how a value should be interpreted. This is behavior implemented by Terraform CLI as it decodes the command line and environment, rather than behavior of the Terraform Language itself. The type constraint doesnβt affect the parsing of variable values in any other context.
$ terraform plan -var 'local_vsphere_config={"username":"foo","host":"foo","password":"foo"}'
β·
β Error: Error in function call
β
β on main.tf line 26, in locals:
β 26: vsphere_config = merge(
β 27: var.vsphere_config_defaults,
β 28: var.local_vsphere_config,
β 29: )
β βββββββββββββββββ
β β var.local_vsphere_config is "{\"username\":\"foo\",\"host\":\"foo\",\"password\":\"foo\"}"
β β var.vsphere_config_defaults is object with 3 attributes
β
β Call to function "merge" failed: arguments must be maps or objects, got "string".
Ok, I see where I went wrong. Itβs the local_vsphere_config variable that has to be explicitly typed in the manifest (whereas I used just {}). It works now. Thanks!