Home > Back-end >  how to pass and iterate through a list variable in terraform?
how to pass and iterate through a list variable in terraform?

Time:11-04

sorry for the basic question, new to terraform. I am running through some sample examples in terraform where lots of example show declaration of local variable, i.e. locals, by name it sounds like the scope of it, is local to the file. instead of locals, we should be able to pass this list as variable right? such as .also, the examples use for_each construct or locals.names[count.index] , where count.index = length(locals.names) , what is the best way to pass and iterate such list in terraform?

variable "name_list"{
    names = ["luke", "Tom", ...]
    type = ...
}

file - main.tf

locals{
   names = ["luke", "Tom", "Jerry"]
}


resource "aws..." "example..."{

foreach 

}

I have tried it as locals but want to pass the list as variable.

CodePudding user response:

If you are familiar with general-purpose programming languages then it may be helpful to think of a Terraform module as being similar to a function, and then the three different kinds of named values within a module also have analogies:

  • An input variable is like a function argument.
  • A local value is like a local variable within the function.
  • An output value is like a return value.

The analogy isn't perfect because e.g. in many languages a function can only return one value, but Terraform allows a module to return many separate named values. But hopefully this does still make it easier to imagine the scope and purpose of each of these.

Elsewhere in your module, expressions can refer both to input variables and to local values:

  • var.name_list refers to the variable "name_list" declaration you showed in your example.
  • local.names refers to the names local value you showed in your example.

You mentioned wanting to use this with for_each, and the important thing for for_each is that the value you assign to it must be either a map or a set of strings. for_each primarily wants to work with maps, but if you assign a set like toset(["a", "b"]) then as a convenience for_each will interpret it as if you had written tomap({"a" = "a", "b" = "b"}), so you you can write this more concisely when you have a situation where there isn't any useful value to associate with each of your elements.

Since you've shown a collection of unique names in your example it seems like a set of strings would be sufficient for your purposes, and so the following two examples show how to declare a set of strings and use it in for_each, first with a local value and then with an input variable.

locals {
  names = toset(["Luke", "Tom", "Jerry"])
}

resource "example" "example" {
  for_each = local.names

  # ...
}
variable "names" {
  type = set(string)
}

resource "example" "example" {
  for_each = var.names

  # ...
}

If you use the second example in your root Terraform module then you'll need to set the names value from outside the module when you run terraform apply. There are various different ways to do that, but an easy one for the sake of example here is to create a file named example.tfvars and write the following content into it:

names = ["Luke", "Tom", "Jerry"]

Then you can run terraform apply -var-file=example.tfvars to apply this configuration with that set of names. Note that you don't need to (and must not) write toset(...) in the .tfvars file, because for input variables it's the responsibility of the module itself to decide the type, as we did by writing type = set(string) in the configuration above. Terraform will therefore automatically effectively pass this value through toset before passing it into the module.

You should typically only use root module input variables for values you expect will need to change between runs without editing the module's own source code. A local value is a better choice for something that is fixed as part of the definition of the module.

CodePudding user response:

It seems some of the things got mixed up in your understanding of the types of variables. There are local variables (denoted with a locals block) and input variables [1] (they start with variable and are usually defined in a separate file). What the documentation says about locals [2]:

Local values can be helpful to avoid repeating the same values or expressions multiple times in a configuration, but if overused they can also make a configuration hard to read by future maintainers by hiding the actual values used.

Use local values only in moderation, in situations where a single value or result is used in many places and that value is likely to be changed in future. The ability to easily change the value in a central place is the key advantage of local values.

To expand further, there are some inaccuracies in your question. For example, count.index is used only with the count meta-argument, not for_each. The latter requires having a set or a map. If you want to use a variable (either local or input) of type list with for_each, you can cast it to a set by using the toset [3] built-in function.

To continue further, if you have defined an input variable, you can reference it by using var.<variable_name> [4]:

Note: Input variables are created by a variable block, but you reference them as attributes on an object named var.

To get to the last point, an example on how to use local variables with for_each:

resource "aws..." "example..."{
  for_each = toset(local.names)

}

With the declared input variable:

resource "aws..." "example..."{
  for_each = toset(var.name_list) 

}

As you can see, in the second example you are using the object var followed by the variable name, i.e., var.name_list.


[1] https://developer.hashicorp.com/terraform/language/values/variables

[2] https://developer.hashicorp.com/terraform/language/values/locals#when-to-use-local-values

[3] https://developer.hashicorp.com/terraform/language/functions/toset

[4] https://developer.hashicorp.com/terraform/language/values/variables#using-input-variable-values

  • Related