How can I structure my Terraform CDK code in TypeScript to create a simple VPC using multiple files and classes for each building block? I am looking for a way to organize my code in a more modular and maintainable way.
This is my main code:
import { App } from 'cdktf'; // import the App class from the cdktf library
import { RegionStack } from './lib/region-stack'; // import the RegionStack class from the './lib/region-stack' module
// Create a new App object
const app = new App();
// Create a new RegionStack object and pass it the app object, a string identifier, and a configuration object
new RegionStack(app, `aws`, {
environment: 'dev', // field for the environment in which the region stack will be created
region: 'eu-south-1', // field for the AWS region in which the region stack will be created
});
// Synthesize the CloudFormation template for the AWS resources specified in the code
app.synth();
I will call the RegionStack class:
import { Construct } from 'constructs';
import { TerraformStack } from 'cdktf';
import { VpcStack } from './vpc-stack';
import { AwsProvider } from '@cdktf/provider-aws/lib/provider';
// Interface for the RegionStackConfig object
interface RegionStackConfig {
environment: string; // required field for the configuration object
region?: string; // optional field for the configuration object
}
// The RegionStack class represents a stack of AWS resources for creating resources in a region
export class RegionStack extends TerraformStack {
// Constructor for the RegionStack class
// - scope: the Construct object that represents the scope for the region stack
// - id: a string that is used to identify the region stack
// - config: a RegionStackConfig object that contains configuration information for the region stack
constructor(scope: Construct, id: string, config: RegionStackConfig) {
// Call the parent constructor
super(scope, id);
// Create a new AwsProvider object and pass it the region field of the config object as the region field in its configuration object
new AwsProvider(this, 'AWS', { region: config.region });
// Create a new VpcStack object and pass it a configuration object with the name, cidr_block, and environment fields
new VpcStack(this, 'test', {
name: 'test',
cidr_block: '10.0.0.0/16',
environment: config.environment,
});
}
}
and then the VpcStack class:
import { Construct } from 'constructs';
import { TerraformStack } from 'cdktf';
import { Vpc } from '@cdktf/provider-aws/lib/vpc';
// The VpcStack class represents a stack of AWS resources for creating a VPC
export class VpcStack extends TerraformStack {
// property to hold the VPC object
vpc: any;
// property to hold the Internet Gateway object
InetGw: any;
// Constructor for the VpcStack class
// - scope: the Construct object that represents the scope for the VPC stack
// - id: a string that is used to identify the VPC stack
// - config: an object that contains configuration information for the VPC stack, including the cidr_block and name fields
constructor(scope: Construct, id: string, config: any) {
// Call the parent constructor
super(scope, id);
// Create a new Vpc object and assign it to the vpc property of the VpcStack object
// The Vpc object is created with the cidr_block and enable_dns_hostnames fields from the config object
this.vpc = new Vpc(this, `vpc${config.name}`, {
cidrBlock: config.cidr_block,
enableDnsHostnames: true,
});
}
}
and this is the error what I get:
ubuntu@ip-172-31-16-130:~/CloudServiceTree$ cdktf deploy
⠴ Synthesizing
[2023-01-01T15:41:54.338] [ERROR] default - /home/ubuntu/CloudServiceTree/node_modules/cdktf/lib/terraform-stack.ts:342
throw new Error(
^
[2023-01-01T15:41:54.340] [ERROR] default - Error: Validation failed with the following errors:
[aws/test] Found resources without a matching provider construct. Please make sure to add provider constructs [e.g. new RandomProvider(...)] to your stack 'test' for the following providers: aws
at RegionStack.runAllValidations (/home/ubuntu/CloudServiceTree/node_modules/cdktf/lib/terraform-stack.ts:342:13)
at StackSynthesizer.synthesize (/home/ubuntu/CloudServiceTree/node_modules/cdktf/lib/synthesize/synthesizer.ts:30:18)
at /home/ubuntu/CloudServiceTree/node_modules/cdktf/lib/app.ts:129:49
at Array.forEach (<anonymous>)
at App.synth (/home/ubuntu/CloudServiceTree/node_modules/cdktf/lib/app.ts:129:12)
at Object.<anonymous> (/home/ubuntu/CloudServiceTree/main.ts:14:5)
at Module._compile (node:internal/modules/cjs/loader:1120:14)
at Module.m._compile (/home/ubuntu/CloudServiceTree/node_modules/ts-node/src/index.ts:1618:23)
at Module._extensions..js (node:internal/modules/cjs/loader:1174:10)
ERROR: cdktf encountered an error while synthesizing
Synth command: npx ts-node main.ts
Error: non-zero exit code 1
Question: I am using the Terraform CDK with TypeScript and I am trying to pass the AwsProvider to my sub-classes. However, if I create an AwsProvider object in each of my sub-classes, I will end up with multiple stacks. How can I avoid this and pass the AwsProvider object to all of my sub-classes while still maintaining a clean and modular structure?
This is not true, you end up with multiple stacks if you extend from
TerraformStack
multiple times. Each stack needs to have all providers defined you want to use in them. If you are after a more modular structure you should extend fromConstruct
, see this part of the docs.If you want to keep the seperate stacks but you don't want to repeat your provider definition you can have a intermediary class like this: