Score:1

GCP Terraform: Unable to set subnets to be advertised via BGP on cloud router

ua flag

I'm attempting to create a cloud router, with two network ranges being advertised from it, however I'm getting some very vague errors from terraform and I can't quite put my finger on what's wrong.

resource "google_compute_router" "router1" {
  name     = "${var.alias}-prod1-ha-vpn-cloud-router-1"
  project  = var.project_name
  network  = var.network1
  region   = var.region1
  bgp {
    asn = var.asn
    advertise_mode = "CUSTOM"
    dynamic "advertised_ip_ranges" {
      for_each = var.advertised_ip_ranges_prod1
      content {
        range = advertised_ip_ranges_prod1.value["cidr"]
        description = advertised_ip_ranges_prod1.value["desc"]
      }
    }
  }
}

And the actual module code:

module "vpn-ha-gateway" {
  source          = "-----"
  project_name    = var.project_name
  customer        = var.customer
  alias           = var.alias
  region1         = var.region1
  count           = (var.vpn_type == "ha-vpn" ? 1 : 0)   ## Build if vpn_type is ha-vpn
  network1        = module.prod1-vpc.self_link
  customer_redundancy = var.customer_redundancy
  customer_ha_vpn_peers = var.customer_ha_vpn_peers
  shared_secret   = var.shared_secret
  asn             = var.asn
  cust_asn        = var.cust_asn
  advertised_ip_ranges_prod1      = var.advertised_ip_ranges_prod1
}

We define the advertised_ip_ranges_prod1 as a map, as we don't know how many there will be per module:

variable "advertised_ip_ranges_prod1" {
  type = list(map(string))
  description = "advertised by BGP on prod1"
  default = [
    {
        cidr = "1.2.3.4/28" ## Prod1 advertised range
        desc = "secondary range advertised via BGP"
    },
    {
        cidr = "5.6.7.8/28" # Test advertised range
        desc = "Test range advertised via BGP"
    },
  ]
}

And while I have other modules built in the same way (with the for_each) working correctly, this one keeps throwing up these vague errors:

Error: Reference to undeclared resource

  on .terraform\modules\vpn-ha\main.tf line 36, in resource "google_compute_router" "router1":
  36:         range = advertised_ip_ranges_prod1.value["cidr"]

A managed resource "advertised_ip_ranges_prod1" "value" has not been declared
in module.vpn-ha-gateway.


Error: Reference to undeclared resource

  on .terraform\modules\vpn-ha-gateway\main.tf line 37, in resource "google_compute_router" "router1":
  37:         description = advertised_ip_ranges_prod1.value["desc"]

A managed resource "advertised_ip_ranges_prod1" "value" has not been declared
in module.vpn-ha-gateway.```

Score:1
bw flag

So the issue (I think) is with how you reference the current iteration of the dynamic element from within the for_each "block". In general, the name of the "variable" that you use to reference the current iterator value in the for_each block is actually the name of the dynamic tag itself. As a result, I think you need to replace this:

resource "google_compute_router" "router1" {
  name     = "${var.alias}-prod1-ha-vpn-cloud-router-1"
  project  = var.project_name
  network  = var.network1
  region   = var.region1
  bgp {
    asn = var.asn
    advertise_mode = "CUSTOM"
    dynamic "advertised_ip_ranges" {
      for_each = var.advertised_ip_ranges_prod1
      content {
        range = advertised_ip_ranges_prod1.value["cidr"]
        description = advertised_ip_ranges_prod1.value["desc"]
      }
    }
  }
}

With this:

resource "google_compute_router" "router1" {
  name     = "${var.alias}-prod1-ha-vpn-cloud-router-1"
  project  = var.project_name
  network  = var.network1
  region   = var.region1
  bgp {
    asn = var.asn
    advertise_mode = "CUSTOM"
    dynamic "advertised_ip_ranges" {
      for_each = var.advertised_ip_ranges_prod1
      content {
        range = advertised_ip_ranges.value["cidr"]
        description = advertised_ip_ranges.value["desc"]
      }
    }
  }
}

e.g. s/advertised_ip_ranges_prod1/advertised_ip_ranges/

For reference, see the very first example on their documentation about this, which is the following:

resource "aws_elastic_beanstalk_environment" "tfenvtest" {
  name                = "tf-test-name"
  application         = "${aws_elastic_beanstalk_application.tftest.name}"
  solution_stack_name = "64bit Amazon Linux 2018.03 v2.11.4 running Go 1.12.6"

  dynamic "setting" {
    for_each = var.settings
    content {
      namespace = setting.value["namespace"]
      name = setting.value["name"]
      value = setting.value["value"]
    }
  }
}

Note that they use setting.value, even though the name of the variable is settings. You're basically running into that exact same, rather confusing, difference.

djsmiley2kStaysInside avatar
ua flag
Excellent answer, thank you. It's the little things like this in terraform which are really tripping me up!.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.