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.
2
Answers
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 withvariable
and are usually defined in a separate file). What the documentation says aboutlocals
[2]:To expand further, there are some inaccuracies in your question. For example,
count.index
is used only with thecount
meta-argument, notfor_each
. The latter requires having a set or a map. If you want to use a variable (either local or input) of type list withfor_each
, you can cast it to a set by using thetoset
[3] built-in function.To continue further, if you have defined an input variable, you can reference it by using
var.<variable_name>
[4]:To get to the last point, an example on how to use local variables with
for_each
:With the declared input variable:
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
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:
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 thevariable "name_list"
declaration you showed in your example.local.names
refers to thenames
local value you showed in your example.You mentioned wanting to use this with
for_each
, and the important thing forfor_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 liketoset(["a", "b"])
then as a conveniencefor_each
will interpret it as if you had writtentomap({"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.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 runterraform apply
. There are various different ways to do that, but an easy one for the sake of example here is to create a file namedexample.tfvars
and write the following content into it: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) writetoset(...)
in the.tfvars
file, because for input variables it’s the responsibility of the module itself to decide the type, as we did by writingtype = set(string)
in the configuration above. Terraform will therefore automatically effectively pass this value throughtoset
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.