From fa00b9a04bc808f191d3435ba82f80b6269b39fb Mon Sep 17 00:00:00 2001 From: Luke Guan <150387335+awslukeguan@users.noreply.github.com> Date: Mon, 19 Aug 2024 15:32:46 -0400 Subject: [PATCH] Updated tests and README.md --- .../aws-cdk-lib/custom-resources/README.md | 14 ++--- .../custom-resource-config.ts | 6 +- .../custom-resource-config.test.ts | 63 ++++++++++++++++++- 3 files changed, 71 insertions(+), 12 deletions(-) diff --git a/packages/aws-cdk-lib/custom-resources/README.md b/packages/aws-cdk-lib/custom-resources/README.md index 119f452a92535..c6075de19e30c 100644 --- a/packages/aws-cdk-lib/custom-resources/README.md +++ b/packages/aws-cdk-lib/custom-resources/README.md @@ -827,6 +827,8 @@ new cr.AwsCustomResource(this, 'CrossAccount', { #### Custom Resource Config +**This feature is currently experimental** + You can configure every CDK-vended custom resource in a given scope with `CustomResourceConfig`. Note that `CustomResourceConfig` uses Aspects to modify your constructs. There is no guarantee in the order in which Aspects modify the construct tree, which means that adding the same Aspect more than once to a given scope produces undefined behavior. This example guarantees that every affected resource will have a log retention of ten years or one day, but you cannot know which: @@ -908,17 +910,15 @@ new s3deploy.BucketDeployment(nestedStackB, "s3deployB", { The following example configures custom resource log groups removal policy to `DESTROY`: ```ts import * as cdk from 'aws-cdk-lib'; -import * as s3deploy from 'aws-cdk-lib/aws-s3-deployment'; +import * as ses from 'aws-cdk-lib/aws-ses'; import { CustomResourceConfig } from 'aws-cdk-lib/custom-resources'; const app = new cdk.App(); const stack = new cdk.Stack(app, 'Stack'); +CustomResourceConfig.of(this).addLogRetentionLifetime(logs.RetentionDays.TEN_YEARS); CustomResourceConfig.of(app).addRemovalPolicy(cdk.RemovalPolicy.DESTROY); -let websiteBucket = new s3.Bucket(stack, 'WebsiteBucket', {}); -new s3deploy.BucketDeployment(stack, 'BucketDeployment', { - sources: [s3deploy.Source.jsonData('file.json', { a: 'b' })], - destinationBucket: websiteBucket, - logGroup: new logs.logGroup(stack, 'LogGroup', {}); -}); // logGroup removalPolicy overridden by the `DESTROY` set by `CustomResourceConfig`. +new ses.ReceiptRuleSet(this, 'RuleSet', { + dropSpam: true, +}); ``` diff --git a/packages/aws-cdk-lib/custom-resources/lib/custom-resource-config/custom-resource-config.ts b/packages/aws-cdk-lib/custom-resources/lib/custom-resource-config/custom-resource-config.ts index bb3d52728db16..a10299a0a46d2 100644 --- a/packages/aws-cdk-lib/custom-resources/lib/custom-resource-config/custom-resource-config.ts +++ b/packages/aws-cdk-lib/custom-resources/lib/custom-resource-config/custom-resource-config.ts @@ -11,7 +11,7 @@ export const CUSTOM_RESOURCE_SINGLETON_LOG_GROUP = 'aws:cdk:is-custom-resource-h export const CUSTOM_RESOURCE_SINGLETON_LOG_RETENTION = 'aws:cdk:is-custom-resource-handler-logRetention'; /** - * Manages AWS vended Custom Resources + * Manages AWS-vended Custom Resources */ export class CustomResourceConfig { /** @@ -40,7 +40,7 @@ export class CustomResourceConfig { } /** - * Manages log retention for AWS vended custom resources. + * Manages log retention for AWS-vended custom resources. */ export class CustomResourceLogRetention implements IAspect { private readonly logRetention: logs.RetentionDays; @@ -87,7 +87,7 @@ export class CustomResourceLogRetention implements IAspect { } /** - * Manages removal policy for AWS vended custom resources. + * Manages removal policy for AWS-vended custom resources. */ export class CustomResourceRemovalPolicy implements IAspect { private readonly removalPolicy: RemovalPolicy; diff --git a/packages/aws-cdk-lib/custom-resources/test/custom-resource-config/custom-resource-config.test.ts b/packages/aws-cdk-lib/custom-resources/test/custom-resource-config/custom-resource-config.test.ts index 565704bf77738..9487d4f4ebb20 100644 --- a/packages/aws-cdk-lib/custom-resources/test/custom-resource-config/custom-resource-config.test.ts +++ b/packages/aws-cdk-lib/custom-resources/test/custom-resource-config/custom-resource-config.test.ts @@ -201,7 +201,7 @@ test('addLogRetentionLifetime modifies the retention period of the custom resour }); }); -describe('when custom resource logGroup is default set to Retain', () => { +describe('when custom resource logGroup removalPolicy is undefined', () => { test('addRemovalPolicy modifies custom resource logGroup to Delete', () => { // GIVEN const customResourceRemovalPolicy = cdk.RemovalPolicy.DESTROY; @@ -211,7 +211,9 @@ describe('when custom resource logGroup is default set to Retain', () => { new s3deploy.BucketDeployment(stack, 'BucketDeployment', { sources: [s3deploy.Source.jsonData('file.json', { a: 'b' })], destinationBucket: websiteBucket, - logGroup: new logs.LogGroup(stack, 'LogGroup', {}), + logGroup: new logs.LogGroup(stack, 'LogGroup', { + removalPolicy: cdk.RemovalPolicy.RETAIN, /* Explicitly set to the default value `RETAIN` */ + }), }); // WHEN @@ -250,4 +252,61 @@ describe('when custom resource logGroup is default set to Retain', () => { DeletionPolicy: 'Delete', }); }); + + test('addRemovalPolicy keeps custom resource logGroup to Retain', () => { + // GIVEN + const customResourceRemovalPolicy = cdk.RemovalPolicy.RETAIN; + const app = new cdk.App(); + const stack = new cdk.Stack(app); + const websiteBucket = new s3.Bucket(stack, 'WebsiteBucket', {}); + new s3deploy.BucketDeployment(stack, 'BucketDeployment', { + sources: [s3deploy.Source.jsonData('file.json', { a: 'b' })], + destinationBucket: websiteBucket, + logGroup: new logs.LogGroup(stack, 'LogGroup1', {}), + }); + + // WHEN + CustomResourceConfig.of(app).addRemovalPolicy(customResourceRemovalPolicy); + + // THEN + const template = Template.fromStack(stack); + template.resourceCountIs('AWS::Logs::LogGroup', 1); + template.hasResource('AWS::Logs::LogGroup', { + UpdateReplacePolicy: 'Retain', + DeletionPolicy: 'Retain', + }); + }); + + test('addRemovalPolicy modifies custom resource logGroup to Delete and non-custom resource logGroup unmodified at Retain', () => { + // GIVEN + const customResourceRemovalPolicy = cdk.RemovalPolicy.DESTROY; + const app = new cdk.App(); + const stack = new cdk.Stack(app); + const websiteBucket = new s3.Bucket(stack, 'WebsiteBucket', {}); + new s3deploy.BucketDeployment(stack, 'BucketDeployment', { + sources: [s3deploy.Source.jsonData('file.json', { a: 'b' })], + destinationBucket: websiteBucket, + logGroup: new logs.LogGroup(stack, 'LogGroup1', { + removalPolicy: cdk.RemovalPolicy.RETAIN, + }), + }); + new logs.LogGroup(stack, 'LogGroup2', { + removalPolicy: cdk.RemovalPolicy.RETAIN, + }); + + // WHEN + CustomResourceConfig.of(app).addRemovalPolicy(customResourceRemovalPolicy); + + // THEN + const template = Template.fromStack(stack); + template.resourceCountIs('AWS::Logs::LogGroup', 2); + template.hasResource('AWS::Logs::LogGroup', { + UpdateReplacePolicy: 'Delete', + DeletionPolicy: 'Delete', + }); + template.hasResource('AWS::Logs::LogGroup', { + UpdateReplacePolicy: 'Retain', + DeletionPolicy: 'Retain', + }); + }); });