Porting Transit Gateway module example to cdktf

I’m running into errors while porting the reference example from Terraform Transit Gateway module using cdktf.

cdktf.json

{
  "language": "python",
  "app": "pipenv run python main.py",
  "terraformProviders": ["aws@~> 2.0"],
  "terraformModules": [ 
    "terraform-aws-modules/vpc/aws",
    "terraform-aws-modules/transit-gateway/aws"
  ],
  "codeMakerOutput": "imports"
}

app.py:

    #!/usr/bin/env python
    from constructs import Construct
    from cdktf import App, TerraformStack, Token, TerraformOutput
    from imports.aws import SnsTopic, AwsProvider, DataAwsCallerIdentity
    from imports.terraform_aws_modules.vpc.aws import Vpc
    from imports.terraform_aws_modules.transit_gatway.aws import TransitGateway


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

        AwsProvider(self, 'Aws', region='us-west-2')

        vpc1 = Vpc(self, 'AriVpc2',
            name = 'ari-vpc1',
            cidr = '10.10.0.0/16',
            azs = ['us-west-2a', 'us-west-2b', 'us-west-2c'],
            private_subnets = ['10.10.1.0/24', '10.10.2.0/24', '10.10.3.0/24'],
            public_subnets = ['10.10.101.0/24', '10.10.102.0/24', '10.10.103.0/24'],
            enable_nat_gateway = True)

        vpc2 = Vpc(self, 'AriVpc2',
            name = 'ari-vpc2',
            cidr = '10.20.0.0/16',
            azs = ['us-west-2a', 'us-west-2b', 'us-west-2c'],
            private_subnets = ['10.20.1.0/24', '10.20.2.0/24', '10.20.3.0/24'])    

        TransitGateway(self, 'AriTGW',
            name = 'ari-tgw',
            amazon_side_asn = '64632',
            enable_auto_accept_shared_attachements = True,
            vpc_attachments = {{
                vpc1: {
                        vpc_id: vpc1.id,
                        subnet_ids: vpc1.cloudformation_endpoint_subnet_ids,
                        dns_support: True,
                        ipv6_support: True,
                        transit_gateway_default_route_table_association: False,
                        transit_gateway_default_route_table_propagation: False,   
                        tgw_routes: [
                            {
                                destination_cidr_block: "30.0.0.0/16"
                            },
                            {
                                blackhole: True,
                                destination_cidr_block: "0.0.0.0/0"
                            }   
                        ]
                    },
               vpc2: {
                        vpc_id: vpc2.id,
                        subnet_ids: vpc2.cloudformation_endpoint_subnet_ids,
                        tgw_routes: [
                            {
                             destination_cidr_block: "50.0.0.0/16"
                            },
                            {
                                blackhole: True,
                                destination_cidr_block: "10.10.10.10/32"
                            }
                        ]
                    }
            }})


        TerraformOutput(self, 'create_user_arn',
            value=DataAwsCallerIdentity(self, 'current').arn)


    app = App()
    MyStack(app, "python-aws")

    app.synth()    

Error:

$ cdktf get

(I can see transit_gateway/aws is imported in 'imports')

$ cdktf synth
      
⠋ synthesizing ...
Traceback (most recent call last):
File "main.py", line 6, in <module>
from imports.terraform_aws_modules.transit_gatway.aws 
import TransitGateway
⠸ synthesizing ...
non-zero exit code 1

What am I missing?

To start with, gateway is misspelled on the import.
Also need to change the construct id on vpc1.
I think some issues with vpc_attachments as well.

Thanks for the typo fix :slight_smile: How do you set the vpc ids? Terraform uses
‘data’ variables, I think.

When using the vpc module, you’ll want to access vpc_id_output. If you have an existing vpc, you can use DataAwsVpc as a data source.

Where do you access vpc_id_output? Where should I import DataAwsVpc from?

In the code you posted, it would be vpc1.vpc_id_output.
DataAwsVpc is in imports.aws

I get the following not so helpful error now with fixes you suggested. I’m looking for a simple example to create two vpcs and create a transit gateway between them.

#!/usr/bin/env python
from constructs import Construct
from cdktf import App, TerraformStack, Token, TerraformOutput
from imports.aws import SnsTopic, AwsProvider, DataAwsCallerIdentity
from imports.terraform_aws_modules.vpc.aws import Vpc
from imports.terraform_aws_modules.transit_gateway.aws import TransitGateway


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

        AwsProvider(self, 'Aws', region='us-west-2')

        vpc1 = Vpc(self, 'AriVpc1',
            name = 'ari-vpc1',
            cidr = '10.10.0.0/16',
            azs = ['us-west-2a', 'us-west-2b', 'us-west-2c'],
            private_subnets = ['10.10.1.0/24', '10.10.2.0/24', '10.10.3.0/24'],
            public_subnets = ['10.10.101.0/24', '10.10.102.0/24', '10.10.103.0/24'],
            enable_nat_gateway = True)

        vpc2 = Vpc(self, 'AriVpc2',
            name = 'ari-vpc2',
            cidr = '10.20.0.0/16',
            azs = ['us-west-2a', 'us-west-2b', 'us-west-2c'],
            private_subnets = ['10.20.1.0/24', '10.20.2.0/24', '10.20.3.0/24'])    

        TransitGateway(self, 'AriTGW',
            name = 'ari-tgw',
            amazon_side_asn = '64632',
            enable_auto_accept_shared_attachements = True,
            vpc_attachments = [{
                'vpc1': {
                        'vpc_id': vpc1.vpc_id_output,
                        'subnet_ids': vpc1.cloudformation_endpoint_subnet_ids,
                        'dns_support': True,
                        'ipv6_support': True,
                        'transit_gateway_default_route_table_association': False,
                        'transit_gateway_default_route_table_propagation': False,   
                        'tgw_routes': [
                            {
                                'destination_cidr_block': "30.0.0.0/16"
                            },
                            {
                                'blackhole': True,
                                'destination_cidr_block': "0.0.0.0/0"
                            }   
                        ]
                    },
               'vpc2': {
                        'vpc_id': vpc2.vpc_id_output,
                        'subnet_ids': vpc2.cloudformation_endpoint_subnet_ids,
                        'tgw_routes': [
                            {
                             'destination_cidr_block': "50.0.0.0/16"
                            },
                            {
                                'blackhole': True,
                                'destination_cidr_block': "10.10.10.10/32"
                            }
                        ]
                    }
            }])

        TerraformOutput(self, 'create_user_arn', value = DataAwsCallerIdentity(self, 'current').arn)


app = App()
MyStack(app, "python-aws")

app.synth()
Traceback (most recent call last):
  File "main.py", line 70, in <module>
    MyStack(app, "python-aws")
  File "/Users/.../lib/python3.8/site-packages/jsii/_runtime.py", line 69, in __call__
    inst = super().__call__(*args, **kwargs)
  File "main.py", line 29, in __init__
    TransitGateway(self, 'AribaTGW',
  File "/.../lib/python3.8/site-packages/jsii/_runtime.py", line 69, in __call__
    inst = super().__call__(*args, **kwargs)
⠙ synthesizing ...
non-zero exit code 1
(base) 

Suggestions?

This gets closer:

#!/usr/bin/env python
from constructs import Construct
from cdktf import App, TerraformStack, Token, TerraformOutput
from imports.aws import SnsTopic, AwsProvider, DataAwsCallerIdentity
from imports.terraform_aws_modules.vpc.aws import Vpc
from imports.terraform_aws_modules.transit_gateway.aws import TransitGateway


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

        AwsProvider(self, 'Aws', region='us-west-2')

        vpc1 = Vpc(self, 'AriVpc1',
            name = 'ari-vpc1',
            cidr = '10.10.0.0/16',
            azs = ['us-west-2a', 'us-west-2b', 'us-west-2c'],
            private_subnets = ['10.10.1.0/24', '10.10.2.0/24', '10.10.3.0/24'],
            public_subnets = ['10.10.101.0/24', '10.10.102.0/24', '10.10.103.0/24'],
            enable_nat_gateway = True)

        vpc2 = Vpc(self, 'AriVpc2',
            name = 'ari-vpc2',
            cidr = '10.20.0.0/16',
            azs = ['us-west-2a', 'us-west-2b', 'us-west-2c'],
            private_subnets = ['10.20.1.0/24', '10.20.2.0/24', '10.20.3.0/24'])    

        gateway = TransitGateway(self, 'AriTGW',
            name = 'ari-tgw',
            amazon_side_asn = '64632',
            enable_auto_accept_shared_attachments = True,
            vpc_attachments = {
                'vpc1': {
                        'vpc_id': vpc1.vpc_id_output,
                        'subnet_ids': vpc1.private_subnets_output,
                        'dns_support': True,
                        'ipv6_support': True,
                        'transit_gateway_default_route_table_association': False,
                        'transit_gateway_default_route_table_propagation': False,   
                        'tgw_routes': [
                            {
                                'destination_cidr_block': "30.0.0.0/16"
                            },
                            {
                                'blackhole': True,
                                'destination_cidr_block': "0.0.0.0/0"
                            }   
                        ]
                    },
               'vpc2': {
                        'vpc_id': vpc2.vpc_id_output,
                        'subnet_ids': vpc2.private_subnets_output,
                        'tgw_routes': [
                            {
                             'destination_cidr_block': "50.0.0.0/16"
                            },
                            {
                                'blackhole': True,
                                'destination_cidr_block': "10.10.10.10/32"
                            }
                        ]
                    }
            })

        TerraformOutput(self, 'create_user_arn', value = DataAwsCallerIdentity(self, 'current').arn)


app = App()
MyStack(app, "python-aws")

app.synth()

It then runs into a bug described in the module.

You could draw on what the module is doing and create the resources directly.

Thanks a lot, appreciate your guidance. I do get a new error now on creation of TransitGateway, and would not have identified the root cause as the bug you referenced. How were you able to map this error to the existing bug?

File "main.py", line 29, in __init__
    TransitGateway(self, 'AriTGW',

I don’t actually get an error at that point anymore. cdktf synth is successful for me. The error I see now comes when running cdktf diff.

As far as diagnosing other errors, I referred back to the module documentation and the generated typings in __init__.py files in the imports folder; making sure to fix any typos and to use valid outputs. I was just in a text editor, but a good IDE would have likely point out some of the issues.