Aspects allow you to apply an operation to all constructs within a given scope. You may want to use them in your CDK for Terraform (CDKTF) application to mutate elements (e.g., add tags to cloud resources) or for validation (e.g., ensure all S3 Buckets are encrypted).
To create an aspect, you must import the Aspects class and the IAspect interface and implement one or more methods for IAspect. Then, you can call the aspect one or more times on any construct within your application.
Everything within a CDKTF application descends from the Construct class, so you could call the construct on any instantiated element. This includes the entire application, a particular stack, or all of the resources for a specific provider. When you call the aspect, CDKTF applies its methods to all of the the constructs that fall within the specified scope.
The following TypeScript example defines an aspect to add tags to resources.
import{IConstruct}from"constructs";import{Aspects,IAspect}from"cdktf";// Not all constructs are taggable, so we need to filter ittypeTaggableConstruct=IConstruct&{
tags?:{[key:string]:string};
tagsInput?:{[key:string]:string};};functionisTaggableConstruct(x:IConstruct): x isTaggableConstruct{return"tags"in x &&"tagsInput"in x;}exportclassTagsAddingAspectimplementsIAspect{constructor(private tagsToAdd:Record<string,string>){}// This method is called on every Construct within the specified scope (resources, data sources, etc.).visit(node:IConstruct){if(isTaggableConstruct(node)){// We need to take the input value to not create a circular referenceconst currentTags = node.tagsInput||{};
node.tags={...this.tagsToAdd,...currentTags };}}}// Add tags to every resource defined within `myStack`.Aspects.of(myStack).add(newTagsAddingAspect({ createdBy:"cdktf"}));
import{IConstruct}from"constructs";import{Aspects,IAspect}from"cdktf";// Not all constructs are taggable, so we need to filter ittypeTaggableConstruct=IConstruct&{ tags?:{[key:string]:string}; tagsInput?:{[key:string]:string};};functionisTaggableConstruct(x:IConstruct): x isTaggableConstruct{return"tags"in x &&"tagsInput"in x;}exportclassTagsAddingAspectimplementsIAspect{constructor(private tagsToAdd:Record<string,string>){}// This method is called on every Construct within the specified scope (resources, data sources, etc.).visit(node:IConstruct){if(isTaggableConstruct(node)){// We need to take the input value to not create a circular referenceconst currentTags = node.tagsInput||{}; node.tags={...this.tagsToAdd,...currentTags };}}}// Add tags to every resource defined within `myStack`.Aspects.of(myStack).add(newTagsAddingAspect({ createdBy:"cdktf"}));
You can also use aspects for validation. The following TypeScript example defines an aspect that checks whether all S3 Buckets start with the correct prefix.
import{IConstruct}from"constructs";import{Aspects,IAspect,Annotations}from"cdktf";import{ s3 }from"./.gen/providers/aws";exportclassValidateS3IsPrefixedimplementsIAspect{constructor(private prefix:string){}// This method is called on every Construct within the defined scope (resource, data sources, etc.).visit(node:IConstruct){if(node instanceofs3.S3Bucket){if(node.bucket&&!node.bucket.startsWith(this.prefix)){// You can include `addInfo`, `addWarning`, and `addError`.// CDKTF prints these messages when the user runs `synth`, `plan`, or `deploy`.Annotations.of(node).addError(`Each S3 Bucket name needs to start with ${this.prefix}`);}}}}// Check the prefix for every resource within `myStack`.Aspects.of(myStack).add(newValidateS3IsPrefixed("myPrefix"));
import{IConstruct}from"constructs";import{Aspects,IAspect,Annotations}from"cdktf";import{ s3 }from"./.gen/providers/aws";exportclassValidateS3IsPrefixedimplementsIAspect{constructor(private prefix:string){}// This method is called on every Construct within the defined scope (resource, data sources, etc.).visit(node:IConstruct){if(node instanceofs3.S3Bucket){if(node.bucket&&!node.bucket.startsWith(this.prefix)){// You can include `addInfo`, `addWarning`, and `addError`.// CDKTF prints these messages when the user runs `synth`, `plan`, or `deploy`.Annotations.of(node).addError(`Each S3 Bucket name needs to start with ${this.prefix}`);}}}}// Check the prefix for every resource within `myStack`.Aspects.of(myStack).add(newValidateS3IsPrefixed("myPrefix"));