I am trying to copy contents of a list and map into a file in terraform. Here is my variables.tf file.
variable "fruits" {
type = list
description = "List Of Fruits"
default = [ "Apple" , "Banana" , "Mango" ]
}
variable "animals" {
type = map
description = "Map of animals"
default = {
herbivores = "sheep"
carnovore = "lion"
omnivore = "bear"
}
}
variable "birds" {
type = string
description = "A string for Bird"
default = "parrot"
}
variable "bool" {
default = "true"
}
variable "filenames" {
default = "Terraform_Basics.txt"
}
I am trying to create a resource type local_file which will have contents of the map and list values. Able to copy single value but not able to capture all the values at once to be copied to the file.
resource "local_file" "pet" {
filename = var.filenames
content = var.fruits[0]
}
I am new to terraform, can someone help in how I can achieve this.
CodePudding user response:
To do that, there needs to be one very important change. Even if you manage to get it to work for all the elements, you would get the following error:
var.fruits is a list of dynamic, known only after apply
var.pets is a map of dynamic, known only after apply
For these kinds of tests, I usually suggest using local
variables [1]. Their values are not dynamic and are known. So for the first part, I would change variable definitions to local variables:
locals {
fruits = ["Apple", "Banana", "Mango"]
pets = {
herbivores = "sheep"
carnovore = "lion"
omnivore = "bear"
}
filenames = "Terraform_Basics.txt"
}
Now, another thing to note is that you gave the file in the example you posted a logical name of pets
while you were trying to output the values of fruits, which could lead to a lot of confusion down the road. Here is how your resource
blocks should look like:
resource "local_file" "fruits" {
...
}
resource "local_file" "pets" {
...
}
I will explain the content that needs to be added to the resource blocks. You want to fetch all the elements of a map/list. For that, you can use the splat
expression [2].If it is a list, then you can simply do:
resource "local_file" "fruits" {
filename = local.filenames
content = join(", ", local.fruits[*])
}
For a map, there is a slightly different syntax as you would use the values
built-in function [3] which also returns a list, hence why the splat expression is required in this case as well:
resource "local_file" "pets" {
filename = local.filenames
content = join(", ", values(local.pets)[*])
}
Note that there is an additional built-in function you need to use and that is join
[4]. If you were to try to pass only the local variable value in the content
, you would get the following error:
Inappropriate value for attribute "content": string required.
If you are looking to further improve the code, my suggestion would be to create a different filename for pets and fruits because otherwise it will get overridden constantly:
locals {
fruits = ["Apple", "Banana", "Mango"]
pets = {
herbivores = "sheep"
carnovore = "lion"
omnivore = "bear"
}
filename_pets = "Terraform_Basics_Pets.txt"
filename_fruits = "Terraform_Basics_Fruits.txt"
}
And then, in the resources blocks:
resource "local_file" "fruits" {
filename = local.filename_fruits
content = join(", ", local.fruits[*])
}
resource "local_file" "pets" {
filename = local.filename_pets
content = join(", ", values(local.pets)[*])
}
[1] https://www.terraform.io/language/values/locals
[2] https://www.terraform.io/language/expressions/splat