iits-consulting / terraform-opentelekomcloud-project-factory

This repository helps to create an OTC-based cloud-native infrastructure landscape with Kubernetes, load balancers, VPCs, etc. With these modules, we provide you a rocket start while you can still deep-dive into detailed configuration later.
GNU General Public License v3.0
83 stars 20 forks source link

SNAT: Example from README.md gives error #51

Closed k11h-de closed 2 years ago

k11h-de commented 2 years ago

Hi iits-Team,

before submitting I want to thank you for sharing and enhancing these modules.

I was using the example VPC and SNAT module usage from the snat readme

this is what my test looks like:

module "vpc" {
  source  = "registry.terraform.io/iits-consulting/project-factory/opentelekomcloud//modules/vpc"
  version = "4.2.2"

  cidr_block         = var.vpc_cidr
  name               = "vpc-${var.context_name}-${var.stage_name}"
  enable_shared_snat = false
  subnets = {
    "subnet-0" = cidrsubnet(var.vpc_cidr, 2, 0)
    "subnet-1" = cidrsubnet(var.vpc_cidr, 2, 1)
    "subnet-2" = cidrsubnet(var.vpc_cidr, 2, 2)
    "subnet-3" = cidrsubnet(var.vpc_cidr, 2, 3)
  }
  tags = var.tags
}

module "snat" {
  source  = "registry.terraform.io/iits-consulting/project-factory/opentelekomcloud//modules/snat"
  version = "4.2.2"

  name_prefix = "${var.context_name}-${var.stage_name}"
  subnet_id   = module.vpc.subnets["subnet-0"].id
  vpc_id      = module.vpc.vpc.id
  network_ids = values(module.vpc.subnets)[*].id
  tags        = var.tags
}

this is my variables.auto.tfvars

vpc_cidr     = "10.41.0.0/16"
stage_name   = "nonprod"
context_name = "team1"
tags = {}

While running tf apply I get this error (with TF version v1.2.7 and v1.1.9):

╷
│ Error: Invalid count argument
│ 
│   on .terraform/modules/snat/modules/snat/snat.tf line 22, in resource "opentelekomcloud_nat_snat_rule_v2" "snat_subnet_default":
│   22:   count          = length(var.network_ids) > 0 ? 0 : 1
│ 
│ The "count" value depends on resource attributes that cannot be determined
│ until apply, so Terraform cannot predict how many instances will be
│ created. To work around this, use the -target argument to first apply only
│ the resources that the count depends on.
╵
╷
│ Error: Invalid for_each argument
│ 
│   on .terraform/modules/snat/modules/snat/snat.tf line 30, in resource "opentelekomcloud_nat_snat_rule_v2" "snat_subnet":
│   30:   for_each       = var.network_ids
│     ├────────────────
│     │ var.network_ids is set of string with 4 elements
│ 
│ The "for_each" value depends on resource attributes that cannot be
│ determined until apply, so Terraform cannot predict how many instances will
│ be created. To work around this, use the -target argument to first apply
│ only the resources that the for_each depends on.

What I tried:

I can work around this problem by:

  1. comment out the snat module && tf apply 1a. comment in again the snat module && tf apply or
  2. separate the state of vpc and snat (different folders / backends) and use a data source

Do you see any chance to get this applied together in the same tfstate? Did you every got the example in the snat readme working; if yes, with which version of terraform?

Any hint is very welcome. Thanks Karsten

victorgetz commented 2 years ago

Hi Karsten we have a automated testing for most of our modules. But it just tests simple setups. You can find one here: https://github.com/iits-consulting/terraform-opentelekomcloud-project-factory/blob/master/Terratest/cce/main.tf

@canaykin this goes very deep so i think it is the best you take a look

canaykin commented 2 years ago

I have tested this a lot and unfortunately this is a limitation on Terraform's side.

Even in the error message, you can see that it knows the number of elements in set but still complains about not knowing the number of instances to be created:

│     │ var.network_ids is set of string with 4 elements
│ The "for_each" value depends on resource attributes that cannot be
│ determined until apply, so Terraform cannot predict how many instances will
│ be created. To work around this, use the -target argument to first apply
│ only the resources that the for_each depends on.

However, in this use case where you are using the SNAT for the entire VPC, there is a simple solution:

module "snat" {
  source        = "../../modules/snat"
  name_prefix   = "${var.context}-${var.stage}"
  subnet_id     = module.vpc.subnets["subnet-0"].id
  network_cidrs = [var.vpc_cidr]
  vpc_id        = module.vpc.vpc.id
}

I will update the module README.md with this code as well.