Terraform: ${module.xxx.zzz} doesn't work across modules

Created on 1 Mar 2016  ยท  7Comments  ยท  Source: hashicorp/terraform

Simple test:

  • infrastructure.tf
module "first" {
  source = "./modules/first"
  vpc_cidr = "10.128.0.0/16"
}

module "second" {
  source = "./modules/second"
  vpc_cidr = "10.129.0.0/16"
}
  • modules/first/first.tf
variable "vpc_cidr" { }

resource "aws_vpc" "main" {
  cidr_block = "${var.vpc_cidr}"
  enable_dns_hostnames = true
}

resource "aws_security_group" "main" {
  name = "first"
  vpc_id = "${aws_vpc.main.id}"
}

output "owner_id" {
  value = "${aws_security_group.main.owner_id}"
}

output "vpc_id" {
  value = "${aws_vpc.main.id}"
}
  • modules/second/second.tf
variable "vpc_cidr" { }

resource "aws_vpc" "main" {
  cidr_block = "${var.vpc_cidr}"
  enable_dns_hostnames = true
}

resource "aws_security_group" "main" {
  name = "first"
  vpc_id = "${aws_vpc.main.id}"
}

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

resource "aws_vpc_peering_connection" "first-second" {
  peer_owner_id = "${module.first.owner_id}"
  peer_vpc_id = "${module.first.vpc_id}"
  vpc_id = "${module.second.vpc_id}"
  auto_accept = true
}

This results in:

$ terraform plan
Error configuring: 3 error(s) occurred:

* aws_vpc_peering_connection.first-second: missing dependency: module.first.output.vpc_id
* aws_vpc_peering_connection.first-second: missing dependency: module.second.output.vpc_id
* aws_vpc_peering_connection.first-second: missing dependency: module.first.output.owner_id

This works, however, if I move the aws_vpc_peering_connection to infrastructure.tf. However, in the "real world" (in my real config which mirror this), Terraform keeps deleting and re-adding the peering (and the corresponding routes I didn't put in the example).

I really didn't want them in the top file, but either I'm doing something wrong, or this is a bug (or it's not designed to work cross-module).. I was hoping that if I could put the peering in the module where it belongs, it would simplify my life and also not keep re-adding them every time...

documentation

Most helpful comment

Oh yes, you're right... sorry I didn't read closely enough.

In fact the problem here is that modules form a tree and a module can only directly refer to the outputs from its child modules. Your first and second modules are siblings in the tree, and so they cannot directly interact with one another.

If one module needs access to a value from one of its siblings, the way to achieve that is to make the parent pass through an output from one module as a variable (input) to another.

So your root module would look something like this:

module "first" {
  source = "./modules/first"
  vpc_cidr = "10.128.0.0/16"
}

module "second" {
  source = "./modules/second"
  vpc_cidr = "10.129.0.0/16"
  first_vpc_id = "${module.first.vpc_id}"
  first_owner_id = "${module.first.owner_id}"
}

and then your second child module would reference these passed in values as additional variables:

variable "vpc_cidr" { }
variable "first_vpc_id" { }
variable "first_owner_id" { }

resource "aws_vpc" "main" {
  cidr_block = "${var.vpc_cidr}"
  enable_dns_hostnames = true
}

resource "aws_security_group" "main" {
  name = "first"
  vpc_id = "${aws_vpc.main.id}"
}

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

resource "aws_vpc_peering_connection" "first-second" {
  peer_owner_id = "${var.first_owner_id}"
  peer_vpc_id = "${var.first_vpc_id}"
  vpc_id = "${aws_vpc.main.id}"
  auto_accept = true
}

All 7 comments

@FransUrbo the interpolation format for a module output is module.first.vpc_id, rather than module.first.output.vpc_id. (This is an annoying inconsistency between terraform_remote_state and directly-instantiated modules.)

If you look at the output, I _DID_ use module.first.vpc_id. It is the output of Terraform that uses module.first.output.vpc_id...

Oh yes, you're right... sorry I didn't read closely enough.

In fact the problem here is that modules form a tree and a module can only directly refer to the outputs from its child modules. Your first and second modules are siblings in the tree, and so they cannot directly interact with one another.

If one module needs access to a value from one of its siblings, the way to achieve that is to make the parent pass through an output from one module as a variable (input) to another.

So your root module would look something like this:

module "first" {
  source = "./modules/first"
  vpc_cidr = "10.128.0.0/16"
}

module "second" {
  source = "./modules/second"
  vpc_cidr = "10.129.0.0/16"
  first_vpc_id = "${module.first.vpc_id}"
  first_owner_id = "${module.first.owner_id}"
}

and then your second child module would reference these passed in values as additional variables:

variable "vpc_cidr" { }
variable "first_vpc_id" { }
variable "first_owner_id" { }

resource "aws_vpc" "main" {
  cidr_block = "${var.vpc_cidr}"
  enable_dns_hostnames = true
}

resource "aws_security_group" "main" {
  name = "first"
  vpc_id = "${aws_vpc.main.id}"
}

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

resource "aws_vpc_peering_connection" "first-second" {
  peer_owner_id = "${var.first_owner_id}"
  peer_vpc_id = "${var.first_vpc_id}"
  vpc_id = "${aws_vpc.main.id}"
  auto_accept = true
}

I see, thank you. Could this then be tagged "Documentation" or something?

Yes, I suppose you're right that this could be spelled out a bit more clearly in the module docs.

Sorry for the long silence here!

The module documentation mentioned by @apparentlymart has been completely revised as part of the Terraform 0.12 release and now gives more information about what it means to call a module, and how to refer to module outputs.

Along with that, we also have a specific guide on Module Composition which describes patterns and best practices for using multiple modules together in a configuration.

Documentation can always be improved further, so it's difficult to decide whether this counts as this issue being "done", but we're going to close it in the hope that the new documentation is sufficient. If not, we'll iterate on the documentation further in other issues as further questions arise.

Thanks for reporting this!

I'm going to lock this issue because it has been closed for _30 days_ โณ. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rkulagowski picture rkulagowski  ยท  3Comments

c4milo picture c4milo  ยท  3Comments

rjinski picture rjinski  ยท  3Comments

zeninfinity picture zeninfinity  ยท  3Comments

jrnt30 picture jrnt30  ยท  3Comments