Terraform Nested Module Calling and Outputs

ColossusMark1 picture ColossusMark1 · Jan 23, 2019 · Viewed 8.5k times · Source

I'm working on infrastructure provisioning, so I'm calling modules as nested.

There is my file system tree.

   ├── main.tf
   └── modules
       ├── client.tf
       └── in
          └── main.tf

My files showing as below .

   #main.tf 
   module "my_vpc" {
          source = "./modules"
   }

   # modules/client.tf
   provider "aws" {
          region = "us-east-2"
   }

   module "inner" {
          source = "./in"
   }

  # in/main.tf

  provider "aws" {
        region = "us-east-2"
  }

  resource "aws_vpc" "main" {
        cidr_block = "10.0.0.0/16"
  }

  output "vpc_id" {
      value = "${aws_vpc.main.id}"
  }

So in my case, I want to get the outputs coming from resource-created modules at in/main.tf. But when I ran the terraform apply command there is no output.

How I can solve this problem?

Answer

rclement picture rclement · Jan 23, 2019

You have two modules being used but only one output statement.

./main.tf creates module my_vpc from ./modules/client.tf in client.tf you create module inner from ./modules/in/main.tf

The module inner has a single output vpc_id defined in ./modules/in/main.tf You need to make an output statement at the ./modules/client.tf level as well. Any module that you want an output from, must have an output statement for that variable, even if the output is chaining the output of an inner module.

# ./modules/client.tf
provider "aws" {
   region = "us-east-2"
}

module "inner" {
   source = "./in"
}

output "vpc_id" {
   value = "${modules.inner.vpc_id}"
}

Now the module defined in ./modules/client.tf outputs the value you want at the top level. You can interact with it in ./main.tf like this:

#main.tf 
module "my_vpc" {
   source = "./modules"
}

locals {
   vpc_id = "${modules.my_vpc.vpc_id}"
}

# output the vpc id if you need to
output "vpc_id" {
   value = "${modules.my_vpc.vpc_id}"
}

As a side note, as you scale up your terraform and module usage, being consistent will help. If you are going to have a module inside of another module, I recommend having a consistent folder structure like the following.

├── main.tf
└── modules
   ├── vpc
      ├── modules
      ├  └── in
      ├     └── main.tf
      └── client.tf
   └── another_module
      └── main.tf