Terraform version: 0.9.5
I have two terraform modules ct-vpc and ct-vpc-peering and I am trying to establish connection between the two modules. here below, I document my approach:
variables.tf
variable vpc_name {}
variable cidr {}
variable environment {}
variable enable {}
variable replication_factor {}
# Inter module dependency hack
# https://github.com/hashicorp/terraform/issues/1178
variable dependency_id {}
variable enable_dns_support {
default = true
}
variable enable_dns_hostnames {
default = true
}
variable azs {
type = "list"
}
main.tf
:
# By default nothing is exposed to the Internet
resource "aws_default_route_table" "private" {
count = "${var.enable}"
default_route_table_id = "${aws_vpc.vpc.default_route_table_id}"
route = [{"cidr_block" = "0.0.0.0/0", "nat_gateway_id" = "${aws_nat_gateway.nat.id}"}]
tags {
Name = "${var.vpc_name}-private-rt"
environment = "${var.environment}"
dependency_id = "${var.dependency_id}"
}
}
# Public routing table
resource "aws_route_table" "public" {
count = "${var.enable}"
vpc_id = "${aws_vpc.vpc.id}"
route = [{"cidr_block" = "0.0.0.0/0", "gateway_id" = "${aws_internet_gateway.igw.id}"}]
tags {
Name = "${var.vpc_name}-public-rt"
environment = "${var.environment}"
dependency_id = "${var.dependency_id}"
}
}
resource "null_resource" "dummy_dependency_1" {
depends_on = ["aws_default_route_table.private", "aws_route_table.public"]
}
:
outputs.tf
:
output "vpc_private_routing_table_id" {
value = "${aws_default_route_table.private.id}"
}
output "vpc_public_routing_table_id" {
value = "${aws_route_table.public.id}"
}
output "dependency_id" {
value = "${null_resource.dummy_dependency_1.id}"
}
:
variables.tf
variable enable {}
variable environment {}
variable vpc {
type = "map"
}
variable vpc_route_table_ids {
type = "list"
}
variable peer_vpc {
type = "map"
}
variable peer_vpc_route_table_ids {
type = "list"
default = []
}
variable dependency_id {
type = "list"
}
main.tf
resource "aws_vpc_peering_connection" "peering" {
count = "${var.enable}"
peer_owner_id = "${lookup(var.peer_vpc, "owner_id")}"
peer_vpc_id = "${lookup(var.peer_vpc, "vpc_id")}"
vpc_id = "${lookup(var.vpc, "vpc_id")}"
auto_accept = "${lookup(var.peer_vpc, "owner_id") == lookup(var.vpc, "owner_id") ? true : false}"
accepter {
allow_remote_vpc_dns_resolution = "${lookup(var.peer_vpc, "owner_id") == lookup(var.vpc, "owner_id") ? true : false}"
}
requester {
allow_remote_vpc_dns_resolution = "${lookup(var.peer_vpc, "owner_id") == lookup(var.vpc, "owner_id") ? true : false}"
}
tags {
Name = "VPC Peering between stateful and stateless"
environment = "${var.environment}"
dependency_id = "${var.dependency_id}"
}
}
# routing table entry for terraformed stateless environment
resource "aws_route" "peer-routing" {
count = "${var.enable * length(var.vpc_route_table_ids)}"
route_table_id = "${element(var.vpc_route_table_ids, count.index)}"
destination_cidr_block = "${lookup(var.peer_vpc, "cidr")}"
vpc_peering_connection_id = "${aws_vpc_peering_connection.peering.id}"
}
# conditional routing table entry for stateful environment
resource "aws_route" "peer-routing-stateful" {
count = "${var.enable * length(var.peer_vpc_route_table_ids)}"
route_table_id = "${element(var.peer_vpc_route_table_ids, count.index)}"
destination_cidr_block = "${lookup(var.vpc, "cidr")}"
vpc_peering_connection_id = "${aws_vpc_peering_connection.peering.id}"
}
resource "null_resource" "dummy_dependency" {
depends_on = ["aws_vpc_peering_connection.peering"]
}
module "vpc_1" {
source = "../terraform_modules/ct-vpc/"
enable = 1
vpc_name = "${var.ct_environment_name}-stateful"
cidr = "${var.ct_stateful_vpc_cidr}"
azs = "${var.ct_azs}"
environment = "${var.ct_environment_name}"
replication_factor = 3
dependency_id = ""
}
module "vpc_2" {
source = "../terraform_modules/ct-vpc/"
enable = "${replace(replace(var.ct_environment_name, "${var.qa_regex}", 1), "/^[^1].*/", 0)}"
vpc_name = "${var.ct_environment_name}-stateful"
cidr = "${var.ct_stateful_vpc_cidr}"
azs = "${var.ct_azs}"
environment = "${var.ct_environment_name}"
replication_factor = 1
dependency_id = ""
}
module "qa_peering" {
source = "../terraform_modules/ct-vpc-peering/"
enable = "${replace(replace(var.ct_environment_name, "${var.qa_regex}", 1), "/^[^1].*/", 0)}"
environment = "${var.ct_environment_name}"
vpc {
"vpc_id" = "${module.vpc_1.vpc_id}"
"owner_id" = "${var.ct_account_id}"
"cidr" = "${var.ct_vpc_cidr}"
}
# lookup only works on flatmaps
vpc_route_table_ids = ["${module.vpc_1.vpc_private_routing_table_id}", "${module.vpc_1.vpc_public_routing_table_id}"]
peer_vpc {
"vpc_id" = "${module.vpc_2.vpc_id}"
"owner_id" = "${var.ct_account_id}"
"cidr" = "${var.ct_stateful_vpc_cidr}"
}
peer_vpc_route_table_ids = ["${module.vpc_2.vpc_private_routing_table_id}", "${module.vpc_2.vpc_public_routing_table_id}"]
dependency_id = ["${module.vpc_1.dependency_id}", "${module.vpc_2.dependency_id}"]
}
I get the error:
* module.qa_peering.aws_route.peer-routing-stateful: aws_route.peer-routing-stateful: value of 'count' cannot be computed
* module.qa_peering.aws_route.peer-routing: aws_route.peer-routing: value of 'count' cannot be computed
I am guessing it is related to #1178 and #10462
@grubernaut Thanks for the tags. I finally found out the issue why the above config wasn't working!
The issue isn't with inter module dependency but rather with arithmetic operator on count
The problem is with count = "${var.enable * length(var.vpc_route_table_ids)}"
By simply setting count = "${var.enable}" the error disappears!
I am wondering if it is another case of #13980 @apparentlymart can you please confirm?
Hi @Puneeth-n!
Indeed, this is the same problem as we discussed in #13980.
If we follow the path of interpolations here we can trace back to the variable that is "computed" (meaning that Terraform can't know it until the apply step);
count = "${var.enable * length(var.vpc_route_table_ids)}" includes var.vpc_route_table_idsvar.vpc_route_table_ids is set from the root module as ["${module.vpc_1.vpc_private_routing_table_id}", "${module.vpc_1.vpc_public_routing_table_id}"], which includes two interpolations. For the sake of this example, we'll follow module.vpc_1.vpc_private_routing_table_id.module.vpc_1.vpc_private_routing_table_id is an output from an instance of the VPC module, whose value is populated from "${aws_route_table.public.id}" inside the module, which references aws_route_table.public.id.aws_route_table.public.id is a "computed" attribute of this resource, because it can't be known until after the route table has been created.Thus as before the workaround is to first target the modules that are producing the values you need to populate count:
terraform plan -out=tfplan -target=module.vpc_1 -target=module.vpc_2terraform apply tfplanThis should succeed, and create the resources from the VPC module instances, including the public route tables.
Then you can run Terraform as normal to complete the rest of the config:
terraform plan -out=tfplanterraform apply tfplanThe second time it should succeed because the route table ids will already be known.
@apparentlymart Thanks a lot :) Closing the issue! :)
@apparentlymart while we are at it, I am having difficulty tackling an issue. This pretty sure is related to module dependency.
In ct-vpc module as you can see, I am creating private and public routing tables. in ct-vpc-peering I am modifying the routing table and adding vpc-peering-id.
During terraform plan, terraform plans to remove the vpc-peering-id as it is not part of the config in module ct-vpc. terraform apply and routing table has no more vpc-peering entry. terraform apply again and module ct-vpc-peering detects that vpc-peering-id is no longer available and adds it.
How do I overcome this inter module dependency issue?
Completely missed the fact that aws_route_table with inline policies and aws_route overwrite each other! The same with security_group. My bad! closing the issue!
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.
Most helpful comment
Hi @Puneeth-n!
Indeed, this is the same problem as we discussed in #13980.
If we follow the path of interpolations here we can trace back to the variable that is "computed" (meaning that Terraform can't know it until the apply step);
count = "${var.enable * length(var.vpc_route_table_ids)}"includesvar.vpc_route_table_idsvar.vpc_route_table_idsis set from the root module as["${module.vpc_1.vpc_private_routing_table_id}", "${module.vpc_1.vpc_public_routing_table_id}"], which includes two interpolations. For the sake of this example, we'll followmodule.vpc_1.vpc_private_routing_table_id.module.vpc_1.vpc_private_routing_table_idis an output from an instance of the VPC module, whose value is populated from"${aws_route_table.public.id}"inside the module, which referencesaws_route_table.public.id.aws_route_table.public.idis a "computed" attribute of this resource, because it can't be known until after the route table has been created.Thus as before the workaround is to first target the modules that are producing the values you need to populate count:
terraform plan -out=tfplan -target=module.vpc_1 -target=module.vpc_2terraform apply tfplanThis should succeed, and create the resources from the VPC module instances, including the public route tables.
Then you can run Terraform as normal to complete the rest of the config:
terraform plan -out=tfplanterraform apply tfplanThe second time it should succeed because the route table ids will already be known.