Terraform Error: Cycle during the plan phase

Hello,
Running into this issue while trying to a build Aroura Global DB from an existing aurora DB snapshot.


terraform plan -var-file=global_db_vars.tfvars
╷│ Error: Cycle: module.rds_cluster_aurora.output.arn (expand), aws_rds_global_cluster.global, module.rds_cluster_aurora.var.global_cluster_identifier (expand), module.rds_cluster_aurora.aws_rds_cluster.default


Here is my TF module’s structure. This TF module serve 2 user cases

  1. Builds a complete new aurora global database based on user supplied inputs
  2. Trying to enhance the same module so that aurora global database can be built based of an user suppled snapshot identifier.
Root Module 
 Inside the root module, have the following resources

main.tf 
 {
 is_global_db is a flag which triggers to build the aurora DB cluster. 
 
Global cluster resource
------------------------
resource "aws_rds_global_cluster" "global" {
  count                     = var.is_global_db && var.enabled ? 1 : 0
  global_cluster_identifier = var.global_cluster_identifier != "" ? var.global_cluster_identifier : local.global_identifier
  database_name             = var.snapshot_identifier == null ? var.db_name : null
  engine                    = var.snapshot_identifier == null ? var.db_platform : null
  engine_version            = var.snapshot_identifier == null ? var.engine_version : null
  storage_encrypted         = var.snapshot_identifier == null ? true : null
  force_destroy             = true 
  source_db_cluster_identifier = var.snapshot_identifier != null ? module.rds_cluster_aurora.arn : null
}
Invoking the aurora cluster submodule
-------------------------------------
module "rds_cluster_aurora" {
  source = "./modules/aurora"
  enabled                   = var.enable_aurora && var.enable_rds_postgres == false ? true : false
  env                       = lower(lookup(module.tags.tags, "env-type"))
  db_name                   = (var.snapshot_identifier != null || length(var.restore_to_point_in_time) > 0 ) ? null : var.db_name
  master_username           = (var.snapshot_identifier != null || length(var.restore_to_point_in_time) > 0 ) ? null : local.master_username
  global_cluster_identifier = (var.is_global_db && var.snapshot_identifier == null) ? join("", aws_rds_global_cluster.global.*.id) : null
  
  //** I am able to built aurora global DB from snapshot when i removed the above input parameter global_cluster_identifier as this attribute will auto populate. However, i have to use the same code to build global db without snapshot where i need that input **/
  
  snapshot_identifier       = var.snapshot_identifier
  
  /** Additional parameters removed for simiplicty ***/
 }

Invoking the same aurora submodule to build the aurora global DB in another region.
-----------------------------------------------------------------------------------
module "global_cluster_aurora" {
  count      = var.is_global_db ? 1 : 0
  source     = "./modules/aurora"
  depends_on = [module.rds_cluster_aurora]
  providers = {
    aws = aws.secondary
  }
  /** Additional parameters removed for simiplicty ***/
  source_region             = var.secondary_aws_region
  global_cluster_identifier = join("", aws_rds_global_cluster.global.*.id) : null
}

Root module outputs
--------------------
outputs.tf
{
output "global_db_endpoint" {
  value       = var.is_global_db ? module.global_cluster_aurora[0].endpoint : null
  description = "A writer endpoint for the Aurora global cluster, this will get activated during failover"
}
output "arn" {
  value       = join("", [module.rds_cluster_aurora.arn])
  description = "Amazon Resource Name (ARN) of database"
}
}

Aurora Submodule 
--------------------------------
./modules/aurora/main.tf 
{
resource "aws_rds_cluster" "default" {
  count = var.enabled ? 1 : 0
  cluster_identifier      = var.cluster_identifier != "" ? var.cluster_identifier : "${local.clus_identifier}-clus"
  database_name           = var.db_name
  master_username         = var.master_username
  
  /** Additional parameters removed for simplicity ***/
    
  snapshot_identifier                 = var.snapshot_identifier
  global_cluster_identifier = var.global_cluster_identifier
  source_region             = var.source_region

  lifecycle {
    ignore_changes = [
      tags,
      global_cluster_identifier
    ]
  }
}

resource "aws_rds_cluster_instance" "default" {
  count = var.enabled  ? local.cluster_size : 0
  identifier         = "${local.ins_identifier}-${count.index + 1}"
  cluster_identifier = join("", aws_rds_cluster.default.*.id)

/** Additional parameter removed for simiplicty ***/
 
  tags = var.tags
  lifecycle {
    ignore_changes = [
      tags,
      availability_zone
    ]
  }
}

Outputs from this submodule (outputs.tf) 
----------------------------------------
outputs.tf
{
output "cluster_identifier" {
  value       = join("", aws_rds_cluster.default.*.cluster_identifier)
  description = "Cluster Identifier"
}

output "arn" {
  value       = join("", aws_rds_cluster.default.*.arn)
  description = "Amazon Resource Name (ARN) of cluster"
}
}

Any ideas , how to trouble shoot the issue ?

Regards
Raj

Hi @rcg,

The method to start troubleshooting this is to walk through each of the object listed in the cycle error, following the references between them. This can be tricky in some situations where dependencies were transitive, but in your case each object has a direct reference to the previous. I’m not sure what the logic is supposed to be here, but your module.rds_cluster_aurora.aws_rds_cluster.default and aws_rds_global_cluster.global both depend on values from the other.

Thank you @jbardin , i was able to resolve my issue