Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Terraform: modules + output from for_each

I have a Terraform script using modules. I want to create multiple resources so I'm using the for_each method.

Below is my variable configuration:

variable bridge_domains {
  description = "Bridge Domain"
  type     = map
  default  = {
    bd1 = {
      name  = "BD1",
    },
    bd2 = {
      name    = "BD2"
    }
  }
}

In the root main.tf file, I'm looping over that variable using for_each:

module "schema_template_bd" {
  source = "./modules/schema_template_bd"
  for_each     =    var.bridge_domains
  
  schema       =    module.tenant.mso_schema.id 
  template     =    var.template

  bd           =    each.value.name
}

Then in the modules/schema_template_bd file I have the following:

resource "mso_schema_template_bd" "bd" {
  schema_id              =      var.schema
  template_name          =      var.template
  name                   =      var.bd
}

The module has an output where I have defined the following:

output "mso_bd" {
  value = mso_schema_template_bd.bd[*]
}

The idea is to output the names from all the objects that were created. So I have defined an output.tf file (at root level) containing the following code:

output "bd_name" {
  value = module.schema_template_bd.mso_bd.*.name
}

I always get:

This object does not have an attribute named "name".

Normally the bd object has a name so the error has to do with a wrong syntax in my view.

like image 282
wiwa1978 Avatar asked Nov 24 '20 14:11

wiwa1978


People also ask

Can I use For_each in output Terraform?

for_each is a meta-argument defined by the Terraform language. It can be used with modules and with every resource type.

How do you reference modules in Terraform?

Modules on the public Terraform Registry can be referenced using a registry source address of the form <NAMESPACE>/<NAME>/<PROVIDER> , with each module's information page on the registry site including the exact address to use.

How can I create dynamic output from a Terraform Module?

We know we can define a Terraform module that produces output for another module to use as input. But how can we build dynamic output from a module that creates a set resources, and format that output just right to act as input elsewhere? It's possible with the help of Terraform for and for_each expressions and the zipmap function.

How do I add an IP address to a terraform configuration?

From the virtual machine module, create an output for the IP address, then use the IP address as an input value for the firewall child module. Below is an example of adding an output value to a Terraform configuration. Use the output keyword followed by an identifier for the output.

What is a terraform configuration file?

You may have written a Terraform configuration file that deployed multiple cloud resources, like a network, public IP address, and virtual machine. While you can define all these resources in a single configuration file, you can also break out different components into their own modules.

What is the root module in TerraForm?

Every Terraform configuration has at least one module called the root module. The root module is any .tf and/or .tf.json files stored in the main working directory. Let’s say you have a Terraform configuration saved in a root module folder named web-app consisting of three files: main.tf – used to define providers, remote backend state file.


Video Answer


2 Answers

The [*] and .* operators are intended for use with lists only. Because this resource uses for_each rather than count, its value in other expressions is a map, not a list.

To make your configuration work you'll need to decide whether it's better to return a map of names where the keys are the var.bridge_domains keys, or to return just a set of ids where the caller then couldn't determine which name belongs to which of the elements of var.bridge_domains:

output "bd_name" {
  value = {
    for k, bd in mso_schema_template_bd.bd : k => bd.name
  }
}

OR

output "bd_name" {
  value = [
    for bd in mso_schema_template_bd.bd : bd.name
  ]
}

If only unique results are desirable in the second example, the function toset can be used:

output "bd_name" {
  value = toset([
    for bd in mso_schema_template_bd.bd : bd.name
  ])
}

This uses for expressions, which are the more general counterpart of splat expressions that work with collections of any type and which can produce both sequences and mappings as their result, whereas splat expressions work only with lists.

like image 152
Martin Atkins Avatar answered Oct 24 '22 07:10

Martin Atkins


Leaving this here in case someone is interested

output "bd_name" {
  value = values(mso_schema_template_bd.bd).*.name
}
like image 13
kiabso Avatar answered Oct 24 '22 08:10

kiabso