[Terraform] How to reference instance argument value created with for_each meta-argument in another instance in the same map

Original question is asked here.

My end goal is to have Terraform create instances of a resource generated with the for_each meta argument in a specific sequence. HCL is known to be a declarative language and when Terraform applies a configuration it can create resources randomly unless you use the depends_on argument or refer from one resource (instance) to another. However, the depends_on argument does not take values that are “calculated”, so I don’t know how to use it in modules.

For this reason, in order to force Terraform to create instances of a resource in a specific sequence, I decided to try to make the value of a certain argument in an instance it creates “calculated” based on the values of the same argument from another instance.

Below you can find a more practical example.

Let’s take a test module that instantiates the cloudflare_page_rule resource:

# Module is placed to module\main.tf

terraform {
  experiments = [module_variable_optional_attrs]
}

terraform {
  required_providers {
    cloudflare = {
      source  = "cloudflare/cloudflare"
      version = ">= 3.10.0"
    }
  }
}

variable "zone" {
  type        = string
  description = "The DNS zone name which will be added, e.g. example.com."
}

variable "page_rules" {
  type = list(object({
    page_rule_name = string
    target         = string
    actions = object({
      forwarding_url = optional(object({
        url         = string
        status_code = number
      }))
    })
    priority   = optional(number)
    status     = optional(string)
    depends_on = optional(string)
  }))
  description = "Zone's page rules."
  default     = []
}

//noinspection HILUnresolvedReference
locals {
  page_rule_dependencies = { for p in var.page_rules : p.page_rule_name => p.depends_on if p.depends_on != null }
}

# https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/zone
resource "cloudflare_zone" "this" {
  zone = var.zone
}

# https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/page_rule
//noinspection HILUnresolvedReference
resource "cloudflare_page_rule" "this" {
  for_each = var.page_rules != null ? { for p in var.page_rules : p.page_rule_name => p } : {}

  zone_id = cloudflare_zone.this.id

  target = each.value.target
  actions {
    //noinspection HILUnresolvedReference
    forwarding_url {
      status_code = each.value.actions.forwarding_url.status_code
      url         = each.value.actions.forwarding_url.url
    }
  }
  priority = each.value.depends_on != null ? cloudflare_page_rule.this[local.page_rule_dependencies[each.key]].priority + 1 : each.value.priority
  status = each.value.status
}

output "page_rule_dependencies" {
  value = local.page_rule_dependencies
}

And a configuration that is used to create resources:

terraform {
  required_version = ">= 0.15.0"

  required_providers {
    cloudflare = {
      source  = "cloudflare/cloudflare"
      version = ">= 3.10.1"
    }
  }
}

variable "cloudflare_api_token" {
  type      = string
  sensitive = true
}

provider "cloudflare" {
  api_token = var.cloudflare_api_token
}

module "acme_com" {
  source = "./module"
  zone   = "acme.com"
  page_rules = [
    {
      page_rule_name = "page_rule_1"
      target         = "acme.com/url1"
      actions = {
        forwarding_url = {
          status_code = 301
          url         = "https://www.example.com/url1"
        }
      }
      priority = 1
    },
    {
      page_rule_name = "page_rule_2"
      target         = "acme.com/url2"
      actions = {
        forwarding_url = {
          status_code = 301
          url         = "https://www.example.com/url2"
        }
      }
      priority   = 2
      depends_on = "page_rule_1"
    },
    {
      page_rule_name = "page_rule_3"
      target         = "acme.com/url3"
      actions = {
        forwarding_url = {
          status_code = 301
          url         = "https://www.example.com/url3"
        }
      }
      priority   = 3
      depends_on = "page_rule_2"
    }
  ]
}

output "page_rule_dependencies" {
  value = module.acme_com.page_rule_dependencies
}

In this particular example, I’ve added the depends_on argument to the page_rules variable (don’t confuse this argument with the depends_on meta argument). For the value of the depends_on argument, I specified the name of a page_fule on which another page_fule depends.

Next, I created a local variable page_rule_dependencies, the value of which, after calculations, is the following (you can check this yourself by replacing the priority = each.value.depends_on != null ? cloudflare_page_rule.this[local.page_rule_dependencies[each.key]].priority + 1 : each.value.priority construct with priority = each.value.priority and executing terraform apply):

page_rule_dependencies = {
  "page_rule_2" = "page_rule_1"
  "page_rule_3" = "page_rule_2"
}

Further, in the priority = each.value.depends_on != null ? cloudflare_page_rule.this[local.page_rule_dependencies[each.key]].priority + 1 : each.value.priority construct, I refer to the values ​​of the local variable, thereby forming a “reference” to the page_fule instance, on which the current instance depends:

  1. When creating page_rule_1, the value of its argument priority = 1.
  2. When creating page_rule_2, the value of its argument priority = cloudflare_page_rule.this["page_rule_1"].priority + 1.
  3. When creating page_rule_3, the value of its argument priority = cloudflare_page_rule.this["page_rule_2"].priority + 1.

However, I get an Error: Cycle: module.acme_com.cloudflare_page_rule.this["page_rule_3"], module.acme_com.cloudflare_page_rule.this["page_rule_2"], module.acme_com.cloudflare_page_rule.this["page_rule_1"] error.

Either I’m doing something wrong, or it’s some kind of Terraform limitation/bug. Is there a way to get rid of this error?

P.S. Resulting graph after terraform graph -draw-cycles | dot -Tsvg > graph.svg or terraform graph -draw-cycles -type=plan | dot -Tsvg > graph-plan.svg (the same result):

P.P.S. I use Terraform v1.1.7.

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.