Skip to main content
Knowledge Base

How to link dependencies across modules to work around Terraform limitations?

Answer

I am working on deploying some new lambdas using gruntworks. At our company, we always deploy our go lambdas via an s3_bucket, so I thought it would be nice if i made my own module which used the s3 service module and the lambda service module. The `main.tf` of that composite module looks roughly like this: ``` module "s3" { source = "git::git@github.com:gruntwork-io/terraform-aws-service-catalog.git//modules/data-stores/s3-bucket?ref=v0.63.0" primary_bucket = "${var.lambda_name}-${var.account_name}" enable_versioning = true } module "lambda" { source = "git::git@github.com:gruntwork-io/terraform-aws-service-catalog.git//modules/services/lambda?ref=v0.63.0" name = var.lambda_name timeout = var.timeout memory_size = var.memory_size s3_bucket = module.s3.primary_bucket_arn s3_key = var.s3_key s3_object_version = var.tag runtime = var.runtime handler = var.handler description = var.description alarm_sns_topic_arns = var.alarm_sns_topic_arns run_in_vpc = var.run_in_vpc vpc_id = var.vpc_id subnet_ids = var.subnet_ids should_create_outbound_rule = var.should_create_outbound_rule } ``` the problem is that I receive this error when trying to run an initial `terragrunt plan`: ```╷ │ Error: Invalid count argument │ │ on .terraform/modules/lambda.lambda_function/modules/lambda/main.tf line 115, in resource "null_resource" "assert_exactly_one_of": │ 115: count = length(compact([var.image_uri, var.source_path, var.s3_bucket])) == 1 ? 0 : "ERROR: exactly one of image_uri, source_path, or s3_bucket must be specified." │ │ The "count" value depends on resource attributes that cannot be determined │ until apply, so Terraform cannot predict how many instances will be │ created. To work around this, use the -target argument to first apply only │ the resources that the count depends on. ╵ ``` How do I workaround this? --- <ins datetime="2022-06-08T19:40:40Z"> <p><a href="https://support.gruntwork.io/hc/requests/108726">Tracked in ticket #108726</a></p> </ins>

You can set the offending input variable to the plan computable value and then link the dependency in a different way. For this example, you can set the `s3_bucket` input to the same value as the `primary_bucket` field you are passing in to the `s3-bucket` module (`"${var.lambda_name}-${var.account_name}"`), and then you can link the two dependencies by either: - Using `depends_on` at the module level, so you have a `depends_on = [module.s3_bucket]` on the `lambda` module call. - Using a tautology to force a dependency on just the lambda function resource by setting the name to be dependent on the s3 bucket. E.g.: ``` module "lambda" { # ... other args omitted ... name = ( module.s3.primary_bucket_arn != null ? var.lambda_name : var.lambda_name ) } ``` Note that the first option is cleaner, but will lead to a perpetual diff due to a terraform issue where data sources in a module with `depends_on` get automatically deferred to `apply` time, so terraform never gets the full picture at `plan` time.