Home > Enterprise >  Copy Values From List and Map To A File In Terraform
Copy Values From List and Map To A File In Terraform

Time:06-27

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

[3] https://www.terraform.io/language/functions/values

[4] https://www.terraform.io/language/functions/join

  • Related