Open lijok opened 3 years ago
Hi @lijok
Thanks for submitting the example here. While the cycle is initially expected in this configuration, since the s3_bucket_us_east_1
and s3_bucket_us_east_1
module calls reference each other, the inconsistent behavior definitely make this confusing.
When modules are not expanded in any way, they essentially don't exist within the operation of terraform core, only acting as namespaces within the configuration. Once expansion needs to happen, every instance within those modules needs to be expander later based on the parent module's expansion, so modules themselves behave much more like discrete objects, and referencing rules similar to resources apply more strictly.
The tooling to detect and troubleshoot these cycles in complex configurations is definitely something that can be improved in the cli.
@jbardin So under what circumstances do modules get expanded, and when do they not?
@lijok, modules are expanded when you use count
or for_each
. This means that rather than the implied single instance of the module, everything within the module and submodules depends on the modules being "expanded" to determine the final number of instances and their configuration values.
Another way to think about this, in case it's helpful, is to think of the for_each
or count
expression as being a separate dependency node in its own right, with its own dependencies. Anything defined in the module, including the module's output values. implicitly depends on the for_each
or count
expression because Terraform must determine how many to evaluate before it can evaluate any of them.
Conversely, the reason that it works when you don't have for_each
or count
is that then there's no repetition expression for everything in the module to depend on. As previously noted, modules don't normally exist by themselves in the dependency graph -- the dependencies just propagate through individual input variables and output values -- so in normal circumstances it's possible to create dependency chains that thread in opposite directions through a pair of modules.
I stumbled upon a cycle with a "(expand)". I found @jbardin explanation above useful:
modules are expanded when you use
count
orfor_each
[..]
A possible improvement to the error message (although by all means not enough) is to augment "(expand)" with the cause.
Simplified example: Instead of the current
Error: Cycle: module.cloudfront_us_east_1.aws_cloudfront_distribution.this,
module.s3_bucket_us_east_1.output.bucket_name (expand),
module.cloudfront_us_east_1.var.bucket_name (expand), ...
something like
Error: Cycle: module.cloudfront_us_east_1.aws_cloudfront_distribution.this,
module.s3_bucket_us_east_1.output.bucket_name (expand, cause: "count"),
module.cloudfront_us_east_1.var.bucket_name (expand, cause: "for_each"), ...
The cause as @marco-m-pix4d highlights, would be a very valuable addition towards making debugging cycles easier.
Terraform Version
Terraform Configuration Files
Debug Output
Crash Output
Expected Behavior
Resources deployed
Actual Behavior
Error: Cycle: module.cloudfront_us_east_1.aws_cloudfront_distribution.this, module.s3_bucket_us_east_1 (close), module.s3_bucket_us_east_1.aws_s3_bucket.this, module.s3_bucket_us_east_1.output.bucket_name (expand), module.cloudfront_us_east_1.var.bucket_name (expand), module.cloudfront_us_east_1 (close), module.s3_bucket_us_east_1.var.cloudfront_oai (expand), module.s3_bucket_us_east_1.data.aws_iam_policy_document.this
Steps to Reproduce
terraform init
terraform apply
Additional Context
If you replace
each.value
in the module call variables with a static"this"
, this problem dissapearsReferences