terraform-google-kubernetes-engine icon indicating copy to clipboard operation
terraform-google-kubernetes-engine copied to clipboard

A null value cannot be used as the collection in a 'for' expression.

Open jgfincore opened this issue 4 years ago • 10 comments

When using the private-cluster module with 'add_cluster_firewall_rules' as true, the following error is produced during the terraform plan stage if using separate statefile for subnets:

on main.tf line 60, in locals:
  60:   cluster_alias_ranges_cidr = var.add_cluster_firewall_rules ? { for range in toset(data.google_compute_subnetwork.gke_subnetwork[0].secondary_ip_range) : range.range_name => range.ip_cidr_range } : {}
    |----------------
    | data.google_compute_subnetwork.gke_subnetwork[0].secondary_ip_range is null

A null value cannot be used as the collection in a 'for' expression.

jgfincore avatar Jun 18 '20 09:06 jgfincore

Hi @jgfincore Can you confirm the existence of secondary ip ranges on that subnet? Additionally, if you can post your config for this module, that would be great!

bharathkkb avatar Jun 19 '20 03:06 bharathkkb

So, we're using terragrunt. The gke module is dependent an a vpc and subnet module. Those network modules 'plan' just fine, it is only gke which fails with the error above. If I apply, it all works fine -- but the gke module failing on 'plan' stage creates issues in our workflow.

I'll try to clean up and post a excerpt from the gke module and get it up here shortly

jgfincore avatar Jun 24 '20 14:06 jgfincore

We are getting this error with terraform destroy:

Error: Iteration over null value

  on .terraform/modules/gke/terraform-google-kubernetes-engine-10.0.0/modules/beta-private-cluster-update-variant/main.tf line 72, in locals:
  72:   cluster_alias_ranges_cidr = var.add_cluster_firewall_rules ? { for range in toset(data.google_compute_subnetwork.gke_subnetwork[0].secondary_ip_range) : range.range_name => range.ip_cidr_range } : {}
    |----------------
    | data.google_compute_subnetwork.gke_subnetwork[0].secondary_ip_range is null

A null value cannot be used as the collection in a 'for' expression.

avthart avatar Jul 15 '20 05:07 avthart

As a workaround, you can try setting add_cluster_firewall_rules = false.

The real fix would be something like:

  cluster_alias_ranges_cidr = (var.add_cluster_firewall_rules && data.google_compute_subnetwork.gke_subnetwork[0].secondary_ip_range != null) ? { for range in toset(data.google_compute_subnetwork.gke_subnetwork[0].secondary_ip_range) : range.range_name => range.ip_cidr_range } : {}

morgante avatar Jul 15 '20 14:07 morgante

We are seeing this as well( terraform 12.29). Behavior is a little strange, we have tested multiple scenarios. Our goal is to add a second vpc and cluster together, we cannot do that directly.

  • Empty state, empty project, try to create vpc with 2 subnets(and secondary ranges) and 2 corresponding clusters with add_cluster_firewall_rules = true: works fine

  • State has vpc with 1 subnet and 1 cluster, try to add subnet and cluster (with add_cluster_firewall_rules = true) together: fails with error mentioned above

  • State has vpc with 1 subnet and 1 cluster, try to add subnet and cluster (with add_cluster_firewall_rules = false) together: works(as expcted) can enable firewall rules after creation

  • State has vpc with 2 subnets and 1 cluster, try to add second cluster: works(as expected)

Is there a way to use the reference to the secondary range rather than use data?

robertb724 avatar Sep 09 '20 15:09 robertb724

@robertb724 Do you mind sharing your Terraform config? I'm really curious why (2) is failing.

morgante avatar Sep 14 '20 15:09 morgante

Hey! I just encountered the same problem. I am using the network module to create a VPC and I supply that to the gke (beta-private-cluster) module. I'd like to use add_cluster_firewall_rules to make sure Istio's admission controller will work fine in the private cluster.

My guess: it uses data to get the secondary range and it fails, because it is not yet created. Is there a way to make sure it uses the supplied subnetwork instead of querying the data?

MrBlaise avatar Sep 16 '20 07:09 MrBlaise

As a workaround, you can try setting add_cluster_firewall_rules = false.

The real fix would be something like:

  cluster_alias_ranges_cidr = (var.add_cluster_firewall_rules && data.google_compute_subnetwork.gke_subnetwork[0].secondary_ip_range != null) ? { for range in toset(data.google_compute_subnetwork.gke_subnetwork[0].secondary_ip_range) : range.range_name => range.ip_cidr_range } : {}

Had the same error with terraform destroy, adding the condition check for the for loop (real fix) fixes it for me

meganzhao10 avatar Sep 22 '20 05:09 meganzhao10

Same problem here. To work around this issue, I created separate firewall rules :(

matteovivona avatar Nov 11 '20 07:11 matteovivona

I did some digging into this. In particular with 0.13 there is a change in how data sources are evaluated (https://www.terraform.io/docs/language/data-sources/index.html#data-resource-behavior,https://github.com/hashicorp/terraform/issues/27583). To workaround these limitations and use add_cluster_firewall_rules, we can either

  • apply subnets in a separate configurations, then the data source will be able to read subnet data
  • if subnets and GKE has to be created in one config, source the subnet name from a computed attribute like the self_link. This will force the data source to defer read to apply time

The original comment in this issue seems to have happened because the networks config had just been planned and not applied. Hence during GKE plan, the data source was unable read the subnet.

bharathkkb avatar Jan 27 '21 04:01 bharathkkb