Using for_each in CDK for Terraform using Python?

I am generating list of VPCs ID per region dynamically using boto3(and outside the scope of the terraform stack) and its named as “aws_vpc_list_per_region”.

How can I iterate over this list for creating resources in CDKTF for a given stack?

Below is snippet of the code and how I am trying escape hatch using add_override.

                AwsTgwVpcAttachment(self, id="id",
                                    region="us-east-1",
                                    security_domain_name="sd_name",
                                    tgw_name="test TGW",
                                   vpc_account_name="name",
                                    vpc_id=""

                                    )

                AwsTgwVpcAttachment.add_override(self, "vpc_id", "for_each" = aws_vpc_list_per_region, vpc_id = key)

off course, above code doesn’t work.

Hi @exaws

If aws_vpc_list_per_region contains the ids already, you could also use a loop in Python and create multiple instances of AwsTgwVpcAttachment and pass each of them a different id and a different vpc_id.

Hi @ansgarm . thanks for replying. I know I can do that ( :grinning:) but there is more to the story.

Story: I am migrating the code from HCL (which is already deployed) to Python.

in HCL, AwsTgwVpcAttachment construct has only one id (eg. aws_tgw_vpc_attachment_abc) (in HCL context, its the name of the resource:aws_tgw_vpc_attachment).

I am going to import the config from different state file(created by HCL) to a state file created by python. this is were things gets clumsy as I have to import each VPC if I take the approach you suggested.

the clean code would be to use add_override and I wonder if there is way to make it work.

Hi @exaws!

Ah, I see. Makes sense :+1:
In a similar vain to this workaround, something like the following might work:

AwsTgwVpcAttachment(self, id="id",
  region="us-east-1",
  security_domain_name="sd_name",
  tgw_name="test TGW",
  vpc_account_name="name",
  vpc_id="${each.value}"
)

AwsTgwVpcAttachment.add_override(self, "for_each", aws_vpc_list_per_region)

I have not tested this, however.

Thanks for replying.

Unfortunately, it doesn’t work and throws the error while executing the Terraform stack.

╷
│ Error: Extraneous JSON object property
│
│   on cdk.tf.json line 175:
│  175:   "for_each": "${([vpc-abc])}"
│
│ No argument or block type is named "for_each".

I tried few other things but no luck so far.I’ll let everyone know if I find a solution.

Hi @exaws

I just had another try at it and was able to get this example working:

#!/usr/bin/env python
from constructs import Construct
from cdktf import App, TerraformStack, Fn
from imports.random import RandomProvider, Pet


class MyStack(TerraformStack):
    def __init__(self, scope: Construct, ns: str):
        super().__init__(scope, ns)

        # define resources here
        RandomProvider(self, "random")
        prefixes = ['"petA"', '"petB"']
        pets = Pet(self, "pets", prefix="${each.value}")
        pets.add_override("for_each", Fn.toset(prefixes))


app = App()
MyStack(app, "cdktf-test-python-foreach")

app.synth()

I still have to figure out why I had to add those double quotes (") to my constant values but the example works.

Hope it helps!

Thanks a million !

I converted the list of the VPC to a dictionary as its difficult to implement those double quotes(") for each element of the list.

Passing dictionary to the escape hatch worked fine.

Hello! Any ideas how can I convert this

data "kustomization_build" "test" {                                                
  path = "~/kustomize/default"
}                                                                                  
                                                                                   
resource "kustomization_resource" "test" {                                         
  for_each = data.kustomization_build.test.ids                                     
                                                                                   
  manifest = data.kustomization_build.test.manifests[each.value]                   
}  

to cdktf with python?

I am trying something like this

        testdata = DataKustomizationBuild(                                      
            self,                                                               
            "test",                                                
            path="~/kustomize/default",
        )                                                                       
                                                                                
        test = KustomizationResource(                              
            self,                                                               
            "test",                                                             
            manifest="${each.value}"                                            
        )                                                                       
        testdata.add_override("for_each", Fn.toset(testdata.ids)) 

But when I do cdktf apply

│ Error: github.com/kbst/terraform-provider-kustomize/kustomize.kustomizationResourceCreate: JSON parse error: invalid character 'r' looking for beginning of value

This seems to work but I don’t know if its the best solution :confused:

        test = KustomizationResource(
            self,
            "test",
            manifest="${" + testdata.fqn + ".manifests[each.value]}"
        )
        test.add_override("for_each", "${" + testdata.fqn + ".ids}")

``

I would have expected you to be able to use add_override("for_each", testdata.ids), but otherwise it looks good.

1 Like