How can I achieve dependency between modules
module “common” {
source = “./modules/aws/common”
}
module “rds” {
source = “./modules/aws/rds”
depends_on = [module.common]
}
module “ec2_dsm” {
source = “./modules/aws/ec2”
depends_on = [module.common]
}
module “dsm” {
source = “./modules/aws/dsm”
depends_on = [module.rds]
depends_on = [module.ec2_dsm]
}
The name “depends_on” is reserved for use in a future version of Terraform.
Hi @buamod,
In Terraform dependencies are normally created automatically by references, rather than explicitly using depends_on
. Since you didn’t show what input variables and output values your modules have I can’t show a specific example for your case, but I’ve taken a guess as to what these modules might do for the sake of showing the pattern:
module "common" {
source = "./modules/aws/common"
}
module "rds" {
source = "./modules/aws/rds"
vpc_subnet_ids = module.common.vpc_subnet_ids
}
module "ec2_dsm" {
source = "./modules/aws/ec2"
vpc_subnet_ids = module.common.vpc_subnet_ids
}
module "dsm" {
source = "./modules/aws/dsm"
instance_ip_addresses = module.ec2_dsm.instance_ip_addresses
database_endpoint = module.rds.endpoint
}
Inside your common
module you might declare that vpc_subnet_ids
output value like this:
output "vpc_subnet_ids" {
value = aws_subnet.example[*].id
}
Then inside the “rds” module you might declare and use its vpc_subnet_ids
input variable like this:
variable "vpc_subnet_ids" {
type = set(string)
}
resource "aws_db_subnet_group" "example" {
# ...
subnet_ids = var.vpc_subnet_ids
# ...
}
By doing the above, Terraform can understand automatically that the subnet group depends on the VPC, even though they are in separate modules, because it can see the connection between them through the input variable and the output value.
In special situations where this sort of automatic reference-based dependency isn’t sufficient, you can use output values and input variables to pass explicit dependencies that wouldn’t otherwise be visible to Terraform through references.
In the module being depended on, you can write an output value whose value is irrelevant but which uses depends_on
to set its dependencies. For example, in the “ec2_dsm” module, you could write something like this:
output "instance_ip_addresses" {
# The primary value is the set of IP addresses...
value = aws_instance.example[*].private_ip
# ...but the instances aren't usable until their
# security group rules and IAM policies are active,
# so anything refering to this output value must
# also wait until these are complete...
depends_on = [
aws_security_group_rule.example,
aws_iam_role_policy.example,
aws_iam_instance_profile.example,
]
}
Inside your “dsm” module, you’d then have a variable declaration for the IP addresses as normal:
variable "instance_ip_addresses" {
type = set(string)
}
Anything in that module that refers to var.instance_ip_addresses
will depend on the instance_ip_addresses
output from the “ec2_dsm” module due to the expression in the module "dsm"
block, and will therefore in turn depend on the EC2 instances and their security groups and IAM roles.
In the most extreme case – this situation tends to be very rare, because most problems can be expressed more easily using the patterns above – you can also use an input variable to pass just dependencies and ignore its value.
For example, if you want to have the ability for the caller of the “ec2_dsm” module to define arbitrary extra dependencies for the EC2 instances inside, which wouldn’t occur automatically as a result of other references, you could define a variable like the following inside that module:
variable "ec2_instance_depends_on" {
# the value is irrelevant; we only care about
# dependencies for this one.
type = any
}
resource "aws_instance" "example" {
# This resource will depend on whatever this
# variable depends on, as decided by the
# module caller.
depends_on = [var.ec2_instance_depends_on]
# ...
}
Then in your calling module you can set this argument to any expression that refers to all of the objects you want to create extra dependencies on:
module "ec2_dsm" {
source = "./modules/aws/ec2"
vpc_subnet_ids = module.common.vpc_subnet_ids
# Note that this is just a normal variable as far
# as Terraform is concerned. The dependencies pass
# just as a natural consequence of how Terraform
# tracks references and passes dependencies through
# input variables.
# The child module ignores the value of this, but
# the fact that it depends on
# aws_vpc_peering_connection.example causes an
# additional dependency for the nested
# aws_instance resource.
ec2_instance_depends_on = [
aws_vpc_peering_connection.example,
]
}