Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.3k views
in Technique[技术] by (71.8m points)

terraform - Using an environment variable as a map for common tags in a locals block

I've run into a specific problem while trying to automate a tagging process in terraform. I've set an environment variable that is essentially a list of all the tags we'd be using for all resources provisioned in the apply. It looks like this...

export TF_VAR_taglist='{JiraEpic = "ETOS-56","AssignedResearcherPri" = "Isaac",AssignedResearcherSec = "Matt"}'

After setting the environment variable I added a variable called "taglist" in the variables.tf file that grabs the aforementioned environment variable. It looks like this...

variable "taglist"{}

Lastly, I have another locals.tf file where i set a common_tags variable. Like so...

locals { common_tags ="${var.taglist}" }

When i terraform apply, the build fails while trying to map the tags properly. This is the error i receive...

Error: Incorrect attribute value type

  on kube_master_worker_nodes_ec2.tf line 9, in resource "aws_instance" "master":
   9:   tags = local.common_tags
    |----------------
    | local.common_tags is "{JiraEpic = "ETOS-56",AssignedResearcherPri = "Isaac ",AssignedResearcherSec = "Matt"}"

Inappropriate value for attribute "tags": map of string required.

I then decided to define the type of the variable as map(string in the variables.tf file like this variable "taglist"{ type = map(string) } I had hoped that this would allow terraform to recognize this variable as a map of strings and not just a string literal, but I was wrong, and these are the errors I get when that definition is applied.

Error: Missing attribute separator

  on <value for var.taglist> line 1:
  (source code not available)

Expected a newline or comma to mark the beginning of the next attribute.


Error: No value for required variable

  on variables.tf line 11:
  11: variable "taglist"{

The root module input variable "taglist" is not set, and has no default value.
Use a -var or -var-file command line argument to provide a value for this
variable.

I'm really stuck on this, and I feel like I'm close. Can anyone provide some insight into this and how I should go about solving it?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Terraform uses the type constraint of a variable to decide how to interpret a string representation of its value. By default, Terraform will assume the value expects a primitive type such as a string or number, because that's the most typical case for variables set via the command line or environment variables.

Since your tag list is a list you need Terraform to interpret it as a map expression rather than as a string. You can tell Terraform to do that by telling Terraform which type of value you expect:

variable "taglist" {
  type = map(string)
}

You can read more about this in the Terraform documentation section Complex-typed Values.

You then need to make sure that the value in the environment variable is a valid object expression in order to avoid a syntax error. If you're setting the environment variable from the shell command line then you need to be mindful of escaping/quoting to ensure that Terraform will see the value with all of the quotes intact, and without any extra metacharacters.

The result is often hard to read clearly, which is why the Terraform documentation recommends using a .tfvars file to set complex-typed variables, instead of the -var command line option or environment variables. However, since you are using automation you might find it easier to generate a .tfvars.json file instead, which uses standard JSON format and is therefore easier to generate using JSON libraries available in most programming languages. Here's the .tfvars.json equivalent of the value you showed in your question:

{
  "taglist": {
    "JiraEpic": "ETOS-56",
    "AssignedResearcherPri": "Isaac",
    "AssignedResearcherSec": "Matt"
  }
}

Note that subjectively I'd find it pretty confusing to have a variable whose name ends in list when it actually expects a map. A more typical name for this variable would be just tags, though if it's useful to mention its type in order to distinguish it from other variables then I'd suggest tag_map instead, to make it less confusing.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...