diff --git a/packages/@aws-cdk/aws-lambda/README.md b/packages/@aws-cdk/aws-lambda/README.md index 7091fdce9c04d..419425f44f6a5 100644 --- a/packages/@aws-cdk/aws-lambda/README.md +++ b/packages/@aws-cdk/aws-lambda/README.md @@ -85,9 +85,9 @@ To deploy a `DockerImageFunction` on Lambda `arm64` architecture, specify `Archi This will bundle docker image assets for `arm64` architecture with `--platform linux/arm64` even if build within an `x86_64` host. ```ts -new DockerImageFunction(this, 'AssetFunction', { - code: DockerImageCode.fromImageAsset(path.join(__dirname, 'docker-arm64-handler')), - architecture: Architecture.ARM_64, +new lambda.DockerImageFunction(this, 'AssetFunction', { + code: lambda.DockerImageCode.fromImageAsset(path.join(__dirname, 'docker-arm64-handler')), + architecture: lambda.Architecture.ARM_64, }); ``` @@ -283,6 +283,19 @@ const version = new lambda.Version(this, 'MyVersion', { }); ``` +Or setting the `currentVersionOptions` when creating a new lambda + +```ts +new lambda.Function(this, 'MyVersionedLambda', { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), + currentVersionOptions: { + provisionedConcurrentExecutions: 3, + }, +}); +``` + The major caveat to know here is that a function version must always point to a specific 'version' of the function. When the function is modified, the version will continue to point to the 'then version' of the function. diff --git a/packages/@aws-cdk/aws-lambda/lib/function.ts b/packages/@aws-cdk/aws-lambda/lib/function.ts index 5da300546c576..0976b2962e7cf 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function.ts @@ -858,6 +858,9 @@ export class Function extends FunctionBase { } this.currentVersionOptions = props.currentVersionOptions; + if (props.currentVersionOptions) { + this.currentVersion; + } if (props.filesystem) { if (!props.vpc) { diff --git a/packages/@aws-cdk/aws-lambda/test/function.test.ts b/packages/@aws-cdk/aws-lambda/test/function.test.ts index bad9a95ec8d4e..cd128a5050193 100644 --- a/packages/@aws-cdk/aws-lambda/test/function.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/function.test.ts @@ -2871,7 +2871,7 @@ describe('function', () => { describe('FunctionUrl', () => { test('addFunctionUrl creates a function url with default options', () => { - // GIVEN + // GIVEN const stack = new cdk.Stack(); const fn = new lambda.Function(stack, 'MyLambda', { code: new lambda.InlineCode('hello()'), @@ -2895,7 +2895,7 @@ describe('function', () => { }); test('addFunctionUrl creates a function url with all options', () => { - // GIVEN + // GIVEN const stack = new cdk.Stack(); const fn = new lambda.Function(stack, 'MyLambda', { code: new lambda.InlineCode('hello()'), @@ -3045,6 +3045,31 @@ describe('function', () => { }, }); }); + + test('Generates a version when currentVersionOptions is set', () => { + const stack = new cdk.Stack(); + + new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_14_X, + currentVersionOptions: { + provisionedConcurrentExecutions: 3, + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Version', { + ProvisionedConcurrencyConfig: { + ProvisionedConcurrentExecutions: 3, + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Code: { ZipFile: 'foo' }, + Handler: 'index.handler', + Runtime: 'nodejs14.x', + }); + }); }); test('throws if ephemeral storage size is out of bound', () => { @@ -3141,14 +3166,14 @@ test('set SnapStart to desired value', () => { Template.fromStack(stack).hasResource('AWS::Lambda::Function', { Properties: - { - Code: { ZipFile: 'java11-test-function.zip' }, - Handler: 'example.Handler::handleRequest', - Runtime: 'java11', - SnapStart: { - ApplyOn: 'PublishedVersions', - }, - }, + { + Code: { ZipFile: 'java11-test-function.zip' }, + Handler: 'example.Handler::handleRequest', + Runtime: 'java11', + SnapStart: { + ApplyOn: 'PublishedVersions', + }, + }, }); }); diff --git a/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.js.snapshot/CurrentVersionOptionsDefaultTestDeployAssertF66C8354.assets.json b/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.js.snapshot/CurrentVersionOptionsDefaultTestDeployAssertF66C8354.assets.json new file mode 100644 index 0000000000000..944bb1b8ee642 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.js.snapshot/CurrentVersionOptionsDefaultTestDeployAssertF66C8354.assets.json @@ -0,0 +1,19 @@ +{ + "version": "22.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "CurrentVersionOptionsDefaultTestDeployAssertF66C8354.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.js.snapshot/CurrentVersionOptionsDefaultTestDeployAssertF66C8354.template.json b/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.js.snapshot/CurrentVersionOptionsDefaultTestDeployAssertF66C8354.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.js.snapshot/CurrentVersionOptionsDefaultTestDeployAssertF66C8354.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.js.snapshot/cdk.out b/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.js.snapshot/cdk.out new file mode 100644 index 0000000000000..145739f539580 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"22.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.js.snapshot/current-version-options.assets.json b/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.js.snapshot/current-version-options.assets.json new file mode 100644 index 0000000000000..22942b1c5c086 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.js.snapshot/current-version-options.assets.json @@ -0,0 +1,19 @@ +{ + "version": "22.0.0", + "files": { + "a37f787b341d3d57968efec7be372be0c175afbeae09ab1909503e7a7f7dc6b8": { + "source": { + "path": "current-version-options.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "a37f787b341d3d57968efec7be372be0c175afbeae09ab1909503e7a7f7dc6b8.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.js.snapshot/current-version-options.template.json b/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.js.snapshot/current-version-options.template.json new file mode 100644 index 0000000000000..9826778f6ba00 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.js.snapshot/current-version-options.template.json @@ -0,0 +1,99 @@ +{ + "Resources": { + "FServiceRole3AC82EE1": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "FC4345940": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "\n exports.handler = async(event) => {\n return \"My versioned lambda\";\n };\n " + }, + "Role": { + "Fn::GetAtt": [ + "FServiceRole3AC82EE1", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "FServiceRole3AC82EE1" + ] + }, + "FCurrentVersion58B8A55Dc23085bc26dff8641d9434d378493303": { + "Type": "AWS::Lambda::Version", + "Properties": { + "FunctionName": { + "Ref": "FC4345940" + }, + "ProvisionedConcurrencyConfig": { + "ProvisionedConcurrentExecutions": 3 + } + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.js.snapshot/integ.json b/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.js.snapshot/integ.json new file mode 100644 index 0000000000000..7dda851e5ec00 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "22.0.0", + "testCases": { + "CurrentVersionOptions/DefaultTest": { + "stacks": [ + "current-version-options" + ], + "assertionStack": "CurrentVersionOptions/DefaultTest/DeployAssert", + "assertionStackName": "CurrentVersionOptionsDefaultTestDeployAssertF66C8354" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.js.snapshot/manifest.json b/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.js.snapshot/manifest.json new file mode 100644 index 0000000000000..0358446afe01c --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.js.snapshot/manifest.json @@ -0,0 +1,123 @@ +{ + "version": "22.0.0", + "artifacts": { + "current-version-options.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "current-version-options.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "current-version-options": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "current-version-options.template.json", + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/a37f787b341d3d57968efec7be372be0c175afbeae09ab1909503e7a7f7dc6b8.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "current-version-options.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "current-version-options.assets" + ], + "metadata": { + "/current-version-options/F/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "FServiceRole3AC82EE1" + } + ], + "/current-version-options/F/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "FC4345940" + } + ], + "/current-version-options/F/CurrentVersion/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "FCurrentVersion58B8A55Dc23085bc26dff8641d9434d378493303" + } + ], + "/current-version-options/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/current-version-options/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "current-version-options" + }, + "CurrentVersionOptionsDefaultTestDeployAssertF66C8354.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "CurrentVersionOptionsDefaultTestDeployAssertF66C8354.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "CurrentVersionOptionsDefaultTestDeployAssertF66C8354": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "CurrentVersionOptionsDefaultTestDeployAssertF66C8354.template.json", + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "CurrentVersionOptionsDefaultTestDeployAssertF66C8354.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "CurrentVersionOptionsDefaultTestDeployAssertF66C8354.assets" + ], + "metadata": { + "/CurrentVersionOptions/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/CurrentVersionOptions/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "CurrentVersionOptions/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.js.snapshot/tree.json b/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.js.snapshot/tree.json new file mode 100644 index 0000000000000..3c2b3b015cfbe --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.js.snapshot/tree.json @@ -0,0 +1,221 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "current-version-options": { + "id": "current-version-options", + "path": "current-version-options", + "children": { + "F": { + "id": "F", + "path": "current-version-options/F", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "current-version-options/F/ServiceRole", + "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "current-version-options/F/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "current-version-options/F/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnRole", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "current-version-options/F/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "zipFile": "\n exports.handler = async(event) => {\n return \"My versioned lambda\";\n };\n " + }, + "role": { + "Fn::GetAtt": [ + "FServiceRole3AC82EE1", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs14.x" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + }, + "CurrentVersion": { + "id": "CurrentVersion", + "path": "current-version-options/F/CurrentVersion", + "children": { + "Resource": { + "id": "Resource", + "path": "current-version-options/F/CurrentVersion/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Version", + "aws:cdk:cloudformation:props": { + "functionName": { + "Ref": "FC4345940" + }, + "provisionedConcurrencyConfig": { + "provisionedConcurrentExecutions": 3 + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnVersion", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Version", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "current-version-options/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "current-version-options/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "CurrentVersionOptions": { + "id": "CurrentVersionOptions", + "path": "CurrentVersionOptions", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "CurrentVersionOptions/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "CurrentVersionOptions/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.168" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "CurrentVersionOptions/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "CurrentVersionOptions/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "CurrentVersionOptions/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.168" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.ts b/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.ts new file mode 100644 index 0000000000000..3f440150fe947 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/test/integ.current-version-options.ts @@ -0,0 +1,26 @@ +import * as cdk from '@aws-cdk/core'; +import * as integ from '@aws-cdk/integ-tests'; +import * as lambda from '../lib'; + +const app = new cdk.App(); + +const stack = new cdk.Stack(app, 'current-version-options'); + +new lambda.Function(stack, 'F', { + code: new lambda.InlineCode(` + exports.handler = async(event) => { + return "My versioned lambda"; + }; + `), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_14_X, + currentVersionOptions: { + provisionedConcurrentExecutions: 3, + }, +}); + +new integ.IntegTest(app, 'CurrentVersionOptions', { + testCases: [stack], +}); + +app.synth(); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-logs/lib/log-retention.ts b/packages/@aws-cdk/aws-logs/lib/log-retention.ts index b275b02cc24d5..0f1c8ebcd8902 100644 --- a/packages/@aws-cdk/aws-logs/lib/log-retention.ts +++ b/packages/@aws-cdk/aws-logs/lib/log-retention.ts @@ -85,6 +85,11 @@ export class LogRetention extends Construct { // Custom resource provider const provider = this.ensureSingletonLogRetentionFunction(props); + // if removalPolicy is DESTROY, add action for DeleteLogGroup + if (props.removalPolicy === cdk.RemovalPolicy.DESTROY) { + provider.grantDeleteLogGroup(props.logGroupName); + } + // Need to use a CfnResource here to prevent lerna dependency cycles // @aws-cdk/aws-cloudformation -> @aws-cdk/aws-lambda -> @aws-cdk/aws-cloudformation const retryOptions = props.logRetentionRetryOptions; @@ -137,15 +142,15 @@ class LogRetentionFunction extends Construct implements cdk.ITaggable { public readonly tags: cdk.TagManager = new cdk.TagManager(cdk.TagType.KEY_VALUE, 'AWS::Lambda::Function'); + private readonly role: iam.IRole; + constructor(scope: Construct, id: string, props: LogRetentionProps) { super(scope, id); - // Code const asset = new s3_assets.Asset(this, 'Code', { path: path.join(__dirname, 'log-retention-provider'), }); - // Role const role = props.role || new iam.Role(this, 'ServiceRole', { assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], @@ -158,29 +163,7 @@ class LogRetentionFunction extends Construct implements cdk.ITaggable { // creates a CF circular dependency. resources: ['*'], })); - // if removalPolicy is DESTROY, add action for DeleteLogGroup and DeleteLogStream - if (props.removalPolicy === cdk.RemovalPolicy.DESTROY) { - role.addToPrincipalPolicy(new iam.PolicyStatement({ - actions: ['logs:DeleteLogGroup'], - //Only allow deleting the specific log group. - resources: [cdk.Stack.of(this).formatArn({ - service: 'logs', - resource: 'log-group', - resourceName: `${props.logGroupName}:*`, - arnFormat: ArnFormat.COLON_RESOURCE_NAME, - })], - })); - role.addToPrincipalPolicy(new iam.PolicyStatement({ - actions: ['logs:DeleteLogStream'], - //Only allow deleting the specific log group. - resources: [cdk.Stack.of(this).formatArn({ - service: 'logs', - resource: `log-group:${props.logGroupName}:log-stream`, - resourceName: '*', - arnFormat: ArnFormat.COLON_RESOURCE_NAME, - })], - })); - } + this.role = role; // Lambda function const resource = new cdk.CfnResource(this, 'Resource', { @@ -210,4 +193,20 @@ class LogRetentionFunction extends Construct implements cdk.ITaggable { } }); } + + /** + * @internal + */ + public grantDeleteLogGroup(logGroupName: string) { + this.role.addToPrincipalPolicy(new iam.PolicyStatement({ + actions: ['logs:DeleteLogGroup'], + //Only allow deleting the specific log group. + resources: [cdk.Stack.of(this).formatArn({ + service: 'logs', + resource: 'log-group', + resourceName: `${logGroupName}:*`, + arnFormat: ArnFormat.COLON_RESOURCE_NAME, + })], + })); + } } diff --git a/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/LogRetentionIntegDefaultTestDeployAssert6ACC5A74.assets.json b/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/LogRetentionIntegDefaultTestDeployAssert6ACC5A74.assets.json index 8ab16782418be..e94f6f6dddb6f 100644 --- a/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/LogRetentionIntegDefaultTestDeployAssert6ACC5A74.assets.json +++ b/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/LogRetentionIntegDefaultTestDeployAssert6ACC5A74.assets.json @@ -1,5 +1,5 @@ { - "version": "20.0.0", + "version": "21.0.0", "files": { "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { "source": { diff --git a/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/aws-cdk-log-retention-integ.assets.json b/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/aws-cdk-log-retention-integ.assets.json index 66652a5a5d5cb..30f1c6896764a 100644 --- a/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/aws-cdk-log-retention-integ.assets.json +++ b/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/aws-cdk-log-retention-integ.assets.json @@ -1,5 +1,5 @@ { - "version": "20.0.0", + "version": "21.0.0", "files": { "d01c24641c7d8cb6488393ffceaefff282370a9a522bf9d77b21da73fa257347": { "source": { @@ -14,7 +14,7 @@ } } }, - "918f6261a4f427af36f4c1a810688fd80eafca576f152cb945787b6e916d00f2": { + "0b36d56a8395399d5e1fa49430910ae11ecc0b6a6f1163109c595a563569dde6": { "source": { "path": "aws-cdk-log-retention-integ.template.json", "packaging": "file" @@ -22,7 +22,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "918f6261a4f427af36f4c1a810688fd80eafca576f152cb945787b6e916d00f2.json", + "objectKey": "0b36d56a8395399d5e1fa49430910ae11ecc0b6a6f1163109c595a563569dde6.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/aws-cdk-log-retention-integ.template.json b/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/aws-cdk-log-retention-integ.template.json index a36f6ce90427d..51498424a6643 100644 --- a/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/aws-cdk-log-retention-integ.template.json +++ b/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/aws-cdk-log-retention-integ.template.json @@ -61,50 +61,48 @@ { "Action": "logs:DeleteLogGroup", "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":logs:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":log-group:logRetentionLogGroup:*" + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:logRetentionLogGroup2:*" + ] ] - ] - } - }, - { - "Action": "logs:DeleteLogStream", - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":logs:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":log-group:logRetentionLogGroup:log-stream:*" + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:logRetentionLogGroup:*" + ] ] - ] - } + } + ] } ], "Version": "2012-10-17" @@ -139,6 +137,20 @@ "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB", "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRole9741ECFB" ] + }, + "MyLambda2254B54D5": { + "Type": "Custom::LogRetention", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aFD4BFC8A", + "Arn" + ] + }, + "LogGroupName": "logRetentionLogGroup2", + "RetentionInDays": 1, + "RemovalPolicy": "destroy" + } } }, "Parameters": { diff --git a/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/cdk.out b/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/cdk.out index 588d7b269d34f..8ecc185e9dbee 100644 --- a/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/cdk.out +++ b/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"20.0.0"} \ No newline at end of file +{"version":"21.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/integ.json b/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/integ.json index 2aca38f87844c..1e60ecaaa02f4 100644 --- a/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/integ.json +++ b/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/integ.json @@ -1,11 +1,12 @@ { - "version": "20.0.0", + "version": "21.0.0", "testCases": { "LogRetentionInteg/DefaultTest": { "stacks": [ "aws-cdk-log-retention-integ" ], - "assertionStack": "LogRetentionInteg/DefaultTest/DeployAssert" + "assertionStack": "LogRetentionInteg/DefaultTest/DeployAssert", + "assertionStackName": "LogRetentionIntegDefaultTestDeployAssert6ACC5A74" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/manifest.json b/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/manifest.json index e8339eb2177d1..31a303c70c96f 100644 --- a/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/manifest.json +++ b/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "20.0.0", + "version": "21.0.0", "artifacts": { "Tree": { "type": "cdk:tree", @@ -23,7 +23,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/918f6261a4f427af36f4c1a810688fd80eafca576f152cb945787b6e916d00f2.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/0b36d56a8395399d5e1fa49430910ae11ecc0b6a6f1163109c595a563569dde6.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -63,6 +63,12 @@ "data": "LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aFD4BFC8A" } ], + "/aws-cdk-log-retention-integ/MyLambda2/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyLambda2254B54D5" + } + ], "/aws-cdk-log-retention-integ/BootstrapVersion": [ { "type": "aws:cdk:logicalId", diff --git a/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/tree.json b/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/tree.json index 1eef4a34e1437..f26593fd804e2 100644 --- a/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/tree.json +++ b/packages/@aws-cdk/aws-logs/test/integ.log-retention.js.snapshot/tree.json @@ -9,7 +9,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.85" + "version": "10.1.140" } }, "aws-cdk-log-retention-integ": { @@ -24,8 +24,8 @@ "id": "Resource", "path": "aws-cdk-log-retention-integ/MyLambda/Resource", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" } } }, @@ -46,8 +46,8 @@ "id": "Stage", "path": "aws-cdk-log-retention-integ/LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8a/Code/Stage", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" } }, "AssetBucket": { @@ -130,50 +130,48 @@ { "Action": "logs:DeleteLogGroup", "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":logs:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":log-group:logRetentionLogGroup:*" + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:logRetentionLogGroup2:*" + ] ] - ] - } - }, - { - "Action": "logs:DeleteLogStream", - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":logs:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":log-group:logRetentionLogGroup:log-stream:*" + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:logRetentionLogGroup:*" + ] ] - ] - } + } + ] } ], "Version": "2012-10-17" @@ -207,20 +205,38 @@ "id": "Resource", "path": "aws-cdk-log-retention-integ/LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8a/Resource", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" } } }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.85" + "version": "10.1.140" + } + }, + "MyLambda2": { + "id": "MyLambda2", + "path": "aws-cdk-log-retention-integ/MyLambda2", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-log-retention-integ/MyLambda2/Resource", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-logs.LogRetention", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" } }, "LogRetentionInteg": { @@ -236,15 +252,15 @@ "path": "LogRetentionInteg/DefaultTest/Default", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.85" + "version": "10.1.140" } }, "DeployAssert": { "id": "DeployAssert", "path": "LogRetentionInteg/DefaultTest/DeployAssert", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" } } }, @@ -261,8 +277,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-logs/test/integ.log-retention.ts b/packages/@aws-cdk/aws-logs/test/integ.log-retention.ts index a6843df7613a8..03f27144b5a92 100644 --- a/packages/@aws-cdk/aws-logs/test/integ.log-retention.ts +++ b/packages/@aws-cdk/aws-logs/test/integ.log-retention.ts @@ -11,6 +11,12 @@ class LogRetentionIntegStack extends Stack { retention: RetentionDays.ONE_DAY, removalPolicy: RemovalPolicy.DESTROY, }); + + new LogRetention(this, 'MyLambda2', { + logGroupName: 'logRetentionLogGroup2', + retention: RetentionDays.ONE_DAY, + removalPolicy: RemovalPolicy.DESTROY, + }); } } diff --git a/packages/@aws-cdk/aws-logs/test/log-retention.test.ts b/packages/@aws-cdk/aws-logs/test/log-retention.test.ts index 55feace88d552..8d3de4c1db487 100644 --- a/packages/@aws-cdk/aws-logs/test/log-retention.test.ts +++ b/packages/@aws-cdk/aws-logs/test/log-retention.test.ts @@ -105,30 +105,6 @@ describe('log retention', () => { ], }, }, - { - 'Action': 'logs:DeleteLogStream', - 'Effect': 'Allow', - 'Resource': { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':logs:', - { - 'Ref': 'AWS::Region', - }, - ':', - { - 'Ref': 'AWS::AccountId', - }, - ':log-group:group:log-stream:*', - ], - ], - }, - }, ], 'Version': '2012-10-17', }, @@ -200,6 +176,210 @@ describe('log retention', () => { }); }); + describe('multiple log retention resources', () => { + test('both removalPolicy DESTROY', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new LogRetention(stack, 'MyLambda1', { + logGroupName: 'group1', + retention: RetentionDays.ONE_DAY, + removalPolicy: cdk.RemovalPolicy.DESTROY, + }); + + new LogRetention(stack, 'MyLambda2', { + logGroupName: 'group2', + retention: RetentionDays.ONE_DAY, + removalPolicy: cdk.RemovalPolicy.DESTROY, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': [ + { + 'Action': [ + 'logs:PutRetentionPolicy', + 'logs:DeleteRetentionPolicy', + ], + 'Effect': 'Allow', + 'Resource': '*', + }, + { + 'Action': 'logs:DeleteLogGroup', + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': [ + '', + [ + 'arn:', + { + 'Ref': 'AWS::Partition', + }, + ':logs:', + { + 'Ref': 'AWS::Region', + }, + ':', + { + 'Ref': 'AWS::AccountId', + }, + ':log-group:group1:*', + ], + ], + }, + }, + { + 'Action': 'logs:DeleteLogGroup', + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': [ + '', + [ + 'arn:', + { + 'Ref': 'AWS::Partition', + }, + ':logs:', + { + 'Ref': 'AWS::Region', + }, + ':', + { + 'Ref': 'AWS::AccountId', + }, + ':log-group:group2:*', + ], + ], + }, + }, + ], + 'Version': '2012-10-17', + }, + 'PolicyName': 'LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB', + 'Roles': [ + { + 'Ref': 'LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRole9741ECFB', + }, + ], + }); + + Template.fromStack(stack).hasResourceProperties('Custom::LogRetention', { + 'ServiceToken': { + 'Fn::GetAtt': [ + 'LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aFD4BFC8A', + 'Arn', + ], + }, + 'LogGroupName': 'group1', + 'RetentionInDays': 1, + 'RemovalPolicy': 'destroy', + }); + + Template.fromStack(stack).hasResourceProperties('Custom::LogRetention', { + 'ServiceToken': { + 'Fn::GetAtt': [ + 'LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aFD4BFC8A', + 'Arn', + ], + }, + 'LogGroupName': 'group2', + 'RetentionInDays': 1, + 'RemovalPolicy': 'destroy', + }); + }); + + test('with removalPolicy DESTROY and removalPolicy RETAIN', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new LogRetention(stack, 'MyLambda1', { + logGroupName: 'group1', + retention: RetentionDays.ONE_DAY, + removalPolicy: cdk.RemovalPolicy.DESTROY, + }); + + new LogRetention(stack, 'MyLambda2', { + logGroupName: 'group2', + retention: RetentionDays.ONE_DAY, + removalPolicy: cdk.RemovalPolicy.RETAIN, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': [ + { + 'Action': [ + 'logs:PutRetentionPolicy', + 'logs:DeleteRetentionPolicy', + ], + 'Effect': 'Allow', + 'Resource': '*', + }, + { + 'Action': 'logs:DeleteLogGroup', + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': [ + '', + [ + 'arn:', + { + 'Ref': 'AWS::Partition', + }, + ':logs:', + { + 'Ref': 'AWS::Region', + }, + ':', + { + 'Ref': 'AWS::AccountId', + }, + ':log-group:group1:*', + ], + ], + }, + }, + ], + 'Version': '2012-10-17', + }, + 'PolicyName': 'LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRoleDefaultPolicyADDA7DEB', + 'Roles': [ + { + 'Ref': 'LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aServiceRole9741ECFB', + }, + ], + }); + + Template.fromStack(stack).hasResourceProperties('Custom::LogRetention', { + 'ServiceToken': { + 'Fn::GetAtt': [ + 'LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aFD4BFC8A', + 'Arn', + ], + }, + 'LogGroupName': 'group1', + 'RetentionInDays': 1, + 'RemovalPolicy': 'destroy', + }); + + Template.fromStack(stack).hasResourceProperties('Custom::LogRetention', { + 'ServiceToken': { + 'Fn::GetAtt': [ + 'LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aFD4BFC8A', + 'Arn', + ], + }, + 'LogGroupName': 'group2', + 'RetentionInDays': 1, + 'RemovalPolicy': 'retain', + }); + }); + }); + test('the removalPolicy is not set', () => { // GIVEN const stack = new cdk.Stack(); diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/cli-credentials-synthesizer.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/cli-credentials-synthesizer.ts index 7bdef5d8a051f..66857c02b0b08 100644 --- a/packages/@aws-cdk/core/lib/stack-synthesizers/cli-credentials-synthesizer.ts +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/cli-credentials-synthesizer.ts @@ -117,6 +117,9 @@ export class CliCredentialsStackSynthesizer extends StackSynthesizer { } } + /** + * The qualifier used to bootstrap this stack + */ public get bootstrapQualifier(): string | undefined { return this.qualifier; } diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts index 109029d05e184..6d5aa60a3517f 100644 --- a/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts @@ -324,6 +324,9 @@ export class DefaultStackSynthesizer extends StackSynthesizer { } } + /** + * The qualifier used to bootstrap this stack + */ public get bootstrapQualifier(): string | undefined { return this.qualifier; } diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/nested.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/nested.ts index bf89868bd0fc6..6ccccacc5062b 100644 --- a/packages/@aws-cdk/core/lib/stack-synthesizers/nested.ts +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/nested.ts @@ -11,6 +11,9 @@ import { IStackSynthesizer, ISynthesisSession } from './types'; * App builder do not need to use this class directly. */ export class NestedStackSynthesizer extends StackSynthesizer { + /** + * The qualifier used to bootstrap this stack + */ public readonly bootstrapQualifier?: string; constructor(private readonly parentDeployment: IStackSynthesizer) { super(); diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/stack-synthesizer.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/stack-synthesizer.ts index d3cbcbcfc1880..311a648561bd3 100644 --- a/packages/@aws-cdk/core/lib/stack-synthesizers/stack-synthesizer.ts +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/stack-synthesizer.ts @@ -19,8 +19,6 @@ import { IStackSynthesizer, ISynthesisSession } from './types'; * and could not be accessed by external implementors. */ export abstract class StackSynthesizer implements IStackSynthesizer { - public readonly bootstrapQualifier?: string; - private _boundStack?: Stack; /** diff --git a/packages/awslint/lib/rules/resource.ts b/packages/awslint/lib/rules/resource.ts index 24df37d0160fc..19eb107c7f267 100644 --- a/packages/awslint/lib/rules/resource.ts +++ b/packages/awslint/lib/rules/resource.ts @@ -187,6 +187,7 @@ resourceLinter.add({ resourceLinter.add({ code: 'resource-attribute', + warning: true, message: 'resources must represent all cloudformation attributes as attribute properties. ' + '"@attribute ATTR[,ATTR]" can be used to tag non-standard attribute names. ' +