FAQ | This is a LIVE service | Changelog

Invalid for_each argument on initial deployment caused by `module.uptime_monitoring` & `local.monitor_hosts`

What is the problem?

When deploying this module for the first time, and with disable_monitoring set to false (its default), this module fails with the following error.


│ Error: Invalid for_each argument

│   on /terraform_data/modules/webapp/main.tf line 236, in module "uptime_monitoring":
│  236:   for_each = local.monitor_hosts
│     ├────────────────
│     │ local.monitor_hosts will be known only after apply

│ The "for_each" map includes keys derived from resource attributes that cannot be determined until apply, and so Terraform cannot determine the full set of keys that will identify the instances of this
│ resource.

│ When working with unknown values in for_each, it's better to define the map keys statically in your configuration and place apply-time results only in the map values.

│ Alternatively, you could use the -target planning option to first apply only the resources that the for_each value depends on, and then apply a second time to fully converge.

Potential cause

This is because the monitor_hosts local references the google_cloud_run_service.webapp resource which is also being created by this module but cannot exist until after the first run. The monitor_hosts local is defined as follows.

  # Map containing the hosts to monitor and whether an auth proxy and egress connector
  # should be configured.
  monitor_hosts = var.disable_monitoring ? {} : merge(
    {
      trimsuffix(trimprefix(google_cloud_run_service.webapp.status[0].url, "https://"), "/") = {
        "enable_auth_proxy"       = !var.allow_unauthenticated_invocations || local.webapp_allowed_ingress != "all",
        "enable_egress_connector" = local.webapp_allowed_ingress != "all"
      },
    },
    local.can_monitor_custom_dns ? {
      for dns_name in local.dns_names :
      (dns_name) => {
        "enable_auth_proxy"       = local.webapp_allowed_ingress == "internal",
        "enable_egress_connector" = local.webapp_allowed_ingress == "internal"
      }
    } : {}
  )

Workarounds

There are two workarounds available.

  1. Set the disable_monitoring argument to true for the first run of the module and then run a second apply with disable_monitoring set to false again.
  2. Run a targeted apply of the google_cloud_run_service.webapp resource first and then a full apply as a second task.

Both of these options are not ideal and require multiple apply operations.

Actions

Need to investigate options to remove the dependency on the google_cloud_run_service.webapp resource in the monitor_hosts local.

This issue ties in with a couple of other open issues for this repo (#26 (closed) & #7 (closed)). Ideally we refactor all of these at the same time and ensure that the module can be deployed with a single apply operation, regardless of which arguments are provided etc.