diff --git a/.dependabot/config.yml b/.dependabot/config.yml deleted file mode 100644 index c54ea38a24f81..0000000000000 --- a/.dependabot/config.yml +++ /dev/null @@ -1,19 +0,0 @@ ---- -# See: https://dependabot.com/docs/config-file/ -version: 1 -update_configs: - # Dependabot will detect the lerna mono-repo and discover packages in there - - directory: / - package_manager: javascript - update_schedule: live - version_requirement_updates: increase_versions - ignored_updates: - - match: - dependency_name: "jsii*" - - match: - dependency_name: "@jsii/*" - - match: - dependency_name: "codemaker" - - match: - dependency_name: "@types/node" - version_requirement: ">=11.0.0-0" diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000000..1d4633809b73b --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +# Reference: https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates +# NOTE: dependabot only takes care of updating non-npm deps +# npm dependencies are updated through the "yarn-upgrade" github workflow. + +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + labels: + - "pr/auto-approve" + open-pull-requests-limit: 5 diff --git a/.github/workflows/auto-approve-dependabot.yml b/.github/workflows/auto-approve-dependabot.yml deleted file mode 100644 index 5eb14a05c1890..0000000000000 --- a/.github/workflows/auto-approve-dependabot.yml +++ /dev/null @@ -1,27 +0,0 @@ -# Automatically approve PRs made by Dependabot -# -# Written to look at the original author of the PR (instead of the current -# actor) in order to be able to backresolve existing PRs using this action (by -# mass labeling them). Leads to slightly unnecessary spammage of aprovals in a -# PR... -# -# Only does approvals! A different GitHub Action takes care of merging. -name: Auto-approve Dependabot -on: - pull_request: - types: - - labeled - - opened - - ready_for_review - - reopened - - synchronize - - unlabeled - - unlocked -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: hmarr/auto-approve-action@7782c7e2bdf62b4d79bdcded8332808fd2f179cd - if: github.event.pull_request.user.login == 'dependabot[bot]' || github.event.pull_request.user.login == 'dependabot-preview[bot]' - with: - github-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/auto-approve.yml b/.github/workflows/auto-approve.yml new file mode 100644 index 0000000000000..81bd372dfb3ed --- /dev/null +++ b/.github/workflows/auto-approve.yml @@ -0,0 +1,17 @@ +# Approve PRs with "pr/auto-approve". mergify takes care of the actual merge. + +name: auto-approve +on: pull_request + +jobs: + auto-approve: + if: > + contains(github.event.pull_request.labels.*.name, 'pr/auto-approve') && + (github.event.pull_request.user.login == 'aws-cdk-automation' + || github.event.pull_request.user.login == 'dependabot[bot]' + || github.event.pull_request.user.login == 'dependabot-preview[bot]') + runs-on: ubuntu-latest + steps: + - uses: hmarr/auto-approve-action@v2.0.0 + with: + github-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/v2-pull-request.yml b/.github/workflows/v2-pull-request.yml index c4118d3298a00..e820647947705 100644 --- a/.github/workflows/v2-pull-request.yml +++ b/.github/workflows/v2-pull-request.yml @@ -32,15 +32,3 @@ jobs: uses: stefanzweifel/git-auto-commit-action@v4 with: commit_message: 'automatic pkglint fixes' - - # Approve automated PRs - # Only approve! mergify takes care of the actual merge. - auto-approve: - if: > - github.event.pull_request.user.login == 'aws-cdk-automation' - && contains(github.event.pull_request.labels.*.name, 'pr/auto-approve') - runs-on: ubuntu-latest - steps: - - uses: hmarr/auto-approve-action@v2.0.0 - with: - github-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/yarn-upgrade.yml b/.github/workflows/yarn-upgrade.yml index 6734719a67184..17617a75537d3 100644 --- a/.github/workflows/yarn-upgrade.yml +++ b/.github/workflows/yarn-upgrade.yml @@ -25,7 +25,7 @@ jobs: run: echo "::set-output name=dir::$(yarn cache dir)" - name: Restore Yarn cache - uses: actions/cache@v2 + uses: actions/cache@v2.1.4 with: path: ${{ steps.yarn-cache.outputs.dir }} key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} @@ -74,7 +74,7 @@ jobs: title: 'chore: npm-check-updates && yarn upgrade' body: |- Ran npm-check-updates and yarn upgrade to keep the `yarn.lock` file up-to-date. - labels: contribution/core,dependencies + labels: contribution/core,dependencies,pr/auto-approve team-reviewers: aws-cdk-team # Privileged token so automated PR validation happens token: ${{ secrets.AUTOMATION_GITHUB_TOKEN }} diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json index 6a9f04c284047..6b7a3f0e42086 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json @@ -400,7 +400,9 @@ "Type": "AWS::SQS::Queue", "Properties": { "MessageRetentionPeriod": 1209600 - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "nameserviceTaskRecordManagerEventsQueueF805A6C1": { "Type": "AWS::SQS::Queue", @@ -415,7 +417,9 @@ "maxReceiveCount": 500 }, "VisibilityTimeout": 30 - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "nameserviceTaskRecordManagerEventsQueuePolicy65CC6F9E": { "Type": "AWS::SQS::QueuePolicy", @@ -746,14 +750,12 @@ ] } }, - "Handler": "index.queue_handler", "Role": { "Fn::GetAtt": [ "nameserviceTaskRecordManagerEventHandlerServiceRoleE66EE52A", "Arn" ] }, - "Runtime": "python3.8", "Environment": { "Variables": { "HOSTED_ZONE_ID": { @@ -777,7 +779,9 @@ } } }, + "Handler": "index.queue_handler", "ReservedConcurrentExecutions": 1, + "Runtime": "python3.8", "Timeout": 30 }, "DependsOn": [ @@ -788,14 +792,14 @@ "nameserviceTaskRecordManagerEventHandlerSqsEventSourceawsecsintegnameserviceTaskRecordManagerEventsQueueC5EE9A869F1EB155": { "Type": "AWS::Lambda::EventSourceMapping", "Properties": { + "FunctionName": { + "Ref": "nameserviceTaskRecordManagerEventHandler4B8C6905" + }, "EventSourceArn": { "Fn::GetAtt": [ "nameserviceTaskRecordManagerEventsQueueF805A6C1", "Arn" ] - }, - "FunctionName": { - "Ref": "nameserviceTaskRecordManagerEventHandler4B8C6905" } } }, @@ -909,13 +913,13 @@ ] } }, - "Handler": "index.cleanup_resource_handler", "Role": { "Fn::GetAtt": [ "nameserviceTaskRecordManagerCleanupResourceProviderHandlerServiceRoleCCA462F0", "Arn" ] }, + "Handler": "index.cleanup_resource_handler", "Runtime": "python3.8", "Timeout": 300 }, @@ -1022,14 +1026,12 @@ ] } }, - "Handler": "framework.onEvent", "Role": { "Fn::GetAtt": [ "nameserviceTaskRecordManagerCleanupResourceProviderframeworkonEventServiceRoleF0570BD0", "Arn" ] }, - "Runtime": "nodejs10.x", "Description": "AWS CDK resource provider framework - onEvent (aws-ecs-integ/name-service/TaskRecordManager/CleanupResourceProvider)", "Environment": { "Variables": { @@ -1041,6 +1043,8 @@ } } }, + "Handler": "framework.onEvent", + "Runtime": "nodejs10.x", "Timeout": 900 }, "DependsOn": [ @@ -1242,13 +1246,13 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs12.x", "Timeout": 120 }, diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.imported-environment.expected.json b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.imported-environment.expected.json index 80156c0ed0d2d..dbc216370e40d 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.imported-environment.expected.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.imported-environment.expected.json @@ -49,7 +49,9 @@ ] ] } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "ServiceloadbalancerD5D60894": { "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", diff --git a/packages/@aws-cdk/aws-apigateway/README.md b/packages/@aws-cdk/aws-apigateway/README.md index 4d4d1a79eb797..759b013272bcf 100644 --- a/packages/@aws-cdk/aws-apigateway/README.md +++ b/packages/@aws-cdk/aws-apigateway/README.md @@ -163,7 +163,7 @@ The following example shows how to use an API Key with a usage plan: ```ts const hello = new lambda.Function(this, 'hello', { - runtime: lambda.Runtime.NODEJS_10_X, + runtime: lambda.Runtime.NODEJS_12_X, handler: 'hello.handler', code: lambda.Code.fromAsset('lambda') }); @@ -230,7 +230,7 @@ The following example shows how to use a rate limited api key : ```ts const hello = new lambda.Function(this, 'hello', { - runtime: lambda.Runtime.NODEJS_10_X, + runtime: lambda.Runtime.NODEJS_12_X, handler: 'hello.handler', code: lambda.Code.fromAsset('lambda') }); @@ -260,7 +260,7 @@ have to define your models and mappings for the request, response, and integrati ```ts const hello = new lambda.Function(this, 'hello', { - runtime: lambda.Runtime.NODEJS_10_X, + runtime: lambda.Runtime.NODEJS_12_X, handler: 'hello.handler', code: lambda.Code.fromAsset('lambda') }); diff --git a/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.cognito-authorizer.expected.json b/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.cognito-authorizer.expected.json index 990619cb495d4..ef5bfef19c2c3 100644 --- a/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.cognito-authorizer.expected.json +++ b/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.cognito-authorizer.expected.json @@ -27,7 +27,9 @@ "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } - } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" }, "myauthorizer23CB99DD": { "Type": "AWS::ApiGateway::Authorizer", diff --git a/packages/@aws-cdk/aws-apigateway/test/integ.restapi-import.lit.expected.json b/packages/@aws-cdk/aws-apigateway/test/integ.restapi-import.lit.expected.json index 349ae37ce27c8..54805c9f2e682 100644 --- a/packages/@aws-cdk/aws-apigateway/test/integ.restapi-import.lit.expected.json +++ b/packages/@aws-cdk/aws-apigateway/test/integ.restapi-import.lit.expected.json @@ -130,7 +130,9 @@ "Ref": "RestApi0C43BF4B" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "integrestapiimportBooksStackNestedStackintegrestapiimportBooksStackNestedStackResource395C2C9B": { "Type": "AWS::CloudFormation::Stack", @@ -192,7 +194,9 @@ "Ref": "RestApi0C43BF4B" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "integrestapiimportDeployStackNestedStackintegrestapiimportDeployStackNestedStackResource0D0EE737": { "Type": "AWS::CloudFormation::Stack", @@ -252,7 +256,9 @@ "DependsOn": [ "integrestapiimportBooksStackNestedStackintegrestapiimportBooksStackNestedStackResource395C2C9B", "integrestapiimportPetsStackNestedStackintegrestapiimportPetsStackNestedStackResource2B31898B" - ] + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.expected.json b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.expected.json index b53be9c1b9c27..17e2ae9976378 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.expected.json +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.expected.json @@ -157,7 +157,9 @@ "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } - } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" }, "userpoolmyclientFAD947AB": { "Type": "AWS::Cognito::UserPoolClient", diff --git a/packages/@aws-cdk/aws-appsync/README.md b/packages/@aws-cdk/aws-appsync/README.md index 1d217960b79ed..d15051d191a25 100644 --- a/packages/@aws-cdk/aws-appsync/README.md +++ b/packages/@aws-cdk/aws-appsync/README.md @@ -107,9 +107,13 @@ const secret = new rds.DatabaseSecret(stack, 'AuroraSecret', { username: 'clusteradmin', }); -// Create the DB cluster, provide all values needed to customise the database. -const cluster = new rds.DatabaseCluster(stack, 'AuroraCluster', { - engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_2_07_1 }), +// The VPC to place the cluster in +const vpc = new ec2.Vpc(stack, 'AuroraVpc'); + +// Create the serverless cluster, provide all values needed to customise the database. +const cluster = new rds.ServerlessCluster(stack, 'AuroraCluster', { + engine: rds.DatabaseClusterEngine.AURORA_MYSQL, + vpc, credentials: { username: 'clusteradmin' }, clusterIdentifier: 'db-endpoint-test', defaultDatabaseName: 'demos', diff --git a/packages/@aws-cdk/aws-appsync/lib/data-source.ts b/packages/@aws-cdk/aws-appsync/lib/data-source.ts index 00895965a23a3..ac22771916400 100644 --- a/packages/@aws-cdk/aws-appsync/lib/data-source.ts +++ b/packages/@aws-cdk/aws-appsync/lib/data-source.ts @@ -1,7 +1,7 @@ import { ITable } from '@aws-cdk/aws-dynamodb'; import { Grant, IGrantable, IPrincipal, IRole, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; import { IFunction } from '@aws-cdk/aws-lambda'; -import { IDatabaseCluster } from '@aws-cdk/aws-rds'; +import { IServerlessCluster } from '@aws-cdk/aws-rds'; import { ISecret } from '@aws-cdk/aws-secretsmanager'; import { IResolvable, Lazy, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; @@ -126,7 +126,11 @@ export abstract class BaseDataSource extends CoreConstruct { * creates a new resolver for this datasource and API using the given properties */ public createResolver(props: BaseResolverProps): Resolver { - return this.api.createResolver({ dataSource: this, ...props }); + return new Resolver(this, `${props.typeName}${props.fieldName}Resolver`, { + api: this.api, + dataSource: this, + ...props, + }); } /** @@ -299,9 +303,9 @@ export class LambdaDataSource extends BackedDataSource { */ export interface RdsDataSourceProps extends BackedDataSourceProps { /** - * The database cluster to call to interact with this data source + * The serverless cluster to call to interact with this data source */ - readonly databaseCluster: IDatabaseCluster; + readonly serverlessCluster: IServerlessCluster; /** * The secret containing the credentials for the database */ @@ -323,12 +327,12 @@ export class RdsDataSource extends BackedDataSource { type: 'RELATIONAL_DATABASE', relationalDatabaseConfig: { rdsHttpEndpointConfig: { - awsRegion: props.databaseCluster.stack.region, + awsRegion: props.serverlessCluster.stack.region, dbClusterIdentifier: Lazy.string({ produce: () => { return Stack.of(this).formatArn({ service: 'rds', - resource: `cluster:${props.databaseCluster.clusterIdentifier}`, + resource: `cluster:${props.serverlessCluster.clusterIdentifier}`, }); }, }), @@ -340,7 +344,7 @@ export class RdsDataSource extends BackedDataSource { }); const clusterArn = Stack.of(this).formatArn({ service: 'rds', - resource: `cluster:${props.databaseCluster.clusterIdentifier}`, + resource: `cluster:${props.serverlessCluster.clusterIdentifier}`, }); props.secretStore.grantRead(this); diff --git a/packages/@aws-cdk/aws-appsync/lib/graphqlapi-base.ts b/packages/@aws-cdk/aws-appsync/lib/graphqlapi-base.ts index 4e28e337fd1c5..060d57a34c276 100644 --- a/packages/@aws-cdk/aws-appsync/lib/graphqlapi-base.ts +++ b/packages/@aws-cdk/aws-appsync/lib/graphqlapi-base.ts @@ -1,6 +1,6 @@ import { ITable } from '@aws-cdk/aws-dynamodb'; import { IFunction } from '@aws-cdk/aws-lambda'; -import { IDatabaseCluster } from '@aws-cdk/aws-rds'; +import { IServerlessCluster } from '@aws-cdk/aws-rds'; import { ISecret } from '@aws-cdk/aws-secretsmanager'; import { CfnResource, IResource, Resource } from '@aws-cdk/core'; import { DynamoDbDataSource, HttpDataSource, LambdaDataSource, NoneDataSource, RdsDataSource, AwsIamConfig } from './data-source'; @@ -97,14 +97,14 @@ export interface IGraphqlApi extends IResource { * add a new Rds data source to this API * * @param id The data source's id - * @param databaseCluster The database cluster to interact with this data source - * @param secretStore The secret store that contains the username and password for the database cluster + * @param serverlessCluster The serverless cluster to interact with this data source + * @param secretStore The secret store that contains the username and password for the serverless cluster * @param databaseName The optional name of the database to use within the cluster * @param options The optional configuration for this data source */ addRdsDataSource( id: string, - databaseCluster: IDatabaseCluster, + serverlessCluster: IServerlessCluster, secretStore: ISecret, databaseName?: string, options?: DataSourceOptions @@ -206,14 +206,14 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi { /** * add a new Rds data source to this API * @param id The data source's id - * @param databaseCluster The database cluster to interact with this data source - * @param secretStore The secret store that contains the username and password for the database cluster + * @param serverlessCluster The serverless cluster to interact with this data source + * @param secretStore The secret store that contains the username and password for the serverless cluster * @param databaseName The optional name of the database to use within the cluster * @param options The optional configuration for this data source */ public addRdsDataSource( id: string, - databaseCluster: IDatabaseCluster, + serverlessCluster: IServerlessCluster, secretStore: ISecret, databaseName?: string, options?: DataSourceOptions, @@ -222,7 +222,7 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi { api: this, name: options?.name, description: options?.description, - databaseCluster, + serverlessCluster, secretStore, databaseName, }); diff --git a/packages/@aws-cdk/aws-appsync/test/appsync-rds.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync-rds.test.ts index 12c2f5d91cf8c..5a1b278dfc10f 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync-rds.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync-rds.test.ts @@ -1,7 +1,7 @@ import '@aws-cdk/assert/jest'; import * as path from 'path'; -import { Vpc, SecurityGroup, SubnetType, InstanceType, InstanceClass, InstanceSize } from '@aws-cdk/aws-ec2'; -import { DatabaseSecret, DatabaseCluster, DatabaseClusterEngine, AuroraMysqlEngineVersion } from '@aws-cdk/aws-rds'; +import { Vpc, SecurityGroup, SubnetType } from '@aws-cdk/aws-ec2'; +import { DatabaseSecret, DatabaseClusterEngine, AuroraMysqlEngineVersion, ServerlessCluster } from '@aws-cdk/aws-rds'; import * as cdk from '@aws-cdk/core'; import * as appsync from '../lib'; @@ -21,7 +21,7 @@ beforeEach(() => { describe('Rds Data Source configuration', () => { // GIVEN let secret: DatabaseSecret; - let cluster: DatabaseCluster; + let cluster: ServerlessCluster; beforeEach(() => { const vpc = new Vpc(stack, 'Vpc', { maxAzs: 2 }); const securityGroup = new SecurityGroup(stack, 'AuroraSecurityGroup', { @@ -31,16 +31,13 @@ describe('Rds Data Source configuration', () => { secret = new DatabaseSecret(stack, 'AuroraSecret', { username: 'clusteradmin', }); - cluster = new DatabaseCluster(stack, 'AuroraCluster', { + cluster = new ServerlessCluster(stack, 'AuroraCluster', { engine: DatabaseClusterEngine.auroraMysql({ version: AuroraMysqlEngineVersion.VER_2_07_1 }), credentials: { username: 'clusteradmin' }, clusterIdentifier: 'db-endpoint-test', - instanceProps: { - instanceType: InstanceType.of(InstanceClass.BURSTABLE2, InstanceSize.SMALL), - vpcSubnets: { subnetType: SubnetType.PRIVATE }, - vpc, - securityGroups: [securityGroup], - }, + vpc, + vpcSubnets: { subnetType: SubnetType.PRIVATE }, + securityGroups: [securityGroup], defaultDatabaseName: 'Animals', }); }); @@ -205,7 +202,7 @@ describe('Rds Data Source configuration', () => { describe('adding rds data source from imported api', () => { // GIVEN let secret: DatabaseSecret; - let cluster: DatabaseCluster; + let cluster: ServerlessCluster; beforeEach(() => { const vpc = new Vpc(stack, 'Vpc', { maxAzs: 2 }); const securityGroup = new SecurityGroup(stack, 'AuroraSecurityGroup', { @@ -215,16 +212,13 @@ describe('adding rds data source from imported api', () => { secret = new DatabaseSecret(stack, 'AuroraSecret', { username: 'clusteradmin', }); - cluster = new DatabaseCluster(stack, 'AuroraCluster', { + cluster = new ServerlessCluster(stack, 'AuroraCluster', { engine: DatabaseClusterEngine.auroraMysql({ version: AuroraMysqlEngineVersion.VER_2_07_1 }), credentials: { username: 'clusteradmin' }, clusterIdentifier: 'db-endpoint-test', - instanceProps: { - instanceType: InstanceType.of(InstanceClass.BURSTABLE2, InstanceSize.SMALL), - vpcSubnets: { subnetType: SubnetType.PRIVATE }, - vpc, - securityGroups: [securityGroup], - }, + vpc, + vpcSubnets: { subnetType: SubnetType.PRIVATE }, + securityGroups: [securityGroup], defaultDatabaseName: 'Animals', }); }); diff --git a/packages/@aws-cdk/aws-appsync/test/appsync.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync.test.ts index ca496e99afbff..f4ddfc3ba9da0 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync.test.ts @@ -55,8 +55,7 @@ test('appsync should error when creating pipeline resolver with data source', () // THEN expect(() => { - api.createResolver({ - dataSource: ds, + ds.createResolver({ typeName: 'test', fieldName: 'test2', pipelineConfig: [test1, test2], diff --git a/packages/@aws-cdk/aws-appsync/test/integ.api-import.expected.json b/packages/@aws-cdk/aws-appsync/test/integ.api-import.expected.json index 87f6776cc79d1..e4b54f04116fc 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.api-import.expected.json +++ b/packages/@aws-cdk/aws-appsync/test/integ.api-import.expected.json @@ -135,7 +135,7 @@ } } }, - "ApiQuerygetTestsResolver025B8E0A": { + "ApidsQuerygetTestsResolver952F49EE": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -152,7 +152,7 @@ "Apids0DB53FEA" ] }, - "ApiMutationaddTestResolver7A08AE91": { + "ApidsMutationaddTestResolverBCF0400B": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { diff --git a/packages/@aws-cdk/aws-appsync/test/integ.auth-apikey.expected.json b/packages/@aws-cdk/aws-appsync/test/integ.auth-apikey.expected.json index 390d55bd9bb38..2d1ef3f31504f 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.auth-apikey.expected.json +++ b/packages/@aws-cdk/aws-appsync/test/integ.auth-apikey.expected.json @@ -121,7 +121,7 @@ } } }, - "ApiQuerygetTestsResolver025B8E0A": { + "ApitestDataSourceQuerygetTestsResolverA3BBB672": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -142,7 +142,7 @@ "ApitestDataSource96AE54D5" ] }, - "ApiMutationaddTestResolver7A08AE91": { + "ApitestDataSourceMutationaddTestResolver36203D6B": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { diff --git a/packages/@aws-cdk/aws-appsync/test/integ.graphql-iam.expected.json b/packages/@aws-cdk/aws-appsync/test/integ.graphql-iam.expected.json index 4cd9043b28c4b..374a89dc33d14 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.graphql-iam.expected.json +++ b/packages/@aws-cdk/aws-appsync/test/integ.graphql-iam.expected.json @@ -28,7 +28,9 @@ "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } - } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" }, "ApiF70053CD": { "Type": "AWS::AppSync::GraphQLApi", @@ -150,7 +152,7 @@ } } }, - "ApiQuerygetTestResolver4C1F8B0C": { + "ApidsQuerygetTestResolverCCED7EC2": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -171,7 +173,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetTestsResolver025B8E0A": { + "ApidsQuerygetTestsResolver952F49EE": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -192,7 +194,7 @@ "ApiSchema510EECD7" ] }, - "ApiMutationaddTestResolver7A08AE91": { + "ApidsMutationaddTestResolverBCF0400B": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -400,14 +402,12 @@ ] } }, - "Handler": "iam-query.handler", "Role": { "Fn::GetAtt": [ "LambdaIAM687B49AF", "Arn" ] }, - "Runtime": "nodejs12.x", "Environment": { "Variables": { "APPSYNC_ENDPOINT": { @@ -417,7 +417,9 @@ ] } } - } + }, + "Handler": "iam-query.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "LambdaIAMDefaultPolicy96DEA124", @@ -496,14 +498,12 @@ ] } }, - "Handler": "iam-query.handler", "Role": { "Fn::GetAtt": [ "testFailServiceRole9FF22F85", "Arn" ] }, - "Runtime": "nodejs12.x", "Environment": { "Variables": { "APPSYNC_ENDPOINT": { @@ -513,7 +513,9 @@ ] } } - } + }, + "Handler": "iam-query.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "testFailServiceRole9FF22F85" diff --git a/packages/@aws-cdk/aws-appsync/test/integ.graphql.expected.json b/packages/@aws-cdk/aws-appsync/test/integ.graphql.expected.json index d540f3777ed00..6f9fd9c12d899 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.graphql.expected.json +++ b/packages/@aws-cdk/aws-appsync/test/integ.graphql.expected.json @@ -28,7 +28,9 @@ "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } - } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" }, "ApiF70053CD": { "Type": "AWS::AppSync::GraphQLApi", @@ -90,7 +92,7 @@ "Type": "NONE" } }, - "ApiQuerygetServiceVersionResolver269A74C1": { + "ApinoneQuerygetServiceVersionResolver336A3C2C": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -198,204 +200,7 @@ } } }, - "ApiorderDsServiceRoleCC2040C0": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "appsync.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - } - } - }, - "ApiorderDsServiceRoleDefaultPolicy3315FCF4": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "dynamodb:BatchGetItem", - "dynamodb:GetRecords", - "dynamodb:GetShardIterator", - "dynamodb:Query", - "dynamodb:GetItem", - "dynamodb:Scan", - "dynamodb:ConditionCheckItem", - "dynamodb:BatchWriteItem", - "dynamodb:PutItem", - "dynamodb:UpdateItem", - "dynamodb:DeleteItem" - ], - "Effect": "Allow", - "Resource": [ - { - "Fn::GetAtt": [ - "OrderTable416EB896", - "Arn" - ] - }, - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "OrderTable416EB896", - "Arn" - ] - }, - "/index/*" - ] - ] - } - ] - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "ApiorderDsServiceRoleDefaultPolicy3315FCF4", - "Roles": [ - { - "Ref": "ApiorderDsServiceRoleCC2040C0" - } - ] - } - }, - "ApiorderDsB50C8AAD": { - "Type": "AWS::AppSync::DataSource", - "Properties": { - "ApiId": { - "Fn::GetAtt": [ - "ApiF70053CD", - "ApiId" - ] - }, - "Name": "Order", - "Type": "AMAZON_DYNAMODB", - "DynamoDBConfig": { - "AwsRegion": { - "Ref": "AWS::Region" - }, - "TableName": { - "Ref": "OrderTable416EB896" - } - }, - "ServiceRoleArn": { - "Fn::GetAtt": [ - "ApiorderDsServiceRoleCC2040C0", - "Arn" - ] - } - } - }, - "ApipaymentDsServiceRole0DAC58D6": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "appsync.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - } - } - }, - "ApipaymentDsServiceRoleDefaultPolicy528E42B0": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "dynamodb:BatchGetItem", - "dynamodb:GetRecords", - "dynamodb:GetShardIterator", - "dynamodb:Query", - "dynamodb:GetItem", - "dynamodb:Scan", - "dynamodb:ConditionCheckItem", - "dynamodb:BatchWriteItem", - "dynamodb:PutItem", - "dynamodb:UpdateItem", - "dynamodb:DeleteItem" - ], - "Effect": "Allow", - "Resource": [ - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":dynamodb:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":table/PaymentTable" - ] - ] - }, - { - "Ref": "AWS::NoValue" - } - ] - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "ApipaymentDsServiceRoleDefaultPolicy528E42B0", - "Roles": [ - { - "Ref": "ApipaymentDsServiceRole0DAC58D6" - } - ] - } - }, - "ApipaymentDs95C7AC36": { - "Type": "AWS::AppSync::DataSource", - "Properties": { - "ApiId": { - "Fn::GetAtt": [ - "ApiF70053CD", - "ApiId" - ] - }, - "Name": "Payment", - "Type": "AMAZON_DYNAMODB", - "DynamoDBConfig": { - "AwsRegion": { - "Ref": "AWS::Region" - }, - "TableName": "PaymentTable" - }, - "ServiceRoleArn": { - "Fn::GetAtt": [ - "ApipaymentDsServiceRole0DAC58D6", - "Arn" - ] - } - } - }, - "ApiQuerygetCustomersResolver522EE433": { + "ApicustomerDsQuerygetCustomersResolverA74C8A2E": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -416,7 +221,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetCustomerResolver007520DC": { + "ApicustomerDsQuerygetCustomerResolver3649A130": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -437,7 +242,7 @@ "ApiSchema510EECD7" ] }, - "ApiMutationaddCustomerResolver53321A05": { + "ApicustomerDsMutationaddCustomerResolver4DE5B517": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -458,7 +263,7 @@ "ApiSchema510EECD7" ] }, - "ApiMutationsaveCustomerResolver85516C23": { + "ApicustomerDsMutationsaveCustomerResolver241DD231": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -479,7 +284,7 @@ "ApiSchema510EECD7" ] }, - "ApiMutationsaveCustomerWithFirstOrderResolver66DBDFD0": { + "ApicustomerDsMutationsaveCustomerWithFirstOrderResolver7DE2CBC8": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -500,7 +305,7 @@ "ApiSchema510EECD7" ] }, - "ApiMutationremoveCustomerResolver8435F803": { + "ApicustomerDsMutationremoveCustomerResolverAD3AE7F5": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -521,7 +326,105 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetCustomerOrdersEqResolver6DA88A11": { + "ApiorderDsServiceRoleCC2040C0": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "appsync.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "ApiorderDsServiceRoleDefaultPolicy3315FCF4": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "dynamodb:BatchGetItem", + "dynamodb:GetRecords", + "dynamodb:GetShardIterator", + "dynamodb:Query", + "dynamodb:GetItem", + "dynamodb:Scan", + "dynamodb:ConditionCheckItem", + "dynamodb:BatchWriteItem", + "dynamodb:PutItem", + "dynamodb:UpdateItem", + "dynamodb:DeleteItem" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "OrderTable416EB896", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "OrderTable416EB896", + "Arn" + ] + }, + "/index/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "ApiorderDsServiceRoleDefaultPolicy3315FCF4", + "Roles": [ + { + "Ref": "ApiorderDsServiceRoleCC2040C0" + } + ] + } + }, + "ApiorderDsB50C8AAD": { + "Type": "AWS::AppSync::DataSource", + "Properties": { + "ApiId": { + "Fn::GetAtt": [ + "ApiF70053CD", + "ApiId" + ] + }, + "Name": "Order", + "Type": "AMAZON_DYNAMODB", + "DynamoDBConfig": { + "AwsRegion": { + "Ref": "AWS::Region" + }, + "TableName": { + "Ref": "OrderTable416EB896" + } + }, + "ServiceRoleArn": { + "Fn::GetAtt": [ + "ApiorderDsServiceRoleCC2040C0", + "Arn" + ] + } + } + }, + "ApiorderDsQuerygetCustomerOrdersEqResolverEF9D5350": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -542,7 +445,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetOrderCustomersEqResolverA8612570": { + "ApiorderDsQuerygetOrderCustomersEqResolverE58570FF": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -563,7 +466,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetCustomerOrdersLtResolver284B37E8": { + "ApiorderDsQuerygetCustomerOrdersLtResolver909F3D8F": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -584,7 +487,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetOrderCustomersLtResolver618A88A9": { + "ApiorderDsQuerygetOrderCustomersLtResolver77468800": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -605,7 +508,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetCustomerOrdersLeResolverFB2A506A": { + "ApiorderDsQuerygetCustomerOrdersLeResolverF230A8BE": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -626,7 +529,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetOrderCustomersLeResolverFAA205B9": { + "ApiorderDsQuerygetOrderCustomersLeResolver836A0389": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -647,7 +550,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetCustomerOrdersGtResolver13F90EA5": { + "ApiorderDsQuerygetCustomerOrdersGtResolverF01F806B": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -668,7 +571,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetOrderCustomersGtResolver9487ECD9": { + "ApiorderDsQuerygetOrderCustomersGtResolver3197CCFE": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -689,7 +592,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetCustomerOrdersGeResolver2A181899": { + "ApiorderDsQuerygetCustomerOrdersGeResolver63CAD303": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -710,7 +613,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetOrderCustomersGeResolver8441E608": { + "ApiorderDsQuerygetOrderCustomersGeResolver0B78B0B4": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -731,7 +634,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetCustomerOrdersFilterResolver96245084": { + "ApiorderDsQuerygetCustomerOrdersFilterResolverCD2B8747": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -752,7 +655,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetCustomerOrdersBetweenResolver97B6D708": { + "ApiorderDsQuerygetCustomerOrdersBetweenResolver7DEE368E": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -773,7 +676,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetOrderCustomersFilterResolverF1015ABD": { + "ApiorderDsQuerygetOrderCustomersFilterResolver628CC68D": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -794,7 +697,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetOrderCustomersBetweenResolver92680CEC": { + "ApiorderDsQuerygetOrderCustomersBetweenResolver2048F3CB": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -815,7 +718,106 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetPaymentResolver29598AC3": { + "ApipaymentDsServiceRole0DAC58D6": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "appsync.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "ApipaymentDsServiceRoleDefaultPolicy528E42B0": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "dynamodb:BatchGetItem", + "dynamodb:GetRecords", + "dynamodb:GetShardIterator", + "dynamodb:Query", + "dynamodb:GetItem", + "dynamodb:Scan", + "dynamodb:ConditionCheckItem", + "dynamodb:BatchWriteItem", + "dynamodb:PutItem", + "dynamodb:UpdateItem", + "dynamodb:DeleteItem" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":dynamodb:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":table/PaymentTable" + ] + ] + }, + { + "Ref": "AWS::NoValue" + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "ApipaymentDsServiceRoleDefaultPolicy528E42B0", + "Roles": [ + { + "Ref": "ApipaymentDsServiceRole0DAC58D6" + } + ] + } + }, + "ApipaymentDs95C7AC36": { + "Type": "AWS::AppSync::DataSource", + "Properties": { + "ApiId": { + "Fn::GetAtt": [ + "ApiF70053CD", + "ApiId" + ] + }, + "Name": "Payment", + "Type": "AMAZON_DYNAMODB", + "DynamoDBConfig": { + "AwsRegion": { + "Ref": "AWS::Region" + }, + "TableName": "PaymentTable" + }, + "ServiceRoleArn": { + "Fn::GetAtt": [ + "ApipaymentDsServiceRole0DAC58D6", + "Arn" + ] + } + } + }, + "ApipaymentDsQuerygetPaymentResolverD172BFC9": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -836,7 +838,7 @@ "ApiSchema510EECD7" ] }, - "ApiMutationsavePaymentResolver03088E76": { + "ApipaymentDsMutationsavePaymentResolverE09FE5BB": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -896,7 +898,7 @@ } } }, - "ApiMutationdoPostOnAwsResolverEDACEA42": { + "ApidsMutationdoPostOnAwsResolver9583D8A3": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { diff --git a/packages/@aws-cdk/aws-backup/test/integ.backup.expected.json b/packages/@aws-cdk/aws-backup/test/integ.backup.expected.json index 2ba1356211377..1ad2aefc7c46e 100644 --- a/packages/@aws-cdk/aws-backup/test/integ.backup.expected.json +++ b/packages/@aws-cdk/aws-backup/test/integ.backup.expected.json @@ -24,7 +24,9 @@ "DeletionPolicy": "Delete" }, "FileSystem": { - "Type": "AWS::EFS::FileSystem" + "Type": "AWS::EFS::FileSystem", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "Vault23237E5B": { "Type": "AWS::Backup::BackupVault", diff --git a/packages/@aws-cdk/aws-backup/test/integ.backup.ts b/packages/@aws-cdk/aws-backup/test/integ.backup.ts index bf71de03a1cb8..e04d3ba68671a 100644 --- a/packages/@aws-cdk/aws-backup/test/integ.backup.ts +++ b/packages/@aws-cdk/aws-backup/test/integ.backup.ts @@ -16,7 +16,8 @@ class TestStack extends Stack { removalPolicy: RemovalPolicy.DESTROY, }); - new efs.CfnFileSystem(this, 'FileSystem'); + const fs = new efs.CfnFileSystem(this, 'FileSystem'); + fs.applyRemovalPolicy(RemovalPolicy.DESTROY); const vault = new backup.BackupVault(this, 'Vault', { removalPolicy: RemovalPolicy.DESTROY, diff --git a/packages/@aws-cdk/aws-backup/test/selection.test.ts b/packages/@aws-cdk/aws-backup/test/selection.test.ts index b5523b963c20e..d801efb34894c 100644 --- a/packages/@aws-cdk/aws-backup/test/selection.test.ts +++ b/packages/@aws-cdk/aws-backup/test/selection.test.ts @@ -2,7 +2,7 @@ import '@aws-cdk/assert/jest'; import * as dynamodb from '@aws-cdk/aws-dynamodb'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as efs from '@aws-cdk/aws-efs'; -import { Stack } from '@aws-cdk/core'; +import { RemovalPolicy, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { BackupPlan, BackupResource, BackupSelection } from '../lib'; @@ -128,7 +128,8 @@ test('fromConstruct', () => { class EfsConstruct extends CoreConstruct { constructor(scope: Construct, id: string) { super(scope, id); - new efs.CfnFileSystem(this, 'FileSystem'); + const fs = new efs.CfnFileSystem(this, 'FileSystem'); + fs.applyRemovalPolicy(RemovalPolicy.DESTROY); } } class MyConstruct extends CoreConstruct { diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stack.expected.json b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stack.expected.json index 8626fa9281ca5..d290134fa1cb6 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stack.expected.json +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stack.expected.json @@ -1,7 +1,9 @@ { "Resources": { "SubscriberQueueC193DC66": { - "Type": "AWS::SQS::Queue" + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "SubscriberQueuePolicy25A0799E": { "Type": "AWS::SQS::QueuePolicy", @@ -196,7 +198,9 @@ "Ref": "SubscriberQueueC193DC66" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "NestedStack2NestedStackNestedStack2NestedStackResourceFDF82E43": { "Type": "AWS::CloudFormation::Stack", @@ -250,7 +254,9 @@ "Parameters": { "TopicNamePrefix": "Prefix2" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Parameters": { diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-assets.expected.json b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-assets.expected.json index d18d72744be00..45b52a4c8016d 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-assets.expected.json +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-assets.expected.json @@ -17,7 +17,7 @@ }, "/", { - "Ref": "AssetParameters28e3582cfc7c551f42435f44110c499fb2c415fe0f02a02a77139cf43edd1145S3BucketFDBB032A" + "Ref": "AssetParameters7bd7ccfde94a4ad94f13971f10733ee01020eb6d7538b7a5c2b05966db2c0aabS3Bucket2E4E0318" }, "/", { @@ -27,7 +27,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters28e3582cfc7c551f42435f44110c499fb2c415fe0f02a02a77139cf43edd1145S3VersionKey58263016" + "Ref": "AssetParameters7bd7ccfde94a4ad94f13971f10733ee01020eb6d7538b7a5c2b05966db2c0aabS3VersionKeyF6AB1DF2" } ] } @@ -40,7 +40,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters28e3582cfc7c551f42435f44110c499fb2c415fe0f02a02a77139cf43edd1145S3VersionKey58263016" + "Ref": "AssetParameters7bd7ccfde94a4ad94f13971f10733ee01020eb6d7538b7a5c2b05966db2c0aabS3VersionKeyF6AB1DF2" } ] } @@ -50,40 +50,42 @@ ] }, "Parameters": { - "referencetonestedstacksassetsAssetParametersb13aad60258df1fbe5fb1312a7b2f8f25c03b3e07113782f7c12f00e023e148aS3BucketE2268D38Ref": { - "Ref": "AssetParametersb13aad60258df1fbe5fb1312a7b2f8f25c03b3e07113782f7c12f00e023e148aS3BucketC5E2D427" + "referencetonestedstacksassetsAssetParametersbbe209afddb09a12327bab7a105e085758a29b769b5b4bf5b6320ac41b05fc51S3BucketFE27EEBCRef": { + "Ref": "AssetParametersbbe209afddb09a12327bab7a105e085758a29b769b5b4bf5b6320ac41b05fc51S3Bucket8C5997AB" }, - "referencetonestedstacksassetsAssetParametersb13aad60258df1fbe5fb1312a7b2f8f25c03b3e07113782f7c12f00e023e148aS3VersionKeyD31C6796Ref": { - "Ref": "AssetParametersb13aad60258df1fbe5fb1312a7b2f8f25c03b3e07113782f7c12f00e023e148aS3VersionKey31422F11" + "referencetonestedstacksassetsAssetParametersbbe209afddb09a12327bab7a105e085758a29b769b5b4bf5b6320ac41b05fc51S3VersionKey24D35F02Ref": { + "Ref": "AssetParametersbbe209afddb09a12327bab7a105e085758a29b769b5b4bf5b6320ac41b05fc51S3VersionKey81BEC7FB" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Parameters": { - "AssetParametersb13aad60258df1fbe5fb1312a7b2f8f25c03b3e07113782f7c12f00e023e148aS3BucketC5E2D427": { + "AssetParametersbbe209afddb09a12327bab7a105e085758a29b769b5b4bf5b6320ac41b05fc51S3Bucket8C5997AB": { "Type": "String", - "Description": "S3 bucket for asset \"b13aad60258df1fbe5fb1312a7b2f8f25c03b3e07113782f7c12f00e023e148a\"" + "Description": "S3 bucket for asset \"bbe209afddb09a12327bab7a105e085758a29b769b5b4bf5b6320ac41b05fc51\"" }, - "AssetParametersb13aad60258df1fbe5fb1312a7b2f8f25c03b3e07113782f7c12f00e023e148aS3VersionKey31422F11": { + "AssetParametersbbe209afddb09a12327bab7a105e085758a29b769b5b4bf5b6320ac41b05fc51S3VersionKey81BEC7FB": { "Type": "String", - "Description": "S3 key for asset version \"b13aad60258df1fbe5fb1312a7b2f8f25c03b3e07113782f7c12f00e023e148a\"" + "Description": "S3 key for asset version \"bbe209afddb09a12327bab7a105e085758a29b769b5b4bf5b6320ac41b05fc51\"" }, - "AssetParametersb13aad60258df1fbe5fb1312a7b2f8f25c03b3e07113782f7c12f00e023e148aArtifactHash2897446E": { + "AssetParametersbbe209afddb09a12327bab7a105e085758a29b769b5b4bf5b6320ac41b05fc51ArtifactHashB77349F4": { "Type": "String", - "Description": "Artifact hash for asset \"b13aad60258df1fbe5fb1312a7b2f8f25c03b3e07113782f7c12f00e023e148a\"" + "Description": "Artifact hash for asset \"bbe209afddb09a12327bab7a105e085758a29b769b5b4bf5b6320ac41b05fc51\"" }, - "AssetParameters28e3582cfc7c551f42435f44110c499fb2c415fe0f02a02a77139cf43edd1145S3BucketFDBB032A": { + "AssetParameters7bd7ccfde94a4ad94f13971f10733ee01020eb6d7538b7a5c2b05966db2c0aabS3Bucket2E4E0318": { "Type": "String", - "Description": "S3 bucket for asset \"28e3582cfc7c551f42435f44110c499fb2c415fe0f02a02a77139cf43edd1145\"" + "Description": "S3 bucket for asset \"7bd7ccfde94a4ad94f13971f10733ee01020eb6d7538b7a5c2b05966db2c0aab\"" }, - "AssetParameters28e3582cfc7c551f42435f44110c499fb2c415fe0f02a02a77139cf43edd1145S3VersionKey58263016": { + "AssetParameters7bd7ccfde94a4ad94f13971f10733ee01020eb6d7538b7a5c2b05966db2c0aabS3VersionKeyF6AB1DF2": { "Type": "String", - "Description": "S3 key for asset version \"28e3582cfc7c551f42435f44110c499fb2c415fe0f02a02a77139cf43edd1145\"" + "Description": "S3 key for asset version \"7bd7ccfde94a4ad94f13971f10733ee01020eb6d7538b7a5c2b05966db2c0aab\"" }, - "AssetParameters28e3582cfc7c551f42435f44110c499fb2c415fe0f02a02a77139cf43edd1145ArtifactHash592B4471": { + "AssetParameters7bd7ccfde94a4ad94f13971f10733ee01020eb6d7538b7a5c2b05966db2c0aabArtifactHash63670210": { "Type": "String", - "Description": "Artifact hash for asset \"28e3582cfc7c551f42435f44110c499fb2c415fe0f02a02a77139cf43edd1145\"" + "Description": "Artifact hash for asset \"7bd7ccfde94a4ad94f13971f10733ee01020eb6d7538b7a5c2b05966db2c0aab\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-multi-refs.expected.json b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-multi-refs.expected.json index bc546994b8e41..8e1abf0743734 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-multi-refs.expected.json +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-multi-refs.expected.json @@ -20,7 +20,7 @@ }, "/", { - "Ref": "AssetParametersad23da1cfc8b3fd7916c6ffc7debacadf084765e62fab8acf0b8b0a9b0289f95S3BucketDB605F9E" + "Ref": "AssetParameters2fa66e9dea71b1e05ebeed281df124cbaca34247ae93c767a533b6346cc17703S3BucketD17502DC" }, "/", { @@ -30,7 +30,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersad23da1cfc8b3fd7916c6ffc7debacadf084765e62fab8acf0b8b0a9b0289f95S3VersionKey26685906" + "Ref": "AssetParameters2fa66e9dea71b1e05ebeed281df124cbaca34247ae93c767a533b6346cc17703S3VersionKeyA042251F" } ] } @@ -43,7 +43,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersad23da1cfc8b3fd7916c6ffc7debacadf084765e62fab8acf0b8b0a9b0289f95S3VersionKey26685906" + "Ref": "AssetParameters2fa66e9dea71b1e05ebeed281df124cbaca34247ae93c767a533b6346cc17703S3VersionKeyA042251F" } ] } @@ -65,14 +65,16 @@ "referencetonestedstacksmultirefsAssetParameters495a6bc36c13a0adeb3778c921d18ac4a8205f5471108fcc199a291d14855c3aS3VersionKey5F9CF809Ref": { "Ref": "AssetParameters495a6bc36c13a0adeb3778c921d18ac4a8205f5471108fcc199a291d14855c3aS3VersionKey2CCE0573" }, - "referencetonestedstacksmultirefsAssetParameterscc623add53df153cf6a7df1cea4dc90740d7be087472579110754a633ec90847S3Bucket8F1E17B9Ref": { - "Ref": "AssetParameterscc623add53df153cf6a7df1cea4dc90740d7be087472579110754a633ec90847S3Bucket9A14AA6D" + "referencetonestedstacksmultirefsAssetParametersc2fbfb6df004b51bb870bd1f5cabda73830a59765a6c766aca0e906ec1e22441S3Bucket119ED767Ref": { + "Ref": "AssetParametersc2fbfb6df004b51bb870bd1f5cabda73830a59765a6c766aca0e906ec1e22441S3BucketAF9A3A0F" }, - "referencetonestedstacksmultirefsAssetParameterscc623add53df153cf6a7df1cea4dc90740d7be087472579110754a633ec90847S3VersionKey9EEEF950Ref": { - "Ref": "AssetParameterscc623add53df153cf6a7df1cea4dc90740d7be087472579110754a633ec90847S3VersionKeyF124C0D9" + "referencetonestedstacksmultirefsAssetParametersc2fbfb6df004b51bb870bd1f5cabda73830a59765a6c766aca0e906ec1e22441S3VersionKeyDCF85FE2Ref": { + "Ref": "AssetParametersc2fbfb6df004b51bb870bd1f5cabda73830a59765a6c766aca0e906ec1e22441S3VersionKey2F85340C" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Parameters": { @@ -88,29 +90,29 @@ "Type": "String", "Description": "Artifact hash for asset \"495a6bc36c13a0adeb3778c921d18ac4a8205f5471108fcc199a291d14855c3a\"" }, - "AssetParameterscc623add53df153cf6a7df1cea4dc90740d7be087472579110754a633ec90847S3Bucket9A14AA6D": { + "AssetParametersc2fbfb6df004b51bb870bd1f5cabda73830a59765a6c766aca0e906ec1e22441S3BucketAF9A3A0F": { "Type": "String", - "Description": "S3 bucket for asset \"cc623add53df153cf6a7df1cea4dc90740d7be087472579110754a633ec90847\"" + "Description": "S3 bucket for asset \"c2fbfb6df004b51bb870bd1f5cabda73830a59765a6c766aca0e906ec1e22441\"" }, - "AssetParameterscc623add53df153cf6a7df1cea4dc90740d7be087472579110754a633ec90847S3VersionKeyF124C0D9": { + "AssetParametersc2fbfb6df004b51bb870bd1f5cabda73830a59765a6c766aca0e906ec1e22441S3VersionKey2F85340C": { "Type": "String", - "Description": "S3 key for asset version \"cc623add53df153cf6a7df1cea4dc90740d7be087472579110754a633ec90847\"" + "Description": "S3 key for asset version \"c2fbfb6df004b51bb870bd1f5cabda73830a59765a6c766aca0e906ec1e22441\"" }, - "AssetParameterscc623add53df153cf6a7df1cea4dc90740d7be087472579110754a633ec90847ArtifactHashAF64C405": { + "AssetParametersc2fbfb6df004b51bb870bd1f5cabda73830a59765a6c766aca0e906ec1e22441ArtifactHash5D93ED07": { "Type": "String", - "Description": "Artifact hash for asset \"cc623add53df153cf6a7df1cea4dc90740d7be087472579110754a633ec90847\"" + "Description": "Artifact hash for asset \"c2fbfb6df004b51bb870bd1f5cabda73830a59765a6c766aca0e906ec1e22441\"" }, - "AssetParametersad23da1cfc8b3fd7916c6ffc7debacadf084765e62fab8acf0b8b0a9b0289f95S3BucketDB605F9E": { + "AssetParameters2fa66e9dea71b1e05ebeed281df124cbaca34247ae93c767a533b6346cc17703S3BucketD17502DC": { "Type": "String", - "Description": "S3 bucket for asset \"ad23da1cfc8b3fd7916c6ffc7debacadf084765e62fab8acf0b8b0a9b0289f95\"" + "Description": "S3 bucket for asset \"2fa66e9dea71b1e05ebeed281df124cbaca34247ae93c767a533b6346cc17703\"" }, - "AssetParametersad23da1cfc8b3fd7916c6ffc7debacadf084765e62fab8acf0b8b0a9b0289f95S3VersionKey26685906": { + "AssetParameters2fa66e9dea71b1e05ebeed281df124cbaca34247ae93c767a533b6346cc17703S3VersionKeyA042251F": { "Type": "String", - "Description": "S3 key for asset version \"ad23da1cfc8b3fd7916c6ffc7debacadf084765e62fab8acf0b8b0a9b0289f95\"" + "Description": "S3 key for asset version \"2fa66e9dea71b1e05ebeed281df124cbaca34247ae93c767a533b6346cc17703\"" }, - "AssetParametersad23da1cfc8b3fd7916c6ffc7debacadf084765e62fab8acf0b8b0a9b0289f95ArtifactHashAF8D54FC": { + "AssetParameters2fa66e9dea71b1e05ebeed281df124cbaca34247ae93c767a533b6346cc17703ArtifactHash8853E261": { "Type": "String", - "Description": "Artifact hash for asset \"ad23da1cfc8b3fd7916c6ffc7debacadf084765e62fab8acf0b8b0a9b0289f95\"" + "Description": "Artifact hash for asset \"2fa66e9dea71b1e05ebeed281df124cbaca34247ae93c767a533b6346cc17703\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-multi.expected.json b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-multi.expected.json index 6a10c9252c79a..0145629ff176e 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-multi.expected.json +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-multi.expected.json @@ -17,7 +17,7 @@ }, "/", { - "Ref": "AssetParametersf94d2259295147a175eeb7f8b31856e4beb5d4d4654f0bf956ee51d5e2ee5d8eS3Bucket0211CC54" + "Ref": "AssetParameters686794a6d724e01e517bba15106edebf9db8d4bb309f0c60d5ff55a11db4a856S3BucketDF3BC15F" }, "/", { @@ -27,7 +27,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersf94d2259295147a175eeb7f8b31856e4beb5d4d4654f0bf956ee51d5e2ee5d8eS3VersionKey5D85E7DD" + "Ref": "AssetParameters686794a6d724e01e517bba15106edebf9db8d4bb309f0c60d5ff55a11db4a856S3VersionKey1BCA0E57" } ] } @@ -40,7 +40,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersf94d2259295147a175eeb7f8b31856e4beb5d4d4654f0bf956ee51d5e2ee5d8eS3VersionKey5D85E7DD" + "Ref": "AssetParameters686794a6d724e01e517bba15106edebf9db8d4bb309f0c60d5ff55a11db4a856S3VersionKey1BCA0E57" } ] } @@ -57,7 +57,9 @@ "Ref": "AssetParameterse3410ccec04414535f1c8035ce0ea42f59eedf66d0e6d0eec8bc435c4a4e809dS3VersionKey8C8E79CA" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Parameters": { @@ -73,17 +75,17 @@ "Type": "String", "Description": "Artifact hash for asset \"e3410ccec04414535f1c8035ce0ea42f59eedf66d0e6d0eec8bc435c4a4e809d\"" }, - "AssetParametersf94d2259295147a175eeb7f8b31856e4beb5d4d4654f0bf956ee51d5e2ee5d8eS3Bucket0211CC54": { + "AssetParameters686794a6d724e01e517bba15106edebf9db8d4bb309f0c60d5ff55a11db4a856S3BucketDF3BC15F": { "Type": "String", - "Description": "S3 bucket for asset \"f94d2259295147a175eeb7f8b31856e4beb5d4d4654f0bf956ee51d5e2ee5d8e\"" + "Description": "S3 bucket for asset \"686794a6d724e01e517bba15106edebf9db8d4bb309f0c60d5ff55a11db4a856\"" }, - "AssetParametersf94d2259295147a175eeb7f8b31856e4beb5d4d4654f0bf956ee51d5e2ee5d8eS3VersionKey5D85E7DD": { + "AssetParameters686794a6d724e01e517bba15106edebf9db8d4bb309f0c60d5ff55a11db4a856S3VersionKey1BCA0E57": { "Type": "String", - "Description": "S3 key for asset version \"f94d2259295147a175eeb7f8b31856e4beb5d4d4654f0bf956ee51d5e2ee5d8e\"" + "Description": "S3 key for asset version \"686794a6d724e01e517bba15106edebf9db8d4bb309f0c60d5ff55a11db4a856\"" }, - "AssetParametersf94d2259295147a175eeb7f8b31856e4beb5d4d4654f0bf956ee51d5e2ee5d8eArtifactHashD0519824": { + "AssetParameters686794a6d724e01e517bba15106edebf9db8d4bb309f0c60d5ff55a11db4a856ArtifactHash9043932C": { "Type": "String", - "Description": "Artifact hash for asset \"f94d2259295147a175eeb7f8b31856e4beb5d4d4654f0bf956ee51d5e2ee5d8e\"" + "Description": "Artifact hash for asset \"686794a6d724e01e517bba15106edebf9db8d4bb309f0c60d5ff55a11db4a856\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-nested-export-to-sibling.expected.json b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-nested-export-to-sibling.expected.json index 3cac1b07eb420..115a1f9130ae3 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-nested-export-to-sibling.expected.json +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-nested-export-to-sibling.expected.json @@ -50,7 +50,9 @@ ] ] } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs1.expected.json b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs1.expected.json index cf2e508a0f8eb..299d5005eff0f 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs1.expected.json +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs1.expected.json @@ -70,7 +70,9 @@ ] ] } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Parameters": { diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs2.expected.json b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs2.expected.json index ee7be9113bdcb..c6e818da02313 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs2.expected.json +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs2.expected.json @@ -50,7 +50,9 @@ ] ] } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs3.expected.json b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs3.expected.json index 80a2f7712026c..2ef738be2c023 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs3.expected.json +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs3.expected.json @@ -49,7 +49,9 @@ ] ] } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "Nested2NestedStackNested2NestedStackResource877A1112": { "Type": "AWS::CloudFormation::Stack", @@ -108,7 +110,9 @@ ] } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Parameters": { diff --git a/packages/@aws-cdk/aws-cloudformation/test/test.nested-stack.ts b/packages/@aws-cdk/aws-cloudformation/test/test.nested-stack.ts index 64656faf0fca3..2149c48be5fd3 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/test.nested-stack.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/test.nested-stack.ts @@ -130,6 +130,8 @@ export = { Resources: { nestedstackNestedStacknestedstackNestedStackResource71CDD241: { Type: 'AWS::CloudFormation::Stack', + DeletionPolicy: 'Delete', + UpdateReplacePolicy: 'Delete', Properties: { TemplateURL: { 'Fn::Join': [ @@ -718,7 +720,10 @@ export = { }, }); - const middleStackHash = 'b2670b4c0c3fdf1d8fd9b9272bb8bf8173d18c0f67a888ba165cc569a248a84f'; + const middleStackHash = '7c426f7299a739900279ac1ece040397c1913cdf786f5228677b289f4d5e4c48'; + const bucketSuffix = 'C706B101'; + const versionSuffix = '4B193AA5'; + const hashSuffix = 'E28F0693'; // nested1 wires the nested2 template through parameters, so we expect those expect(nested1).to(haveResource('Resource::1')); @@ -735,9 +740,9 @@ export = { AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3BucketDE3B88D6: { Type: 'String', Description: 'S3 bucket for asset "8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235c"' }, AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3VersionKey3A62EFEA: { Type: 'String', Description: 'S3 key for asset version "8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235c"' }, AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cArtifactHash7DC546E0: { Type: 'String', Description: 'Artifact hash for asset "8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235c"' }, - [`AssetParameters${middleStackHash}S3Bucket3DB431CB`]: { Type: 'String', Description: `S3 bucket for asset "${middleStackHash}"` }, - [`AssetParameters${middleStackHash}S3VersionKeyBFFDABE9`]: { Type: 'String', Description: `S3 key for asset version "${middleStackHash}"` }, - [`AssetParameters${middleStackHash}ArtifactHash8EA52875`]: { Type: 'String', Description: `Artifact hash for asset "${middleStackHash}"` }, + [`AssetParameters${middleStackHash}S3Bucket${bucketSuffix}`]: { Type: 'String', Description: `S3 bucket for asset "${middleStackHash}"` }, + [`AssetParameters${middleStackHash}S3VersionKey${versionSuffix}`]: { Type: 'String', Description: `S3 key for asset version "${middleStackHash}"` }, + [`AssetParameters${middleStackHash}ArtifactHash${hashSuffix}`]: { Type: 'String', Description: `Artifact hash for asset "${middleStackHash}"` }, }); // proxy asset params to nested stack diff --git a/packages/@aws-cdk/aws-cloudfront/README.md b/packages/@aws-cdk/aws-cloudfront/README.md index 34b0922913c4c..debc3b09d734f 100644 --- a/packages/@aws-cdk/aws-cloudfront/README.md +++ b/packages/@aws-cdk/aws-cloudfront/README.md @@ -282,7 +282,7 @@ The following shows a Lambda@Edge function added to the default behavior and tri ```ts const myFunc = new cloudfront.experimental.EdgeFunction(this, 'MyFunction', { - runtime: lambda.Runtime.NODEJS_10_X, + runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), }); @@ -310,7 +310,7 @@ If the stack is in `us-east-1`, a "normal" `lambda.Function` can be used instead ```ts const myFunc = new lambda.Function(this, 'MyFunction', { - runtime: lambda.Runtime.NODEJS_10_X, + runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), }); @@ -321,14 +321,14 @@ you can also set a specific stack ID for each Lambda@Edge. ```ts const myFunc1 = new cloudfront.experimental.EdgeFunction(this, 'MyFunction1', { - runtime: lambda.Runtime.NODEJS_10_X, + runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler1')), stackId: 'edge-lambda-stack-id-1' }); const myFunc2 = new cloudfront.experimental.EdgeFunction(this, 'MyFunction2', { - runtime: lambda.Runtime.NODEJS_10_X, + runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler2')), stackId: 'edge-lambda-stack-id-2' diff --git a/packages/@aws-cdk/aws-cloudtrail/README.md b/packages/@aws-cdk/aws-cloudtrail/README.md index 2e4f38576b540..3deccd47545ea 100644 --- a/packages/@aws-cdk/aws-cloudtrail/README.md +++ b/packages/@aws-cdk/aws-cloudtrail/README.md @@ -175,7 +175,7 @@ configures logging of Lambda data events for a specific Function. ```ts const trail = new cloudtrail.Trail(this, 'MyAmazingCloudTrail'); const amazingFunction = new lambda.Function(stack, 'AnAmazingFunction', { - runtime: lambda.Runtime.NODEJS_10_X, + runtime: lambda.Runtime.NODEJS_12_X, handler: "hello.handler", code: lambda.Code.fromAsset("lambda"), }); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/.gitignore b/packages/@aws-cdk/aws-codepipeline-actions/.gitignore index 0f4bf01dd552c..9f6a9219fad75 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/.gitignore +++ b/packages/@aws-cdk/aws-codepipeline-actions/.gitignore @@ -16,4 +16,5 @@ nyc.config.js *.snk !.eslintrc.js -junit.xml \ No newline at end of file +junit.xml +!jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/.npmignore b/packages/@aws-cdk/aws-codepipeline-actions/.npmignore index a94c531529866..9e88226921c33 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/.npmignore +++ b/packages/@aws-cdk/aws-codepipeline-actions/.npmignore @@ -23,4 +23,5 @@ tsconfig.json # exclude cdk artifacts **/cdk.out junit.xml -test/ \ No newline at end of file +test/ +jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/README.md b/packages/@aws-cdk/aws-codepipeline-actions/README.md index cdc6cf1028ce3..b5aa1f5b502be 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/README.md +++ b/packages/@aws-cdk/aws-codepipeline-actions/README.md @@ -629,7 +629,7 @@ const lambdaCode = lambda.Code.fromCfnParameters(); const func = new lambda.Function(lambdaStack, 'Lambda', { code: lambdaCode, handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, + runtime: lambda.Runtime.NODEJS_12_X, }); // used to make sure each CDK synthesis produces a different Version const version = func.addVersion('NewVersion'); @@ -921,7 +921,7 @@ import * as lambda from '@aws-cdk/aws-lambda'; const lambdaInvokeAction = new codepipeline_actions.LambdaInvokeAction({ actionName: 'Lambda', lambda: new lambda.Function(this, 'Func', { - runtime: lambda.Runtime.NODEJS_10_X, + runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', code: lambda.Code.fromInline(` const AWS = require('aws-sdk'); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/jest.config.js b/packages/@aws-cdk/aws-codepipeline-actions/jest.config.js new file mode 100644 index 0000000000000..54e28beb9798b --- /dev/null +++ b/packages/@aws-cdk/aws-codepipeline-actions/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codepipeline-actions/package.json b/packages/@aws-cdk/aws-codepipeline-actions/package.json index 76381cfdbbb47..6087beb2745df 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/package.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/package.json @@ -69,11 +69,10 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-cloudtrail": "0.0.0", "@types/lodash": "^4.14.168", - "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "lodash": "^4.17.21", - "nodeunit": "^0.11.3", + "nodeunit-shim": "0.0.0", "pkglint": "0.0.0" }, "dependencies": { @@ -177,6 +176,7 @@ }, "maturity": "stable", "cdk-build": { + "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/bitbucket/test.bitbucket-source-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/bitbucket/bitbucket-source-action.test.ts similarity index 97% rename from packages/@aws-cdk/aws-codepipeline-actions/test/bitbucket/test.bitbucket-source-action.ts rename to packages/@aws-cdk/aws-codepipeline-actions/test/bitbucket/bitbucket-source-action.test.ts index a4f120f2abf68..942811b94b2fd 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/bitbucket/test.bitbucket-source-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/bitbucket/bitbucket-source-action.test.ts @@ -2,12 +2,12 @@ import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import { Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as cpactions from '../../lib'; /* eslint-disable quote-props */ -export = { +nodeunitShim({ 'BitBucket source Action': { 'produces the correct configuration when added to a pipeline'(test: Test) { const stack = new Stack(); @@ -82,7 +82,7 @@ export = { test.done(); }, -}; +}); function createBitBucketAndCodeBuildPipeline(stack: Stack, props: { codeBuildCloneOutput: boolean }): void { const sourceOutput = new codepipeline.Artifact(); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test.cloudformation-pipeline-actions.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/cloudformation-pipeline-actions.test.ts similarity index 99% rename from packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test.cloudformation-pipeline-actions.ts rename to packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/cloudformation-pipeline-actions.test.ts index 22bf46a15a641..28a22d970a1c0 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test.cloudformation-pipeline-actions.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/cloudformation-pipeline-actions.test.ts @@ -5,12 +5,12 @@ import * as codecommit from '@aws-cdk/aws-codecommit'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import { PolicyStatement, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as cpactions from '../../lib'; /* eslint-disable quote-props */ -export = { +nodeunitShim({ 'CreateChangeSetAction can be used to make a change set from a CodePipeline'(test: Test) { const stack = new cdk.Stack(); @@ -712,7 +712,7 @@ export = { test.done(); }, }, -}; +}); /** * A test stack with a half-prepared pipeline ready to add CloudFormation actions to diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test.pipeline-actions.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/pipeline-actions.test.ts similarity index 97% rename from packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test.pipeline-actions.ts rename to packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/pipeline-actions.test.ts index 66e23dcfe0584..1433ffc6e2860 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test.pipeline-actions.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/pipeline-actions.test.ts @@ -5,12 +5,12 @@ import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import * as constructs from 'constructs'; import * as _ from 'lodash'; -import * as nodeunit from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as cpactions from '../../lib'; -export = nodeunit.testCase({ +nodeunitShim({ CreateReplaceChangeSet: { - 'works'(test: nodeunit.Test) { + 'works'(test: Test) { const app = new cdk.App(); const stack = new cdk.Stack(app, 'Stack'); const pipelineRole = new RoleDouble(stack, 'PipelineRole'); @@ -51,7 +51,7 @@ export = nodeunit.testCase({ test.done(); }, - 'uses a single permission statement if the same ChangeSet name is used'(test: nodeunit.Test) { + 'uses a single permission statement if the same ChangeSet name is used'(test: Test) { const stack = new cdk.Stack(); const pipelineRole = new RoleDouble(stack, 'PipelineRole'); const artifact = new codepipeline.Artifact('TestArtifact'); @@ -110,7 +110,7 @@ export = nodeunit.testCase({ }, ExecuteChangeSet: { - 'works'(test: nodeunit.Test) { + 'works'(test: Test) { const stack = new cdk.Stack(); const pipelineRole = new RoleDouble(stack, 'PipelineRole'); const stage = new StageDouble({ @@ -137,7 +137,7 @@ export = nodeunit.testCase({ test.done(); }, - 'uses a single permission statement if the same ChangeSet name is used'(test: nodeunit.Test) { + 'uses a single permission statement if the same ChangeSet name is used'(test: Test) { const stack = new cdk.Stack(); const pipelineRole = new RoleDouble(stack, 'PipelineRole'); new StageDouble({ @@ -181,7 +181,7 @@ export = nodeunit.testCase({ }, }, - 'the CreateUpdateStack Action sets the DescribeStack*, Create/Update/DeleteStack & PassRole permissions'(test: nodeunit.Test) { + 'the CreateUpdateStack Action sets the DescribeStack*, Create/Update/DeleteStack & PassRole permissions'(test: Test) { const stack = new cdk.Stack(); const pipelineRole = new RoleDouble(stack, 'PipelineRole'); const action = new cpactions.CloudFormationCreateUpdateStackAction({ @@ -207,7 +207,7 @@ export = nodeunit.testCase({ test.done(); }, - 'the DeleteStack Action sets the DescribeStack*, DeleteStack & PassRole permissions'(test: nodeunit.Test) { + 'the DeleteStack Action sets the DescribeStack*, DeleteStack & PassRole permissions'(test: Test) { const stack = new cdk.Stack(); const pipelineRole = new RoleDouble(stack, 'PipelineRole'); const action = new cpactions.CloudFormationDeleteStackAction({ @@ -238,7 +238,7 @@ interface PolicyStatementJson { } function _assertActionMatches( - test: nodeunit.Test, + test: Test, stack: cdk.Stack, actions: FullAction[], provider: string, @@ -279,7 +279,7 @@ function _hasAction( } function _assertPermissionGranted( - test: nodeunit.Test, + test: Test, stack: cdk.Stack, statements: iam.PolicyStatement[], action: string, diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/codebuild/test.codebuild-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/codebuild/codebuild-action.test.ts similarity index 99% rename from packages/@aws-cdk/aws-codepipeline-actions/test/codebuild/test.codebuild-action.ts rename to packages/@aws-cdk/aws-codepipeline-actions/test/codebuild/codebuild-action.test.ts index 68e5acaa849ca..a451aa51dcc42 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/codebuild/test.codebuild-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/codebuild/codebuild-action.test.ts @@ -5,12 +5,12 @@ import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as s3 from '@aws-cdk/aws-s3'; import * as sns from '@aws-cdk/aws-sns'; import { App, SecretValue, Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as cpactions from '../../lib'; /* eslint-disable quote-props */ -export = { +nodeunitShim({ 'CodeBuild action': { 'that is cross-account and has outputs': { 'causes an error'(test: Test) { @@ -337,4 +337,4 @@ export = { }, }, }, -}; +}); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/codecommit/test.codecommit-source-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/codecommit/codecommit-source-action.test.ts similarity index 99% rename from packages/@aws-cdk/aws-codepipeline-actions/test/codecommit/test.codecommit-source-action.ts rename to packages/@aws-cdk/aws-codepipeline-actions/test/codecommit/codecommit-source-action.test.ts index 3dc5b1c739d4e..c3e2f4b9b6582 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/codecommit/test.codecommit-source-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/codecommit/codecommit-source-action.test.ts @@ -4,12 +4,12 @@ import * as codecommit from '@aws-cdk/aws-codecommit'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as iam from '@aws-cdk/aws-iam'; import { Stack, Lazy } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as cpactions from '../../lib'; /* eslint-disable quote-props */ -export = { +nodeunitShim({ 'CodeCommit Source Action': { 'by default does not poll for source changes and uses Events'(test: Test) { const stack = new Stack(); @@ -430,7 +430,7 @@ export = { test.done(); }, }, -}; +}); function minimalPipeline(stack: Stack, trigger: cpactions.CodeCommitTrigger | undefined): codepipeline.Pipeline { const sourceOutput = new codepipeline.Artifact(); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/codedeploy/test.ecs-deploy-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/codedeploy/ecs-deploy-action.test.ts similarity index 99% rename from packages/@aws-cdk/aws-codepipeline-actions/test/codedeploy/test.ecs-deploy-action.ts rename to packages/@aws-cdk/aws-codepipeline-actions/test/codedeploy/ecs-deploy-action.test.ts index b75809ad8f515..4444ea9d409df 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/codedeploy/test.ecs-deploy-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/codedeploy/ecs-deploy-action.test.ts @@ -2,10 +2,10 @@ import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as codedeploy from '@aws-cdk/aws-codedeploy'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as cpactions from '../../lib'; -export = { +nodeunitShim({ 'CodeDeploy ECS Deploy Action': { 'throws an exception if more than 4 container image inputs are provided'(test: Test) { const stack = new cdk.Stack(); @@ -198,7 +198,7 @@ export = { test.done(); }, }, -}; +}); function addEcsDeploymentGroup(stack: cdk.Stack): codedeploy.IEcsDeploymentGroup { return codedeploy.EcsDeploymentGroup.fromEcsDeploymentGroupAttributes( diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/ecr/test.ecr-source-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/ecr/ecr-source-action.test.ts similarity index 96% rename from packages/@aws-cdk/aws-codepipeline-actions/test/ecr/test.ecr-source-action.ts rename to packages/@aws-cdk/aws-codepipeline-actions/test/ecr/ecr-source-action.test.ts index b27ad5f89f880..aacbb856e065c 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/ecr/test.ecr-source-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/ecr/ecr-source-action.test.ts @@ -3,12 +3,12 @@ import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as ecr from '@aws-cdk/aws-ecr'; import { Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as cpactions from '../../lib'; /* eslint-disable quote-props */ -export = { +nodeunitShim({ 'ECR source Action': { 'exposes variables for other actions to consume'(test: Test) { const stack = new Stack(); @@ -63,4 +63,4 @@ export = { test.done(); }, }, -}; +}); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/ecs/test.ecs-deploy-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/ecs/ecs-deploy-action.test.ts similarity index 98% rename from packages/@aws-cdk/aws-codepipeline-actions/test/ecs/test.ecs-deploy-action.ts rename to packages/@aws-cdk/aws-codepipeline-actions/test/ecs/ecs-deploy-action.test.ts index 1343850871206..841ca3948ec83 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/ecs/test.ecs-deploy-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/ecs/ecs-deploy-action.test.ts @@ -4,10 +4,10 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as cpactions from '../../lib'; -export = { +nodeunitShim({ 'ECS deploy Action': { 'throws an exception if neither inputArtifact nor imageFile were provided'(test: Test) { const service = anyEcsService(); @@ -198,7 +198,7 @@ export = { test.done(); }, }, -}; +}); function anyEcsService(): ecs.FargateService { const stack = new cdk.Stack(); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/github/test.github-source-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/github/github-source-action.test.ts similarity index 98% rename from packages/@aws-cdk/aws-codepipeline-actions/test/github/test.github-source-action.ts rename to packages/@aws-cdk/aws-codepipeline-actions/test/github/github-source-action.test.ts index 56131d3d15b1e..a73726e055459 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/github/test.github-source-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/github/github-source-action.test.ts @@ -2,12 +2,12 @@ import { expect, haveResourceLike, SynthUtils } from '@aws-cdk/assert'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import { SecretValue, Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as cpactions from '../../lib'; /* eslint-disable quote-props */ -export = { +nodeunitShim({ 'GitHub source Action': { 'exposes variables for other actions to consume'(test: Test) { const stack = new Stack(); @@ -208,4 +208,4 @@ export = { test.done(); }, }, -}; +}); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/lambda/test.lambda-invoke-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/lambda/lambda-invoke-action.test.ts similarity index 81% rename from packages/@aws-cdk/aws-codepipeline-actions/test/lambda/test.lambda-invoke-action.ts rename to packages/@aws-cdk/aws-codepipeline-actions/test/lambda/lambda-invoke-action.test.ts index 035d8ddb63a38..e9674e4531695 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/lambda/test.lambda-invoke-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/lambda/lambda-invoke-action.test.ts @@ -1,24 +1,26 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import '@aws-cdk/assert/jest'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as lambda from '@aws-cdk/aws-lambda'; import * as s3 from '@aws-cdk/aws-s3'; import * as sns from '@aws-cdk/aws-sns'; -import { Aws, Lazy, SecretValue, Stack, Token } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { App, Aws, Lazy, SecretValue, Stack, Token } from '@aws-cdk/core'; +import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; import * as cpactions from '../../lib'; /* eslint-disable quote-props */ -export = { - 'Lambda invoke Action': { - 'properly serializes the object passed in userParameters'(test: Test) { +const s3GrantWriteCtx = { '@aws-cdk/aws-s3:grantWriteWithoutAcl': true }; + +describe('', () => { + describe('Lambda invoke Action', () => { + test('properly serializes the object passed in userParameters', () => { const stack = stackIncludingLambdaInvokeCodePipeline({ userParams: { key: 1234, }, }); - expect(stack).to(haveResourceLike('AWS::CodePipeline::Pipeline', { + expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { 'Stages': [ {}, { @@ -31,19 +33,19 @@ export = { ], }, ], - })); + }); + - test.done(); - }, + }); - 'properly resolves any Tokens passed in userParameters'(test: Test) { + test('properly resolves any Tokens passed in userParameters', () => { const stack = stackIncludingLambdaInvokeCodePipeline({ userParams: { key: Lazy.string({ produce: () => Aws.REGION }), }, }); - expect(stack).to(haveResourceLike('AWS::CodePipeline::Pipeline', { + expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { 'Stages': [ {}, { @@ -67,19 +69,19 @@ export = { ], }, ], - })); + }); + - test.done(); - }, + }); - 'properly resolves any stringified Tokens passed in userParameters'(test: Test) { + test('properly resolves any stringified Tokens passed in userParameters', () => { const stack = stackIncludingLambdaInvokeCodePipeline({ userParams: { key: Token.asString(null), }, }); - expect(stack).to(haveResourceLike('AWS::CodePipeline::Pipeline', { + expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { 'Stages': [ {}, { @@ -92,17 +94,17 @@ export = { ], }, ], - })); + }); + - test.done(); - }, + }); - "assigns the Action's Role with read permissions to the Bucket if it has only inputs"(test: Test) { + test("assigns the Action's Role with read permissions to the Bucket if it has only inputs", () => { const stack = stackIncludingLambdaInvokeCodePipeline({ lambdaInput: new codepipeline.Artifact(), }); - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { 'PolicyDocument': { 'Statement': [ { @@ -131,18 +133,18 @@ export = { }, ], }, - })); + }); + - test.done(); - }, + }); - "assigns the Action's Role with write permissions to the Bucket if it has only outputs"(test: Test) { + testFutureBehavior("assigns the Action's Role with write permissions to the Bucket if it has only outputs", s3GrantWriteCtx, App, (app) => { const stack = stackIncludingLambdaInvokeCodePipeline({ lambdaOutput: new codepipeline.Artifact(), // no input to the Lambda Action - we want write permissions only in this case - }); + }, app); - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { 'PolicyDocument': { 'Statement': [ { @@ -157,7 +159,7 @@ export = { { 'Action': [ 's3:DeleteObject*', - 's3:PutObject*', + 's3:PutObject', 's3:Abort*', ], 'Effect': 'Allow', @@ -172,18 +174,18 @@ export = { }, ], }, - })); + }); + - test.done(); - }, + }); - "assigns the Action's Role with read-write permissions to the Bucket if it has both inputs and outputs"(test: Test) { + testFutureBehavior("assigns the Action's Role with read-write permissions to the Bucket if it has both inputs and outputs", s3GrantWriteCtx, App, (app) => { const stack = stackIncludingLambdaInvokeCodePipeline({ lambdaInput: new codepipeline.Artifact(), lambdaOutput: new codepipeline.Artifact(), - }); + }, app); - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { 'PolicyDocument': { 'Statement': [ { @@ -213,7 +215,7 @@ export = { { 'Action': [ 's3:DeleteObject*', - 's3:PutObject*', + 's3:PutObject', 's3:Abort*', ], 'Effect': 'Allow', @@ -228,12 +230,12 @@ export = { }, ], }, - })); + }); - test.done(); - }, - 'exposes variables for other actions to consume'(test: Test) { + }); + + test('exposes variables for other actions to consume', () => { const stack = new Stack(); const sourceOutput = new codepipeline.Artifact(); @@ -269,7 +271,7 @@ export = { ], }); - expect(stack).to(haveResourceLike('AWS::CodePipeline::Pipeline', { + expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source', @@ -290,12 +292,12 @@ export = { ], }, ], - })); + }); - test.done(); - }, - }, -}; + + }); + }); +}); interface HelperProps { readonly userParams?: { [key: string]: any }; @@ -303,8 +305,8 @@ interface HelperProps { readonly lambdaOutput?: codepipeline.Artifact; } -function stackIncludingLambdaInvokeCodePipeline(props: HelperProps) { - const stack = new Stack(); +function stackIncludingLambdaInvokeCodePipeline(props: HelperProps, app?: App) { + const stack = new Stack(app); new codepipeline.Pipeline(stack, 'Pipeline', { stages: [ diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/test.manual-approval.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/manual-approval.test.ts similarity index 96% rename from packages/@aws-cdk/aws-codepipeline-actions/test/test.manual-approval.ts rename to packages/@aws-cdk/aws-codepipeline-actions/test/manual-approval.test.ts index cac35015eda15..121e87cd9eb4e 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/test.manual-approval.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/manual-approval.test.ts @@ -2,12 +2,12 @@ import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as sns from '@aws-cdk/aws-sns'; import { SecretValue, Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as cpactions from '../lib'; /* eslint-disable quote-props */ -export = { +nodeunitShim({ 'manual approval Action': { 'allows passing an SNS Topic when constructing it'(test: Test) { const stack = new Stack(); @@ -75,4 +75,4 @@ export = { test.done(); }, }, -}; +}); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/pipeline.test.ts similarity index 99% rename from packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts rename to packages/@aws-cdk/aws-codepipeline-actions/test/pipeline.test.ts index 242e55b40e039..0c0491d778150 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/pipeline.test.ts @@ -8,12 +8,12 @@ import * as lambda from '@aws-cdk/aws-lambda'; import * as s3 from '@aws-cdk/aws-s3'; import * as sns from '@aws-cdk/aws-sns'; import { App, Aws, CfnParameter, ConstructNode, SecretValue, Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as cpactions from '../lib'; /* eslint-disable quote-props */ -export = { +nodeunitShim({ 'basic pipeline'(test: Test) { const stack = new Stack(); @@ -1126,4 +1126,4 @@ export = { test.done(); }, }, -}; +}); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/s3/test.s3-deploy-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-deploy-action.test.ts similarity index 78% rename from packages/@aws-cdk/aws-codepipeline-actions/test/s3/test.s3-deploy-action.ts rename to packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-deploy-action.test.ts index 8184c61bc3fce..c1e1c3c34c2c8 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/s3/test.s3-deploy-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-deploy-action.test.ts @@ -1,19 +1,19 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import '@aws-cdk/assert/jest'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as s3 from '@aws-cdk/aws-s3'; import { App, Duration, SecretValue, Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; import * as cpactions from '../../lib'; /* eslint-disable quote-props */ -export = { - 'S3 Deploy Action': { - 'by default extract artifacts'(test: Test) { +describe('', () => { + describe('S3 Deploy Action', () => { + test('by default extract artifacts', () => { const stack = new Stack(); minimalPipeline(stack); - expect(stack).to(haveResourceLike('AWS::CodePipeline::Pipeline', { + expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { 'Stages': [ { 'Name': 'Source', @@ -43,16 +43,16 @@ export = { ], }, ], - })); + }); - test.done(); - }, - 'grant the pipeline correct access to the target bucket'(test: Test) { - const stack = new Stack(); + }); + + testFutureBehavior('grant the pipeline correct access to the target bucket', { '@aws-cdk/aws-s3:grantWriteWithoutAcl': true }, App, (app) => { + const stack = new Stack(app); minimalPipeline(stack); - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { 'PolicyDocument': { 'Statement': [ { @@ -62,7 +62,7 @@ export = { 's3:GetBucket*', 's3:List*', 's3:DeleteObject*', - 's3:PutObject*', + 's3:PutObject', 's3:Abort*', ], }, @@ -73,18 +73,18 @@ export = { }, ], }, - })); + }); - test.done(); - }, - 'kebab-case CannedACL value'(test: Test) { + }); + + test('kebab-case CannedACL value', () => { const stack = new Stack(); minimalPipeline(stack, { accessControl: s3.BucketAccessControl.PUBLIC_READ_WRITE, }); - expect(stack).to(haveResourceLike('AWS::CodePipeline::Pipeline', { + expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { 'Stages': [ {}, { @@ -97,12 +97,12 @@ export = { ], }, ], - })); + }); + - test.done(); - }, + }); - 'allow customizing cache-control'(test: Test) { + test('allow customizing cache-control', () => { const stack = new Stack(); minimalPipeline(stack, { cacheControl: [ @@ -112,7 +112,7 @@ export = { ], }); - expect(stack).to(haveResourceLike('AWS::CodePipeline::Pipeline', { + expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { 'Stages': [ {}, { @@ -125,18 +125,18 @@ export = { ], }, ], - })); + }); + - test.done(); - }, + }); - 'allow customizing objectKey (deployment path on S3)'(test: Test) { + test('allow customizing objectKey (deployment path on S3)', () => { const stack = new Stack(); minimalPipeline(stack, { objectKey: '/a/b/c', }); - expect(stack).to(haveResourceLike('AWS::CodePipeline::Pipeline', { + expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { 'Stages': [ {}, { @@ -149,12 +149,12 @@ export = { ], }, ], - })); + }); + - test.done(); - }, + }); - 'correctly makes the action cross-region for a Bucket imported with a different region'(test: Test) { + test('correctly makes the action cross-region for a Bucket imported with a different region', () => { const app = new App(); const stack = new Stack(app, 'PipelineStack', { env: { account: '123456789012', region: 'us-west-2' }, @@ -168,7 +168,7 @@ export = { bucket: deployBucket, }); - expect(stack).to(haveResourceLike('AWS::CodePipeline::Pipeline', { + expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { Stages: [ {}, { @@ -181,12 +181,12 @@ export = { ], }, ], - })); + }); + - test.done(); - }, - }, -}; + }); + }); +}); interface MinimalPipelineOptions { readonly accessControl?: s3.BucketAccessControl; diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/s3/test.s3-source-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-source-action.test.ts similarity index 99% rename from packages/@aws-cdk/aws-codepipeline-actions/test/s3/test.s3-source-action.ts rename to packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-source-action.test.ts index fc069cffae6d3..3ae1210dcd8f7 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/s3/test.s3-source-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-source-action.test.ts @@ -3,12 +3,12 @@ import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as s3 from '@aws-cdk/aws-s3'; import { Lazy, Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as cpactions from '../../lib'; /* eslint-disable quote-props */ -export = { +nodeunitShim({ 'S3 Source Action': { 'by default polls for source changes and does not use Events'(test: Test) { const stack = new Stack(); @@ -269,7 +269,7 @@ export = { test.done(); }, }, -}; +}); interface MinimalPipelineOptions { readonly trigger?: cpactions.S3Trigger; diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/servicecatalog/test.servicecatalog-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/servicecatalog/servicecatalog-action.test.ts similarity index 98% rename from packages/@aws-cdk/aws-codepipeline-actions/test/servicecatalog/test.servicecatalog-action.ts rename to packages/@aws-cdk/aws-codepipeline-actions/test/servicecatalog/servicecatalog-action.test.ts index 8c4101552c37f..1415b2a084eaf 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/servicecatalog/test.servicecatalog-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/servicecatalog/servicecatalog-action.test.ts @@ -2,12 +2,12 @@ import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as codecommit from '@aws-cdk/aws-codecommit'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import { Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as cpactions from '../../lib'; /* eslint-disable quote-props */ -export = { +nodeunitShim({ 'addAction succesfully leads to creation of codepipeline service catalog action with properly formatted TemplateFilePath'(test: Test) { // GIVEN const stack = new TestFixture(); @@ -98,7 +98,7 @@ export = { test.done(); }, -}; +}); /** * A test stack with a half-prepared pipeline ready to add CloudFormation actions to diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/stepfunctions/test.stepfunctions-invoke-actions.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/stepfunctions/stepfunctions-invoke-actions.test.ts similarity index 98% rename from packages/@aws-cdk/aws-codepipeline-actions/test/stepfunctions/test.stepfunctions-invoke-actions.ts rename to packages/@aws-cdk/aws-codepipeline-actions/test/stepfunctions/stepfunctions-invoke-actions.test.ts index af9bf28b90640..47e33e7d5b5d8 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/stepfunctions/test.stepfunctions-invoke-actions.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/stepfunctions/stepfunctions-invoke-actions.test.ts @@ -3,10 +3,10 @@ import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as s3 from '@aws-cdk/aws-s3'; import * as stepfunction from '@aws-cdk/aws-stepfunctions'; import { Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as cpactions from '../../lib'; -export = { +nodeunitShim({ 'StepFunctions Invoke Action': { 'Verify stepfunction configuration properties are set to specific values'(test: Test) { const stack = new Stack(); @@ -144,7 +144,7 @@ export = { }, }, -}; +}); function minimalPipeline(stack: Stack): codepipeline.IStage { const sourceOutput = new codepipeline.Artifact(); diff --git a/packages/@aws-cdk/aws-cognito/README.md b/packages/@aws-cdk/aws-cognito/README.md index 5067ae8f44b63..4a9a8f5b250cb 100644 --- a/packages/@aws-cdk/aws-cognito/README.md +++ b/packages/@aws-cdk/aws-cognito/README.md @@ -343,7 +343,7 @@ on the construct, as so - ```ts const authChallengeFn = new lambda.Function(this, 'authChallengeFn', { - runtime: lambda.Runtime.NODEJS_10_X, + runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', code: lambda.Code.fromInline('auth challenge'), }); @@ -357,7 +357,7 @@ const userpool = new cognito.UserPool(this, 'myuserpool', { }); userpool.addTrigger(cognito.UserPoolOperation.USER_MIGRATION, new lambda.Function(this, 'userMigrationFn', { - runtime: lambda.Runtime.NODEJS_10_X, + runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', code: lambda.Code.fromInline('user migration'), })); @@ -582,12 +582,12 @@ The default behaviour is to allow read and write permissions on all attributes. const pool = new cognito.UserPool(this, 'Pool'); const clientWriteAttributes = (new ClientAttributes()) - .withStandardAttributes({name: true, email: true}) - .withCustomAttributes(['favouritePizza']); + .withStandardAttributes({fullname: true, email: true}) + .withCustomAttributes('favouritePizza', 'favouriteBeverage'); const clientReadAttributes = clientWriteAttributes .withStandardAttributes({emailVerified: true}) - .withCustomAttributes(['pointsEarned']); + .withCustomAttributes('pointsEarned'); pool.addClient('app-client', { // ... diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts index d85199ee6507f..eff29527ab4af 100644 --- a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts @@ -1,6 +1,6 @@ import { IRole, PolicyDocument, PolicyStatement, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; import * as lambda from '@aws-cdk/aws-lambda'; -import { Duration, IResource, Lazy, Names, Resource, Stack, Token } from '@aws-cdk/core'; +import { Duration, IResource, Lazy, Names, RemovalPolicy, Resource, Stack, Token } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { toASCII as punycodeEncode } from 'punycode/'; import { CfnUserPool } from './cognito.generated'; @@ -567,6 +567,13 @@ export interface UserPoolProps { * @default AccountRecovery.PHONE_WITHOUT_MFA_AND_EMAIL */ readonly accountRecovery?: AccountRecovery; + + /** + * Policy to apply when the user pool is removed from the stack + * + * @default RemovalPolicy.RETAIN + */ + readonly removalPolicy?: RemovalPolicy; } /** @@ -756,6 +763,7 @@ export class UserPool extends UserPoolBase { }), accountRecoverySetting: this.accountRecovery(props), }); + userPool.applyRemovalPolicy(props.removalPolicy); this.userPoolId = userPool.ref; this.userPoolArn = userPool.attrArn; diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-client-explicit-props.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-client-explicit-props.expected.json index 6d118b0cf046c..c2c5b4d18b269 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-client-explicit-props.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-client-explicit-props.expected.json @@ -27,7 +27,9 @@ "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "myuserpoolmyuserpoolclientAFB2274E": { "Type": "AWS::Cognito::UserPoolClient", @@ -64,9 +66,25 @@ "COGNITO" ], "WriteAttributes": [ - "address", "birthdate", "custom:attribute_one", "custom:attribute_two", "email", - "family_name", "gender", "given_name", "locale", "middle_name", "name", "nickname", "phone_number", - "picture", "preferred_username", "profile", "updated_at", "website", "zoneinfo" + "address", + "birthdate", + "custom:attribute_one", + "custom:attribute_two", + "email", + "family_name", + "gender", + "given_name", + "locale", + "middle_name", + "name", + "nickname", + "phone_number", + "picture", + "preferred_username", + "profile", + "updated_at", + "website", + "zoneinfo" ] } } diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-client-explicit-props.ts b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-client-explicit-props.ts index 2cd4557cdb48a..d8a058a86d9c8 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-client-explicit-props.ts +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-client-explicit-props.ts @@ -1,10 +1,12 @@ -import { App, Stack } from '@aws-cdk/core'; +import { App, RemovalPolicy, Stack } from '@aws-cdk/core'; import { OAuthScope, UserPool, ClientAttributes } from '../lib'; const app = new App(); const stack = new Stack(app, 'integ-user-pool-client-explicit-props'); -const userpool = new UserPool(stack, 'myuserpool'); +const userpool = new UserPool(stack, 'myuserpool', { + removalPolicy: RemovalPolicy.DESTROY, +}); userpool.addClient('myuserpoolclient', { userPoolClientName: 'myuserpoolclient', diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.expected.json index 5f3a61539ea8a..e9a67d39c9235 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.expected.json @@ -27,7 +27,9 @@ "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "UserPoolDomainD0EA232A": { "Type": "AWS::Cognito::UserPoolDomain", @@ -38,6 +40,27 @@ } } }, + "UserPoolDomainCloudFrontDomainNameCustomResourcePolicy7DE54188": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "cognito-idp:DescribeUserPoolDomain", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "UserPoolDomainCloudFrontDomainNameCustomResourcePolicy7DE54188", + "Roles": [ + { + "Ref": "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2" + } + ] + } + }, "UserPoolDomainCloudFrontDomainNameE213E594": { "Type": "Custom::UserPoolCloudFrontDomainName", "Properties": { @@ -77,11 +100,11 @@ }, "InstallLatestAwsSdk": true }, - "UpdateReplacePolicy": "Delete", - "DeletionPolicy": "Delete", "DependsOn": [ "UserPoolDomainCloudFrontDomainNameCustomResourcePolicy7DE54188" - ] + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2": { "Type": "AWS::IAM::Role", @@ -114,29 +137,12 @@ ] } }, - "UserPoolDomainCloudFrontDomainNameCustomResourcePolicy7DE54188": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ - { - "Action":"cognito-idp:DescribeUserPoolDomain", - "Effect":"Allow", - "Resource": "*" - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "UserPoolDomainCloudFrontDomainNameCustomResourcePolicy7DE54188", - "Roles": [{"Ref":"AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2"}] - } - }, "AWS679f53fac002430cb0da5b7982bd22872D164C4C": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersd731b1475f16a318a48a76c83d255f7422cfa5f025c5bff93537b8f0b8e94557S3BucketA250C084" + "Ref": "AssetParametersb64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94S3Bucket38F1BB8E" }, "S3Key": { "Fn::Join": [ @@ -149,7 +155,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersd731b1475f16a318a48a76c83d255f7422cfa5f025c5bff93537b8f0b8e94557S3VersionKeyDC4F0CD7" + "Ref": "AssetParametersb64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94S3VersionKeyCCDC67C0" } ] } @@ -162,7 +168,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersd731b1475f16a318a48a76c83d255f7422cfa5f025c5bff93537b8f0b8e94557S3VersionKeyDC4F0CD7" + "Ref": "AssetParametersb64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94S3VersionKeyCCDC67C0" } ] } @@ -172,13 +178,13 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs12.x", "Timeout": 120 }, @@ -203,17 +209,17 @@ } }, "Parameters": { - "AssetParametersd731b1475f16a318a48a76c83d255f7422cfa5f025c5bff93537b8f0b8e94557S3BucketA250C084": { + "AssetParametersb64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94S3Bucket38F1BB8E": { "Type": "String", - "Description": "S3 bucket for asset \"d731b1475f16a318a48a76c83d255f7422cfa5f025c5bff93537b8f0b8e94557\"" + "Description": "S3 bucket for asset \"b64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94\"" }, - "AssetParametersd731b1475f16a318a48a76c83d255f7422cfa5f025c5bff93537b8f0b8e94557S3VersionKeyDC4F0CD7": { + "AssetParametersb64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94S3VersionKeyCCDC67C0": { "Type": "String", - "Description": "S3 key for asset version \"d731b1475f16a318a48a76c83d255f7422cfa5f025c5bff93537b8f0b8e94557\"" + "Description": "S3 key for asset version \"b64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94\"" }, - "AssetParametersd731b1475f16a318a48a76c83d255f7422cfa5f025c5bff93537b8f0b8e94557ArtifactHash5701DE73": { + "AssetParametersb64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94ArtifactHash782948FC": { "Type": "String", - "Description": "Artifact hash for asset \"d731b1475f16a318a48a76c83d255f7422cfa5f025c5bff93537b8f0b8e94557\"" + "Description": "Artifact hash for asset \"b64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.ts b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.ts index 7a45e144ffc3c..2c646a52721ae 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.ts +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.ts @@ -1,5 +1,5 @@ /// !cdk-integ pragma:ignore-assets -import { App, CfnOutput, Stack } from '@aws-cdk/core'; +import { App, CfnOutput, RemovalPolicy, Stack } from '@aws-cdk/core'; import { UserPool } from '../lib'; /* @@ -10,7 +10,9 @@ import { UserPool } from '../lib'; const app = new App(); const stack = new Stack(app, 'integ-user-pool-domain-cfdist'); -const userpool = new UserPool(stack, 'UserPool'); +const userpool = new UserPool(stack, 'UserPool', { + removalPolicy: RemovalPolicy.DESTROY, +}); const domain = userpool.addDomain('Domain', { cognitoDomain: { diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-signinurl.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-signinurl.expected.json index 694cf43b5f5ea..f19f82379b701 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-signinurl.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-signinurl.expected.json @@ -27,7 +27,9 @@ "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "UserPoolDomainD0EA232A": { "Type": "AWS::Cognito::UserPoolDomain", diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-signinurl.ts b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-signinurl.ts index 7d55d08fe12bb..7b26359354f9b 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-signinurl.ts +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-signinurl.ts @@ -1,4 +1,4 @@ -import { App, CfnOutput, Stack } from '@aws-cdk/core'; +import { App, CfnOutput, RemovalPolicy, Stack } from '@aws-cdk/core'; import { UserPool } from '../lib'; /* @@ -10,7 +10,9 @@ import { UserPool } from '../lib'; const app = new App(); const stack = new Stack(app, 'integ-user-pool-domain-signinurl'); -const userpool = new UserPool(stack, 'UserPool'); +const userpool = new UserPool(stack, 'UserPool', { + removalPolicy: RemovalPolicy.DESTROY, +}); const domain = userpool.addDomain('Domain', { cognitoDomain: { diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.expected.json index ed77c3b7baa53..50da9815a769b 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.expected.json @@ -37,15 +37,15 @@ "Code": { "ZipFile": "foo" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "createAuthChallengeServiceRole611710B5", "Arn" ] }, - "Runtime": "nodejs12.x", - "FunctionName": "createAuthChallenge" + "FunctionName": "createAuthChallenge", + "Handler": "index.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "createAuthChallengeServiceRole611710B5" @@ -101,15 +101,15 @@ "Code": { "ZipFile": "foo" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "customMessageServiceRoleB4AE7F17", "Arn" ] }, - "Runtime": "nodejs12.x", - "FunctionName": "customMessage" + "FunctionName": "customMessage", + "Handler": "index.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "customMessageServiceRoleB4AE7F17" @@ -165,15 +165,15 @@ "Code": { "ZipFile": "foo" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "defineAuthChallengeServiceRole9E2D15DF", "Arn" ] }, - "Runtime": "nodejs12.x", - "FunctionName": "defineAuthChallenge" + "FunctionName": "defineAuthChallenge", + "Handler": "index.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "defineAuthChallengeServiceRole9E2D15DF" @@ -229,15 +229,15 @@ "Code": { "ZipFile": "foo" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "postAuthenticationServiceRole5B3B242A", "Arn" ] }, - "Runtime": "nodejs12.x", - "FunctionName": "postAuthentication" + "FunctionName": "postAuthentication", + "Handler": "index.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "postAuthenticationServiceRole5B3B242A" @@ -293,15 +293,15 @@ "Code": { "ZipFile": "foo" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "postConfirmationServiceRole864BE5F9", "Arn" ] }, - "Runtime": "nodejs12.x", - "FunctionName": "postConfirmation" + "FunctionName": "postConfirmation", + "Handler": "index.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "postConfirmationServiceRole864BE5F9" @@ -357,15 +357,15 @@ "Code": { "ZipFile": "foo" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "preAuthenticationServiceRole9712F4D8", "Arn" ] }, - "Runtime": "nodejs12.x", - "FunctionName": "preAuthentication" + "FunctionName": "preAuthentication", + "Handler": "index.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "preAuthenticationServiceRole9712F4D8" @@ -421,15 +421,15 @@ "Code": { "ZipFile": "foo" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "preSignUpServiceRole0A7E91EB", "Arn" ] }, - "Runtime": "nodejs12.x", - "FunctionName": "preSignUp" + "FunctionName": "preSignUp", + "Handler": "index.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "preSignUpServiceRole0A7E91EB" @@ -485,15 +485,15 @@ "Code": { "ZipFile": "foo" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "preTokenGenerationServiceRole430C3D14", "Arn" ] }, - "Runtime": "nodejs12.x", - "FunctionName": "preTokenGeneration" + "FunctionName": "preTokenGeneration", + "Handler": "index.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "preTokenGenerationServiceRole430C3D14" @@ -549,15 +549,15 @@ "Code": { "ZipFile": "foo" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "userMigrationServiceRole091766B0", "Arn" ] }, - "Runtime": "nodejs12.x", - "FunctionName": "userMigration" + "FunctionName": "userMigration", + "Handler": "index.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "userMigrationServiceRole091766B0" @@ -613,15 +613,15 @@ "Code": { "ZipFile": "foo" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "verifyAuthChallengeResponseServiceRole7077884C", "Arn" ] }, - "Runtime": "nodejs12.x", - "FunctionName": "verifyAuthChallengeResponse" + "FunctionName": "verifyAuthChallengeResponse", + "Handler": "index.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "verifyAuthChallengeResponseServiceRole7077884C" @@ -843,7 +843,9 @@ "EmailSubject": "verification email subject from the integ test", "SmsMessage": "verification sms message from the integ test. Code is {####}." } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "myuserpoolmyuserpooldomainEE1E11AF": { "Type": "AWS::Cognito::UserPoolDomain", diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.ts b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.ts index 261251e1e2592..1bc35003fa472 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.ts +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.ts @@ -1,11 +1,12 @@ import { Code, Function, IFunction, Runtime } from '@aws-cdk/aws-lambda'; -import { App, CfnOutput, Duration, Stack } from '@aws-cdk/core'; +import { App, CfnOutput, Duration, RemovalPolicy, Stack } from '@aws-cdk/core'; import { BooleanAttribute, DateTimeAttribute, Mfa, NumberAttribute, StringAttribute, UserPool } from '../lib'; const app = new App(); const stack = new Stack(app, 'integ-user-pool'); const userpool = new UserPool(stack, 'myuserpool', { + removalPolicy: RemovalPolicy.DESTROY, userPoolName: 'MyUserPool', userInvitation: { emailSubject: 'invitation email subject from the integ test', diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.amazon.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.amazon.expected.json index e68a262eb7ee3..dd2188ee4e517 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.amazon.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.amazon.expected.json @@ -27,7 +27,9 @@ "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "poolclient2623294C": { "Type": "AWS::Cognito::UserPoolClient", diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.amazon.ts b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.amazon.ts index 7252dfc0a8a40..77b95a5857330 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.amazon.ts +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.amazon.ts @@ -1,4 +1,4 @@ -import { App, CfnOutput, Stack } from '@aws-cdk/core'; +import { App, CfnOutput, RemovalPolicy, Stack } from '@aws-cdk/core'; import { ProviderAttribute, UserPool, UserPoolIdentityProviderAmazon } from '../lib'; /* @@ -9,7 +9,9 @@ import { ProviderAttribute, UserPool, UserPoolIdentityProviderAmazon } from '../ const app = new App(); const stack = new Stack(app, 'integ-user-pool-idp-amazon'); -const userpool = new UserPool(stack, 'pool'); +const userpool = new UserPool(stack, 'pool', { + removalPolicy: RemovalPolicy.DESTROY, +}); new UserPoolIdentityProviderAmazon(stack, 'amazon', { userPool: userpool, diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.google.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.google.expected.json index c767ee9d2d260..b90dd7faec0dd 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.google.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.google.expected.json @@ -27,7 +27,9 @@ "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "poolclient2623294C": { "Type": "AWS::Cognito::UserPoolClient", diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.google.ts b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.google.ts index fac20b8351d38..f4ea4d077286d 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.google.ts +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.google.ts @@ -1,4 +1,4 @@ -import { App, CfnOutput, Stack } from '@aws-cdk/core'; +import { App, CfnOutput, RemovalPolicy, Stack } from '@aws-cdk/core'; import { ProviderAttribute, UserPool, UserPoolIdentityProviderGoogle } from '../lib'; /* @@ -9,7 +9,9 @@ import { ProviderAttribute, UserPool, UserPoolIdentityProviderGoogle } from '../ const app = new App(); const stack = new Stack(app, 'integ-user-pool-idp-google'); -const userpool = new UserPool(stack, 'pool'); +const userpool = new UserPool(stack, 'pool', { + removalPolicy: RemovalPolicy.DESTROY, +}); new UserPoolIdentityProviderGoogle(stack, 'google', { userPool: userpool, diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-resource-server.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-resource-server.expected.json index ffc765b879357..36b033a51f2fb 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-resource-server.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-resource-server.expected.json @@ -28,7 +28,9 @@ "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "myuserpoolmyserver50C4D8E9": { "Type": "AWS::Cognito::UserPoolResourceServer", diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-resource-server.ts b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-resource-server.ts index 8610d7a3e1296..cd56612c65cd7 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-resource-server.ts +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-resource-server.ts @@ -1,4 +1,4 @@ -import { App, CfnOutput, Stack } from '@aws-cdk/core'; +import { App, CfnOutput, RemovalPolicy, Stack } from '@aws-cdk/core'; import { OAuthScope, ResourceServerScope, UserPool } from '../lib'; const app = new App(); @@ -14,6 +14,7 @@ const stack = new Stack(app, 'integ-user-pool-resource-server'); */ const userPool = new UserPool(stack, 'myuserpool', { userPoolName: 'MyUserPool', + removalPolicy: RemovalPolicy.DESTROY, }); const readScope = new ResourceServerScope({ scopeName: 'read', scopeDescription: 'read only' }); diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-code.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-code.expected.json index 5cc13052434f2..091b5f4cb7a8a 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-code.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-code.expected.json @@ -87,7 +87,9 @@ "EmailSubject": "integ-test: Verify your account", "SmsMessage": "integ-test: Account verification code is {####}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "myuserpoolclient8A58A3E4": { "Type": "AWS::Cognito::UserPoolClient", diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-code.ts b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-code.ts index 12e8c1d354ea3..9118b4c912adf 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-code.ts +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-code.ts @@ -1,4 +1,4 @@ -import { App, CfnOutput, Stack } from '@aws-cdk/core'; +import { App, CfnOutput, RemovalPolicy, Stack } from '@aws-cdk/core'; import { UserPool, UserPoolClient, VerificationEmailStyle } from '../lib'; /* @@ -15,6 +15,7 @@ const app = new App(); const stack = new Stack(app, 'integ-user-pool-signup-code'); const userpool = new UserPool(stack, 'myuserpool', { + removalPolicy: RemovalPolicy.DESTROY, userPoolName: 'MyUserPool', autoVerify: { email: true, diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-link.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-link.expected.json index 53c9f89ed8031..f5cca975e608b 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-link.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-link.expected.json @@ -85,7 +85,9 @@ "EmailSubjectByLink": "integ-test: Verify your account", "SmsMessage": "integ-test: Account verification code is {####}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "myuserpoolmyuserpooldomainEE1E11AF": { "Type": "AWS::Cognito::UserPoolDomain", diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-link.ts b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-link.ts index 92f0452010f22..b7121720ad940 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-link.ts +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-link.ts @@ -1,4 +1,4 @@ -import { App, CfnOutput, Stack } from '@aws-cdk/core'; +import { App, CfnOutput, RemovalPolicy, Stack } from '@aws-cdk/core'; import { UserPool, UserPoolClient, VerificationEmailStyle } from '../lib'; /* @@ -15,6 +15,7 @@ const app = new App(); const stack = new Stack(app, 'integ-user-pool-signup-link'); const userpool = new UserPool(stack, 'myuserpool', { + removalPolicy: RemovalPolicy.DESTROY, userPoolName: 'MyUserPool', autoVerify: { email: true, diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool.expected.json index 85214615c050d..a3a50d2f5287b 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool.expected.json @@ -28,7 +28,9 @@ "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool.ts b/packages/@aws-cdk/aws-cognito/test/integ.user-pool.ts index 565a6b1dd549e..5b587b8f94f75 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool.ts +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool.ts @@ -1,4 +1,4 @@ -import { App, CfnOutput, Stack } from '@aws-cdk/core'; +import { App, CfnOutput, RemovalPolicy, Stack } from '@aws-cdk/core'; import { UserPool } from '../lib'; const app = new App(); @@ -6,6 +6,7 @@ const stack = new Stack(app, 'integ-user-pool'); const userpool = new UserPool(stack, 'myuserpool', { userPoolName: 'MyUserPool', + removalPolicy: RemovalPolicy.DESTROY, }); new CfnOutput(stack, 'user-pool-id', { diff --git a/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts b/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts index a2199eecce800..6801e8ada2568 100644 --- a/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts +++ b/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts @@ -1,5 +1,5 @@ import '@aws-cdk/assert/jest'; -import { ABSENT } from '@aws-cdk/assert/lib/assertions/have-resource'; +import { ABSENT, ResourcePart } from '@aws-cdk/assert/lib/assertions/have-resource'; import { Role, ServicePrincipal } from '@aws-cdk/aws-iam'; import * as lambda from '@aws-cdk/aws-lambda'; import { CfnParameter, Duration, Stack, Tags } from '@aws-cdk/core'; @@ -32,6 +32,10 @@ describe('User Pool', () => { SmsConfiguration: ABSENT, lambdaTriggers: ABSENT, }); + + expect(stack).toHaveResource('AWS::Cognito::UserPool', { + DeletionPolicy: 'Retain', + }, ResourcePart.CompleteDefinition); }); test('self sign up option is correctly configured', () => { diff --git a/packages/@aws-cdk/aws-config/README.md b/packages/@aws-cdk/aws-config/README.md index 3d3e24f361549..0a8219a8c3f53 100644 --- a/packages/@aws-cdk/aws-config/README.md +++ b/packages/@aws-cdk/aws-config/README.md @@ -237,7 +237,7 @@ import * as targets from '@aws-cdk/aws-events-targets'; const evalComplianceFn = new lambda.Function(this, 'CustomFunction', { code: lambda.AssetCode.fromInline('exports.handler = (event) => console.log(event);'), handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, + runtime: lambda.Runtime.NODEJS_12_X, }); // A custom rule that runs on configuration changes of EC2 instances diff --git a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts index 30dae02e8a0df..768094c253213 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts @@ -3,8 +3,9 @@ import '@aws-cdk/assert/jest'; import * as appscaling from '@aws-cdk/aws-applicationautoscaling'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; -import { App, Aws, CfnDeletionPolicy, ConstructNode, Duration, PhysicalName, RemovalPolicy, Stack, Tags } from '@aws-cdk/core'; +import { App, Aws, CfnDeletionPolicy, ConstructNode, Duration, PhysicalName, RemovalPolicy, Resource, Stack, Tags } from '@aws-cdk/core'; import { testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { Construct } from 'constructs'; import { Attribute, AttributeType, @@ -16,6 +17,7 @@ import { Table, TableEncryption, Operation, + CfnTable, } from '../lib'; /* eslint-disable quote-props */ @@ -2814,6 +2816,29 @@ describe('global', () => { }); }); +test('L1 inside L2 expects removalpolicy to have been set', () => { + // Check that the "stateful L1 validation generation" works. Do it here + // because we know DDB tables are stateful. + const app = new App(); + const stack = new Stack(app, 'Stack'); + + class FakeTableL2 extends Resource { + constructor(scope: Construct, id: string) { + super(scope, id); + + new CfnTable(this, 'Resource', { + keySchema: [{ attributeName: 'hash', keyType: 'S' }], + }); + } + } + + new FakeTableL2(stack, 'Table'); + + expect(() => { + SynthUtils.toCloudFormation(stack); + }).toThrow(/is a stateful resource type/); +}); + function testGrant(expectedActions: string[], invocation: (user: iam.IPrincipal, table: Table) => void) { // GIVEN const stack = new Stack(); diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.global-replicas-provisioned.expected.json b/packages/@aws-cdk/aws-dynamodb/test/integ.global-replicas-provisioned.expected.json index ec15f88fdfea8..89a9c3807fc21 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.global-replicas-provisioned.expected.json +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.global-replicas-provisioned.expected.json @@ -302,7 +302,9 @@ "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Conditions": { diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json b/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json index 2301663780e86..a66dd3d965ed9 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json @@ -231,7 +231,7 @@ }, "/", { - "Ref": "AssetParameters51ac5fed1b824803906219cb11f0c17572739bd4fb019d961cdc1fbbfefc620eS3Bucket58C634A6" + "Ref": "AssetParametersf8cfc24954f0c95960d9a93888c01bf5e95802f26bfa5dc6fde5c913a1429ceaS3Bucket434BDB62" }, "/", { @@ -241,7 +241,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters51ac5fed1b824803906219cb11f0c17572739bd4fb019d961cdc1fbbfefc620eS3VersionKeyE8ACA4C1" + "Ref": "AssetParametersf8cfc24954f0c95960d9a93888c01bf5e95802f26bfa5dc6fde5c913a1429ceaS3VersionKey01638790" } ] } @@ -254,7 +254,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters51ac5fed1b824803906219cb11f0c17572739bd4fb019d961cdc1fbbfefc620eS3VersionKeyE8ACA4C1" + "Ref": "AssetParametersf8cfc24954f0c95960d9a93888c01bf5e95802f26bfa5dc6fde5c913a1429ceaS3VersionKey01638790" } ] } @@ -264,58 +264,60 @@ ] }, "Parameters": { - "referencetocdkdynamodbglobal20191121AssetParameters23c5f8cc1bdef276fc20dbb166d24d1b7d8cb516a5d5822ed0d38feec9631fd1S3BucketFE71C2D0Ref": { - "Ref": "AssetParameters23c5f8cc1bdef276fc20dbb166d24d1b7d8cb516a5d5822ed0d38feec9631fd1S3Bucket492F02B7" + "referencetocdkdynamodbglobal20191121AssetParametersf13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714S3Bucket71E24D5BRef": { + "Ref": "AssetParametersf13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714S3Bucket1C6779E0" }, - "referencetocdkdynamodbglobal20191121AssetParameters23c5f8cc1bdef276fc20dbb166d24d1b7d8cb516a5d5822ed0d38feec9631fd1S3VersionKey849A4FA5Ref": { - "Ref": "AssetParameters23c5f8cc1bdef276fc20dbb166d24d1b7d8cb516a5d5822ed0d38feec9631fd1S3VersionKeyC7F72494" + "referencetocdkdynamodbglobal20191121AssetParametersf13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714S3VersionKeyD88E8BACRef": { + "Ref": "AssetParametersf13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714S3VersionKey5C1D9275" }, - "referencetocdkdynamodbglobal20191121AssetParameters956c2f92ddbde06f551fdf914445c679dcadb21c6e8d1ee9c9632144ef5a2ad3S3Bucket80086951Ref": { - "Ref": "AssetParameters956c2f92ddbde06f551fdf914445c679dcadb21c6e8d1ee9c9632144ef5a2ad3S3Bucket0EEA1C2E" + "referencetocdkdynamodbglobal20191121AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketC7F3A147Ref": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" }, - "referencetocdkdynamodbglobal20191121AssetParameters956c2f92ddbde06f551fdf914445c679dcadb21c6e8d1ee9c9632144ef5a2ad3S3VersionKeyC3096D21Ref": { - "Ref": "AssetParameters956c2f92ddbde06f551fdf914445c679dcadb21c6e8d1ee9c9632144ef5a2ad3S3VersionKey7BCE18C9" + "referencetocdkdynamodbglobal20191121AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyB6346792Ref": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Parameters": { - "AssetParameters23c5f8cc1bdef276fc20dbb166d24d1b7d8cb516a5d5822ed0d38feec9631fd1S3Bucket492F02B7": { + "AssetParametersf13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714S3Bucket1C6779E0": { "Type": "String", - "Description": "S3 bucket for asset \"23c5f8cc1bdef276fc20dbb166d24d1b7d8cb516a5d5822ed0d38feec9631fd1\"" + "Description": "S3 bucket for asset \"f13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714\"" }, - "AssetParameters23c5f8cc1bdef276fc20dbb166d24d1b7d8cb516a5d5822ed0d38feec9631fd1S3VersionKeyC7F72494": { + "AssetParametersf13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714S3VersionKey5C1D9275": { "Type": "String", - "Description": "S3 key for asset version \"23c5f8cc1bdef276fc20dbb166d24d1b7d8cb516a5d5822ed0d38feec9631fd1\"" + "Description": "S3 key for asset version \"f13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714\"" }, - "AssetParameters23c5f8cc1bdef276fc20dbb166d24d1b7d8cb516a5d5822ed0d38feec9631fd1ArtifactHash43BB7053": { + "AssetParametersf13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714ArtifactHash477AAEA7": { "Type": "String", - "Description": "Artifact hash for asset \"23c5f8cc1bdef276fc20dbb166d24d1b7d8cb516a5d5822ed0d38feec9631fd1\"" + "Description": "Artifact hash for asset \"f13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714\"" }, - "AssetParameters956c2f92ddbde06f551fdf914445c679dcadb21c6e8d1ee9c9632144ef5a2ad3S3Bucket0EEA1C2E": { + "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { "Type": "String", - "Description": "S3 bucket for asset \"956c2f92ddbde06f551fdf914445c679dcadb21c6e8d1ee9c9632144ef5a2ad3\"" + "Description": "S3 bucket for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" }, - "AssetParameters956c2f92ddbde06f551fdf914445c679dcadb21c6e8d1ee9c9632144ef5a2ad3S3VersionKey7BCE18C9": { + "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F": { "Type": "String", - "Description": "S3 key for asset version \"956c2f92ddbde06f551fdf914445c679dcadb21c6e8d1ee9c9632144ef5a2ad3\"" + "Description": "S3 key for asset version \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" }, - "AssetParameters956c2f92ddbde06f551fdf914445c679dcadb21c6e8d1ee9c9632144ef5a2ad3ArtifactHash2CBB11D2": { + "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1ArtifactHashA521A16F": { "Type": "String", - "Description": "Artifact hash for asset \"956c2f92ddbde06f551fdf914445c679dcadb21c6e8d1ee9c9632144ef5a2ad3\"" + "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" }, - "AssetParameters51ac5fed1b824803906219cb11f0c17572739bd4fb019d961cdc1fbbfefc620eS3Bucket58C634A6": { + "AssetParametersf8cfc24954f0c95960d9a93888c01bf5e95802f26bfa5dc6fde5c913a1429ceaS3Bucket434BDB62": { "Type": "String", - "Description": "S3 bucket for asset \"51ac5fed1b824803906219cb11f0c17572739bd4fb019d961cdc1fbbfefc620e\"" + "Description": "S3 bucket for asset \"f8cfc24954f0c95960d9a93888c01bf5e95802f26bfa5dc6fde5c913a1429cea\"" }, - "AssetParameters51ac5fed1b824803906219cb11f0c17572739bd4fb019d961cdc1fbbfefc620eS3VersionKeyE8ACA4C1": { + "AssetParametersf8cfc24954f0c95960d9a93888c01bf5e95802f26bfa5dc6fde5c913a1429ceaS3VersionKey01638790": { "Type": "String", - "Description": "S3 key for asset version \"51ac5fed1b824803906219cb11f0c17572739bd4fb019d961cdc1fbbfefc620e\"" + "Description": "S3 key for asset version \"f8cfc24954f0c95960d9a93888c01bf5e95802f26bfa5dc6fde5c913a1429cea\"" }, - "AssetParameters51ac5fed1b824803906219cb11f0c17572739bd4fb019d961cdc1fbbfefc620eArtifactHashDF827F41": { + "AssetParametersf8cfc24954f0c95960d9a93888c01bf5e95802f26bfa5dc6fde5c913a1429ceaArtifactHashD0E61C22": { "Type": "String", - "Description": "Artifact hash for asset \"51ac5fed1b824803906219cb11f0c17572739bd4fb019d961cdc1fbbfefc620e\"" + "Description": "Artifact hash for asset \"f8cfc24954f0c95960d9a93888c01bf5e95802f26bfa5dc6fde5c913a1429cea\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/lib/volume.ts b/packages/@aws-cdk/aws-ec2/lib/volume.ts index a23614b89ed63..64f920866a17b 100644 --- a/packages/@aws-cdk/aws-ec2/lib/volume.ts +++ b/packages/@aws-cdk/aws-ec2/lib/volume.ts @@ -2,7 +2,7 @@ import * as crypto from 'crypto'; import { AccountRootPrincipal, Grant, IGrantable } from '@aws-cdk/aws-iam'; import { IKey, ViaServicePrincipal } from '@aws-cdk/aws-kms'; -import { IResource, Resource, Size, SizeRoundingBehavior, Stack, Token, Tags, Names } from '@aws-cdk/core'; +import { IResource, Resource, Size, SizeRoundingBehavior, Stack, Token, Tags, Names, RemovalPolicy } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { CfnVolume } from './ec2.generated'; import { IInstance } from './instance'; @@ -431,6 +431,13 @@ export interface VolumeProps { * @default None -- Required for io1 and io2 volumes. The default for gp3 volumes is 3,000 IOPS if omitted. */ readonly iops?: number; + + /** + * Policy to apply when the volume is removed from the stack + * + * @default RemovalPolicy.RETAIN + */ + readonly removalPolicy?: RemovalPolicy; } /** @@ -605,6 +612,7 @@ export class Volume extends VolumeBase { snapshotId: props.snapshotId, volumeType: props.volumeType ?? EbsDeviceVolumeType.GENERAL_PURPOSE_SSD, }); + resource.applyRemovalPolicy(props.removalPolicy); this.volumeId = resource.ref; this.availabilityZone = props.availabilityZone; diff --git a/packages/@aws-cdk/aws-ec2/test/volume.test.ts b/packages/@aws-cdk/aws-ec2/test/volume.test.ts index 4e5da04a38976..edd0323bc84ef 100644 --- a/packages/@aws-cdk/aws-ec2/test/volume.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/volume.test.ts @@ -41,7 +41,9 @@ describe('volume', () => { VolumeType: 'gp2', }, ResourcePart.Properties)); - + cdkExpect(stack).to(haveResource('AWS::EC2::Volume', { + DeletionPolicy: 'Retain', + }, ResourcePart.CompleteDefinition)); }); test('fromVolumeAttributes', () => { diff --git a/packages/@aws-cdk/aws-ecr-assets/test/integ.nested-stacks-docker.expected.json b/packages/@aws-cdk/aws-ecr-assets/test/integ.nested-stacks-docker.expected.json index 779ad22187591..f86d0e5fea7ab 100644 --- a/packages/@aws-cdk/aws-ecr-assets/test/integ.nested-stacks-docker.expected.json +++ b/packages/@aws-cdk/aws-ecr-assets/test/integ.nested-stacks-docker.expected.json @@ -49,7 +49,9 @@ ] ] } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Parameters": { @@ -66,4 +68,4 @@ "Description": "Artifact hash for asset \"41589ef1a760129e41441e85e58fe02db5f019ed532b8a4a20729f3245b0593b\"" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-isolated.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-isolated.expected.json index d19d9c6a9fbb9..b1d88ed107154 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-isolated.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-isolated.expected.json @@ -668,7 +668,9 @@ "Type": "AWS::SQS::Queue", "Properties": { "MessageRetentionPeriod": 1209600 - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "IsolatedQueueServiceEcsProcessingQueueCCE172F1": { "Type": "AWS::SQS::Queue", @@ -682,7 +684,9 @@ }, "maxReceiveCount": 3 } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "IsolatedQueueServiceQueueProcessingTaskDefTaskRoleCFCB7511": { "Type": "AWS::IAM::Role", diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-public.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-public.expected.json index 104e2f2e6f45f..fd8f791e3a868 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-public.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-public.expected.json @@ -518,7 +518,9 @@ "Type": "AWS::SQS::Queue", "Properties": { "MessageRetentionPeriod": 1209600 - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "PublicQueueServiceEcsProcessingQueue84CD309D": { "Type": "AWS::SQS::Queue", @@ -532,7 +534,9 @@ }, "maxReceiveCount": 3 } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "PublicQueueServiceQueueProcessingTaskDefTaskRole172D980F": { "Type": "AWS::IAM::Role", diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.expected.json index 3fd9825b7db3b..889eeefcd985e 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.expected.json @@ -359,7 +359,9 @@ "Type": "AWS::SQS::Queue", "Properties": { "MessageRetentionPeriod": 1209600 - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "QueueProcessingServiceEcsProcessingQueue552F0B37": { "Type": "AWS::SQS::Queue", @@ -373,7 +375,9 @@ }, "maxReceiveCount": 3 } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "QueueProcessingServiceQueueProcessingTaskDefTaskRole782B79A6": { "Type": "AWS::IAM::Role", diff --git a/packages/@aws-cdk/aws-ecs/.gitignore b/packages/@aws-cdk/aws-ecs/.gitignore index 255c76b856cb1..52228730a371f 100644 --- a/packages/@aws-cdk/aws-ecs/.gitignore +++ b/packages/@aws-cdk/aws-ecs/.gitignore @@ -16,4 +16,5 @@ nyc.config.js *.snk !.eslintrc.js -junit.xml \ No newline at end of file +junit.xml +!jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/.npmignore b/packages/@aws-cdk/aws-ecs/.npmignore index 40fbede1f02dc..6c1b9b8c69ec6 100644 --- a/packages/@aws-cdk/aws-ecs/.npmignore +++ b/packages/@aws-cdk/aws-ecs/.npmignore @@ -23,4 +23,5 @@ tsconfig.json # exclude cdk artifacts **/cdk.out junit.xml -test/ \ No newline at end of file +test/ +jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/jest.config.js b/packages/@aws-cdk/aws-ecs/jest.config.js new file mode 100644 index 0000000000000..f5d5c4c8ad18f --- /dev/null +++ b/packages/@aws-cdk/aws-ecs/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/package.json b/packages/@aws-cdk/aws-ecs/package.json index 418619f6ee09c..f7408e518f2fe 100644 --- a/packages/@aws-cdk/aws-ecs/package.json +++ b/packages/@aws-cdk/aws-ecs/package.json @@ -53,6 +53,7 @@ }, "cdk-build": { "cloudformation": "AWS::ECS", + "jest": "true", "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -77,7 +78,7 @@ "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "nodeunit": "^0.11.3", + "nodeunit-shim": "0.0.0", "pkglint": "0.0.0", "proxyquire": "^2.1.3" }, diff --git a/packages/@aws-cdk/aws-ecs/test/test.app-mesh-proxy-configuration.ts b/packages/@aws-cdk/aws-ecs/test/app-mesh-proxy-configuration.test.ts similarity index 98% rename from packages/@aws-cdk/aws-ecs/test/test.app-mesh-proxy-configuration.ts rename to packages/@aws-cdk/aws-ecs/test/app-mesh-proxy-configuration.test.ts index 1633d90234ee0..69f3d30e9b865 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.app-mesh-proxy-configuration.ts +++ b/packages/@aws-cdk/aws-ecs/test/app-mesh-proxy-configuration.test.ts @@ -1,9 +1,9 @@ import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; -export = { +nodeunitShim({ 'correctly sets all appMeshProxyConfiguration'(test: Test) { // GIVEN const stack = new cdk.Stack(); @@ -204,4 +204,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/test.aws-log-driver.ts b/packages/@aws-cdk/aws-ecs/test/aws-log-driver.test.ts similarity index 98% rename from packages/@aws-cdk/aws-ecs/test/test.aws-log-driver.ts rename to packages/@aws-cdk/aws-ecs/test/aws-log-driver.test.ts index a4d5c9af9c53d..d36fb943e8b2d 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.aws-log-driver.ts +++ b/packages/@aws-cdk/aws-ecs/test/aws-log-driver.test.ts @@ -1,14 +1,14 @@ import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; import * as logs from '@aws-cdk/aws-logs'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; let stack: cdk.Stack; let td: ecs.TaskDefinition; const image = ecs.ContainerImage.fromRegistry('test-image'); -export = { +nodeunitShim({ 'setUp'(cb: () => void) { stack = new cdk.Stack(); td = new ecs.FargateTaskDefinition(stack, 'TaskDefinition'); @@ -154,4 +154,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/test.container-definition.ts b/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts similarity index 82% rename from packages/@aws-cdk/aws-ecs/test/test.container-definition.ts rename to packages/@aws-cdk/aws-ecs/test/container-definition.test.ts index e994a9174f51d..c167720e362cf 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.container-definition.ts +++ b/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts @@ -1,16 +1,17 @@ +import '@aws-cdk/assert/jest'; import * as path from 'path'; -import { expect, haveResource, haveResourceLike, InspectionFailure } from '@aws-cdk/assert'; +import { InspectionFailure } from '@aws-cdk/assert'; import * as ecr_assets from '@aws-cdk/aws-ecr-assets'; import * as s3 from '@aws-cdk/aws-s3'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; import * as ssm from '@aws-cdk/aws-ssm'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; import * as ecs from '../lib'; -export = { - 'When creating a Task Definition': { - 'add a container using default props'(test: Test) { +describe('container definition', () => { + describe('When creating a Task Definition', () => { + test('add a container using default props', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -22,7 +23,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Essential: true, @@ -31,12 +32,12 @@ export = { Name: 'Container', }, ], - })); + }); + - test.done(); - }, + }); - 'add a container using all props'(test: Test) { + test('add a container using all props', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -85,7 +86,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Command: [ @@ -219,31 +220,31 @@ export = { WorkingDirectory: 'a/b/c', }, ], - })); + }); - test.done(); - }, - 'throws when MemoryLimit is less than MemoryReservationLimit'(test: Test) { + }); + + test('throws when MemoryLimit is less than MemoryReservationLimit', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); // THEN - test.throws(() => { + expect(() => { new ecs.ContainerDefinition(stack, 'Container', { image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), taskDefinition, memoryLimitMiB: 512, memoryReservationMiB: 1024, }); - }, /MemoryLimitMiB should not be less than MemoryReservationMiB./); + }).toThrow(/MemoryLimitMiB should not be less than MemoryReservationMiB./); + - test.done(); - }, + }); - 'With network mode AwsVpc': { - 'throws when Host port is different from container port'(test: Test) { + describe('With network mode AwsVpc', () => { + test('throws when Host port is different from container port', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -256,17 +257,17 @@ export = { }); // THEN - test.throws(() => { + expect(() => { container.addPortMappings({ containerPort: 8080, hostPort: 8081, }); - }); + }).toThrow(); - test.done(); - }, - 'Host port is the same as container port'(test: Test) { + }); + + test('Host port is the same as container port', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -284,10 +285,10 @@ export = { }); // THEN no exception raised - test.done(); - }, - 'Host port can be empty '(test: Test) { + }); + + test('Host port can be empty ', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -305,12 +306,12 @@ export = { }); // THEN no exception raised - test.done(); - }, - }, - 'With network mode Host ': { - 'throws when Host port is different from container port'(test: Test) { + }); + }); + + describe('With network mode Host ', () => { + test('throws when Host port is different from container port', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -323,17 +324,17 @@ export = { }); // THEN - test.throws(() => { + expect(() => { container.addPortMappings({ containerPort: 8080, hostPort: 8081, }); - }); + }).toThrow(); - test.done(); - }, - 'when host port is the same as container port'(test: Test) { + }); + + test('when host port is the same as container port', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -351,10 +352,10 @@ export = { }); // THEN no exception raised - test.done(); - }, - 'Host port can be empty '(test: Test) { + }); + + test('Host port can be empty ', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -372,10 +373,10 @@ export = { }); // THEN no exception raised - test.done(); - }, - 'errors when adding links'(test: Test) { + }); + + test('errors when adding links', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -393,16 +394,16 @@ export = { }); // THEN - test.throws(() => { + expect(() => { container.addLink(logger); - }); + }).toThrow(); - test.done(); - }, - }, - 'With network mode Bridge': { - 'when Host port is empty '(test: Test) { + }); + }); + + describe('With network mode Bridge', () => { + test('when Host port is empty ', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -419,10 +420,10 @@ export = { }); // THEN no exception raises - test.done(); - }, - 'when Host port is not empty '(test: Test) { + }); + + test('when Host port is not empty ', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -440,10 +441,10 @@ export = { }); // THEN no exception raises - test.done(); - }, - 'allows adding links'(test: Test) { + }); + + test('allows adding links', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -463,12 +464,12 @@ export = { // THEN container.addLink(logger); - test.done(); - }, - }, - 'With network mode NAT': { - 'produces undefined CF networkMode property'(test: Test) { + }); + }); + + describe('With network mode NAT', () => { + test('produces undefined CF networkMode property', () => { // GIVEN const stack = new cdk.Stack(); @@ -479,22 +480,22 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', (props: any, inspection: InspectionFailure) => { + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', (props: any, inspection: InspectionFailure) => { if (props.NetworkMode === undefined) { return true; } inspection.failureReason = 'CF template should not have NetworkMode defined for a task definition that relies on NAT network mode.'; return false; - })); + }); - test.done(); - }, - }, - }, - 'Container Port': { - 'should return the first container port in PortMappings'(test: Test) { + }); + }); + }); + + describe('Container Port', () => { + test('should return the first container port in PortMappings', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -518,11 +519,11 @@ export = { // THEN const expected = 8080; - test.equal(actual, expected, 'containerPort should return the first container port in PortMappings'); - test.done(); - }, + expect(actual).toEqual(expected); - 'throws when calling containerPort with no PortMappings'(test: Test) { + }); + + test('throws when calling containerPort with no PortMappings', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -535,19 +536,19 @@ export = { }); // THEN - test.throws(() => { + expect(() => { const actual = container.containerPort; const expected = 8080; - test.equal(actual, expected); - }, /Container MyContainer hasn't defined any ports. Call addPortMappings()./); + expect(actual).toEqual(expected); + }).toThrow(/Container MyContainer hasn't defined any ports. Call addPortMappings()./); + - test.done(); - }, - }, + }); + }); - 'Ingress Port': { - 'With network mode AwsVpc': { - 'Ingress port should be the same as container port'(test: Test) { + describe('Ingress Port', () => { + describe('With network mode AwsVpc', () => { + test('Ingress port should be the same as container port', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -567,11 +568,11 @@ export = { // THEN const expected = 8080; - test.equal(actual, expected, 'Ingress port should be the same as container port'); - test.done(); - }, + expect(actual).toEqual(expected); - 'throws when calling ingressPort with no PortMappings'(test: Test) { + }); + + test('throws when calling ingressPort with no PortMappings', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -584,18 +585,18 @@ export = { }); // THEN - test.throws(() => { + expect(() => { const actual = container.ingressPort; const expected = 8080; - test.equal(actual, expected); - }, /Container MyContainer hasn't defined any ports. Call addPortMappings()./); + expect(actual).toEqual(expected); + }).toThrow(/Container MyContainer hasn't defined any ports. Call addPortMappings()./); - test.done(); - }, - }, - 'With network mode Host ': { - 'Ingress port should be the same as container port'(test: Test) { + }); + }); + + describe('With network mode Host ', () => { + test('Ingress port should be the same as container port', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -615,13 +616,13 @@ export = { // THEN const expected = 8080; - test.equal(actual, expected); - test.done(); - }, - }, + expect(actual).toEqual( expected); - 'With network mode Bridge': { - 'Ingress port should be the same as host port if supplied'(test: Test) { + }); + }); + + describe('With network mode Bridge', () => { + test('Ingress port should be the same as host port if supplied', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -642,11 +643,11 @@ export = { // THEN const expected = 8081; - test.equal(actual, expected); - test.done(); - }, + expect(actual).toEqual( expected); + + }); - 'Ingress port should be 0 if not supplied'(test: Test) { + test('Ingress port should be 0 if not supplied', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -666,13 +667,13 @@ export = { // THEN const expected = 0; - test.equal(actual, expected); - test.done(); - }, - }, - }, + expect(actual).toEqual(expected); + + }); + }); + }); - 'can add environment variables to the container definition'(test: Test) { + test('can add environment variables to the container definition', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -687,7 +688,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Environment: [{ @@ -696,15 +697,14 @@ export = { }], }, ], - })); + }); - test.done(); - }, + }); - 'Environment Files': { - 'with EC2 task definitions': { - 'can add asset environment file to the container definition'(test: Test) { + describe('Environment Files', () => { + describe('with EC2 task definitions', () => { + test('can add asset environment file to the container definition', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -717,7 +717,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { EnvironmentFiles: [{ @@ -763,11 +763,11 @@ export = { }], }, ], - })); + }); - test.done(); - }, - 'can add s3 bucket environment file to the container definition'(test: Test) { + + }); + test('can add s3 bucket environment file to the container definition', () => { // GIVEN const stack = new cdk.Stack(); const bucket = new s3.Bucket(stack, 'Bucket', { @@ -783,7 +783,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { EnvironmentFiles: [{ @@ -803,13 +803,13 @@ export = { }], }, ], - })); + }); - test.done(); - }, - }, - 'with Fargate task definitions': { - 'can add asset environment file to the container definition'(test: Test) { + + }); + }); + describe('with Fargate task definitions', () => { + test('can add asset environment file to the container definition', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.FargateTaskDefinition(stack, 'TaskDef'); @@ -822,7 +822,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { EnvironmentFiles: [{ @@ -868,11 +868,11 @@ export = { }], }, ], - })); + }); - test.done(); - }, - 'can add s3 bucket environment file to the container definition'(test: Test) { + + }); + test('can add s3 bucket environment file to the container definition', () => { // GIVEN const stack = new cdk.Stack(); const bucket = new s3.Bucket(stack, 'Bucket', { @@ -888,7 +888,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { EnvironmentFiles: [{ @@ -908,15 +908,15 @@ export = { }], }, ], - })); + }); - test.done(); - }, - }, - }, - 'Given GPU count parameter': { - 'will add resource requirements to container definition'(test: Test) { + }); + }); + }); + + describe('Given GPU count parameter', () => { + test('will add resource requirements to container definition', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -929,7 +929,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Image: 'test', @@ -941,13 +941,13 @@ export = { ], }, ], - })); + }); - test.done(); - }, - }, - 'can add secret environment variables to the container definition'(test: Test) { + }); + }); + + test('can add secret environment variables to the container definition', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -969,7 +969,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Secrets: [ @@ -1005,9 +1005,9 @@ export = { ], }, ], - })); + }); - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -1052,13 +1052,12 @@ export = { ], Version: '2012-10-17', }, - })); + }); - test.done(); - }, + }); - 'use a specific secret JSON key as environment variable'(test: Test) { + test('use a specific secret JSON key as environment variable', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1075,7 +1074,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Secrets: [ @@ -1096,13 +1095,12 @@ export = { ], }, ], - })); + }); - test.done(); - }, + }); - 'use a specific secret JSON field as environment variable for a Fargate task'(test: Test) { + test('use a specific secret JSON field as environment variable for a Fargate task', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.FargateTaskDefinition(stack, 'TaskDef'); @@ -1119,7 +1117,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Secrets: [ @@ -1140,12 +1138,12 @@ export = { ], }, ], - })); + }); + - test.done(); - }, + }); - 'can add AWS logging to container definition'(test: Test) { + test('can add AWS logging to container definition', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1158,7 +1156,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { LogConfiguration: { @@ -1171,9 +1169,9 @@ export = { }, }, ], - })); + }); - expect(stack).to(haveResource('AWS::IAM::Policy', { + expect(stack).toHaveResource('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -1184,12 +1182,12 @@ export = { ], Version: '2012-10-17', }, - })); + }); - test.done(); - }, - 'can set Health Check with defaults'(test: Test) { + }); + + test('can set Health Check with defaults', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1205,7 +1203,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { HealthCheck: { @@ -1216,12 +1214,12 @@ export = { }, }, ], - })); + }); - test.done(); - }, - 'throws when setting Health Check with no commands'(test: Test) { + }); + + test('throws when setting Health Check with no commands', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1236,8 +1234,8 @@ export = { }); // THEN - test.throws(() => { - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(() => { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { HealthCheck: { @@ -1248,13 +1246,13 @@ export = { }, }, ], - })); - }, /At least one argument must be supplied for health check command./); + }); + }).toThrow(/At least one argument must be supplied for health check command./); - test.done(); - }, - 'can specify Health Check values in shell form'(test: Test) { + }); + + test('can specify Health Check values in shell form', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1273,7 +1271,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { HealthCheck: { @@ -1285,12 +1283,12 @@ export = { }, }, ], - })); + }); - test.done(); - }, - 'can specify Health Check values in array form starting with CMD-SHELL'(test: Test) { + }); + + test('can specify Health Check values in array form starting with CMD-SHELL', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1309,7 +1307,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { HealthCheck: { @@ -1321,12 +1319,12 @@ export = { }, }, ], - })); + }); + - test.done(); - }, + }); - 'can specify Health Check values in array form starting with CMD'(test: Test) { + test('can specify Health Check values in array form starting with CMD', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1345,7 +1343,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { HealthCheck: { @@ -1357,12 +1355,12 @@ export = { }, }, ], - })); + }); + - test.done(); - }, + }); - 'can specify private registry credentials'(test: Test) { + test('can specify private registry credentials', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1379,7 +1377,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Image: 'user-x/my-app', @@ -1388,9 +1386,9 @@ export = { }, }, ], - })); + }); - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -1403,13 +1401,13 @@ export = { }, ], }, - })); + }); - test.done(); - }, - '_linkContainer works properly': { - 'when the props passed in is an essential container'(test: Test) { + }); + + describe('_linkContainer works properly', () => { + test('when the props passed in is an essential container', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1422,12 +1420,12 @@ export = { }); // THEN - test.equal(taskDefinition.defaultContainer, container); + expect(taskDefinition.defaultContainer).toEqual( container); + - test.done(); - }, + }); - 'when the props passed in is not an essential container'(test: Test) { + test('when the props passed in is not an essential container', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1440,14 +1438,14 @@ export = { }); // THEN - test.equal(taskDefinition.defaultContainer, undefined); + expect(taskDefinition.defaultContainer).toEqual( undefined); + - test.done(); - }, - }, + }); + }); - 'Can specify linux parameters': { - 'with only required properties set, it correctly sets default properties'(test: Test) { + describe('Can specify linux parameters', () => { + test('with only required properties set, it correctly sets default properties', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1462,7 +1460,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Image: 'test', @@ -1471,12 +1469,12 @@ export = { }, }, ], - })); + }); - test.done(); - }, - 'before calling addContainer'(test: Test) { + }); + + test('before calling addContainer', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1497,7 +1495,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Image: 'test', @@ -1511,12 +1509,12 @@ export = { }, }, ], - })); + }); - test.done(); - }, - 'after calling addContainer'(test: Test) { + }); + + test('after calling addContainer', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1539,7 +1537,7 @@ export = { linuxParameters.dropCapabilities(ecs.Capability.SETUID); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Image: 'test', @@ -1553,12 +1551,12 @@ export = { }, }, ], - })); + }); + - test.done(); - }, + }); - 'with one or more host devices'(test: Test) { + test('with one or more host devices', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1580,7 +1578,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Image: 'test', @@ -1595,12 +1593,12 @@ export = { }, }, ], - })); + }); - test.done(); - }, - 'with the tmpfs mount for a container'(test: Test) { + }); + + test('with the tmpfs mount for a container', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1623,7 +1621,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Image: 'test', @@ -1639,19 +1637,14 @@ export = { }, }, ], - })); + }); - test.done(); - }, - }, - 'can use a DockerImageAsset directly for a container image'(test: Test) { - // GIVEN - const app = new cdk.App({ - context: { - '@aws-cdk/aws-ecr-assets:dockerIgnoreSupport': true, - }, }); + }); + + testFutureBehavior('can use a DockerImageAsset directly for a container image', { '@aws-cdk/aws-ecr-assets:dockerIgnoreSupport': true }, cdk.App, (app) => { + // GIVEN const stack = new cdk.Stack(app, 'Stack'); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); const asset = new ecr_assets.DockerImageAsset(stack, 'MyDockerImage', { @@ -1665,7 +1658,7 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Essential: true, @@ -1686,8 +1679,8 @@ export = { Name: 'default', }, ], - })); - expect(stack).to(haveResource('AWS::IAM::Policy', { + }); + expect(stack).toHaveResource('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -1712,17 +1705,12 @@ export = { ], Version: '2012-10-17', }, - })); - test.done(); - }, + }); - 'docker image asset options can be used when using container image'(test: Test) { + }); + + testFutureBehavior('docker image asset options can be used when using container image', { '@aws-cdk/aws-ecr-assets:dockerIgnoreSupport': true }, cdk.App, (app) => { // GIVEN - const app = new cdk.App({ - context: { - '@aws-cdk/aws-ecr-assets:dockerIgnoreSupport': true, - }, - }); const stack = new cdk.Stack(app, 'MyStack'); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1737,7 +1725,7 @@ export = { // THEN const asm = app.synth(); - test.deepEqual(asm.getStackArtifact(stack.artifactId).assets[0], { + expect(asm.getStackArtifact(stack.artifactId).assets[0]).toEqual({ repositoryName: 'aws-cdk/assets', imageTag: 'ce3419d7c5d2d44e2789b13ccbd2d54ddf682557669f68bcee753231f5f1c0a5', id: 'ce3419d7c5d2d44e2789b13ccbd2d54ddf682557669f68bcee753231f5f1c0a5', @@ -1747,6 +1735,6 @@ export = { target: 'build-target', file: 'index.py', }); - test.done(); - }, -}; + + }); +}); diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/test.cross-stack.ts b/packages/@aws-cdk/aws-ecs/test/ec2/cross-stack.test.ts similarity index 97% rename from packages/@aws-cdk/aws-ecs/test/ec2/test.cross-stack.ts rename to packages/@aws-cdk/aws-ecs/test/ec2/cross-stack.test.ts index 5eb7c61a6d346..12d908957fc88 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/test.cross-stack.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/cross-stack.test.ts @@ -2,7 +2,7 @@ import { expect, haveResource } from '@aws-cdk/assert'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import { App, Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../../lib'; // Test various cross-stack Cluster/Service/ALB scenario's @@ -13,7 +13,7 @@ let stack2: Stack; let cluster: ecs.Cluster; let service: ecs.Ec2Service; -export = { +nodeunitShim({ 'setUp'(cb: () => void) { app = new App(); @@ -89,7 +89,7 @@ export = { test.done(); }, -}; +}); function expectIngress(stack: Stack) { expect(stack).to(haveResource('AWS::EC2::SecurityGroupIngress', { diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-service.ts b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-service.test.ts similarity index 99% rename from packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-service.ts rename to packages/@aws-cdk/aws-ecs/test/ec2/ec2-service.test.ts index c4b2816234595..2279245aebaa4 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-service.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-service.test.ts @@ -4,12 +4,12 @@ import * as elb from '@aws-cdk/aws-elasticloadbalancing'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import * as cloudmap from '@aws-cdk/aws-servicediscovery'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../../lib'; import { DeploymentControllerType, LaunchType, PropagatedTagSource } from '../../lib/base/base-service'; import { PlacementConstraint, PlacementStrategy } from '../../lib/placement'; -export = { +nodeunitShim({ 'When creating an EC2 Service': { 'with only required properties set, it correctly sets default properties'(test: Test) { // GIVEN @@ -2269,4 +2269,4 @@ export = { test.done(); }, }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-task-definition.ts b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts similarity index 84% rename from packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-task-definition.ts rename to packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts index 9264c47e4550c..bea2e3c0733e5 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-task-definition.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts @@ -1,33 +1,33 @@ +import '@aws-cdk/assert/jest'; import * as path from 'path'; -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; import { Protocol } from '@aws-cdk/aws-ec2'; import { Repository } from '@aws-cdk/aws-ecr'; import * as iam from '@aws-cdk/aws-iam'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; import * as ssm from '@aws-cdk/aws-ssm'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; import * as ecs from '../../lib'; -export = { - 'When creating an ECS TaskDefinition': { - 'with only required properties set, it correctly sets default properties'(test: Test) { +describe('ec2 task definition', () => { + describe('When creating an ECS TaskDefinition', () => { + test('with only required properties set, it correctly sets default properties', () => { // GIVEN const stack = new cdk.Stack(); new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef'); // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { Family: 'Ec2TaskDef', NetworkMode: ecs.NetworkMode.BRIDGE, RequiresCompatibilities: ['EC2'], - })); + }); // test error if no container defs? - test.done(); - }, - 'with all properties set'(test: Test) { + }); + + test('with all properties set', () => { // GIVEN const stack = new cdk.Stack(); new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { @@ -55,7 +55,7 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { ExecutionRoleArn: { 'Fn::GetAtt': [ 'ExecutionRole605A040B', @@ -89,12 +89,12 @@ export = { Name: 'scratch', }, ], - })); + }); - test.done(); - }, - 'correctly sets placement constraint'(test: Test) { + }); + + test('correctly sets placement constraint', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef'); @@ -103,7 +103,7 @@ export = { taskDefinition.addPlacementConstraint(ecs.PlacementConstraint.memberOf('attribute:ecs.instance-type =~ t2.*')); // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { PlacementConstraints: [ { Expression: 'attribute:ecs.instance-type =~ t2.*', @@ -111,12 +111,12 @@ export = { }, ], - })); + }); - test.done(); - }, - 'correctly sets network mode'(test: Test) { + }); + + test('correctly sets network mode', () => { // GIVEN const stack = new cdk.Stack(); new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { @@ -124,14 +124,14 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { NetworkMode: ecs.NetworkMode.AWS_VPC, - })); + }); + - test.done(); - }, + }); - 'correctly sets ipc mode'(test: Test) { + test('correctly sets ipc mode', () => { // GIVEN const stack = new cdk.Stack(); new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { @@ -139,14 +139,14 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { IpcMode: ecs.IpcMode.TASK, - })); + }); + - test.done(); - }, + }); - 'correctly sets pid mode'(test: Test) { + test('correctly sets pid mode', () => { // GIVEN const stack = new cdk.Stack(); new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { @@ -154,14 +154,14 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { PidMode: ecs.PidMode.HOST, - })); + }); + - test.done(); - }, + }); - 'correctly sets containers'(test: Test) { + test('correctly sets containers', () => { // GIVEN const stack = new cdk.Stack(); @@ -193,7 +193,7 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { Family: 'Ec2TaskDef', ContainerDefinitions: [{ Essential: true, @@ -219,9 +219,9 @@ export = { }, ], }], - })); + }); - expect(stack).to(haveResource('AWS::IAM::Policy', { + expect(stack).toHaveResource('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [ @@ -232,12 +232,12 @@ export = { }, ], }, - })); + }); - test.done(); - }, - 'all container definition options defined'(test: Test) { + }); + + test('all container definition options defined', () => { // GIVEN const stack = new cdk.Stack(); @@ -287,7 +287,7 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { Family: 'Ec2TaskDef', ContainerDefinitions: [ { @@ -434,12 +434,12 @@ export = { WorkingDirectory: 'app/', }, ], - })); + }); - test.done(); - }, - 'correctly sets containers from ECR repository using all props'(test: Test) { + }); + + test('correctly sets containers from ECR repository using all props', () => { // GIVEN const stack = new cdk.Stack(); @@ -460,16 +460,16 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', { + expect(stack).toHaveResource('AWS::ECR::Repository', { LifecyclePolicy: { // eslint-disable-next-line max-len LifecyclePolicyText: '{"rules":[{"rulePriority":10,"selection":{"tagStatus":"tagged","tagPrefixList":["abc"],"countType":"imageCountMoreThan","countNumber":1},"action":{"type":"expire"}}]}', RegistryId: '123456789101', }, RepositoryName: 'project-a/amazon-ecs-sample', - })); + }); - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { Family: 'Ec2TaskDef', ContainerDefinitions: [{ Essential: true, @@ -525,12 +525,12 @@ export = { }, Name: 'web', }], - })); + }); + - test.done(); - }, + }); - 'correctly sets containers from ECR repository using default props'(test: Test) { + test('correctly sets containers from ECR repository using default props', () => { // GIVEN const stack = new cdk.Stack(); @@ -543,12 +543,12 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', {})); + expect(stack).toHaveResource('AWS::ECR::Repository', {}); + - test.done(); - }, + }); - 'warns when setting containers from ECR repository using fromRegistry method'(test: Test) { + test('warns when setting containers from ECR repository using fromRegistry method', () => { // GIVEN const stack = new cdk.Stack(); @@ -561,11 +561,11 @@ export = { }); // THEN - test.deepEqual(container.node.metadata[0].data, "Proper policies need to be attached before pulling from ECR repository, or use 'fromEcrRepository'."); - test.done(); - }, + expect(container.node.metadata[0].data).toEqual("Proper policies need to be attached before pulling from ECR repository, or use 'fromEcrRepository'."); - 'warns when setting containers from ECR repository by creating a RepositoryImage class'(test: Test) { + }); + + test('warns when setting containers from ECR repository by creating a RepositoryImage class', () => { // GIVEN const stack = new cdk.Stack(); @@ -580,18 +580,13 @@ export = { }); // THEN - test.deepEqual(container.node.metadata[0].data, "Proper policies need to be attached before pulling from ECR repository, or use 'fromEcrRepository'."); + expect(container.node.metadata[0].data).toEqual("Proper policies need to be attached before pulling from ECR repository, or use 'fromEcrRepository'."); + - test.done(); - }, + }); - 'correctly sets containers from asset using default props'(test: Test) { + testFutureBehavior('correctly sets containers from asset using default props', { '@aws-cdk/aws-ecr-assets:dockerIgnoreSupport': true }, cdk.App, (app) => { // GIVEN - const app = new cdk.App({ - context: { - '@aws-cdk/aws-ecr-assets:dockerIgnoreSupport': true, - }, - }); const stack = new cdk.Stack(app, 'Stack'); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef'); @@ -603,7 +598,7 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { Family: 'StackEc2TaskDefF03698CF', ContainerDefinitions: [ { @@ -631,12 +626,12 @@ export = { Name: 'web', }, ], - })); + }); + - test.done(); - }, + }); - 'correctly sets containers from asset using all props'(test: Test) { + test('correctly sets containers from asset using all props', () => { // GIVEN const stack = new cdk.Stack(); @@ -649,10 +644,10 @@ export = { memoryLimitMiB: 512, }); - test.done(); - }, - 'correctly sets scratch space'(test: Test) { + }); + + test('correctly sets scratch space', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef'); @@ -670,7 +665,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { Family: 'Ec2TaskDef', ContainerDefinitions: [{ MountPoints: [ @@ -687,11 +682,11 @@ export = { }, Name: 'scratch', }], - })); + }); - test.done(); - }, - 'correctly sets container dependenices'(test: Test) { + + }); + test('correctly sets container dependenices', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef'); @@ -721,7 +716,7 @@ export = { ); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { Family: 'Ec2TaskDef', ContainerDefinitions: [{ Name: 'dependency1', @@ -740,11 +735,11 @@ export = { ContainerName: 'dependency2', }], }], - })); + }); + - test.done(); - }, - 'correctly sets links'(test: Test) { + }); + test('correctly sets links', () => { const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { @@ -770,7 +765,7 @@ export = { container.addLink(linkedContainer2); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Links: [ @@ -786,12 +781,12 @@ export = { Name: 'linked2', }, ], - })); + }); + - test.done(); - }, + }); - 'correctly set policy statement to the task IAM role'(test: Test) { + test('correctly set policy statement to the task IAM role', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef'); @@ -803,7 +798,7 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::IAM::Policy', { + expect(stack).toHaveResource('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [ @@ -814,11 +809,11 @@ export = { }, ], }, - })); + }); + - test.done(); - }, - 'correctly sets volumes from'(test: Test) { + }); + test('correctly sets volumes from', () => { const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', {}); @@ -834,7 +829,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [{ VolumesFrom: [ { @@ -843,12 +838,12 @@ export = { }, ], }], - })); + }); - test.done(); - }, - 'correctly set policy statement to the task execution IAM role'(test: Test) { + }); + + test('correctly set policy statement to the task execution IAM role', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef'); @@ -860,7 +855,7 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::IAM::Policy', { + expect(stack).toHaveResource('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [ @@ -871,12 +866,12 @@ export = { }, ], }, - })); + }); + - test.done(); - }, + }); - 'correctly sets volumes'(test: Test) { + test('correctly sets volumes', () => { // GIVEN const stack = new cdk.Stack(); const volume = { @@ -904,7 +899,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { Family: 'Ec2TaskDef', ContainerDefinitions: [{ MountPoints: [ @@ -921,12 +916,12 @@ export = { }, Name: 'scratch', }], - })); + }); - test.done(); - }, - 'correctly sets placement constraints'(test: Test) { + }); + + test('correctly sets placement constraints', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { @@ -941,19 +936,19 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { PlacementConstraints: [ { Expression: 'attribute:ecs.instance-type =~ t2.*', Type: 'memberOf', }, ], - })); + }); - test.done(); - }, - 'correctly sets taskRole'(test: Test) { + }); + + test('correctly sets taskRole', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { @@ -968,27 +963,27 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { TaskRoleArn: stack.resolve(taskDefinition.taskRole.roleArn), - })); + }); - test.done(); - }, - 'automatically sets taskRole by default'(test: Test) { + }); + + test('automatically sets taskRole by default', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef'); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { TaskRoleArn: stack.resolve(taskDefinition.taskRole.roleArn), - })); + }); + - test.done(); - }, + }); - 'correctly sets dockerVolumeConfiguration'(test: Test) { + test('correctly sets dockerVolumeConfiguration', () => { // GIVEN const stack = new cdk.Stack(); const volume = { @@ -1012,7 +1007,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { Family: 'Ec2TaskDef', Volumes: [{ Name: 'scratch', @@ -1024,12 +1019,12 @@ export = { }, }, }], - })); + }); + - test.done(); - }, + }); - 'correctly sets efsVolumeConfiguration'(test: Test) { + test('correctly sets efsVolumeConfiguration', () => { // GIVEN const stack = new cdk.Stack(); const volume = { @@ -1049,7 +1044,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { Family: 'Ec2TaskDef', Volumes: [{ Name: 'scratch', @@ -1057,13 +1052,13 @@ export = { FileSystemId: 'local', }, }], - })); + }); - test.done(); - }, - }, - 'throws when setting proxyConfiguration without networkMode AWS_VPC'(test: Test) { + }); + }); + + test('throws when setting proxyConfiguration without networkMode AWS_VPC', () => { // GIVEN const stack = new cdk.Stack(); @@ -1079,10 +1074,10 @@ export = { }); // THEN - test.throws(() => { + expect(() => { new ecs.Ec2TaskDefinition(stack, 'TaskDef', { networkMode: ecs.NetworkMode.BRIDGE, proxyConfiguration }); - }, /ProxyConfiguration can only be used with AwsVpc network mode, got: bridge/); + }).toThrow(/ProxyConfiguration can only be used with AwsVpc network mode, got: bridge/); + - test.done(); - }, -}; + }); +}); diff --git a/packages/@aws-cdk/aws-ecs/test/test.ecs-cluster.ts b/packages/@aws-cdk/aws-ecs/test/ecs-cluster.test.ts similarity index 99% rename from packages/@aws-cdk/aws-ecs/test/test.ecs-cluster.ts rename to packages/@aws-cdk/aws-ecs/test/ecs-cluster.test.ts index 7741c6b5bdb9f..119e6d11a93ce 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.ecs-cluster.ts +++ b/packages/@aws-cdk/aws-ecs/test/ecs-cluster.test.ts @@ -9,10 +9,10 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as kms from '@aws-cdk/aws-kms'; import * as cloudmap from '@aws-cdk/aws-servicediscovery'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; -export = { +nodeunitShim({ 'When creating an ECS Cluster': { 'with no properties set, it correctly sets default properties'(test: Test) { // GIVEN @@ -1731,4 +1731,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/test.environment-file.ts b/packages/@aws-cdk/aws-ecs/test/environment-file.test.ts similarity index 96% rename from packages/@aws-cdk/aws-ecs/test/test.environment-file.ts rename to packages/@aws-cdk/aws-ecs/test/environment-file.test.ts index a0d6fc29d3aed..e80651cbbd65b 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.environment-file.ts +++ b/packages/@aws-cdk/aws-ecs/test/environment-file.test.ts @@ -1,11 +1,11 @@ import * as path from 'path'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; /* eslint-disable dot-notation */ -export = { +nodeunitShim({ 'ecs.EnvironmentFile.fromAsset': { 'fails if asset is not a single file'(test: Test) { // GIVEN @@ -45,7 +45,7 @@ export = { test.done(); }, }, -}; +}); function defineContainerDefinition(stack: cdk.Stack, environmentFile: ecs.EnvironmentFile) { const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/test.fargate-service.ts b/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts similarity index 99% rename from packages/@aws-cdk/aws-ecs/test/fargate/test.fargate-service.ts rename to packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts index ebb36580d19ba..acddf713d6d0a 100644 --- a/packages/@aws-cdk/aws-ecs/test/fargate/test.fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts @@ -6,11 +6,11 @@ import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; import * as cloudmap from '@aws-cdk/aws-servicediscovery'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../../lib'; import { DeploymentControllerType, LaunchType } from '../../lib/base/base-service'; -export = { +nodeunitShim({ 'When creating a Fargate Service': { 'with only required properties set, it correctly sets default properties'(test: Test) { // GIVEN @@ -1935,4 +1935,4 @@ export = { test.done(); }, }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/test.fargate-task-definition.ts b/packages/@aws-cdk/aws-ecs/test/fargate/fargate-task-definition.test.ts similarity index 97% rename from packages/@aws-cdk/aws-ecs/test/fargate/test.fargate-task-definition.ts rename to packages/@aws-cdk/aws-ecs/test/fargate/fargate-task-definition.test.ts index 99aeb6da886f9..00ec0028ef1a3 100644 --- a/packages/@aws-cdk/aws-ecs/test/fargate/test.fargate-task-definition.ts +++ b/packages/@aws-cdk/aws-ecs/test/fargate/fargate-task-definition.test.ts @@ -1,10 +1,10 @@ import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../../lib'; -export = { +nodeunitShim({ 'When creating an Fargate TaskDefinition': { 'with only required properties set, it correctly sets default properties'(test: Test) { // GIVEN @@ -114,4 +114,4 @@ export = { test.done(); }, }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/test.firelens-log-driver.ts b/packages/@aws-cdk/aws-ecs/test/firelens-log-driver.test.ts similarity index 98% rename from packages/@aws-cdk/aws-ecs/test/test.firelens-log-driver.ts rename to packages/@aws-cdk/aws-ecs/test/firelens-log-driver.test.ts index 3a1fb264d6b34..99a1c6b935b64 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.firelens-log-driver.ts +++ b/packages/@aws-cdk/aws-ecs/test/firelens-log-driver.test.ts @@ -1,13 +1,13 @@ import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; let stack: cdk.Stack; let td: ecs.TaskDefinition; const image = ecs.ContainerImage.fromRegistry('test-image'); -export = { +nodeunitShim({ 'setUp'(cb: () => void) { stack = new cdk.Stack(); td = new ecs.Ec2TaskDefinition(stack, 'TaskDefinition'); @@ -229,4 +229,4 @@ export = { test.done(); }, }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/test.fluentd-log-driver.ts b/packages/@aws-cdk/aws-ecs/test/fluentd-log-driver.test.ts similarity index 97% rename from packages/@aws-cdk/aws-ecs/test/test.fluentd-log-driver.ts rename to packages/@aws-cdk/aws-ecs/test/fluentd-log-driver.test.ts index 5d451ec365683..a317699d1075d 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.fluentd-log-driver.ts +++ b/packages/@aws-cdk/aws-ecs/test/fluentd-log-driver.test.ts @@ -1,13 +1,13 @@ import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; let stack: cdk.Stack; let td: ecs.TaskDefinition; const image = ecs.ContainerImage.fromRegistry('test-image'); -export = { +nodeunitShim({ 'setUp'(cb: () => void) { stack = new cdk.Stack(); td = new ecs.Ec2TaskDefinition(stack, 'TaskDefinition'); @@ -138,4 +138,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/test.gelf-log-driver.ts b/packages/@aws-cdk/aws-ecs/test/gelf-log-driver.test.ts similarity index 95% rename from packages/@aws-cdk/aws-ecs/test/test.gelf-log-driver.ts rename to packages/@aws-cdk/aws-ecs/test/gelf-log-driver.test.ts index f62941f010f59..7907b0532b0ac 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.gelf-log-driver.ts +++ b/packages/@aws-cdk/aws-ecs/test/gelf-log-driver.test.ts @@ -1,13 +1,13 @@ import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; let stack: cdk.Stack; let td: ecs.TaskDefinition; const image = ecs.ContainerImage.fromRegistry('test-image'); -export = { +nodeunitShim({ 'setUp'(cb: () => void) { stack = new cdk.Stack(); td = new ecs.Ec2TaskDefinition(stack, 'TaskDefinition'); @@ -68,4 +68,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/images/test.tag-parameter-container-image.ts b/packages/@aws-cdk/aws-ecs/test/images/tag-parameter-container-image.test.ts similarity index 91% rename from packages/@aws-cdk/aws-ecs/test/images/test.tag-parameter-container-image.ts rename to packages/@aws-cdk/aws-ecs/test/images/tag-parameter-container-image.test.ts index 2a96c471b1417..d0fe101252e26 100644 --- a/packages/@aws-cdk/aws-ecs/test/images/test.tag-parameter-container-image.ts +++ b/packages/@aws-cdk/aws-ecs/test/images/tag-parameter-container-image.test.ts @@ -1,10 +1,10 @@ import { SynthUtils } from '@aws-cdk/assert'; import * as ecr from '@aws-cdk/aws-ecr'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../../lib'; -export = { +nodeunitShim({ 'TagParameter container image': { 'throws an error when tagParameterName() is used without binding the image'(test: Test) { // GIVEN @@ -22,4 +22,4 @@ export = { test.done(); }, }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/test.journald-log-driver.ts b/packages/@aws-cdk/aws-ecs/test/journald-log-driver.test.ts similarity index 96% rename from packages/@aws-cdk/aws-ecs/test/test.journald-log-driver.ts rename to packages/@aws-cdk/aws-ecs/test/journald-log-driver.test.ts index f71d796b6d380..31bec4a42e47f 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.journald-log-driver.ts +++ b/packages/@aws-cdk/aws-ecs/test/journald-log-driver.test.ts @@ -1,13 +1,13 @@ import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; let stack: cdk.Stack; let td: ecs.TaskDefinition; const image = ecs.ContainerImage.fromRegistry('test-image'); -export = { +nodeunitShim({ 'setUp'(cb: () => void) { stack = new cdk.Stack(); td = new ecs.Ec2TaskDefinition(stack, 'TaskDefinition'); @@ -86,4 +86,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/test.json-file-log-driver.ts b/packages/@aws-cdk/aws-ecs/test/json-file-log-driver.test.ts similarity index 96% rename from packages/@aws-cdk/aws-ecs/test/test.json-file-log-driver.ts rename to packages/@aws-cdk/aws-ecs/test/json-file-log-driver.test.ts index c7e3f6acec377..e75ff398eeb03 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.json-file-log-driver.ts +++ b/packages/@aws-cdk/aws-ecs/test/json-file-log-driver.test.ts @@ -1,13 +1,13 @@ import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; let stack: cdk.Stack; let td: ecs.TaskDefinition; const image = ecs.ContainerImage.fromRegistry('test-image'); -export = { +nodeunitShim({ 'setUp'(cb: () => void) { stack = new cdk.Stack(); td = new ecs.Ec2TaskDefinition(stack, 'TaskDefinition'); @@ -86,4 +86,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/test.splunk-log-driver.ts b/packages/@aws-cdk/aws-ecs/test/splunk-log-driver.test.ts similarity index 97% rename from packages/@aws-cdk/aws-ecs/test/test.splunk-log-driver.ts rename to packages/@aws-cdk/aws-ecs/test/splunk-log-driver.test.ts index 960f3b749f183..c8afd01daade1 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.splunk-log-driver.ts +++ b/packages/@aws-cdk/aws-ecs/test/splunk-log-driver.test.ts @@ -1,13 +1,13 @@ import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; let stack: cdk.Stack; let td: ecs.TaskDefinition; const image = ecs.ContainerImage.fromRegistry('test-image'); -export = { +nodeunitShim({ 'setUp'(cb: () => void) { stack = new cdk.Stack(); td = new ecs.Ec2TaskDefinition(stack, 'TaskDefinition'); @@ -103,4 +103,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/test.syslog-log-driver.ts b/packages/@aws-cdk/aws-ecs/test/syslog-log-driver.test.ts similarity index 96% rename from packages/@aws-cdk/aws-ecs/test/test.syslog-log-driver.ts rename to packages/@aws-cdk/aws-ecs/test/syslog-log-driver.test.ts index cde1a2a6b1b63..b14c05a5b3234 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.syslog-log-driver.ts +++ b/packages/@aws-cdk/aws-ecs/test/syslog-log-driver.test.ts @@ -1,13 +1,13 @@ import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; let stack: cdk.Stack; let td: ecs.TaskDefinition; const image = ecs.ContainerImage.fromRegistry('test-image'); -export = { +nodeunitShim({ 'setUp'(cb: () => void) { stack = new cdk.Stack(); td = new ecs.Ec2TaskDefinition(stack, 'TaskDefinition'); @@ -86,4 +86,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/test.task-definition.ts b/packages/@aws-cdk/aws-ecs/test/task-definition.test.ts similarity index 88% rename from packages/@aws-cdk/aws-ecs/test/test.task-definition.ts rename to packages/@aws-cdk/aws-ecs/test/task-definition.test.ts index 299e2f81b0651..34a7306106d66 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.task-definition.ts +++ b/packages/@aws-cdk/aws-ecs/test/task-definition.test.ts @@ -1,9 +1,9 @@ import { expect, haveResource } from '@aws-cdk/assert'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; -export = { +nodeunitShim({ 'A task definition with both compatibilities defaults to networkmode AwsVpc'(test: Test) { // GIVEN const stack = new cdk.Stack(); @@ -22,4 +22,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-eks/README.md b/packages/@aws-cdk/aws-eks/README.md index ee758461b986f..59909c9ea9a0b 100644 --- a/packages/@aws-cdk/aws-eks/README.md +++ b/packages/@aws-cdk/aws-eks/README.md @@ -466,6 +466,8 @@ const cluster = new eks.Cluster(this, 'hello-eks', { }); ``` +The default value is `eks.EndpointAccess.PUBLIC_AND_PRIVATE`. Which means the cluster endpoint is accessible from outside of your VPC, but worker node traffic and `kubectl` commands issued by this library stay within your VPC. + ### VPC Support You can specify the VPC of the cluster using the `vpc` and `vpcSubnets` properties: @@ -634,8 +636,6 @@ $ aws eks update-kubeconfig --name cluster-xxxxx --role-arn arn:aws:iam::1122334 Added new context arn:aws:eks:rrrrr:112233445566:cluster/cluster-xxxxx to /home/boom/.kube/config ``` -The default value is `eks.EndpointAccess.PUBLIC_AND_PRIVATE`. Which means the cluster endpoint is accessible from outside of your VPC, but worker node traffic and `kubectl` commands issued by this library stay within your VPC. - ### Encryption When you create an Amazon EKS cluster, envelope encryption of Kubernetes secrets using the AWS Key Management Service (AWS KMS) can be enabled. diff --git a/packages/@aws-cdk/aws-eks/lib/kubectl-provider.ts b/packages/@aws-cdk/aws-eks/lib/kubectl-provider.ts index e4c71cfda381c..b5bd8ed51b876 100644 --- a/packages/@aws-cdk/aws-eks/lib/kubectl-provider.ts +++ b/packages/@aws-cdk/aws-eks/lib/kubectl-provider.ts @@ -106,6 +106,7 @@ export class KubectlProvider extends NestedStack { onEventHandler: handler, vpc: cluster.kubectlPrivateSubnets ? cluster.vpc : undefined, vpcSubnets: cluster.kubectlPrivateSubnets ? { subnets: cluster.kubectlPrivateSubnets } : undefined, + securityGroups: cluster.kubectlSecurityGroup ? [cluster.kubectlSecurityGroup] : undefined, }); this.serviceToken = provider.serviceToken; diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.expected.json index e15fc8ae19bea..e7e1f394cdc7f 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.expected.json @@ -1179,7 +1179,9 @@ "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "awscdkawseksKubectlProviderNestedStackawscdkawseksKubectlProviderNestedStackResourceA7AEBA6B": { "Type": "AWS::CloudFormation::Stack", @@ -1194,7 +1196,7 @@ }, "/", { - "Ref": "AssetParameters3a065cef8968eb7f7e62ccb379c68400a56c31aceb97265d4e8f5f4620452db9S3Bucket7930790A" + "Ref": "AssetParameters93bb4c1c6bbced2c1adce602d7643d5475c6e463f4f57f4cd863e064d82a3d82S3Bucket8670C328" }, "/", { @@ -1204,7 +1206,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters3a065cef8968eb7f7e62ccb379c68400a56c31aceb97265d4e8f5f4620452db9S3VersionKey648E56F4" + "Ref": "AssetParameters93bb4c1c6bbced2c1adce602d7643d5475c6e463f4f57f4cd863e064d82a3d82S3VersionKeyCEFB3AF5" } ] } @@ -1217,7 +1219,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters3a065cef8968eb7f7e62ccb379c68400a56c31aceb97265d4e8f5f4620452db9S3VersionKey648E56F4" + "Ref": "AssetParameters93bb4c1c6bbced2c1adce602d7643d5475c6e463f4f57f4cd863e064d82a3d82S3VersionKeyCEFB3AF5" } ] } @@ -1272,9 +1274,6 @@ "referencetoawscdkekshandlersinvpctestAssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyCE91E7FDRef": { "Ref": "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyF55A2EA9" }, - "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStackDefaultVpcE40EA7ACRef": { - "Ref": "EksAllHandlersInVpcStackDefaultVpcBE11D4AE" - }, "referencetoawscdkekshandlersinvpctestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket9D7E9998Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" }, @@ -1282,7 +1281,9 @@ "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Outputs": { @@ -1400,17 +1401,17 @@ "Type": "String", "Description": "Artifact hash for asset \"70396475d85a52e5c6ccad77894979d07433a207ea3c2668b929f3e70ffde081\"" }, - "AssetParameters3a065cef8968eb7f7e62ccb379c68400a56c31aceb97265d4e8f5f4620452db9S3Bucket7930790A": { + "AssetParameters93bb4c1c6bbced2c1adce602d7643d5475c6e463f4f57f4cd863e064d82a3d82S3Bucket8670C328": { "Type": "String", - "Description": "S3 bucket for asset \"3a065cef8968eb7f7e62ccb379c68400a56c31aceb97265d4e8f5f4620452db9\"" + "Description": "S3 bucket for asset \"93bb4c1c6bbced2c1adce602d7643d5475c6e463f4f57f4cd863e064d82a3d82\"" }, - "AssetParameters3a065cef8968eb7f7e62ccb379c68400a56c31aceb97265d4e8f5f4620452db9S3VersionKey648E56F4": { + "AssetParameters93bb4c1c6bbced2c1adce602d7643d5475c6e463f4f57f4cd863e064d82a3d82S3VersionKeyCEFB3AF5": { "Type": "String", - "Description": "S3 key for asset version \"3a065cef8968eb7f7e62ccb379c68400a56c31aceb97265d4e8f5f4620452db9\"" + "Description": "S3 key for asset version \"93bb4c1c6bbced2c1adce602d7643d5475c6e463f4f57f4cd863e064d82a3d82\"" }, - "AssetParameters3a065cef8968eb7f7e62ccb379c68400a56c31aceb97265d4e8f5f4620452db9ArtifactHash66195F00": { + "AssetParameters93bb4c1c6bbced2c1adce602d7643d5475c6e463f4f57f4cd863e064d82a3d82ArtifactHashBEC324DA": { "Type": "String", - "Description": "Artifact hash for asset \"3a065cef8968eb7f7e62ccb379c68400a56c31aceb97265d4e8f5f4620452db9\"" + "Description": "Artifact hash for asset \"93bb4c1c6bbced2c1adce602d7643d5475c6e463f4f57f4cd863e064d82a3d82\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.expected.json index 61915b6442bd0..acbe47374bead 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.expected.json @@ -1100,7 +1100,9 @@ "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "awscdkawseksKubectlProviderNestedStackawscdkawseksKubectlProviderNestedStackResourceA7AEBA6B": { "Type": "AWS::CloudFormation::Stack", @@ -1115,7 +1117,7 @@ }, "/", { - "Ref": "AssetParameterseb49ce353c5ff251ebe2c3225fe00fb3e9a68fcd8b10207e63a36bfc6e981519S3Bucket686DCA97" + "Ref": "AssetParameters8d4ffe9194a1ca97e2e9377049ddbeb3adbdaa984c8a90c08a5d8d6b328bdf7cS3BucketFEA5F85E" }, "/", { @@ -1125,7 +1127,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameterseb49ce353c5ff251ebe2c3225fe00fb3e9a68fcd8b10207e63a36bfc6e981519S3VersionKey7EDC0140" + "Ref": "AssetParameters8d4ffe9194a1ca97e2e9377049ddbeb3adbdaa984c8a90c08a5d8d6b328bdf7cS3VersionKey226CF52C" } ] } @@ -1138,7 +1140,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameterseb49ce353c5ff251ebe2c3225fe00fb3e9a68fcd8b10207e63a36bfc6e981519S3VersionKey7EDC0140" + "Ref": "AssetParameters8d4ffe9194a1ca97e2e9377049ddbeb3adbdaa984c8a90c08a5d8d6b328bdf7cS3VersionKey226CF52C" } ] } @@ -1193,9 +1195,6 @@ "referencetoawscdkeksclusterprivateendpointtestAssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKey548D79B4Ref": { "Ref": "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyF55A2EA9" }, - "referencetoawscdkeksclusterprivateendpointtestVpcFCD064BFRef": { - "Ref": "Vpc8378EB38" - }, "referencetoawscdkeksclusterprivateendpointtestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket7DDAFC04Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" }, @@ -1203,7 +1202,9 @@ "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Outputs": { @@ -1321,17 +1322,17 @@ "Type": "String", "Description": "Artifact hash for asset \"75667ab2bbef2c8efc57fb73bf352f345af1d471fb09cb11f5b7bc27d009b609\"" }, - "AssetParameterseb49ce353c5ff251ebe2c3225fe00fb3e9a68fcd8b10207e63a36bfc6e981519S3Bucket686DCA97": { + "AssetParameters8d4ffe9194a1ca97e2e9377049ddbeb3adbdaa984c8a90c08a5d8d6b328bdf7cS3BucketFEA5F85E": { "Type": "String", - "Description": "S3 bucket for asset \"eb49ce353c5ff251ebe2c3225fe00fb3e9a68fcd8b10207e63a36bfc6e981519\"" + "Description": "S3 bucket for asset \"8d4ffe9194a1ca97e2e9377049ddbeb3adbdaa984c8a90c08a5d8d6b328bdf7c\"" }, - "AssetParameterseb49ce353c5ff251ebe2c3225fe00fb3e9a68fcd8b10207e63a36bfc6e981519S3VersionKey7EDC0140": { + "AssetParameters8d4ffe9194a1ca97e2e9377049ddbeb3adbdaa984c8a90c08a5d8d6b328bdf7cS3VersionKey226CF52C": { "Type": "String", - "Description": "S3 key for asset version \"eb49ce353c5ff251ebe2c3225fe00fb3e9a68fcd8b10207e63a36bfc6e981519\"" + "Description": "S3 key for asset version \"8d4ffe9194a1ca97e2e9377049ddbeb3adbdaa984c8a90c08a5d8d6b328bdf7c\"" }, - "AssetParameterseb49ce353c5ff251ebe2c3225fe00fb3e9a68fcd8b10207e63a36bfc6e981519ArtifactHashE5817DEB": { + "AssetParameters8d4ffe9194a1ca97e2e9377049ddbeb3adbdaa984c8a90c08a5d8d6b328bdf7cArtifactHashA6BF0EB3": { "Type": "String", - "Description": "Artifact hash for asset \"eb49ce353c5ff251ebe2c3225fe00fb3e9a68fcd8b10207e63a36bfc6e981519\"" + "Description": "Artifact hash for asset \"8d4ffe9194a1ca97e2e9377049ddbeb3adbdaa984c8a90c08a5d8d6b328bdf7c\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json index 45306f411eb84..c157211d73f87 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json @@ -3862,7 +3862,9 @@ "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "awscdkawseksKubectlProviderNestedStackawscdkawseksKubectlProviderNestedStackResourceA7AEBA6B": { "Type": "AWS::CloudFormation::Stack", @@ -3877,7 +3879,7 @@ }, "/", { - "Ref": "AssetParameters9f954a0baf5cb008231906c33569617ace43f4b2c804d16d0d4bae15fe9dfabcS3BucketF9C7C3C5" + "Ref": "AssetParameterse00474136b86298d67c0ad626f1dafe622c51168233097531c5ba6791d43aba3S3Bucket5829AD66" }, "/", { @@ -3887,7 +3889,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters9f954a0baf5cb008231906c33569617ace43f4b2c804d16d0d4bae15fe9dfabcS3VersionKey950894D5" + "Ref": "AssetParameterse00474136b86298d67c0ad626f1dafe622c51168233097531c5ba6791d43aba3S3VersionKey44FDB4A8" } ] } @@ -3900,7 +3902,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters9f954a0baf5cb008231906c33569617ace43f4b2c804d16d0d4bae15fe9dfabcS3VersionKey950894D5" + "Ref": "AssetParameterse00474136b86298d67c0ad626f1dafe622c51168233097531c5ba6791d43aba3S3VersionKey44FDB4A8" } ] } @@ -3955,9 +3957,6 @@ "referencetoawscdkeksclustertestAssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKey1CADE360Ref": { "Ref": "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyF55A2EA9" }, - "referencetoawscdkeksclustertestVpc9A302ADDRef": { - "Ref": "Vpc8378EB38" - }, "referencetoawscdkeksclustertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket0815E7B5Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" }, @@ -3965,7 +3964,9 @@ "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "LaunchTemplate": { "Type": "AWS::EC2::LaunchTemplate", @@ -4709,17 +4710,17 @@ "Type": "String", "Description": "Artifact hash for asset \"264acf17cbf0c643f47bec1f4dbaed805e3bd1bad3f018c093d16fb936227daa\"" }, - "AssetParameters9f954a0baf5cb008231906c33569617ace43f4b2c804d16d0d4bae15fe9dfabcS3BucketF9C7C3C5": { + "AssetParameterse00474136b86298d67c0ad626f1dafe622c51168233097531c5ba6791d43aba3S3Bucket5829AD66": { "Type": "String", - "Description": "S3 bucket for asset \"9f954a0baf5cb008231906c33569617ace43f4b2c804d16d0d4bae15fe9dfabc\"" + "Description": "S3 bucket for asset \"e00474136b86298d67c0ad626f1dafe622c51168233097531c5ba6791d43aba3\"" }, - "AssetParameters9f954a0baf5cb008231906c33569617ace43f4b2c804d16d0d4bae15fe9dfabcS3VersionKey950894D5": { + "AssetParameterse00474136b86298d67c0ad626f1dafe622c51168233097531c5ba6791d43aba3S3VersionKey44FDB4A8": { "Type": "String", - "Description": "S3 key for asset version \"9f954a0baf5cb008231906c33569617ace43f4b2c804d16d0d4bae15fe9dfabc\"" + "Description": "S3 key for asset version \"e00474136b86298d67c0ad626f1dafe622c51168233097531c5ba6791d43aba3\"" }, - "AssetParameters9f954a0baf5cb008231906c33569617ace43f4b2c804d16d0d4bae15fe9dfabcArtifactHash5984E3CE": { + "AssetParameterse00474136b86298d67c0ad626f1dafe622c51168233097531c5ba6791d43aba3ArtifactHashB6A3908A": { "Type": "String", - "Description": "Artifact hash for asset \"9f954a0baf5cb008231906c33569617ace43f4b2c804d16d0d4bae15fe9dfabc\"" + "Description": "Artifact hash for asset \"e00474136b86298d67c0ad626f1dafe622c51168233097531c5ba6791d43aba3\"" }, "SsmParameterValueawsserviceeksoptimizedami119amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { "Type": "AWS::SSM::Parameter::Value", @@ -4738,4 +4739,4 @@ "Default": "/aws/service/eks/optimized-ami/1.19/amazon-linux-2-gpu/recommended/image_id" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.expected.json b/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.expected.json index bae69481f9ded..441cac51ffd69 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.expected.json @@ -1177,7 +1177,9 @@ "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "awscdkawseksKubectlProviderNestedStackawscdkawseksKubectlProviderNestedStackResourceA7AEBA6B": { "Type": "AWS::CloudFormation::Stack", @@ -1192,7 +1194,7 @@ }, "/", { - "Ref": "AssetParameters37d93b8a35af568f83ecce5e05c6f06adaa06c68b84dfad9c3d82f57cd54ff13S3BucketDCD73A4E" + "Ref": "AssetParametersedcd50bb250cf7cf664a737720e623ad66ada9b9e609205686c476e516cf2f23S3Bucket586F6135" }, "/", { @@ -1202,7 +1204,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters37d93b8a35af568f83ecce5e05c6f06adaa06c68b84dfad9c3d82f57cd54ff13S3VersionKey796F5C1B" + "Ref": "AssetParametersedcd50bb250cf7cf664a737720e623ad66ada9b9e609205686c476e516cf2f23S3VersionKey6EFBFC1D" } ] } @@ -1215,7 +1217,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters37d93b8a35af568f83ecce5e05c6f06adaa06c68b84dfad9c3d82f57cd54ff13S3VersionKey796F5C1B" + "Ref": "AssetParametersedcd50bb250cf7cf664a737720e623ad66ada9b9e609205686c476e516cf2f23S3VersionKey6EFBFC1D" } ] } @@ -1270,9 +1272,6 @@ "referencetoawscdkeksfargateclustertestAssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyFE6D1F78Ref": { "Ref": "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyF55A2EA9" }, - "referencetoawscdkeksfargateclustertestFargateClusterDefaultVpcBD3C976FRef": { - "Ref": "FargateClusterDefaultVpcE69D3A13" - }, "referencetoawscdkeksfargateclustertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket8EEF0922Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" }, @@ -1280,7 +1279,9 @@ "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Outputs": { @@ -1398,17 +1399,17 @@ "Type": "String", "Description": "Artifact hash for asset \"3d252d05ccf0ae2934dd20707e8a709b466b2b8ea00c04ee8735667f90b17ac1\"" }, - "AssetParameters37d93b8a35af568f83ecce5e05c6f06adaa06c68b84dfad9c3d82f57cd54ff13S3BucketDCD73A4E": { + "AssetParametersedcd50bb250cf7cf664a737720e623ad66ada9b9e609205686c476e516cf2f23S3Bucket586F6135": { "Type": "String", - "Description": "S3 bucket for asset \"37d93b8a35af568f83ecce5e05c6f06adaa06c68b84dfad9c3d82f57cd54ff13\"" + "Description": "S3 bucket for asset \"edcd50bb250cf7cf664a737720e623ad66ada9b9e609205686c476e516cf2f23\"" }, - "AssetParameters37d93b8a35af568f83ecce5e05c6f06adaa06c68b84dfad9c3d82f57cd54ff13S3VersionKey796F5C1B": { + "AssetParametersedcd50bb250cf7cf664a737720e623ad66ada9b9e609205686c476e516cf2f23S3VersionKey6EFBFC1D": { "Type": "String", - "Description": "S3 key for asset version \"37d93b8a35af568f83ecce5e05c6f06adaa06c68b84dfad9c3d82f57cd54ff13\"" + "Description": "S3 key for asset version \"edcd50bb250cf7cf664a737720e623ad66ada9b9e609205686c476e516cf2f23\"" }, - "AssetParameters37d93b8a35af568f83ecce5e05c6f06adaa06c68b84dfad9c3d82f57cd54ff13ArtifactHash8F2277C1": { + "AssetParametersedcd50bb250cf7cf664a737720e623ad66ada9b9e609205686c476e516cf2f23ArtifactHashB34EB8FE": { "Type": "String", - "Description": "Artifact hash for asset \"37d93b8a35af568f83ecce5e05c6f06adaa06c68b84dfad9c3d82f57cd54ff13\"" + "Description": "Artifact hash for asset \"edcd50bb250cf7cf664a737720e623ad66ada9b9e609205686c476e516cf2f23\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/test.cluster.ts b/packages/@aws-cdk/aws-eks/test/test.cluster.ts index 97d5e287e25bb..46554d34dceb0 100644 --- a/packages/@aws-cdk/aws-eks/test/test.cluster.ts +++ b/packages/@aws-cdk/aws-eks/test/test.cluster.ts @@ -2083,6 +2083,27 @@ export = { }, + 'kubectl provider passes security group to provider'(test: Test) { + + const { stack } = testFixture(); + + new eks.Cluster(stack, 'Cluster1', { + version: CLUSTER_VERSION, + prune: false, + endpointAccess: eks.EndpointAccess.PRIVATE, + kubectlEnvironment: { + Foo: 'Bar', + }, + }); + + // the kubectl provider is inside a nested stack. + const nested = stack.node.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; + test.deepEqual(expect(nested).value.Resources.ProviderframeworkonEvent83C1D0A7.Properties.VpcConfig.SecurityGroupIds, + [{ Ref: 'referencetoStackCluster18DFEAC17ClusterSecurityGroupId' }]); + + test.done(); + }, + 'kubectl provider passes environment to lambda'(test: Test) { const { stack } = testFixture(); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/integ.cognito.lit.expected.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/integ.cognito.lit.expected.json index 7aeccb623d6dd..206ab8458383d 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/integ.cognito.lit.expected.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/integ.cognito.lit.expected.json @@ -450,22 +450,28 @@ "LoadBalancerArn": { "Ref": "LB8A12904C" }, - "Port": 443, - "Protocol": "HTTPS", "Certificates": [ { "CertificateArn": "" } - ] + ], + "Port": 443, + "Protocol": "HTTPS" } }, "UserPool6BA7E5F2": { "Type": "AWS::Cognito::UserPool", "Properties": { - "AccountRecoverySetting": { + "AccountRecoverySetting": { "RecoveryMechanisms": [ - { "Name": "verified_phone_number", "Priority": 1 }, - { "Name": "verified_email", "Priority": 2 } + { + "Name": "verified_phone_number", + "Priority": 1 + }, + { + "Name": "verified_email", + "Priority": 2 + } ] }, "AdminCreateUserConfig": { @@ -480,7 +486,9 @@ "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } - } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" }, "Client4A7F64DF": { "Type": "AWS::Cognito::UserPoolClient", @@ -544,4 +552,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-elasticsearch/lib/domain.ts b/packages/@aws-cdk/aws-elasticsearch/lib/domain.ts index 28728e6cdf58f..905ea5360f139 100644 --- a/packages/@aws-cdk/aws-elasticsearch/lib/domain.ts +++ b/packages/@aws-cdk/aws-elasticsearch/lib/domain.ts @@ -569,6 +569,13 @@ export interface DomainProps { */ readonly enableVersionUpgrade?: boolean; + /** + * Policy to apply when the domain is removed from the stack + * + * @default RemovalPolicy.RETAIN + */ + readonly removalPolicy?: cdk.RemovalPolicy; + /** * To configure a custom domain configure these options * @@ -1663,6 +1670,7 @@ export class Domain extends DomainBase implements IDomain { } : undefined, }); + this.domain.applyRemovalPolicy(props.removalPolicy); if (props.enableVersionUpgrade) { this.domain.cfnOptions.updatePolicy = { diff --git a/packages/@aws-cdk/aws-elasticsearch/test/domain.test.ts b/packages/@aws-cdk/aws-elasticsearch/test/domain.test.ts index 98a6f350d6f34..afd5bf6b45430 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/domain.test.ts +++ b/packages/@aws-cdk/aws-elasticsearch/test/domain.test.ts @@ -30,6 +30,16 @@ const readWriteActions = [ ...writeActions, ]; +test('default removalpolicy is retain', () => { + new Domain(stack, 'Domain', { + version: ElasticsearchVersion.V7_1, + }); + + expect(stack).toHaveResource('AWS::Elasticsearch::Domain', { + DeletionPolicy: 'Retain', + }, assert.ResourcePart.CompleteDefinition); +}); + test('grants kms permissions if needed', () => { const key = new kms.Key(stack, 'Key'); diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.advancedsecurity.expected.json b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.advancedsecurity.expected.json index dac2d95d68b54..84333cb6005d7 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.advancedsecurity.expected.json +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.advancedsecurity.expected.json @@ -44,7 +44,9 @@ "NodeToNodeEncryptionOptions": { "Enabled": true } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.advancedsecurity.ts b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.advancedsecurity.ts index 5baf8f4e1b99d..828a5c9fe75e7 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.advancedsecurity.ts +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.advancedsecurity.ts @@ -1,5 +1,5 @@ import { User } from '@aws-cdk/aws-iam'; -import { App, Stack, StackProps } from '@aws-cdk/core'; +import { App, RemovalPolicy, Stack, StackProps } from '@aws-cdk/core'; import { Construct } from 'constructs'; import * as es from '../lib'; @@ -10,6 +10,7 @@ class TestStack extends Stack { const user = new User(this, 'User'); new es.Domain(this, 'Domain', { + removalPolicy: RemovalPolicy.DESTROY, version: es.ElasticsearchVersion.V7_1, fineGrainedAccessControl: { masterUserArn: user.userArn, diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.expected.json b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.expected.json index 1da03e98c1984..309d8c2831e8d 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.expected.json +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.expected.json @@ -221,7 +221,9 @@ "DependsOn": [ "DomainESLogGroupPolicyc82ca7bfe2f2589b859ebab89e88da2efd284adfadCustomResourcePolicy0B41F6DF", "DomainESLogGroupPolicyc82ca7bfe2f2589b859ebab89e88da2efd284adfadA70E756D" - ] + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "DomainESAccessPolicyCustomResourcePolicy9747FC42": { "Type": "AWS::IAM::Policy", @@ -420,13 +422,13 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs12.x", "Timeout": 120 }, diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.ts b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.ts index 57152d5c70d5c..24bb07e4660ff 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.ts +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.ts @@ -1,7 +1,7 @@ import { EbsDeviceVolumeType } from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; -import { App, Stack, StackProps } from '@aws-cdk/core'; +import { App, RemovalPolicy, Stack, StackProps } from '@aws-cdk/core'; import { Construct } from 'constructs'; import * as es from '../lib'; @@ -12,6 +12,7 @@ class TestStack extends Stack { const key = new kms.Key(this, 'Key'); const domainProps: es.DomainProps = { + removalPolicy: RemovalPolicy.DESTROY, version: es.ElasticsearchVersion.V7_1, ebs: { volumeSize: 10, diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.expected.json b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.expected.json index e43b6bb5f62e6..e510eb3534625 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.expected.json +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.expected.json @@ -183,7 +183,9 @@ "DependsOn": [ "Domain1ESLogGroupPolicyc8858d5dba055f677469d76cb6ad538fd732ba69a6CustomResourcePolicy24436E05", "Domain1ESLogGroupPolicyc8858d5dba055f677469d76cb6ad538fd732ba69a6D8BDCF36" - ] + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "Domain1ESAccessPolicyCustomResourcePolicyC04432B6": { "Type": "AWS::IAM::Policy", @@ -352,13 +354,13 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs12.x", "Timeout": 120 }, @@ -549,7 +551,9 @@ "DependsOn": [ "Domain2ESLogGroupPolicyc8405238e455eeabd840cf6933e1814efc51d2de71CustomResourcePolicy77691A33", "Domain2ESLogGroupPolicyc8405238e455eeabd840cf6933e1814efc51d2de71F1DE93A1" - ] + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "Domain2ESAccessPolicyCustomResourcePolicy8EED1F24": { "Type": "AWS::IAM::Policy", diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ts b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ts index 4a6232d3ab130..448896e321957 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ts +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ts @@ -1,6 +1,6 @@ import { EbsDeviceVolumeType } from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; -import { App, Stack, StackProps } from '@aws-cdk/core'; +import { App, RemovalPolicy, Stack, StackProps } from '@aws-cdk/core'; import { Construct } from 'constructs'; import * as es from '../lib'; @@ -9,6 +9,7 @@ class TestStack extends Stack { super(scope, id, props); const domainProps: es.DomainProps = { + removalPolicy: RemovalPolicy.DESTROY, version: es.ElasticsearchVersion.V7_1, ebs: { volumeSize: 10, diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ultrawarm.expected.json b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ultrawarm.expected.json index c24aeb2f30740..702d302029600 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ultrawarm.expected.json +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ultrawarm.expected.json @@ -34,7 +34,9 @@ "NodeToNodeEncryptionOptions": { "Enabled": false } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ultrawarm.ts b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ultrawarm.ts index 259f43fe0cef2..c7c581252fc7e 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ultrawarm.ts +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ultrawarm.ts @@ -1,4 +1,4 @@ -import { App, Stack, StackProps } from '@aws-cdk/core'; +import { App, RemovalPolicy, Stack, StackProps } from '@aws-cdk/core'; import { Construct } from 'constructs'; import * as es from '../lib'; @@ -7,6 +7,7 @@ class TestStack extends Stack { super(scope, id, props); new es.Domain(this, 'Domain', { + removalPolicy: RemovalPolicy.DESTROY, version: es.ElasticsearchVersion.V7_1, capacity: { masterNodes: 2, diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.expected.json b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.expected.json index b55ac9e14df69..065e569573421 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.expected.json +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.expected.json @@ -58,7 +58,9 @@ "NodeToNodeEncryptionOptions": { "Enabled": true } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "DomainESAccessPolicyCustomResourcePolicy9747FC42": { "Type": "AWS::IAM::Policy", @@ -255,13 +257,13 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs12.x", "Timeout": 120 }, diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.ts b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.ts index 8844e5937305c..5e7fb2787972d 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.ts +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.ts @@ -1,4 +1,4 @@ -import { App, Stack, StackProps } from '@aws-cdk/core'; +import { App, RemovalPolicy, Stack, StackProps } from '@aws-cdk/core'; import { Construct } from 'constructs'; import * as es from '../lib'; @@ -7,6 +7,7 @@ class TestStack extends Stack { super(scope, id, props); new es.Domain(this, 'Domain', { + removalPolicy: RemovalPolicy.DESTROY, version: es.ElasticsearchVersion.V7_1, useUnsignedBasicAuth: true, }); diff --git a/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.expected.json b/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.expected.json index c9efaffc51134..007503de08383 100644 --- a/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.expected.json @@ -340,7 +340,9 @@ } }, "MyQueueE6CA6235": { - "Type": "AWS::SQS::Queue" + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "MyQueuePolicy6BBEDDAC": { "Type": "AWS::SQS::QueuePolicy", @@ -422,4 +424,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-events-targets/test/sns/integ.sns-event-rule-target.expected.json b/packages/@aws-cdk/aws-events-targets/test/sns/integ.sns-event-rule-target.expected.json index f4aea52c23274..37a78f010d792 100644 --- a/packages/@aws-cdk/aws-events-targets/test/sns/integ.sns-event-rule-target.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/sns/integ.sns-event-rule-target.expected.json @@ -45,7 +45,9 @@ } }, "MyQueueE6CA6235": { - "Type": "AWS::SQS::Queue" + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "MyQueuePolicy6BBEDDAC": { "Type": "AWS::SQS::QueuePolicy", diff --git a/packages/@aws-cdk/aws-events-targets/test/sqs/integ.sqs-event-rule-target.expected.json b/packages/@aws-cdk/aws-events-targets/test/sqs/integ.sqs-event-rule-target.expected.json index 645845bc1f44b..eebbc3a996344 100644 --- a/packages/@aws-cdk/aws-events-targets/test/sqs/integ.sqs-event-rule-target.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/sqs/integ.sqs-event-rule-target.expected.json @@ -19,7 +19,9 @@ } }, "MyQueueE6CA6235": { - "Type": "AWS::SQS::Queue" + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "MyQueuePolicy6BBEDDAC": { "Type": "AWS::SQS::QueuePolicy", diff --git a/packages/@aws-cdk/aws-fsx/lib/file-system.ts b/packages/@aws-cdk/aws-fsx/lib/file-system.ts index 22b4f64d8cd3b..d19c0e7686151 100644 --- a/packages/@aws-cdk/aws-fsx/lib/file-system.ts +++ b/packages/@aws-cdk/aws-fsx/lib/file-system.ts @@ -1,6 +1,6 @@ import { Connections, IConnectable, ISecurityGroup, IVpc } from '@aws-cdk/aws-ec2'; import { IKey } from '@aws-cdk/aws-kms'; -import { Resource } from '@aws-cdk/core'; +import { RemovalPolicy, Resource } from '@aws-cdk/core'; /** * Interface to implement FSx File Systems. @@ -52,6 +52,13 @@ export interface FileSystemProps { * For SCRATCH_2 and PERSISTENT_1 types, valid values are 1,200, 2,400, then continuing in increments of 2,400 GiB. */ readonly storageCapacityGiB: number; + + /** + * Policy to apply when the file system is removed from the stack + * + * @default RemovalPolicy.RETAIN + */ + readonly removalPolicy?: RemovalPolicy; } /** diff --git a/packages/@aws-cdk/aws-fsx/lib/lustre-file-system.ts b/packages/@aws-cdk/aws-fsx/lib/lustre-file-system.ts index 9d27da5bca3cd..2206bb31dfad3 100644 --- a/packages/@aws-cdk/aws-fsx/lib/lustre-file-system.ts +++ b/packages/@aws-cdk/aws-fsx/lib/lustre-file-system.ts @@ -198,6 +198,7 @@ export class LustreFileSystem extends FileSystemBase { securityGroupIds: [securityGroup.securityGroupId], storageCapacity: props.storageCapacityGiB, }); + this.fileSystem.applyRemovalPolicy(props.removalPolicy); this.fileSystemId = this.fileSystem.ref; this.dnsName = `${this.fileSystemId}.fsx.${this.stack.region}.${Aws.URL_SUFFIX}`; diff --git a/packages/@aws-cdk/aws-fsx/test/integ.lustre-file-system.expected.json b/packages/@aws-cdk/aws-fsx/test/integ.lustre-file-system.expected.json index 0164e2f1f0067..c5826b996a6bf 100644 --- a/packages/@aws-cdk/aws-fsx/test/integ.lustre-file-system.expected.json +++ b/packages/@aws-cdk/aws-fsx/test/integ.lustre-file-system.expected.json @@ -593,7 +593,9 @@ } ], "StorageCapacity": 1200 - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "instInstanceSecurityGroup54790689": { "Type": "AWS::EC2::SecurityGroup", diff --git a/packages/@aws-cdk/aws-fsx/test/integ.lustre-file-system.ts b/packages/@aws-cdk/aws-fsx/test/integ.lustre-file-system.ts index 00b32cea3b297..5202df62b2d08 100644 --- a/packages/@aws-cdk/aws-fsx/test/integ.lustre-file-system.ts +++ b/packages/@aws-cdk/aws-fsx/test/integ.lustre-file-system.ts @@ -1,5 +1,5 @@ import { AmazonLinuxGeneration, AmazonLinuxImage, Instance, InstanceClass, InstanceSize, InstanceType, SubnetType, Vpc } from '@aws-cdk/aws-ec2'; -import { App, Stack } from '@aws-cdk/core'; +import { App, RemovalPolicy, Stack } from '@aws-cdk/core'; import { LustreDeploymentType, LustreFileSystem } from '../lib'; const app = new App(); @@ -17,6 +17,7 @@ const fs = new LustreFileSystem(stack, 'FsxLustreFileSystem', { storageCapacityGiB: storageCapacity, vpc, vpcSubnet: vpc.privateSubnets[0], + removalPolicy: RemovalPolicy.DESTROY, }); const inst = new Instance(stack, 'inst', { diff --git a/packages/@aws-cdk/aws-fsx/test/lustre-file-system.test.ts b/packages/@aws-cdk/aws-fsx/test/lustre-file-system.test.ts index 43541cd858fce..fe0159a212140 100644 --- a/packages/@aws-cdk/aws-fsx/test/lustre-file-system.test.ts +++ b/packages/@aws-cdk/aws-fsx/test/lustre-file-system.test.ts @@ -1,5 +1,5 @@ import { strictEqual } from 'assert'; -import { expect as expectCDK, haveResource } from '@aws-cdk/assert'; +import { expect as expectCDK, haveResource, ResourcePart } from '@aws-cdk/assert'; import { ISubnet, Port, SecurityGroup, Subnet, Vpc } from '@aws-cdk/aws-ec2'; import { Key } from '@aws-cdk/aws-kms'; import { Aws, Stack, Token } from '@aws-cdk/core'; @@ -40,6 +40,10 @@ describe('FSx for Lustre File System', () => { strictEqual( fileSystem.dnsName, `${fileSystem.fileSystemId}.fsx.${stack.region}.${Aws.URL_SUFFIX}`); + + expectCDK(stack).to(haveResource('AWS::FSx::FileSystem', { + DeletionPolicy: 'Retain', + }, ResourcePart.CompleteDefinition)); }); test('file system is created correctly when security group is provided', () => { diff --git a/packages/@aws-cdk/aws-kms/lib/key.ts b/packages/@aws-cdk/aws-kms/lib/key.ts index 4e18d228fe38e..2176d28f5b5bc 100644 --- a/packages/@aws-cdk/aws-kms/lib/key.ts +++ b/packages/@aws-cdk/aws-kms/lib/key.ts @@ -285,7 +285,7 @@ export interface KeyProps { /** * Custom policy document to attach to the KMS key. * - * NOTE - If the '@aws-cdk/aws-kms:defaultKeyPolicies' feature flag is set (the default for new projects), + * NOTE - If the `@aws-cdk/aws-kms:defaultKeyPolicies` feature flag is set (the default for new projects), * this policy will *override* the default key policy and become the only key policy for the key. If the * feature flag is not set, this policy will be appended to the default key policy. * @@ -322,12 +322,12 @@ export interface KeyProps { * to how it works for other AWS resources). This matches the default behavior * when creating KMS keys via the API or console. * - * If the '@aws-cdk/aws-kms:defaultKeyPolicies' feature flag is set (the default for new projects), + * If the `@aws-cdk/aws-kms:defaultKeyPolicies` feature flag is set (the default for new projects), * this flag will always be treated as 'true' and does not need to be explicitly set. * - * @default - false, unless the '@aws-cdk/aws-kms:defaultKeyPolicies' feature flag is set. + * @default - false, unless the `@aws-cdk/aws-kms:defaultKeyPolicies` feature flag is set. * @see https://docs.aws.amazon.com/kms/latest/developerguide/key-policies.html#key-policy-default-allow-root-enable-iam - * @deprecated redundant with the '@aws-cdk/aws-kms:defaultKeyPolicies' feature flag + * @deprecated redundant with the `@aws-cdk/aws-kms:defaultKeyPolicies` feature flag */ readonly trustAccountIdentities?: boolean; @@ -471,7 +471,7 @@ export class Key extends KeyBase { * Grants the account admin privileges -- not full account access -- plus the GenerateDataKey action. * The GenerateDataKey action was added for interop with S3 in https://github.com/aws/aws-cdk/issues/3458. * - * This policy is discouraged and deprecated by the '@aws-cdk/aws-kms:defaultKeyPolicies' feature flag. + * This policy is discouraged and deprecated by the `@aws-cdk/aws-kms:defaultKeyPolicies` feature flag. * * @link https://docs.aws.amazon.com/kms/latest/developerguide/key-policies.html#key-policy-default * @deprecated diff --git a/packages/@aws-cdk/aws-lambda-destinations/test/integ.destinations.expected.json b/packages/@aws-cdk/aws-lambda-destinations/test/integ.destinations.expected.json index c9c1d8cd64563..510fe8cef21a8 100644 --- a/packages/@aws-cdk/aws-lambda-destinations/test/integ.destinations.expected.json +++ b/packages/@aws-cdk/aws-lambda-destinations/test/integ.destinations.expected.json @@ -4,7 +4,9 @@ "Type": "AWS::SNS::Topic" }, "Queue4A7E3555": { - "Type": "AWS::SQS::Queue" + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "SnsSqsServiceRole869866F7": { "Type": "AWS::IAM::Role", @@ -80,13 +82,13 @@ "Code": { "ZipFile": "exports.handler = async (event) => {\n if (event === 'OK') return 'success';\n throw new Error('failure');\n };" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "SnsSqsServiceRole869866F7", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs10.x" }, "DependsOn": [ @@ -165,13 +167,13 @@ "Code": { "ZipFile": "exports.handler = async (event) => {\n console.log(event);\n };" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "OnSuccesServiceRole75E399CF", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs10.x" }, "DependsOn": [ @@ -246,13 +248,13 @@ "Code": { "ZipFile": "exports.handler = async (event) => {\n if (event === 'OK') return 'success';\n throw new Error('failure');\n };" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "EventBusLambdaServiceRole9BC8901F", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs10.x" }, "DependsOn": [ diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesiswithdlq.expected.json b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesiswithdlq.expected.json index 0e57bd7dc85d1..4d0a6c1a54707 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesiswithdlq.expected.json +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesiswithdlq.expected.json @@ -93,13 +93,13 @@ "Code": { "ZipFile": "exports.handler = async function handler(event) {\n // eslint-disable-next-line no-console\n console.log('event:', JSON.stringify(event, undefined, 2));\n throw new Error();\n}" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "FServiceRole3AC82EE1", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs10.x" }, "DependsOn": [ @@ -110,12 +110,6 @@ "FKinesisEventSourcelambdaeventsourcekinesiswithdlqSD357FCB87EEA8CB4": { "Type": "AWS::Lambda::EventSourceMapping", "Properties": { - "EventSourceArn": { - "Fn::GetAtt": [ - "S509448A1", - "Arn" - ] - }, "FunctionName": { "Ref": "FC4345940" }, @@ -130,6 +124,12 @@ } } }, + "EventSourceArn": { + "Fn::GetAtt": [ + "S509448A1", + "Arn" + ] + }, "MaximumRetryAttempts": 0, "StartingPosition": "TRIM_HORIZON" } @@ -154,7 +154,9 @@ } }, "Q63C6E3AB": { - "Type": "AWS::SQS::Queue" + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.sqs.expected.json b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.sqs.expected.json index e0bc8e07fece0..9f5565aff21d6 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.sqs.expected.json +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.sqs.expected.json @@ -69,13 +69,13 @@ "Code": { "ZipFile": "exports.handler = async function handler(event) {\n console.log('event:', JSON.stringify(event, undefined, 2));\n return { event };\n}" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "FServiceRole3AC82EE1", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs10.x" }, "DependsOn": [ @@ -86,20 +86,22 @@ "FSqsEventSourcelambdaeventsourcesqsQ67DE9201754EC819": { "Type": "AWS::Lambda::EventSourceMapping", "Properties": { + "FunctionName": { + "Ref": "FC4345940" + }, + "BatchSize": 5, "EventSourceArn": { "Fn::GetAtt": [ "Q63C6E3AB", "Arn" ] - }, - "FunctionName": { - "Ref": "FC4345940" - }, - "BatchSize": 5 + } } }, "Q63C6E3AB": { - "Type": "AWS::SQS::Queue" + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda-nodejs/README.md b/packages/@aws-cdk/aws-lambda-nodejs/README.md index bfaa99eb0b243..f35062120fb9d 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/README.md +++ b/packages/@aws-cdk/aws-lambda-nodejs/README.md @@ -162,13 +162,17 @@ It is possible to run additional commands by specifying the `commandHooks` prop: ```ts new lambda.NodejsFunction(this, 'my-handler-with-commands', { - commandHooks: { - // Copy a file so that it will be included in the bundled asset - afterBundling(inputDir: string, outputDir: string): string[] { - return [`cp ${inputDir}/my-binary.node ${outputDir}`]; + bundling: { + commandHooks: { + // Copy a file so that it will be included in the bundled asset + afterBundling(inputDir: string, outputDir: string): string[] { + return [`cp ${inputDir}/my-binary.node ${outputDir}`]; + } + // ... } // ... } + }); ``` diff --git a/packages/@aws-cdk/aws-lambda-nodejs/package.json b/packages/@aws-cdk/aws-lambda-nodejs/package.json index ba3c210cc7663..c2e2f658febac 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/package.json +++ b/packages/@aws-cdk/aws-lambda-nodejs/package.json @@ -67,7 +67,7 @@ "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "delay": "5.0.0", - "esbuild": "^0.8.49", + "esbuild": "^0.8.50", "pkglint": "0.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-lambda/README.md b/packages/@aws-cdk/aws-lambda/README.md index 98994962ec129..b3fb466ec7253 100644 --- a/packages/@aws-cdk/aws-lambda/README.md +++ b/packages/@aws-cdk/aws-lambda/README.md @@ -18,7 +18,7 @@ import * as lambda from '@aws-cdk/aws-lambda'; import * as path from 'path'; const fn = new lambda.Function(this, 'MyFunction', { - runtime: lambda.Runtime.NODEJS_10_X, + runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), }); @@ -88,7 +88,7 @@ function. To reference the autogenerated Role: ```ts const fn = new lambda.Function(this, 'MyFunction', { - runtime: lambda.Runtime.NODEJS_10_X, + runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), @@ -101,7 +101,7 @@ it appropriate permissions: ```ts const fn = new lambda.Function(this, 'MyFunction', { - runtime: lambda.Runtime.NODEJS_10_X, + runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), role: myRole // user-provided role @@ -251,7 +251,7 @@ setting the `deadLetterQueueEnabled: true` configuration. import * as lambda from '@aws-cdk/aws-lambda'; const fn = new lambda.Function(this, 'MyFunction', { - runtime: lambda.Runtime.NODEJS_10_X, + runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', code: lambda.Code.fromInline('exports.handler = function(event, ctx, cb) { return cb(null, "hi"); }'), deadLetterQueueEnabled: true @@ -266,7 +266,7 @@ import * as sqs from '@aws-cdk/aws-sqs'; const dlq = new sqs.Queue(this, 'DLQ'); const fn = new lambda.Function(this, 'MyFunction', { - runtime: lambda.Runtime.NODEJS_10_X, + runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', code: lambda.Code.fromInline('exports.handler = function(event, ctx, cb) { return cb(null, "hi"); }'), deadLetterQueue: dlq @@ -282,7 +282,7 @@ to learn more about AWS Lambdas and DLQs. import * as lambda from '@aws-cdk/aws-lambda'; const fn = new lambda.Function(this, 'MyFunction', { - runtime: lambda.Runtime.NODEJS_10_X, + runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', code: lambda.Code.fromInline('exports.handler = function(event, ctx, cb) { return cb(null, "hi"); }'), tracing: lambda.Tracing.ACTIVE @@ -321,7 +321,7 @@ to learn more about AWS Lambda's Profiling support. import * as lambda from '@aws-cdk/aws-lambda'; const fn = new lambda.Function(this, 'MyFunction', { - runtime: lambda.Runtime.NODEJS_10_X, + runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', code: lambda.Code.fromInline('exports.handler = function(event, ctx, cb) { return cb(null, "hi"); }'), reservedConcurrentExecutions: 100 diff --git a/packages/@aws-cdk/aws-rds/README.md b/packages/@aws-cdk/aws-rds/README.md index b00e3c64187f0..cb431cecbcd10 100644 --- a/packages/@aws-cdk/aws-rds/README.md +++ b/packages/@aws-cdk/aws-rds/README.md @@ -525,7 +525,7 @@ const cluster = new rds.ServerlessCluster(this, 'AnotherCluster', { }); const fn = new lambda.Function(this, 'MyFunction', { - runtime: lambda.Runtime.NODEJS_10_X, + runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), environment: { diff --git a/packages/@aws-cdk/aws-rds/lib/cluster.ts b/packages/@aws-cdk/aws-rds/lib/cluster.ts index e0f2618a2fdf2..a3f06555afdb9 100644 --- a/packages/@aws-cdk/aws-rds/lib/cluster.ts +++ b/packages/@aws-cdk/aws-rds/lib/cluster.ts @@ -10,7 +10,7 @@ import { IClusterEngine } from './cluster-engine'; import { DatabaseClusterAttributes, IDatabaseCluster } from './cluster-ref'; import { Endpoint } from './endpoint'; import { IParameterGroup } from './parameter-group'; -import { applyRemovalPolicy, DEFAULT_PASSWORD_EXCLUDE_CHARS, defaultDeletionProtection, renderCredentials, setupS3ImportExport } from './private/util'; +import { DEFAULT_PASSWORD_EXCLUDE_CHARS, defaultDeletionProtection, renderCredentials, setupS3ImportExport, helperRemovalPolicy, renderUnless } from './private/util'; import { BackupProps, Credentials, InstanceProps, PerformanceInsightRetention, RotationSingleUserOptions, RotationMultiUserOptions } from './props'; import { DatabaseProxy, DatabaseProxyOptions, ProxyTarget } from './proxy'; import { CfnDBCluster, CfnDBClusterProps, CfnDBInstance } from './rds.generated'; @@ -310,7 +310,7 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { description: `Subnets for ${id} database`, vpc: props.instanceProps.vpc, vpcSubnets: props.instanceProps.vpcSubnets, - removalPolicy: props.removalPolicy === RemovalPolicy.RETAIN ? props.removalPolicy : undefined, + removalPolicy: renderUnless(helperRemovalPolicy(props.removalPolicy), RemovalPolicy.DESTROY), }); this.securityGroups = props.instanceProps.securityGroups ?? [ @@ -512,7 +512,7 @@ export class DatabaseCluster extends DatabaseClusterNew { defaultPort: ec2.Port.tcp(this.clusterEndpoint.port), }); - applyRemovalPolicy(cluster, props.removalPolicy); + cluster.applyRemovalPolicy(props.removalPolicy ?? RemovalPolicy.SNAPSHOT); if (secret) { this.secret = secret.attach(this); @@ -608,7 +608,7 @@ export class DatabaseClusterFromSnapshot extends DatabaseClusterNew { defaultPort: ec2.Port.tcp(this.clusterEndpoint.port), }); - applyRemovalPolicy(cluster, props.removalPolicy); + cluster.applyRemovalPolicy(props.removalPolicy ?? RemovalPolicy.SNAPSHOT); setLogRetention(this, props); createInstances(this, props, this.subnetGroup); @@ -712,13 +712,11 @@ function createInstances(cluster: DatabaseClusterNew, props: DatabaseClusterBase deleteAutomatedBackups: props.instanceProps.deleteAutomatedBackups, }); - // If removalPolicy isn't explicitly set, - // it's Snapshot for Cluster. - // Because of that, in this case, - // we can safely use the CFN default of Delete for DbInstances with dbClusterIdentifier set. - if (props.removalPolicy) { - applyRemovalPolicy(instance, props.removalPolicy); - } + // For instances that are part of a cluster: + // + // Cluster DESTROY or SNAPSHOT -> DESTROY (snapshot is good enough to recreate) + // Cluster RETAIN -> RETAIN (otherwise cluster state will disappear) + instance.applyRemovalPolicy(helperRemovalPolicy(props.removalPolicy)); // We must have a dependency on the NAT gateway provider here to create // things in the right order. diff --git a/packages/@aws-cdk/aws-rds/lib/instance.ts b/packages/@aws-cdk/aws-rds/lib/instance.ts index cb4c3d3487a8c..f6bbe5481a112 100644 --- a/packages/@aws-cdk/aws-rds/lib/instance.ts +++ b/packages/@aws-cdk/aws-rds/lib/instance.ts @@ -12,7 +12,7 @@ import { Endpoint } from './endpoint'; import { IInstanceEngine } from './instance-engine'; import { IOptionGroup } from './option-group'; import { IParameterGroup } from './parameter-group'; -import { applyRemovalPolicy, DEFAULT_PASSWORD_EXCLUDE_CHARS, defaultDeletionProtection, engineDescription, renderCredentials, setupS3ImportExport } from './private/util'; +import { DEFAULT_PASSWORD_EXCLUDE_CHARS, defaultDeletionProtection, engineDescription, renderCredentials, setupS3ImportExport, helperRemovalPolicy, renderUnless } from './private/util'; import { Credentials, PerformanceInsightRetention, RotationMultiUserOptions, RotationSingleUserOptions, SnapshotCredentials } from './props'; import { DatabaseProxy, DatabaseProxyOptions, ProxyTarget } from './proxy'; import { CfnDBInstance, CfnDBInstanceProps } from './rds.generated'; @@ -642,7 +642,7 @@ abstract class DatabaseInstanceNew extends DatabaseInstanceBase implements IData description: `Subnet group for ${this.node.id} database`, vpc: this.vpc, vpcSubnets: this.vpcPlacement, - removalPolicy: props.removalPolicy === RemovalPolicy.RETAIN ? props.removalPolicy : undefined, + removalPolicy: renderUnless(helperRemovalPolicy(props.removalPolicy), RemovalPolicy.DESTROY), }); const securityGroups = props.securityGroups || [new ec2.SecurityGroup(this, 'SecurityGroup', { @@ -976,7 +976,7 @@ export class DatabaseInstance extends DatabaseInstanceSource implements IDatabas const portAttribute = Token.asNumber(instance.attrEndpointPort); this.instanceEndpoint = new Endpoint(instance.attrEndpointAddress, portAttribute); - applyRemovalPolicy(instance, props.removalPolicy); + instance.applyRemovalPolicy(props.removalPolicy ?? RemovalPolicy.SNAPSHOT); if (secret) { this.secret = secret.attach(this); @@ -1052,7 +1052,7 @@ export class DatabaseInstanceFromSnapshot extends DatabaseInstanceSource impleme const portAttribute = Token.asNumber(instance.attrEndpointPort); this.instanceEndpoint = new Endpoint(instance.attrEndpointAddress, portAttribute); - applyRemovalPolicy(instance, props.removalPolicy); + instance.applyRemovalPolicy(props.removalPolicy ?? RemovalPolicy.SNAPSHOT); if (secret) { this.secret = secret.attach(this); @@ -1128,7 +1128,7 @@ export class DatabaseInstanceReadReplica extends DatabaseInstanceNew implements const portAttribute = Token.asNumber(instance.attrEndpointPort); this.instanceEndpoint = new Endpoint(instance.attrEndpointAddress, portAttribute); - applyRemovalPolicy(instance, props.removalPolicy); + instance.applyRemovalPolicy(props.removalPolicy ?? RemovalPolicy.SNAPSHOT); this.setLogRetention(); } diff --git a/packages/@aws-cdk/aws-rds/lib/private/util.ts b/packages/@aws-cdk/aws-rds/lib/private/util.ts index f97486b5daddf..0b6e2b72ff0be 100644 --- a/packages/@aws-cdk/aws-rds/lib/private/util.ts +++ b/packages/@aws-cdk/aws-rds/lib/private/util.ts @@ -1,6 +1,6 @@ import * as iam from '@aws-cdk/aws-iam'; import * as s3 from '@aws-cdk/aws-s3'; -import { CfnDeletionPolicy, CfnResource, RemovalPolicy } from '@aws-cdk/core'; +import { RemovalPolicy } from '@aws-cdk/core'; import { DatabaseSecret } from '../database-secret'; import { IEngine } from '../engine'; import { Credentials } from '../props'; @@ -76,17 +76,6 @@ export function engineDescription(engine: IEngine) { return engine.engineType + (engine.engineVersion?.fullVersion ? `-${engine.engineVersion.fullVersion}` : ''); } -export function applyRemovalPolicy(cfnDatabase: CfnResource, removalPolicy?: RemovalPolicy): void { - if (!removalPolicy) { - // the default DeletionPolicy is 'Snapshot', which is fine, - // but we should also make it 'Snapshot' for UpdateReplace policy - cfnDatabase.cfnOptions.updateReplacePolicy = CfnDeletionPolicy.SNAPSHOT; - } else { - // just apply whatever removal policy the customer explicitly provided - cfnDatabase.applyRemovalPolicy(removalPolicy); - } -} - /** * By default, deletion protection is disabled. * Enable if explicitly provided or if the RemovalPolicy has been set to RETAIN @@ -118,3 +107,28 @@ export function renderCredentials(scope: Construct, engine: IEngine, credentials return renderedCredentials; } + +/** + * The RemovalPolicy that should be applied to a "helper" resource, if the base resource has the given removal policy + * + * - For Clusters, this determines the RemovalPolicy for Instances/SubnetGroups. + * - For Instances, this determines the RemovalPolicy for SubnetGroups. + * + * If the basePolicy is: + * + * DESTROY or SNAPSHOT -> DESTROY (snapshot is good enough to recreate) + * RETAIN -> RETAIN (anything else will lose data or fail to deploy) + * (undefined) -> DESTROY (base policy is assumed to be SNAPSHOT) + */ +export function helperRemovalPolicy(basePolicy?: RemovalPolicy): RemovalPolicy { + return basePolicy === RemovalPolicy.RETAIN + ? RemovalPolicy.RETAIN + : RemovalPolicy.DESTROY; +} + +/** + * Return a given value unless it's the same as another value + */ +export function renderUnless(value: A, suppressValue: A): A | undefined { + return value === suppressValue ? undefined : value; +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/lib/serverless-cluster.ts b/packages/@aws-cdk/aws-rds/lib/serverless-cluster.ts index 39258de8c7748..90438cbaa1c79 100644 --- a/packages/@aws-cdk/aws-rds/lib/serverless-cluster.ts +++ b/packages/@aws-cdk/aws-rds/lib/serverless-cluster.ts @@ -8,7 +8,7 @@ import { IClusterEngine } from './cluster-engine'; import { Endpoint } from './endpoint'; import { IParameterGroup } from './parameter-group'; import { DATA_API_ACTIONS } from './perms'; -import { applyRemovalPolicy, defaultDeletionProtection, DEFAULT_PASSWORD_EXCLUDE_CHARS, renderCredentials } from './private/util'; +import { defaultDeletionProtection, DEFAULT_PASSWORD_EXCLUDE_CHARS, renderCredentials } from './private/util'; import { Credentials, RotationMultiUserOptions, RotationSingleUserOptions } from './props'; import { CfnDBCluster } from './rds.generated'; import { ISubnetGroup, SubnetGroup } from './subnet-group'; @@ -468,7 +468,7 @@ export class ServerlessCluster extends ServerlessClusterBase { defaultPort: ec2.Port.tcp(this.clusterEndpoint.port), }); - applyRemovalPolicy(cluster, props.removalPolicy); + cluster.applyRemovalPolicy(props.removalPolicy ?? RemovalPolicy.SNAPSHOT); if (secret) { this.secret = secret.attach(this); diff --git a/packages/@aws-cdk/aws-rds/test/cluster.test.ts b/packages/@aws-cdk/aws-rds/test/cluster.test.ts index ec7c36129b30d..11f18100e9fbe 100644 --- a/packages/@aws-cdk/aws-rds/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-rds/test/cluster.test.ts @@ -1,18 +1,19 @@ -import { ABSENT, countResources, expect, haveResource, haveResourceLike, ResourcePart, SynthUtils } from '@aws-cdk/assert'; +import '@aws-cdk/assert/jest'; +import { ABSENT, ResourcePart, SynthUtils } from '@aws-cdk/assert'; import * as ec2 from '@aws-cdk/aws-ec2'; import { ManagedPolicy, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as logs from '@aws-cdk/aws-logs'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; -import { nodeunitShim, Test } from 'nodeunit-shim'; +import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; import { AuroraEngineVersion, AuroraMysqlEngineVersion, AuroraPostgresEngineVersion, CfnDBCluster, Credentials, DatabaseCluster, DatabaseClusterEngine, DatabaseClusterFromSnapshot, ParameterGroup, PerformanceInsightRetention, SubnetGroup, } from '../lib'; -nodeunitShim({ - 'creating a Cluster also creates 2 DB Instances'(test: Test) { +describe('cluster', () => { + test('creating a Cluster also creates 2 DB Instances', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -31,7 +32,7 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBCluster', { + expect(stack).toHaveResource('AWS::RDS::DBCluster', { Properties: { Engine: 'aurora', DBSubnetGroupName: { Ref: 'DatabaseSubnets56F17B9A' }, @@ -39,20 +40,20 @@ nodeunitShim({ MasterUserPassword: 'tooshort', VpcSecurityGroupIds: [{ 'Fn::GetAtt': ['DatabaseSecurityGroup5C91FDCB', 'GroupId'] }], }, - DeletionPolicy: ABSENT, + DeletionPolicy: 'Snapshot', UpdateReplacePolicy: 'Snapshot', - }, ResourcePart.CompleteDefinition)); + }, ResourcePart.CompleteDefinition); - expect(stack).to(countResources('AWS::RDS::DBInstance', 2)); - expect(stack).to(haveResource('AWS::RDS::DBInstance', { - DeletionPolicy: ABSENT, - UpdateReplacePolicy: ABSENT, - }, ResourcePart.CompleteDefinition)); + expect(stack).toCountResources('AWS::RDS::DBInstance', 2); + expect(stack).toHaveResource('AWS::RDS::DBInstance', { + DeletionPolicy: 'Delete', + UpdateReplacePolicy: 'Delete', + }, ResourcePart.CompleteDefinition); - test.done(); - }, - 'can create a cluster with a single instance'(test: Test) { + }); + + test('can create a cluster with a single instance', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -72,18 +73,18 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBCluster', { + expect(stack).toHaveResource('AWS::RDS::DBCluster', { Engine: 'aurora', DBSubnetGroupName: { Ref: 'DatabaseSubnets56F17B9A' }, MasterUsername: 'admin', MasterUserPassword: 'tooshort', VpcSecurityGroupIds: [{ 'Fn::GetAtt': ['DatabaseSecurityGroup5C91FDCB', 'GroupId'] }], - })); + }); - test.done(); - }, - 'can create a cluster with imported vpc and security group'(test: Test) { + }); + + test('can create a cluster with imported vpc and security group', () => { // GIVEN const stack = testStack(); const vpc = ec2.Vpc.fromLookup(stack, 'VPC', { @@ -107,18 +108,18 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBCluster', { + expect(stack).toHaveResource('AWS::RDS::DBCluster', { Engine: 'aurora', DBSubnetGroupName: { Ref: 'DatabaseSubnets56F17B9A' }, MasterUsername: 'admin', MasterUserPassword: 'tooshort', VpcSecurityGroupIds: ['SecurityGroupId12345'], - })); + }); - test.done(); - }, - 'cluster with parameter group'(test: Test) { + }); + + test('cluster with parameter group', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -145,14 +146,14 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBCluster', { + expect(stack).toHaveResource('AWS::RDS::DBCluster', { DBClusterParameterGroupName: { Ref: 'ParamsA8366201' }, - })); + }); + - test.done(); - }, + }); - "sets the retention policy of the SubnetGroup to 'Retain' if the Cluster is created with 'Retain'"(test: Test) { + test("sets the retention policy of the SubnetGroup to 'Retain' if the Cluster is created with 'Retain'", () => { const stack = new cdk.Stack(); const vpc = new ec2.Vpc(stack, 'Vpc'); @@ -166,15 +167,15 @@ nodeunitShim({ removalPolicy: cdk.RemovalPolicy.RETAIN, }); - expect(stack).to(haveResourceLike('AWS::RDS::DBSubnetGroup', { + expect(stack).toHaveResourceLike('AWS::RDS::DBSubnetGroup', { DeletionPolicy: 'Retain', UpdateReplacePolicy: 'Retain', - }, ResourcePart.CompleteDefinition)); + }, ResourcePart.CompleteDefinition); - test.done(); - }, - 'creates a secret when master credentials are not specified'(test: Test) { + }); + + test('creates a secret when master credentials are not specified', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -193,7 +194,7 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBCluster', { + expect(stack).toHaveResource('AWS::RDS::DBCluster', { MasterUsername: { 'Fn::Join': [ '', @@ -218,21 +219,21 @@ nodeunitShim({ ], ], }, - })); + }); - expect(stack).to(haveResource('AWS::SecretsManager::Secret', { + expect(stack).toHaveResource('AWS::SecretsManager::Secret', { GenerateSecretString: { ExcludeCharacters: '\"@/\\', GenerateStringKey: 'password', PasswordLength: 30, SecretStringTemplate: '{"username":"admin"}', }, - })); + }); + - test.done(); - }, + }); - 'create an encrypted cluster with custom KMS key'(test: Test) { + test('create an encrypted cluster with custom KMS key', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -251,19 +252,19 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBCluster', { + expect(stack).toHaveResource('AWS::RDS::DBCluster', { KmsKeyId: { 'Fn::GetAtt': [ 'Key961B73FD', 'Arn', ], }, - })); + }); + - test.done(); - }, + }); - 'cluster with instance parameter group'(test: Test) { + test('cluster with instance parameter group', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -287,18 +288,17 @@ nodeunitShim({ }, }); - expect(stack).to(haveResource('AWS::RDS::DBInstance', { + expect(stack).toHaveResource('AWS::RDS::DBInstance', { DBParameterGroupName: { Ref: 'ParameterGroup5E32DECB', }, - })); + }); - test.done(); - }, + }); - 'performance insights': { - 'cluster with all performance insights properties'(test: Test) { + describe('performance insights', () => { + test('cluster with all performance insights properties', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -317,16 +317,16 @@ nodeunitShim({ }, }); - expect(stack).to(haveResource('AWS::RDS::DBInstance', { + expect(stack).toHaveResource('AWS::RDS::DBInstance', { EnablePerformanceInsights: true, PerformanceInsightsRetentionPeriod: 731, PerformanceInsightsKMSKeyId: { 'Fn::GetAtt': ['Key961B73FD', 'Arn'] }, - })); + }); - test.done(); - }, - 'setting performance insights fields enables performance insights'(test: Test) { + }); + + test('setting performance insights fields enables performance insights', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -343,20 +343,20 @@ nodeunitShim({ }, }); - expect(stack).to(haveResource('AWS::RDS::DBInstance', { + expect(stack).toHaveResource('AWS::RDS::DBInstance', { EnablePerformanceInsights: true, PerformanceInsightsRetentionPeriod: 731, - })); + }); - test.done(); - }, - 'throws if performance insights fields are set but performance insights is disabled'(test: Test) { + }); + + test('throws if performance insights fields are set but performance insights is disabled', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); - test.throws(() => { + expect(() => { new DatabaseCluster(stack, 'Database', { engine: DatabaseClusterEngine.AURORA, credentials: { @@ -368,13 +368,13 @@ nodeunitShim({ performanceInsightRetention: PerformanceInsightRetention.DEFAULT, }, }); - }, /`enablePerformanceInsights` disabled, but `performanceInsightRetention` or `performanceInsightEncryptionKey` was set/); + }).toThrow(/`enablePerformanceInsights` disabled, but `performanceInsightRetention` or `performanceInsightEncryptionKey` was set/); - test.done(); - }, - }, - 'cluster with disable automatic upgrade of minor version'(test: Test) { + }); + }); + + test('cluster with disable automatic upgrade of minor version', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -388,14 +388,14 @@ nodeunitShim({ }, }); - expect(stack).to(haveResource('AWS::RDS::DBInstance', { + expect(stack).toHaveResource('AWS::RDS::DBInstance', { AutoMinorVersionUpgrade: false, - })); + }); + - test.done(); - }, + }); - 'cluster with allow upgrade of major version'(test: Test) { + test('cluster with allow upgrade of major version', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -409,14 +409,14 @@ nodeunitShim({ }, }); - expect(stack).to(haveResourceLike('AWS::RDS::DBInstance', { + expect(stack).toHaveResourceLike('AWS::RDS::DBInstance', { AllowMajorVersionUpgrade: true, - })); + }); + - test.done(); - }, + }); - 'cluster with disallow remove backups'(test: Test) { + test('cluster with disallow remove backups', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -430,14 +430,14 @@ nodeunitShim({ }, }); - expect(stack).to(haveResourceLike('AWS::RDS::DBInstance', { + expect(stack).toHaveResourceLike('AWS::RDS::DBInstance', { DeleteAutomatedBackups: false, - })); + }); + - test.done(); - }, + }); - 'create a cluster using a specific version of MySQL'(test: Test) { + test('create a cluster using a specific version of MySQL', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -457,15 +457,15 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBCluster', { + expect(stack).toHaveResource('AWS::RDS::DBCluster', { Engine: 'aurora-mysql', EngineVersion: '5.7.mysql_aurora.2.04.4', - })); + }); + - test.done(); - }, + }); - 'create a cluster using a specific version of Postgresql'(test: Test) { + test('create a cluster using a specific version of Postgresql', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -485,15 +485,15 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBCluster', { + expect(stack).toHaveResource('AWS::RDS::DBCluster', { Engine: 'aurora-postgresql', EngineVersion: '10.7', - })); + }); - test.done(); - }, - 'cluster exposes different read and write endpoints'(test: Test) { + }); + + test('cluster exposes different read and write endpoints', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -511,15 +511,12 @@ nodeunitShim({ }); // THEN - test.notDeepEqual( - stack.resolve(cluster.clusterEndpoint), - stack.resolve(cluster.clusterReadEndpoint), - ); + expect(stack.resolve(cluster.clusterEndpoint)).not.toEqual(stack.resolve(cluster.clusterReadEndpoint)); + - test.done(); - }, + }); - 'imported cluster with imported security group honors allowAllOutbound'(test: Test) { + test('imported cluster with imported security group honors allowAllOutbound', () => { // GIVEN const stack = testStack(); @@ -539,41 +536,41 @@ nodeunitShim({ cluster.connections.allowToAnyIpv4(ec2.Port.tcp(443)); // THEN - expect(stack).to(haveResource('AWS::EC2::SecurityGroupEgress', { + expect(stack).toHaveResource('AWS::EC2::SecurityGroupEgress', { GroupId: 'sg-123456789', - })); + }); + - test.done(); - }, + }); - 'can import a cluster with minimal attributes'(test: Test) { + test('can import a cluster with minimal attributes', () => { const stack = testStack(); const cluster = DatabaseCluster.fromDatabaseClusterAttributes(stack, 'Database', { clusterIdentifier: 'identifier', }); - test.equals(cluster.clusterIdentifier, 'identifier'); + expect(cluster.clusterIdentifier).toEqual('identifier'); - test.done(); - }, - 'minimal imported cluster throws on accessing attributes for unprovided parameters'(test: Test) { + }); + + test('minimal imported cluster throws on accessing attributes for unprovided parameters', () => { const stack = testStack(); const cluster = DatabaseCluster.fromDatabaseClusterAttributes(stack, 'Database', { clusterIdentifier: 'identifier', }); - test.throws(() => cluster.clusterEndpoint, /Cannot access `clusterEndpoint` of an imported cluster/); - test.throws(() => cluster.clusterReadEndpoint, /Cannot access `clusterReadEndpoint` of an imported cluster/); - test.throws(() => cluster.instanceIdentifiers, /Cannot access `instanceIdentifiers` of an imported cluster/); - test.throws(() => cluster.instanceEndpoints, /Cannot access `instanceEndpoints` of an imported cluster/); + expect(() => cluster.clusterEndpoint).toThrow(/Cannot access `clusterEndpoint` of an imported cluster/); + expect(() => cluster.clusterReadEndpoint).toThrow(/Cannot access `clusterReadEndpoint` of an imported cluster/); + expect(() => cluster.instanceIdentifiers).toThrow(/Cannot access `instanceIdentifiers` of an imported cluster/); + expect(() => cluster.instanceEndpoints).toThrow(/Cannot access `instanceEndpoints` of an imported cluster/); + - test.done(); - }, + }); - 'imported cluster can access properties if attributes are provided'(test: Test) { + test('imported cluster can access properties if attributes are provided', () => { const stack = testStack(); const cluster = DatabaseCluster.fromDatabaseClusterAttributes(stack, 'Database', { @@ -588,15 +585,15 @@ nodeunitShim({ })], }); - test.equals(cluster.clusterEndpoint.socketAddress, 'addr:3306'); - test.equals(cluster.clusterReadEndpoint.socketAddress, 'reader-address:3306'); - test.deepEqual(cluster.instanceIdentifiers, ['identifier']); - test.deepEqual(cluster.instanceEndpoints.map(endpoint => endpoint.socketAddress), ['instance-addr:3306']); + expect(cluster.clusterEndpoint.socketAddress).toEqual('addr:3306'); + expect(cluster.clusterReadEndpoint.socketAddress).toEqual('reader-address:3306'); + expect(cluster.instanceIdentifiers).toEqual(['identifier']); + expect(cluster.instanceEndpoints.map(endpoint => endpoint.socketAddress)).toEqual(['instance-addr:3306']); + - test.done(); - }, + }); - 'cluster supports metrics'(test: Test) { + test('cluster supports metrics', () => { const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -611,7 +608,7 @@ nodeunitShim({ }, }); - test.deepEqual(stack.resolve(cluster.metricCPUUtilization()), { + expect(stack.resolve(cluster.metricCPUUtilization())).toEqual({ dimensions: { DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' } }, namespace: 'AWS/RDS', metricName: 'CPUUtilization', @@ -621,10 +618,10 @@ nodeunitShim({ region: 'us-test-1', }); - test.done(); - }, - 'cluster with enabled monitoring'(test: Test) { + }); + + test('cluster with enabled monitoring', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -644,14 +641,14 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBInstance', { + expect(stack).toHaveResource('AWS::RDS::DBInstance', { MonitoringInterval: 60, MonitoringRoleArn: { 'Fn::GetAtt': ['DatabaseMonitoringRole576991DA', 'Arn'], }, - }, ResourcePart.Properties)); + }, ResourcePart.Properties); - expect(stack).to(haveResource('AWS::IAM::Role', { + expect(stack).toHaveResource('AWS::IAM::Role', { AssumeRolePolicyDocument: { Statement: [ { @@ -678,12 +675,12 @@ nodeunitShim({ ], }, ], - })); + }); - test.done(); - }, - 'create a cluster with imported monitoring role'(test: Test) { + }); + + test('create a cluster with imported monitoring role', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -711,17 +708,17 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBInstance', { + expect(stack).toHaveResource('AWS::RDS::DBInstance', { MonitoringInterval: 60, MonitoringRoleArn: { 'Fn::GetAtt': ['MonitoringRole90457BF9', 'Arn'], }, - }, ResourcePart.Properties)); + }, ResourcePart.Properties); + - test.done(); - }, + }); - 'throws when trying to add rotation to a cluster without secret'(test: Test) { + test('throws when trying to add rotation to a cluster without secret', () => { // GIVEN const stack = new cdk.Stack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -740,12 +737,12 @@ nodeunitShim({ }); // THEN - test.throws(() => cluster.addRotationSingleUser(), /without secret/); + expect(() => cluster.addRotationSingleUser()).toThrow(/without secret/); - test.done(); - }, - 'throws when trying to add single user rotation multiple times'(test: Test) { + }); + + test('throws when trying to add single user rotation multiple times', () => { // GIVEN const stack = new cdk.Stack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -762,12 +759,12 @@ nodeunitShim({ cluster.addRotationSingleUser(); // THEN - test.throws(() => cluster.addRotationSingleUser(), /A single user rotation was already added to this cluster/); + expect(() => cluster.addRotationSingleUser()).toThrow(/A single user rotation was already added to this cluster/); + - test.done(); - }, + }); - 'create a cluster with s3 import role'(test: Test) { + test('create a cluster with s3 import role', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -791,7 +788,7 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBCluster', { + expect(stack).toHaveResource('AWS::RDS::DBCluster', { AssociatedRoles: [{ RoleArn: { 'Fn::GetAtt': [ @@ -800,9 +797,9 @@ nodeunitShim({ ], }, }], - })); + }); - expect(stack).to(haveResource('AWS::RDS::DBClusterParameterGroup', { + expect(stack).toHaveResource('AWS::RDS::DBClusterParameterGroup', { Family: 'aurora5.6', Parameters: { aurora_load_from_s3_role: { @@ -812,12 +809,12 @@ nodeunitShim({ ], }, }, - })); + }); + - test.done(); - }, + }); - 'create a cluster with s3 import buckets'(test: Test) { + test('create a cluster with s3 import buckets', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -839,7 +836,7 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBCluster', { + expect(stack).toHaveResource('AWS::RDS::DBCluster', { AssociatedRoles: [{ RoleArn: { 'Fn::GetAtt': [ @@ -848,9 +845,9 @@ nodeunitShim({ ], }, }], - })); + }); - expect(stack).to(haveResource('AWS::RDS::DBClusterParameterGroup', { + expect(stack).toHaveResource('AWS::RDS::DBClusterParameterGroup', { Family: 'aurora5.6', Parameters: { aurora_load_from_s3_role: { @@ -860,9 +857,9 @@ nodeunitShim({ ], }, }, - })); + }); - expect(stack).to(haveResource('AWS::IAM::Policy', { + expect(stack).toHaveResource('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -898,12 +895,12 @@ nodeunitShim({ ], Version: '2012-10-17', }, - })); + }); + - test.done(); - }, + }); - 'cluster with s3 import bucket adds supported feature name to IAM role'(test: Test) { + test('cluster with s3 import bucket adds supported feature name to IAM role', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -927,7 +924,7 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBCluster', { + expect(stack).toHaveResource('AWS::RDS::DBCluster', { AssociatedRoles: [{ RoleArn: { 'Fn::GetAtt': [ @@ -937,12 +934,12 @@ nodeunitShim({ }, FeatureName: 's3Import', }], - })); + }); + - test.done(); - }, + }); - 'throws when s3 import bucket or s3 export bucket is supplied for a Postgres version that does not support it'(test: Test) { + test('throws when s3 import bucket or s3 export bucket is supplied for a Postgres version that does not support it', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -950,7 +947,7 @@ nodeunitShim({ const bucket = new s3.Bucket(stack, 'Bucket'); // WHEN / THEN - test.throws(() => { + expect(() => { new DatabaseCluster(stack, 'Database', { engine: DatabaseClusterEngine.auroraPostgres({ version: AuroraPostgresEngineVersion.VER_10_4, @@ -965,9 +962,9 @@ nodeunitShim({ }, s3ImportBuckets: [bucket], }); - }, /s3Import is not supported for Postgres version: 10.4. Use a version that supports the s3Import feature./); + }).toThrow(/s3Import is not supported for Postgres version: 10.4. Use a version that supports the s3Import feature./); - test.throws(() => { + expect(() => { new DatabaseCluster(stack, 'AnotherDatabase', { engine: DatabaseClusterEngine.auroraPostgres({ version: AuroraPostgresEngineVersion.VER_10_4, @@ -982,12 +979,12 @@ nodeunitShim({ }, s3ExportBuckets: [bucket], }); - }, /s3Export is not supported for Postgres version: 10.4. Use a version that supports the s3Export feature./); + }).toThrow(/s3Export is not supported for Postgres version: 10.4. Use a version that supports the s3Export feature./); - test.done(); - }, - 'cluster with s3 export bucket adds supported feature name to IAM role'(test: Test) { + }); + + test('cluster with s3 export bucket adds supported feature name to IAM role', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -1011,7 +1008,7 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBCluster', { + expect(stack).toHaveResource('AWS::RDS::DBCluster', { AssociatedRoles: [{ RoleArn: { 'Fn::GetAtt': [ @@ -1021,12 +1018,12 @@ nodeunitShim({ }, FeatureName: 's3Export', }], - })); + }); - test.done(); - }, - 'create a cluster with s3 export role'(test: Test) { + }); + + test('create a cluster with s3 export role', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -1050,7 +1047,7 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBCluster', { + expect(stack).toHaveResource('AWS::RDS::DBCluster', { AssociatedRoles: [{ RoleArn: { 'Fn::GetAtt': [ @@ -1059,9 +1056,9 @@ nodeunitShim({ ], }, }], - })); + }); - expect(stack).to(haveResource('AWS::RDS::DBClusterParameterGroup', { + expect(stack).toHaveResource('AWS::RDS::DBClusterParameterGroup', { Family: 'aurora5.6', Parameters: { aurora_select_into_s3_role: { @@ -1071,14 +1068,14 @@ nodeunitShim({ ], }, }, - })); + }); - test.done(); - }, - 'create a cluster with s3 export buckets'(test: Test) { + }); + + testFutureBehavior('create a cluster with s3 export buckets', { '@aws-cdk/aws-s3:grantWriteWithoutAcl': true }, cdk.App, (app) => { // GIVEN - const stack = testStack(); + const stack = testStack(app); const vpc = new ec2.Vpc(stack, 'VPC'); const bucket = new s3.Bucket(stack, 'Bucket'); @@ -1098,7 +1095,7 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBCluster', { + expect(stack).toHaveResource('AWS::RDS::DBCluster', { AssociatedRoles: [{ RoleArn: { 'Fn::GetAtt': [ @@ -1107,9 +1104,9 @@ nodeunitShim({ ], }, }], - })); + }); - expect(stack).to(haveResource('AWS::RDS::DBClusterParameterGroup', { + expect(stack).toHaveResource('AWS::RDS::DBClusterParameterGroup', { Family: 'aurora5.6', Parameters: { aurora_select_into_s3_role: { @@ -1119,9 +1116,9 @@ nodeunitShim({ ], }, }, - })); + }); - expect(stack).to(haveResource('AWS::IAM::Policy', { + expect(stack).toHaveResource('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -1130,7 +1127,7 @@ nodeunitShim({ 's3:GetBucket*', 's3:List*', 's3:DeleteObject*', - 's3:PutObject*', + 's3:PutObject', 's3:Abort*', ], Effect: 'Allow', @@ -1160,12 +1157,12 @@ nodeunitShim({ ], Version: '2012-10-17', }, - })); + }); + - test.done(); - }, + }); - 'create a cluster with s3 import and export buckets'(test: Test) { + test('create a cluster with s3 import and export buckets', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -1189,7 +1186,7 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBCluster', { + expect(stack).toHaveResource('AWS::RDS::DBCluster', { AssociatedRoles: [{ RoleArn: { 'Fn::GetAtt': [ @@ -1206,9 +1203,9 @@ nodeunitShim({ ], }, }], - })); + }); - expect(stack).to(haveResource('AWS::RDS::DBClusterParameterGroup', { + expect(stack).toHaveResource('AWS::RDS::DBClusterParameterGroup', { Family: 'aurora5.6', Parameters: { aurora_load_from_s3_role: { @@ -1224,12 +1221,12 @@ nodeunitShim({ ], }, }, - })); + }); + - test.done(); - }, + }); - 'create a cluster with s3 import and export buckets and custom parameter group'(test: Test) { + test('create a cluster with s3 import and export buckets and custom parameter group', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -1261,7 +1258,7 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBCluster', { + expect(stack).toHaveResource('AWS::RDS::DBCluster', { AssociatedRoles: [{ RoleArn: { 'Fn::GetAtt': [ @@ -1278,9 +1275,9 @@ nodeunitShim({ ], }, }], - })); + }); - expect(stack).to(haveResource('AWS::RDS::DBClusterParameterGroup', { + expect(stack).toHaveResource('AWS::RDS::DBClusterParameterGroup', { Family: 'aurora5.6', Parameters: { key: 'value', @@ -1297,12 +1294,12 @@ nodeunitShim({ ], }, }, - })); + }); - test.done(); - }, - 'PostgreSQL cluster with s3 export buckets does not generate custom parameter group and specifies the correct port'(test: Test) { + }); + + test('PostgreSQL cluster with s3 export buckets does not generate custom parameter group and specifies the correct port', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -1326,7 +1323,7 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResourceLike('AWS::RDS::DBCluster', { + expect(stack).toHaveResourceLike('AWS::RDS::DBCluster', { AssociatedRoles: [{ RoleArn: { 'Fn::GetAtt': [ @@ -1337,14 +1334,14 @@ nodeunitShim({ }], DBClusterParameterGroupName: 'default.aurora-postgresql11', Port: 5432, - })); + }); + + expect(stack).not.toHaveResource('AWS::RDS::DBClusterParameterGroup'); - expect(stack).notTo(haveResource('AWS::RDS::DBClusterParameterGroup')); - test.done(); - }, + }); - 'unversioned PostgreSQL cluster can be used with s3 import and s3 export buckets'(test: Test) { + test('unversioned PostgreSQL cluster can be used with s3 import and s3 export buckets', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -1368,7 +1365,7 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBCluster', { + expect(stack).toHaveResource('AWS::RDS::DBCluster', { AssociatedRoles: [ { FeatureName: 's3Import', @@ -1389,12 +1386,12 @@ nodeunitShim({ }, }, ], - })); + }); + - test.done(); - }, + }); - "Aurora PostgreSQL cluster uses a different default master username than 'admin', which is a reserved word"(test: Test) { + test("Aurora PostgreSQL cluster uses a different default master username than 'admin', which is a reserved word", () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -1408,16 +1405,16 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResourceLike('AWS::SecretsManager::Secret', { + expect(stack).toHaveResourceLike('AWS::SecretsManager::Secret', { GenerateSecretString: { SecretStringTemplate: '{"username":"postgres"}', }, - })); + }); - test.done(); - }, - 'MySQL cluster without S3 exports or imports references the correct default ParameterGroup'(test: Test) { + }); + + test('MySQL cluster without S3 exports or imports references the correct default ParameterGroup', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -1436,16 +1433,16 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResourceLike('AWS::RDS::DBCluster', { + expect(stack).toHaveResourceLike('AWS::RDS::DBCluster', { DBClusterParameterGroupName: 'default.aurora-mysql5.7', - })); + }); + + expect(stack).not.toHaveResource('AWS::RDS::DBClusterParameterGroup'); - expect(stack).notTo(haveResource('AWS::RDS::DBClusterParameterGroup')); - test.done(); - }, + }); - 'throws when s3ExportRole and s3ExportBuckets properties are both specified'(test: Test) { + test('throws when s3ExportRole and s3ExportBuckets properties are both specified', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -1456,7 +1453,7 @@ nodeunitShim({ const exportBucket = new s3.Bucket(stack, 'ExportBucket'); // THEN - test.throws(() => new DatabaseCluster(stack, 'Database', { + expect(() => new DatabaseCluster(stack, 'Database', { engine: DatabaseClusterEngine.AURORA, instances: 1, credentials: { @@ -1468,12 +1465,12 @@ nodeunitShim({ }, s3ExportRole: exportRole, s3ExportBuckets: [exportBucket], - })); + })).toThrow(); - test.done(); - }, - 'throws when s3ImportRole and s3ImportBuckets properties are both specified'(test: Test) { + }); + + test('throws when s3ImportRole and s3ImportBuckets properties are both specified', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -1484,7 +1481,7 @@ nodeunitShim({ const importBucket = new s3.Bucket(stack, 'ImportBucket'); // THEN - test.throws(() => new DatabaseCluster(stack, 'Database', { + expect(() => new DatabaseCluster(stack, 'Database', { engine: DatabaseClusterEngine.AURORA, instances: 1, credentials: { @@ -1496,12 +1493,12 @@ nodeunitShim({ }, s3ImportRole: importRole, s3ImportBuckets: [importBucket], - })); + })).toThrow(); + - test.done(); - }, + }); - 'can set CloudWatch log exports'(test: Test) { + test('can set CloudWatch log exports', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -1521,14 +1518,14 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResourceLike('AWS::RDS::DBCluster', { + expect(stack).toHaveResourceLike('AWS::RDS::DBCluster', { EnableCloudwatchLogsExports: ['error', 'general', 'slowquery', 'audit'], - })); + }); + - test.done(); - }, + }); - 'can set CloudWatch log retention'(test: Test) { + test('can set CloudWatch log retention', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -1549,7 +1546,7 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('Custom::LogRetention', { + expect(stack).toHaveResource('Custom::LogRetention', { ServiceToken: { 'Fn::GetAtt': [ 'LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aFD4BFC8A', @@ -1558,8 +1555,8 @@ nodeunitShim({ }, LogGroupName: { 'Fn::Join': ['', ['/aws/rds/cluster/', { Ref: 'DatabaseB269D8BB' }, '/error']] }, RetentionInDays: 90, - })); - expect(stack).to(haveResource('Custom::LogRetention', { + }); + expect(stack).toHaveResource('Custom::LogRetention', { ServiceToken: { 'Fn::GetAtt': [ 'LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aFD4BFC8A', @@ -1568,17 +1565,17 @@ nodeunitShim({ }, LogGroupName: { 'Fn::Join': ['', ['/aws/rds/cluster/', { Ref: 'DatabaseB269D8BB' }, '/general']] }, RetentionInDays: 90, - })); + }); + - test.done(); - }, + }); - 'throws if given unsupported CloudWatch log exports'(test: Test) { + test('throws if given unsupported CloudWatch log exports', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); - test.throws(() => { + expect(() => { new DatabaseCluster(stack, 'Database', { engine: DatabaseClusterEngine.AURORA, credentials: { @@ -1591,12 +1588,12 @@ nodeunitShim({ }, cloudwatchLogsExports: ['error', 'general', 'slowquery', 'audit', 'thislogdoesnotexist', 'neitherdoesthisone'], }); - }, /Unsupported logs for the current engine type: thislogdoesnotexist,neitherdoesthisone/); + }).toThrow(/Unsupported logs for the current engine type: thislogdoesnotexist,neitherdoesthisone/); - test.done(); - }, - 'can set deletion protection'(test: Test) { + }); + + test('can set deletion protection', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -1616,14 +1613,14 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResourceLike('AWS::RDS::DBCluster', { + expect(stack).toHaveResourceLike('AWS::RDS::DBCluster', { DeletionProtection: true, - })); + }); + - test.done(); - }, + }); - 'does not throw (but adds a node error) if a (dummy) VPC does not have sufficient subnets'(test: Test) { + test('does not throw (but adds a node error) if a (dummy) VPC does not have sufficient subnets', () => { // GIVEN const stack = testStack(); const vpc = ec2.Vpc.fromLookup(stack, 'VPC', { isDefault: true }); @@ -1647,12 +1644,12 @@ nodeunitShim({ // THEN const art = SynthUtils.synthesize(stack); const meta = art.findMetadataByType('aws:cdk:error'); - test.equal(meta[0].data, 'Cluster requires at least 2 subnets, got 0'); + expect(meta[0].data).toEqual('Cluster requires at least 2 subnets, got 0'); - test.done(); - }, - 'create a cluster from a snapshot'(test: Test) { + }); + + test('create a cluster from a snapshot', () => { const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -1666,7 +1663,7 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBCluster', { + expect(stack).toHaveResource('AWS::RDS::DBCluster', { Properties: { Engine: 'aurora', EngineVersion: '5.6.mysql_aurora.1.22.2', @@ -1674,16 +1671,16 @@ nodeunitShim({ VpcSecurityGroupIds: [{ 'Fn::GetAtt': ['DatabaseSecurityGroup5C91FDCB', 'GroupId'] }], SnapshotIdentifier: 'mySnapshot', }, - DeletionPolicy: ABSENT, + DeletionPolicy: 'Snapshot', UpdateReplacePolicy: 'Snapshot', - }, ResourcePart.CompleteDefinition)); + }, ResourcePart.CompleteDefinition); + + expect(stack).toCountResources('AWS::RDS::DBInstance', 2); - expect(stack).to(countResources('AWS::RDS::DBInstance', 2)); - test.done(); - }, + }); - 'reuse an existing subnet group'(test: Test) { + test('reuse an existing subnet group', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -1701,15 +1698,15 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResourceLike('AWS::RDS::DBCluster', { + expect(stack).toHaveResourceLike('AWS::RDS::DBCluster', { DBSubnetGroupName: 'my-subnet-group', - })); - expect(stack).to(countResources('AWS::RDS::DBSubnetGroup', 0)); + }); + expect(stack).toCountResources('AWS::RDS::DBSubnetGroup', 0); - test.done(); - }, - 'defaultChild returns the DB Cluster'(test: Test) { + }); + + test('defaultChild returns the DB Cluster', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -1726,12 +1723,12 @@ nodeunitShim({ }); // THEN - test.ok(cluster.node.defaultChild instanceof CfnDBCluster); + expect(cluster.node.defaultChild instanceof CfnDBCluster).toBeTruthy(); + - test.done(); - }, + }); - 'fromGeneratedSecret'(test: Test) { + test('fromGeneratedSecret', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -1746,7 +1743,7 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBCluster', { + expect(stack).toHaveResource('AWS::RDS::DBCluster', { MasterUsername: 'admin', // username is a string MasterUserPassword: { 'Fn::Join': [ @@ -1760,12 +1757,12 @@ nodeunitShim({ ], ], }, - })); + }); + - test.done(); - }, + }); - 'can set public accessibility for database cluster with instances in private subnet'(test: Test) { + test('can set public accessibility for database cluster with instances in private subnet', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -1782,15 +1779,15 @@ nodeunitShim({ }, }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBInstance', { + expect(stack).toHaveResource('AWS::RDS::DBInstance', { Engine: 'aurora', PubliclyAccessible: true, - })); + }); + - test.done(); - }, + }); - 'can set public accessibility for database cluster with instances in public subnet'(test: Test) { + test('can set public accessibility for database cluster with instances in public subnet', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -1807,15 +1804,15 @@ nodeunitShim({ }, }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBInstance', { + expect(stack).toHaveResource('AWS::RDS::DBInstance', { Engine: 'aurora', PubliclyAccessible: false, - })); + }); - test.done(); - }, - 'database cluster instances in public subnet should by default have publiclyAccessible set to true'(test: Test) { + }); + + test('database cluster instances in public subnet should by default have publiclyAccessible set to true', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -1831,17 +1828,52 @@ nodeunitShim({ }, }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBInstance', { + expect(stack).toHaveResource('AWS::RDS::DBInstance', { Engine: 'aurora', PubliclyAccessible: true, - })); + }); + - test.done(); - }, + }); +}); + +test.each([ + [cdk.RemovalPolicy.RETAIN, 'Retain', 'Retain', 'Retain'], + [cdk.RemovalPolicy.SNAPSHOT, 'Snapshot', 'Delete', ABSENT], + [cdk.RemovalPolicy.DESTROY, 'Delete', 'Delete', ABSENT], +])('if Cluster RemovalPolicy is \'%s\', the DBCluster has DeletionPolicy \'%s\', the DBInstance has \'%s\' and the DBSubnetGroup has \'%s\'', (clusterRemovalPolicy, clusterValue, instanceValue, subnetValue) => { + const stack = new cdk.Stack(); + + // WHEN + new DatabaseCluster(stack, 'Cluster', { + credentials: { username: 'admin' }, + engine: DatabaseClusterEngine.AURORA, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.LARGE), + vpc: new ec2.Vpc(stack, 'Vpc'), + }, + removalPolicy: clusterRemovalPolicy, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::RDS::DBCluster', { + DeletionPolicy: clusterValue, + UpdateReplacePolicy: clusterValue, + }, ResourcePart.CompleteDefinition); + + expect(stack).toHaveResourceLike('AWS::RDS::DBInstance', { + DeletionPolicy: instanceValue, + UpdateReplacePolicy: instanceValue, + }, ResourcePart.CompleteDefinition); + + expect(stack).toHaveResourceLike('AWS::RDS::DBSubnetGroup', { + DeletionPolicy: subnetValue, + UpdateReplacePolicy: subnetValue, + }, ResourcePart.CompleteDefinition); }); -function testStack() { - const stack = new cdk.Stack(undefined, undefined, { env: { account: '12345', region: 'us-test-1' } }); +function testStack(app?: cdk.App) { + const stack = new cdk.Stack(app, undefined, { env: { account: '12345', region: 'us-test-1' } }); stack.node.setContext('availability-zones:12345:us-test-1', ['us-test-1a', 'us-test-1b']); return stack; } diff --git a/packages/@aws-cdk/aws-rds/test/database-secretmanager.test.ts b/packages/@aws-cdk/aws-rds/test/database-secretmanager.test.ts index 760a16e228cd7..d307c0f05cec6 100644 --- a/packages/@aws-cdk/aws-rds/test/database-secretmanager.test.ts +++ b/packages/@aws-cdk/aws-rds/test/database-secretmanager.test.ts @@ -1,4 +1,4 @@ -import { ABSENT, expect, haveResource, ResourcePart } from '@aws-cdk/assert'; +import { expect, haveResource, ResourcePart } from '@aws-cdk/assert'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; import * as cdk from '@aws-cdk/core'; @@ -41,7 +41,7 @@ nodeunitShim({ }, ], }, - DeletionPolicy: ABSENT, + DeletionPolicy: 'Snapshot', UpdateReplacePolicy: 'Snapshot', }, ResourcePart.CompleteDefinition)); diff --git a/packages/@aws-cdk/aws-rds/test/instance.test.ts b/packages/@aws-cdk/aws-rds/test/instance.test.ts index 8c4e4460f65f1..67fc9fd3905ff 100644 --- a/packages/@aws-cdk/aws-rds/test/instance.test.ts +++ b/packages/@aws-cdk/aws-rds/test/instance.test.ts @@ -1,4 +1,5 @@ -import { ABSENT, countResources, expect, haveResource, ResourcePart, haveResourceLike, anything } from '@aws-cdk/assert'; +import '@aws-cdk/assert/jest'; +import { ABSENT, ResourcePart, anything } from '@aws-cdk/assert'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as targets from '@aws-cdk/aws-events-targets'; import { ManagedPolicy, Role, ServicePrincipal, AccountPrincipal } from '@aws-cdk/aws-iam'; @@ -7,20 +8,19 @@ import * as lambda from '@aws-cdk/aws-lambda'; import * as logs from '@aws-cdk/aws-logs'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; -import { nodeunitShim, Test } from 'nodeunit-shim'; +import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; import * as rds from '../lib'; let stack: cdk.Stack; let vpc: ec2.Vpc; -nodeunitShim({ - 'setUp'(cb: () => void) { +describe('instance', () => { + beforeEach(() => { stack = new cdk.Stack(); vpc = new ec2.Vpc(stack, 'VPC'); - cb(); - }, + }); - 'create a DB instance'(test: Test) { + test('create a DB instance', () => { // WHEN new rds.DatabaseInstance(stack, 'Instance', { engine: rds.DatabaseInstanceEngine.oracleSe2({ version: rds.OracleEngineVersion.VER_19_0_0_0_2020_04_R1 }), @@ -48,7 +48,7 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBInstance', { + expect(stack).toHaveResource('AWS::RDS::DBInstance', { Properties: { DBInstanceClass: 'db.t2.medium', AllocatedStorage: '100', @@ -114,11 +114,11 @@ nodeunitShim({ }, ], }, - DeletionPolicy: ABSENT, + DeletionPolicy: 'Snapshot', UpdateReplacePolicy: 'Snapshot', - }, ResourcePart.CompleteDefinition)); + }, ResourcePart.CompleteDefinition); - expect(stack).to(haveResource('AWS::RDS::DBSubnetGroup', { + expect(stack).toHaveResource('AWS::RDS::DBSubnetGroup', { DBSubnetGroupDescription: 'Subnet group for Instance database', SubnetIds: [ { @@ -128,13 +128,13 @@ nodeunitShim({ Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A', }, ], - })); + }); - expect(stack).to(haveResource('AWS::EC2::SecurityGroup', { + expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { GroupDescription: 'Security group for Instance database', - })); + }); - expect(stack).to(haveResource('AWS::IAM::Role', { + expect(stack).toHaveResource('AWS::IAM::Role', { AssumeRolePolicyDocument: { Statement: [ { @@ -161,9 +161,9 @@ nodeunitShim({ ], }, ], - })); + }); - expect(stack).to(haveResource('AWS::SecretsManager::Secret', { + expect(stack).toHaveResource('AWS::SecretsManager::Secret', { Description: { 'Fn::Join': [ '', @@ -181,9 +181,9 @@ nodeunitShim({ PasswordLength: 30, SecretStringTemplate: '{"username":"syscdk"}', }, - })); + }); - expect(stack).to(haveResource('AWS::SecretsManager::SecretTargetAttachment', { + expect(stack).toHaveResource('AWS::SecretsManager::SecretTargetAttachment', { SecretId: { Ref: 'InstanceSecret478E0A47', }, @@ -191,14 +191,14 @@ nodeunitShim({ Ref: 'InstanceC1063A87', }, TargetType: 'AWS::RDS::DBInstance', - })); + }); + + expect(stack).toCountResources('Custom::LogRetention', 4); - expect(stack).to(countResources('Custom::LogRetention', 4)); - test.done(); - }, + }); - 'instance with option and parameter group'(test: Test) { + test('instance with option and parameter group', () => { const optionGroup = new rds.OptionGroup(stack, 'OptionGroup', { engine: rds.DatabaseInstanceEngine.oracleSe2({ version: rds.OracleEngineVersion.VER_19_0_0_0_2020_04_R1 }), configurations: [ @@ -227,19 +227,19 @@ nodeunitShim({ parameterGroup, }); - expect(stack).to(haveResource('AWS::RDS::DBInstance', { + expect(stack).toHaveResource('AWS::RDS::DBInstance', { DBParameterGroupName: { Ref: 'ParameterGroup5E32DECB', }, OptionGroupName: { Ref: 'OptionGroupACA43DC1', }, - })); + }); - test.done(); - }, - 'can specify subnet type'(test: Test) { + }); + + test('can specify subnet type', () => { new rds.DatabaseInstance(stack, 'Instance', { engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19, @@ -251,13 +251,13 @@ nodeunitShim({ }, }); - expect(stack).to(haveResource('AWS::RDS::DBInstance', { + expect(stack).toHaveResource('AWS::RDS::DBInstance', { DBSubnetGroupName: { Ref: 'InstanceSubnetGroupF2CBA54F', }, PubliclyAccessible: false, - })); - expect(stack).to(haveResource('AWS::RDS::DBSubnetGroup', { + }); + expect(stack).toHaveResource('AWS::RDS::DBSubnetGroup', { DBSubnetGroupDescription: 'Subnet group for Instance database', SubnetIds: [ { @@ -267,13 +267,13 @@ nodeunitShim({ Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A', }, ], - })); + }); - test.done(); - }, - 'DatabaseInstanceFromSnapshot': { - 'create an instance from snapshot'(test: Test) { + }); + + describe('DatabaseInstanceFromSnapshot', () => { + test('create an instance from snapshot', () => { new rds.DatabaseInstanceFromSnapshot(stack, 'Instance', { snapshotIdentifier: 'my-snapshot', engine: rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_12_3 }), @@ -281,14 +281,14 @@ nodeunitShim({ vpc, }); - expect(stack).to(haveResource('AWS::RDS::DBInstance', { + expect(stack).toHaveResource('AWS::RDS::DBInstance', { DBSnapshotIdentifier: 'my-snapshot', - })); + }); - test.done(); - }, - 'can generate a new snapshot password'(test: Test) { + }); + + test('can generate a new snapshot password', () => { new rds.DatabaseInstanceFromSnapshot(stack, 'Instance', { snapshotIdentifier: 'my-snapshot', engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19 }), @@ -298,13 +298,13 @@ nodeunitShim({ }), }); - expect(stack).to(haveResourceLike('AWS::RDS::DBInstance', { + expect(stack).toHaveResourceLike('AWS::RDS::DBInstance', { MasterUsername: ABSENT, MasterUserPassword: { 'Fn::Join': ['', ['{{resolve:secretsmanager:', { Ref: 'InstanceSecret478E0A47' }, ':SecretString:password::}}']], }, - })); - expect(stack).to(haveResource('AWS::SecretsManager::Secret', { + }); + expect(stack).toHaveResource('AWS::SecretsManager::Secret', { Description: { 'Fn::Join': ['', ['Generated by the CDK for stack: ', { Ref: 'AWS::StackName' }]], }, @@ -314,12 +314,12 @@ nodeunitShim({ PasswordLength: 30, SecretStringTemplate: '{"username":"admin"}', }, - })); + }); - test.done(); - }, - 'fromGeneratedSecret'(test: Test) { + }); + + test('fromGeneratedSecret', () => { new rds.DatabaseInstanceFromSnapshot(stack, 'Instance', { snapshotIdentifier: 'my-snapshot', engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19 }), @@ -329,29 +329,29 @@ nodeunitShim({ }), }); - expect(stack).to(haveResourceLike('AWS::RDS::DBInstance', { + expect(stack).toHaveResourceLike('AWS::RDS::DBInstance', { MasterUsername: ABSENT, MasterUserPassword: { // logical id of secret has a hash 'Fn::Join': ['', ['{{resolve:secretsmanager:', { Ref: 'InstanceSecretB6DFA6BE8ee0a797cad8a68dbeb85f8698cdb5bb' }, ':SecretString:password::}}']], }, - })); + }); - test.done(); - }, - 'throws if generating a new password without a username'(test: Test) { - test.throws(() => new rds.DatabaseInstanceFromSnapshot(stack, 'Instance', { + }); + + test('throws if generating a new password without a username', () => { + expect(() => new rds.DatabaseInstanceFromSnapshot(stack, 'Instance', { snapshotIdentifier: 'my-snapshot', engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19 }), vpc, credentials: { generatePassword: true }, - }), /`credentials` `username` must be specified when `generatePassword` is set to true/); + })).toThrow(/`credentials` `username` must be specified when `generatePassword` is set to true/); + - test.done(); - }, + }); - 'can set a new snapshot password from an existing SecretValue'(test: Test) { + test('can set a new snapshot password from an existing SecretValue', () => { new rds.DatabaseInstanceFromSnapshot(stack, 'Instance', { snapshotIdentifier: 'my-snapshot', engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19 }), @@ -360,15 +360,15 @@ nodeunitShim({ }); // TODO - Expect this to be broken - expect(stack).to(haveResourceLike('AWS::RDS::DBInstance', { + expect(stack).toHaveResourceLike('AWS::RDS::DBInstance', { MasterUsername: ABSENT, MasterUserPassword: 'mysecretpassword', - })); + }); + - test.done(); - }, + }); - 'can set a new snapshot password from an existing Secret'(test: Test) { + test('can set a new snapshot password from an existing Secret', () => { const secret = new rds.DatabaseSecret(stack, 'DBSecret', { username: 'admin', encryptionKey: new kms.Key(stack, 'PasswordKey'), @@ -380,18 +380,18 @@ nodeunitShim({ credentials: rds.SnapshotCredentials.fromSecret(secret), }); - expect(stack).to(haveResourceLike('AWS::RDS::DBInstance', { + expect(stack).toHaveResourceLike('AWS::RDS::DBInstance', { MasterUsername: ABSENT, MasterUserPassword: { 'Fn::Join': ['', ['{{resolve:secretsmanager:', { Ref: 'DBSecretD58955BC' }, ':SecretString:password::}}']], }, - })); + }); - test.done(); - }, - }, - 'create a read replica in the same region - with the subnet group name'(test: Test) { + }); + }); + + test('create a read replica in the same region - with the subnet group name', () => { const sourceInstance = new rds.DatabaseInstance(stack, 'Instance', { engine: rds.DatabaseInstanceEngine.MYSQL, instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), @@ -406,7 +406,7 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBInstance', { + expect(stack).toHaveResource('AWS::RDS::DBInstance', { SourceDBInstanceIdentifier: { 'Fn::Join': ['', [ 'arn:', @@ -422,12 +422,12 @@ nodeunitShim({ DBSubnetGroupName: { Ref: 'ReadReplicaSubnetGroup680C605C', }, - })); + }); + - test.done(); - }, + }); - 'on event'(test: Test) { + test('on event', () => { const instance = new rds.DatabaseInstance(stack, 'Instance', { engine: rds.DatabaseInstanceEngine.MYSQL, vpc, @@ -442,7 +442,7 @@ nodeunitShim({ instance.onEvent('InstanceEvent', { target: new targets.LambdaFunction(fn) }); // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { + expect(stack).toHaveResource('AWS::Events::Rule', { EventPattern: { source: [ 'aws.rds', @@ -484,12 +484,12 @@ nodeunitShim({ Id: 'Target0', }, ], - })); + }); - test.done(); - }, - 'on event without target'(test: Test) { + }); + + test('on event without target', () => { const instance = new rds.DatabaseInstance(stack, 'Instance', { engine: rds.DatabaseInstanceEngine.MYSQL, vpc, @@ -499,7 +499,7 @@ nodeunitShim({ instance.onEvent('InstanceEvent'); // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { + expect(stack).toHaveResource('AWS::Events::Rule', { EventPattern: { source: [ 'aws.rds', @@ -530,12 +530,12 @@ nodeunitShim({ }, ], }, - })); + }); + - test.done(); - }, + }); - 'can use metricCPUUtilization'(test: Test) { + test('can use metricCPUUtilization', () => { // WHEN const instance = new rds.DatabaseInstance(stack, 'Instance', { engine: rds.DatabaseInstanceEngine.MYSQL, @@ -543,7 +543,7 @@ nodeunitShim({ }); // THEN - test.deepEqual(stack.resolve(instance.metricCPUUtilization()), { + expect(stack.resolve(instance.metricCPUUtilization())).toEqual({ dimensions: { DBInstanceIdentifier: { Ref: 'InstanceC1063A87' } }, namespace: 'AWS/RDS', metricName: 'CPUUtilization', @@ -551,21 +551,21 @@ nodeunitShim({ statistic: 'Average', }); - test.done(); - }, - 'can resolve endpoint port and socket address'(test: Test) { + }); + + test('can resolve endpoint port and socket address', () => { // WHEN const instance = new rds.DatabaseInstance(stack, 'Instance', { engine: rds.DatabaseInstanceEngine.MYSQL, vpc, }); - test.deepEqual(stack.resolve(instance.instanceEndpoint.port), { + expect(stack.resolve(instance.instanceEndpoint.port)).toEqual({ 'Fn::GetAtt': ['InstanceC1063A87', 'Endpoint.Port'], }); - test.deepEqual(stack.resolve(instance.instanceEndpoint.socketAddress), { + expect(stack.resolve(instance.instanceEndpoint.socketAddress)).toEqual({ 'Fn::Join': [ '', [ @@ -576,10 +576,10 @@ nodeunitShim({ ], }); - test.done(); - }, - 'can deactivate backup'(test: Test) { + }); + + test('can deactivate backup', () => { // WHEN new rds.DatabaseInstance(stack, 'Instance', { engine: rds.DatabaseInstanceEngine.MYSQL, @@ -588,14 +588,14 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBInstance', { + expect(stack).toHaveResource('AWS::RDS::DBInstance', { BackupRetentionPeriod: 0, - })); + }); - test.done(); - }, - 'imported instance with imported security group with allowAllOutbound set to false'(test: Test) { + }); + + test('imported instance with imported security group with allowAllOutbound set to false', () => { const instance = rds.DatabaseInstance.fromDatabaseInstanceAttributes(stack, 'Database', { instanceEndpointAddress: 'address', instanceIdentifier: 'identifier', @@ -609,14 +609,14 @@ nodeunitShim({ instance.connections.allowToAnyIpv4(ec2.Port.tcp(443)); // THEN - expect(stack).to(haveResource('AWS::EC2::SecurityGroupEgress', { + expect(stack).toHaveResource('AWS::EC2::SecurityGroupEgress', { GroupId: 'sg-123456789', - })); + }); + - test.done(); - }, + }); - 'create an instance with imported monitoring role'(test: Test) { + test('create an instance with imported monitoring role', () => { const monitoringRole = new Role(stack, 'MonitoringRole', { assumedBy: new ServicePrincipal('monitoring.rds.amazonaws.com'), managedPolicies: [ @@ -633,17 +633,17 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBInstance', { + expect(stack).toHaveResource('AWS::RDS::DBInstance', { MonitoringInterval: 60, MonitoringRoleArn: { 'Fn::GetAtt': ['MonitoringRole90457BF9', 'Arn'], }, - }, ResourcePart.Properties)); + }, ResourcePart.Properties); - test.done(); - }, - 'create an instance with an existing security group'(test: Test) { + }); + + test('create an instance with an existing security group', () => { const securityGroup = ec2.SecurityGroup.fromSecurityGroupId(stack, 'SG', 'sg-123456789', { allowAllOutbound: false, }); @@ -657,11 +657,11 @@ nodeunitShim({ instance.connections.allowDefaultPortFromAnyIpv4(); // THEN - expect(stack).to(haveResource('AWS::RDS::DBInstance', { + expect(stack).toHaveResource('AWS::RDS::DBInstance', { VPCSecurityGroups: ['sg-123456789'], - })); + }); - expect(stack).to(haveResource('AWS::EC2::SecurityGroupIngress', { + expect(stack).toHaveResource('AWS::EC2::SecurityGroupIngress', { FromPort: { 'Fn::GetAtt': [ 'InstanceC1063A87', @@ -675,12 +675,12 @@ nodeunitShim({ 'Endpoint.Port', ], }, - })); + }); - test.done(); - }, - 'throws when trying to add rotation to an instance without secret'(test: Test) { + }); + + test('throws when trying to add rotation to an instance without secret', () => { const instance = new rds.DatabaseInstance(stack, 'Database', { engine: rds.DatabaseInstanceEngine.SQL_SERVER_EE, credentials: rds.Credentials.fromUsername('syscdk', { password: cdk.SecretValue.plainText('tooshort') }), @@ -688,12 +688,12 @@ nodeunitShim({ }); // THEN - test.throws(() => instance.addRotationSingleUser(), /without secret/); + expect(() => instance.addRotationSingleUser()).toThrow(/without secret/); + - test.done(); - }, + }); - 'throws when trying to add single user rotation multiple times'(test: Test) { + test('throws when trying to add single user rotation multiple times', () => { const instance = new rds.DatabaseInstance(stack, 'Database', { engine: rds.DatabaseInstanceEngine.SQL_SERVER_EE, instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), @@ -705,12 +705,12 @@ nodeunitShim({ instance.addRotationSingleUser(); // THEN - test.throws(() => instance.addRotationSingleUser(), /A single user rotation was already added to this instance/); + expect(() => instance.addRotationSingleUser()).toThrow(/A single user rotation was already added to this instance/); + - test.done(); - }, + }); - 'throws when timezone is set for non-sqlserver database engine'(test: Test) { + test('throws when timezone is set for non-sqlserver database engine', () => { const tzSupportedEngines = [rds.DatabaseInstanceEngine.SQL_SERVER_EE, rds.DatabaseInstanceEngine.SQL_SERVER_EX, rds.DatabaseInstanceEngine.SQL_SERVER_SE, rds.DatabaseInstanceEngine.SQL_SERVER_WEB]; const tzUnsupportedEngines = [rds.DatabaseInstanceEngine.MYSQL, rds.DatabaseInstanceEngine.POSTGRES, @@ -718,25 +718,25 @@ nodeunitShim({ // THEN tzSupportedEngines.forEach((engine) => { - test.ok(new rds.DatabaseInstance(stack, `${engine.engineType}-db`, { + expect(new rds.DatabaseInstance(stack, `${engine.engineType}-db`, { engine, timezone: 'Europe/Zurich', vpc, - })); + })).toBeDefined(); }); tzUnsupportedEngines.forEach((engine) => { - test.throws(() => new rds.DatabaseInstance(stack, `${engine.engineType}-db`, { + expect(() => new rds.DatabaseInstance(stack, `${engine.engineType}-db`, { engine, timezone: 'Europe/Zurich', vpc, - }), /timezone property can not be configured for/); + })).toThrow(/timezone property can not be configured for/); }); - test.done(); - }, - 'create an instance from snapshot with maximum allocated storage'(test: Test) { + }); + + test('create an instance from snapshot with maximum allocated storage', () => { // WHEN new rds.DatabaseInstanceFromSnapshot(stack, 'Instance', { snapshotIdentifier: 'my-snapshot', @@ -746,15 +746,15 @@ nodeunitShim({ maxAllocatedStorage: 200, }); - expect(stack).to(haveResource('AWS::RDS::DBInstance', { + expect(stack).toHaveResource('AWS::RDS::DBInstance', { DBSnapshotIdentifier: 'my-snapshot', MaxAllocatedStorage: 200, - })); + }); + - test.done(); - }, + }); - 'create a DB instance with maximum allocated storage'(test: Test) { + test('create a DB instance with maximum allocated storage', () => { // WHEN new rds.DatabaseInstance(stack, 'Instance', { engine: rds.DatabaseInstanceEngine.MYSQL, @@ -764,28 +764,28 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBInstance', { + expect(stack).toHaveResource('AWS::RDS::DBInstance', { BackupRetentionPeriod: 0, MaxAllocatedStorage: 250, - })); + }); + - test.done(); - }, + }); - 'iam authentication - off by default'(test: Test) { + test('iam authentication - off by default', () => { new rds.DatabaseInstance(stack, 'Instance', { engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19 }), vpc, }); - expect(stack).to(haveResourceLike('AWS::RDS::DBInstance', { + expect(stack).toHaveResourceLike('AWS::RDS::DBInstance', { EnableIAMDatabaseAuthentication: ABSENT, - })); + }); + - test.done(); - }, + }); - 'createGrant - creates IAM policy and enables IAM auth'(test: Test) { + test('createGrant - creates IAM policy and enables IAM auth', () => { const instance = new rds.DatabaseInstance(stack, 'Instance', { engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19 }), vpc, @@ -795,10 +795,10 @@ nodeunitShim({ }); instance.grantConnect(role); - expect(stack).to(haveResourceLike('AWS::RDS::DBInstance', { + expect(stack).toHaveResourceLike('AWS::RDS::DBInstance', { EnableIAMDatabaseAuthentication: true, - })); - expect(stack).to(haveResource('AWS::IAM::Policy', { + }); + expect(stack).toHaveResource('AWS::IAM::Policy', { PolicyDocument: { Statement: [{ Effect: 'Allow', @@ -809,12 +809,12 @@ nodeunitShim({ }], Version: '2012-10-17', }, - })); + }); + - test.done(); - }, + }); - 'createGrant - throws if IAM auth disabled'(test: Test) { + test('createGrant - throws if IAM auth disabled', () => { const instance = new rds.DatabaseInstance(stack, 'Instance', { engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19 }), vpc, @@ -824,12 +824,12 @@ nodeunitShim({ assumedBy: new AccountPrincipal(stack.account), }); - test.throws(() => { instance.grantConnect(role); }, /Cannot grant connect when IAM authentication is disabled/); + expect(() => { instance.grantConnect(role); }).toThrow(/Cannot grant connect when IAM authentication is disabled/); - test.done(); - }, - 'domain - sets domain property'(test: Test) { + }); + + test('domain - sets domain property', () => { const domain = 'd-90670a8d36'; // WHEN @@ -840,14 +840,14 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResourceLike('AWS::RDS::DBInstance', { + expect(stack).toHaveResourceLike('AWS::RDS::DBInstance', { Domain: domain, - })); + }); + - test.done(); - }, + }); - 'domain - uses role if provided'(test: Test) { + test('domain - uses role if provided', () => { const domain = 'd-90670a8d36'; // WHEN @@ -860,15 +860,15 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResourceLike('AWS::RDS::DBInstance', { + expect(stack).toHaveResourceLike('AWS::RDS::DBInstance', { Domain: domain, DomainIAMRoleName: stack.resolve(role.roleName), - })); + }); + - test.done(); - }, + }); - 'domain - creates role if not provided'(test: Test) { + test('domain - creates role if not provided', () => { const domain = 'd-90670a8d36'; // WHEN @@ -879,12 +879,12 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResourceLike('AWS::RDS::DBInstance', { + expect(stack).toHaveResourceLike('AWS::RDS::DBInstance', { Domain: domain, DomainIAMRoleName: anything(), - })); + }); - expect(stack).to(haveResource('AWS::IAM::Role', { + expect(stack).toHaveResource('AWS::IAM::Role', { AssumeRolePolicyDocument: { Statement: [ { @@ -911,12 +911,12 @@ nodeunitShim({ ], }, ], - })); + }); + - test.done(); - }, + }); - 'throws when domain is set for mariadb database engine'(test: Test) { + test('throws when domain is set for mariadb database engine', () => { const domainSupportedEngines = [rds.DatabaseInstanceEngine.SQL_SERVER_EE, rds.DatabaseInstanceEngine.SQL_SERVER_EX, rds.DatabaseInstanceEngine.SQL_SERVER_SE, rds.DatabaseInstanceEngine.SQL_SERVER_WEB, rds.DatabaseInstanceEngine.MYSQL, rds.DatabaseInstanceEngine.POSTGRES, rds.DatabaseInstanceEngine.ORACLE_EE]; @@ -924,28 +924,28 @@ nodeunitShim({ // THEN domainSupportedEngines.forEach((engine) => { - test.ok(new rds.DatabaseInstance(stack, `${engine.engineType}-db`, { + expect(() => new rds.DatabaseInstance(stack, `${engine.engineType}-db`, { engine, domain: 'd-90670a8d36', vpc, - })); + })).not.toThrow(); }); domainUnsupportedEngines.forEach((engine) => { const expectedError = new RegExp(`domain property cannot be configured for ${engine.engineType}`); - test.throws(() => new rds.DatabaseInstance(stack, `${engine.engineType}-db`, { + expect(() => new rds.DatabaseInstance(stack, `${engine.engineType}-db`, { engine, domain: 'd-90670a8d36', vpc, - }), expectedError); + })).toThrow(expectedError); }); - test.done(); - }, - 'performance insights': { - 'instance with all performance insights properties'(test: Test) { + }); + + describe('performance insights', () => { + test('instance with all performance insights properties', () => { new rds.DatabaseInstance(stack, 'Instance', { engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19 }), vpc, @@ -954,72 +954,72 @@ nodeunitShim({ performanceInsightEncryptionKey: new kms.Key(stack, 'Key'), }); - expect(stack).to(haveResource('AWS::RDS::DBInstance', { + expect(stack).toHaveResource('AWS::RDS::DBInstance', { EnablePerformanceInsights: true, PerformanceInsightsRetentionPeriod: 731, PerformanceInsightsKMSKeyId: { 'Fn::GetAtt': ['Key961B73FD', 'Arn'] }, - })); + }); + - test.done(); - }, + }); - 'setting performance insights fields enables performance insights'(test: Test) { + test('setting performance insights fields enables performance insights', () => { new rds.DatabaseInstance(stack, 'Instance', { engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19 }), vpc, performanceInsightRetention: rds.PerformanceInsightRetention.LONG_TERM, }); - expect(stack).to(haveResource('AWS::RDS::DBInstance', { + expect(stack).toHaveResource('AWS::RDS::DBInstance', { EnablePerformanceInsights: true, PerformanceInsightsRetentionPeriod: 731, - })); + }); + - test.done(); - }, + }); - 'throws if performance insights fields are set but performance insights is disabled'(test: Test) { - test.throws(() => { + test('throws if performance insights fields are set but performance insights is disabled', () => { + expect(() => { new rds.DatabaseInstance(stack, 'Instance', { engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19 }), vpc, enablePerformanceInsights: false, performanceInsightRetention: rds.PerformanceInsightRetention.DEFAULT, }); - }, /`enablePerformanceInsights` disabled, but `performanceInsightRetention` or `performanceInsightEncryptionKey` was set/); + }).toThrow(/`enablePerformanceInsights` disabled, but `performanceInsightRetention` or `performanceInsightEncryptionKey` was set/); - test.done(); - }, - }, - 'reuse an existing subnet group'(test: Test) { + }); + }); + + test('reuse an existing subnet group', () => { new rds.DatabaseInstance(stack, 'Database', { engine: rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_12_3 }), vpc, subnetGroup: rds.SubnetGroup.fromSubnetGroupName(stack, 'SubnetGroup', 'my-subnet-group'), }); - expect(stack).to(haveResourceLike('AWS::RDS::DBInstance', { + expect(stack).toHaveResourceLike('AWS::RDS::DBInstance', { DBSubnetGroupName: 'my-subnet-group', - })); - expect(stack).to(countResources('AWS::RDS::DBSubnetGroup', 0)); + }); + expect(stack).toCountResources('AWS::RDS::DBSubnetGroup', 0); - test.done(); - }, - 'defaultChild returns the DB Instance'(test: Test) { + }); + + test('defaultChild returns the DB Instance', () => { const instance = new rds.DatabaseInstance(stack, 'Database', { engine: rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_12_3 }), vpc, }); // THEN - test.ok(instance.node.defaultChild instanceof rds.CfnDBInstance); + expect(instance.node.defaultChild instanceof rds.CfnDBInstance).toBeTruthy(); + - test.done(); - }, + }); - "PostgreSQL database instance uses a different default master username than 'admin', which is a reserved word"(test: Test) { + test("PostgreSQL database instance uses a different default master username than 'admin', which is a reserved word", () => { new rds.DatabaseInstance(stack, 'Instance', { vpc, engine: rds.DatabaseInstanceEngine.postgres({ @@ -1028,17 +1028,19 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResourceLike('AWS::SecretsManager::Secret', { + expect(stack).toHaveResourceLike('AWS::SecretsManager::Secret', { GenerateSecretString: { SecretStringTemplate: '{"username":"postgres"}', }, - })); + }); - test.done(); - }, - 'S3 Import/Export': { - 'instance with s3 import and export buckets'(test: Test) { + }); + + describe('S3 Import/Export', () => { + testFutureBehavior('instance with s3 import and export buckets', { '@aws-cdk/aws-s3:grantWriteWithoutAcl': true }, cdk.App, (app) => { + stack = new cdk.Stack(app); + vpc = new ec2.Vpc(stack, 'VPC'); new rds.DatabaseInstance(stack, 'DB', { engine: rds.DatabaseInstanceEngine.sqlServerSe({ version: rds.SqlServerEngineVersion.VER_14_00_3192_2_V1 }), vpc, @@ -1046,7 +1048,7 @@ nodeunitShim({ s3ExportBuckets: [new s3.Bucket(stack, 'S3Export')], }); - expect(stack).to(haveResource('AWS::RDS::DBInstance', { + expect(stack).toHaveResource('AWS::RDS::DBInstance', { AssociatedRoles: [ { FeatureName: 'S3_INTEGRATION', @@ -1054,10 +1056,10 @@ nodeunitShim({ }, ], OptionGroupName: { Ref: 'DBInstanceOptionGroup46C68006' }, - })); + }); // Can read from import bucket, and read/write from export bucket - expect(stack).to(haveResource('AWS::IAM::Policy', { + expect(stack).toHaveResource('AWS::IAM::Policy', { PolicyDocument: { Statement: [{ Action: [ @@ -1077,7 +1079,7 @@ nodeunitShim({ 's3:GetBucket*', 's3:List*', 's3:DeleteObject*', - 's3:PutObject*', + 's3:PutObject', 's3:Abort*', ], Effect: 'Allow', @@ -1088,58 +1090,58 @@ nodeunitShim({ }], Version: '2012-10-17', }, - })); + }); - test.done(); - }, - 'throws if using s3 import on unsupported engine'(test: Test) { + }); + + test('throws if using s3 import on unsupported engine', () => { const s3ImportRole = new Role(stack, 'S3ImportRole', { assumedBy: new ServicePrincipal('rds.amazonaws.com'), }); - test.throws(() => { + expect(() => { new rds.DatabaseInstance(stack, 'DBWithImportBucket', { engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19 }), vpc, s3ImportBuckets: [new s3.Bucket(stack, 'S3Import')], }); - }, /Engine 'mysql-8.0.19' does not support S3 import/); - test.throws(() => { + }).toThrow(/Engine 'mysql-8.0.19' does not support S3 import/); + expect(() => { new rds.DatabaseInstance(stack, 'DBWithImportRole', { engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19 }), vpc, s3ImportRole, }); - }, /Engine 'mysql-8.0.19' does not support S3 import/); + }).toThrow(/Engine 'mysql-8.0.19' does not support S3 import/); + - test.done(); - }, + }); - 'throws if using s3 export on unsupported engine'(test: Test) { + test('throws if using s3 export on unsupported engine', () => { const s3ExportRole = new Role(stack, 'S3ExportRole', { assumedBy: new ServicePrincipal('rds.amazonaws.com'), }); - test.throws(() => { + expect(() => { new rds.DatabaseInstance(stack, 'DBWithExportBucket', { engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19 }), vpc, s3ExportBuckets: [new s3.Bucket(stack, 'S3Export')], }); - }, /Engine 'mysql-8.0.19' does not support S3 export/); - test.throws(() => { + }).toThrow(/Engine 'mysql-8.0.19' does not support S3 export/); + expect(() => { new rds.DatabaseInstance(stack, 'DBWithExportRole', { engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19 }), vpc, s3ExportRole: s3ExportRole, }); - }, /Engine 'mysql-8.0.19' does not support S3 export/); + }).toThrow(/Engine 'mysql-8.0.19' does not support S3 export/); + - test.done(); - }, + }); - 'throws if provided two different roles for import/export'(test: Test) { + test('throws if provided two different roles for import/export', () => { const s3ImportRole = new Role(stack, 'S3ImportRole', { assumedBy: new ServicePrincipal('rds.amazonaws.com'), }); @@ -1147,20 +1149,20 @@ nodeunitShim({ assumedBy: new ServicePrincipal('rds.amazonaws.com'), }); - test.throws(() => { + expect(() => { new rds.DatabaseInstance(stack, 'DBWithExportBucket', { engine: rds.DatabaseInstanceEngine.sqlServerEe({ version: rds.SqlServerEngineVersion.VER_14_00_3192_2_V1 }), vpc, s3ImportRole, s3ExportRole, }); - }, /S3 import and export roles must be the same/); + }).toThrow(/S3 import and export roles must be the same/); - test.done(); - }, - }, - 'fromGeneratedSecret'(test: Test) { + }); + }); + + test('fromGeneratedSecret', () => { // WHEN new rds.DatabaseInstance(stack, 'Database', { engine: rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_12_3 }), @@ -1169,7 +1171,7 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBInstance', { + expect(stack).toHaveResource('AWS::RDS::DBInstance', { MasterUsername: 'postgres', // username is a string MasterUserPassword: { 'Fn::Join': [ @@ -1183,12 +1185,12 @@ nodeunitShim({ ], ], }, - })); + }); - test.done(); - }, - 'fromPassword'(test: Test) { + }); + + test('fromPassword', () => { // WHEN new rds.DatabaseInstance(stack, 'Database', { engine: rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_12_3 }), @@ -1197,15 +1199,15 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::RDS::DBInstance', { + expect(stack).toHaveResource('AWS::RDS::DBInstance', { MasterUsername: 'postgres', // username is a string MasterUserPassword: '{{resolve:ssm-secure:/dbPassword:1}}', // reference to SSM - })); + }); + - test.done(); - }, + }); - 'can set publiclyAccessible to false with public subnets'(test: Test) { + test('can set publiclyAccessible to false with public subnets', () => { new rds.DatabaseInstance(stack, 'Instance', { engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19, @@ -1217,14 +1219,14 @@ nodeunitShim({ publiclyAccessible: false, }); - expect(stack).to(haveResource('AWS::RDS::DBInstance', { + expect(stack).toHaveResource('AWS::RDS::DBInstance', { PubliclyAccessible: false, - })); + }); + - test.done(); - }, + }); - 'can set publiclyAccessible to true with private subnets'(test: Test) { + test('can set publiclyAccessible to true with private subnets', () => { new rds.DatabaseInstance(stack, 'Instance', { engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19, @@ -1236,10 +1238,41 @@ nodeunitShim({ publiclyAccessible: true, }); - expect(stack).to(haveResource('AWS::RDS::DBInstance', { + expect(stack).toHaveResource('AWS::RDS::DBInstance', { PubliclyAccessible: true, - })); + }); + + + }); +}); - test.done(); - }, +test.each([ + [cdk.RemovalPolicy.RETAIN, 'Retain', 'Retain'], + [cdk.RemovalPolicy.SNAPSHOT, 'Snapshot', ABSENT], + [cdk.RemovalPolicy.DESTROY, 'Delete', ABSENT], +])('if Instance RemovalPolicy is \'%s\', the instance has DeletionPolicy \'%s\' and the DBSubnetGroup has \'%s\'', (instanceRemovalPolicy, instanceValue, subnetValue) => { + // GIVEN + stack = new cdk.Stack(); + vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new rds.DatabaseInstance(stack, 'Instance', { + engine: rds.DatabaseInstanceEngine.mysql({ + version: rds.MysqlEngineVersion.VER_8_0_19, + }), + vpc, + vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC }, + removalPolicy: instanceRemovalPolicy, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::RDS::DBInstance', { + DeletionPolicy: instanceValue, + UpdateReplacePolicy: instanceValue, + }, ResourcePart.CompleteDefinition); + + expect(stack).toHaveResourceLike('AWS::RDS::DBSubnetGroup', { + DeletionPolicy: subnetValue, + UpdateReplacePolicy: subnetValue, + }, ResourcePart.CompleteDefinition); }); diff --git a/packages/@aws-cdk/aws-rds/test/integ.cluster-rotation.lit.expected.json b/packages/@aws-cdk/aws-rds/test/integ.cluster-rotation.lit.expected.json index 05293187edb33..74a0642b875c8 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.cluster-rotation.lit.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.cluster-rotation.lit.expected.json @@ -706,7 +706,8 @@ } ] }, - "UpdateReplacePolicy": "Snapshot" + "UpdateReplacePolicy": "Snapshot", + "DeletionPolicy": "Snapshot" }, "DatabaseInstance1844F58FD": { "Type": "AWS::RDS::DBInstance", @@ -724,7 +725,9 @@ "VPCPrivateSubnet1DefaultRouteAE1D6490", "VPCPrivateSubnet2DefaultRouteF4F5CFD2", "VPCPrivateSubnet3DefaultRoute27F311AE" - ] + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "DatabaseInstance2AA380DEE": { "Type": "AWS::RDS::DBInstance", @@ -742,7 +745,9 @@ "VPCPrivateSubnet1DefaultRouteAE1D6490", "VPCPrivateSubnet2DefaultRouteF4F5CFD2", "VPCPrivateSubnet3DefaultRoute27F311AE" - ] + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "DatabaseRotationSingleUserSecurityGroupAC6E0E73": { "Type": "AWS::EC2::SecurityGroup", diff --git a/packages/@aws-cdk/aws-rds/test/integ.cluster-s3.expected.json b/packages/@aws-cdk/aws-rds/test/integ.cluster-s3.expected.json index 6cafa81fad6a5..3ee9358bebc33 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.cluster-s3.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.cluster-s3.expected.json @@ -652,7 +652,8 @@ } ] }, - "UpdateReplacePolicy": "Snapshot" + "UpdateReplacePolicy": "Snapshot", + "DeletionPolicy": "Snapshot" }, "DatabaseInstance1844F58FD": { "Type": "AWS::RDS::DBInstance", @@ -670,7 +671,9 @@ "DependsOn": [ "VPCPublicSubnet1DefaultRoute91CEF279", "VPCPublicSubnet2DefaultRouteB7481BBA" - ] + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "DatabaseInstance2AA380DEE": { "Type": "AWS::RDS::DBInstance", @@ -688,7 +691,9 @@ "DependsOn": [ "VPCPublicSubnet1DefaultRoute91CEF279", "VPCPublicSubnet2DefaultRouteB7481BBA" - ] + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/test/integ.cluster.expected.json b/packages/@aws-cdk/aws-rds/test/integ.cluster.expected.json index 25f2149bf8a0c..04a2157aba0a8 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.cluster.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.cluster.expected.json @@ -484,7 +484,8 @@ } ] }, - "UpdateReplacePolicy": "Snapshot" + "UpdateReplacePolicy": "Snapshot", + "DeletionPolicy": "Snapshot" }, "DatabaseInstance1844F58FD": { "Type": "AWS::RDS::DBInstance", @@ -502,7 +503,9 @@ "DependsOn": [ "VPCPublicSubnet1DefaultRoute91CEF279", "VPCPublicSubnet2DefaultRouteB7481BBA" - ] + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "DatabaseInstance2AA380DEE": { "Type": "AWS::RDS::DBInstance", @@ -520,7 +523,9 @@ "DependsOn": [ "VPCPublicSubnet1DefaultRoute91CEF279", "VPCPublicSubnet2DefaultRouteB7481BBA" - ] + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/test/integ.instance-from-generated-password.expected.json b/packages/@aws-cdk/aws-rds/test/integ.instance-from-generated-password.expected.json index a01587728dac5..ca2ee08c781ad 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.instance-from-generated-password.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.instance-from-generated-password.expected.json @@ -619,7 +619,8 @@ } ] }, - "UpdateReplacePolicy": "Snapshot" + "UpdateReplacePolicy": "Snapshot", + "DeletionPolicy": "Snapshot" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/test/integ.instance-s3.expected.json b/packages/@aws-cdk/aws-rds/test/integ.instance-s3.expected.json index 49c70139f3394..2b144dedcc3aa 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.instance-s3.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.instance-s3.expected.json @@ -613,4 +613,4 @@ "DeletionPolicy": "Delete" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/test/integ.instance.lit.expected.json b/packages/@aws-cdk/aws-rds/test/integ.instance.lit.expected.json index ca91f92e62644..8a05969830f29 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.instance.lit.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.instance.lit.expected.json @@ -694,7 +694,8 @@ } ] }, - "UpdateReplacePolicy": "Snapshot" + "UpdateReplacePolicy": "Snapshot", + "DeletionPolicy": "Snapshot" }, "InstanceLogRetentiontrace487771C8": { "Type": "Custom::LogRetention", @@ -832,7 +833,6 @@ ] }, "functionName": "awscdkrdsinstanceInstanceRotationSingleUserAFE3C214", - "excludeCharacters": " %+~`#$&*()|[]{}:;<>?!'/@\"\\", "vpcSubnetIds": { "Fn::Join": [ "", @@ -852,7 +852,8 @@ "InstanceRotationSingleUserSecurityGroupF3FB5C25", "GroupId" ] - } + }, + "excludeCharacters": " %+~`#$&*()|[]{}:;<>?!'/@\"\\" } } }, @@ -1094,13 +1095,13 @@ "Code": { "ZipFile": "exports.handler = (event) => console.log(event);" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "FunctionServiceRole675BB04A", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs10.x" }, "DependsOn": [ @@ -1122,4 +1123,4 @@ "Description": "Artifact hash for asset \"884431e2bc651d2b61bd699a29dc9684b0f66911f06bd3ed0635f854bf18e147\"" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/test/integ.proxy.expected.json b/packages/@aws-cdk/aws-rds/test/integ.proxy.expected.json index 52aab8716ba8c..a18c5f5843512 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.proxy.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.proxy.expected.json @@ -495,7 +495,8 @@ } ] }, - "UpdateReplacePolicy": "Snapshot" + "UpdateReplacePolicy": "Snapshot", + "DeletionPolicy": "Snapshot" }, "dbProxyIAMRole662F3AB8": { "Type": "AWS::IAM::Role", diff --git a/packages/@aws-cdk/aws-rds/test/integ.serverless-cluster.expected.json b/packages/@aws-cdk/aws-rds/test/integ.serverless-cluster.expected.json index 3d392f574621e..752eae1b22894 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.serverless-cluster.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.serverless-cluster.expected.json @@ -432,7 +432,8 @@ } ] }, - "UpdateReplacePolicy": "Snapshot" + "UpdateReplacePolicy": "Snapshot", + "DeletionPolicy": "Snapshot" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/test/serverless-cluster.test.ts b/packages/@aws-cdk/aws-rds/test/serverless-cluster.test.ts index 257d23d9ffec2..e370ff915cb6c 100644 --- a/packages/@aws-cdk/aws-rds/test/serverless-cluster.test.ts +++ b/packages/@aws-cdk/aws-rds/test/serverless-cluster.test.ts @@ -1,4 +1,4 @@ -import { ABSENT, expect, haveResource, haveResourceLike, ResourcePart, SynthUtils } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike, ResourcePart, SynthUtils } from '@aws-cdk/assert'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; @@ -44,7 +44,7 @@ nodeunitShim({ }, ], }, - DeletionPolicy: ABSENT, + DeletionPolicy: 'Snapshot', UpdateReplacePolicy: 'Snapshot', }, ResourcePart.CompleteDefinition)); @@ -105,7 +105,7 @@ nodeunitShim({ }, ], }, - DeletionPolicy: ABSENT, + DeletionPolicy: 'Snapshot', UpdateReplacePolicy: 'Snapshot', }, ResourcePart.CompleteDefinition)); test.done(); diff --git a/packages/@aws-cdk/aws-s3-deployment/README.md b/packages/@aws-cdk/aws-s3-deployment/README.md index e7f21b1f54b88..b0bb1e2d9ebd5 100644 --- a/packages/@aws-cdk/aws-s3-deployment/README.md +++ b/packages/@aws-cdk/aws-s3-deployment/README.md @@ -156,39 +156,15 @@ import * as origins from '@aws-cdk/aws-cloudfront-origins'; const bucket = new s3.Bucket(this, 'Destination'); -// Option 1 (Stable): Handles buckets whether or not they are configured for website hosting. +// Handles buckets whether or not they are configured for website hosting. const distribution = new cloudfront.Distribution(this, 'Distribution', { defaultBehavior: { origin: new origins.S3Origin(bucket) }, }); -// Option 2 (Stable): Use this if the bucket has website hosting enabled. -const distribution_for_website_bucket = new cloudfront.CloudFrontWebDistribution(this, 'DistributionForWebBucket', { - originConfigs: [ - { - customOriginSource: { - domainName: bucket.bucketWebsiteDomainName, - }, - behaviors : [ {isDefaultBehavior: true}] - } - ] -}); - -// Option 3 (Stable): Use this version if the bucket does not have website hosting enabled. -const distribution_for_bucket = new cloudfront.CloudFrontWebDistribution(this, 'DistributionForBucket', { - originConfigs: [ - { - s3OriginSource: { - s3BucketSource: bucket - }, - behaviors : [ {isDefaultBehavior: true}] - } - ] -}); - new s3deploy.BucketDeployment(this, 'DeployWithInvalidation', { sources: [s3deploy.Source.asset('./website-dist')], destinationBucket: bucket, - distribution, // or distribution_for_website_bucket or distribution_for_bucket + distribution, distributionPaths: ['/images/*.png'], }); ``` diff --git a/packages/@aws-cdk/aws-s3-notifications/test/sqs/integ.bucket-notifications.expected.json b/packages/@aws-cdk/aws-s3-notifications/test/sqs/integ.bucket-notifications.expected.json index dee4dafe9e74b..0da38cd2026c5 100644 --- a/packages/@aws-cdk/aws-s3-notifications/test/sqs/integ.bucket-notifications.expected.json +++ b/packages/@aws-cdk/aws-s3-notifications/test/sqs/integ.bucket-notifications.expected.json @@ -53,7 +53,9 @@ ] }, "MyQueueE6CA6235": { - "Type": "AWS::SQS::Queue" + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "MyQueuePolicy6BBEDDAC": { "Type": "AWS::SQS::QueuePolicy", @@ -325,7 +327,9 @@ "Arn" ] } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "EncryptedQueuePolicy8AEB1708": { "Type": "AWS::SQS::QueuePolicy", diff --git a/packages/@aws-cdk/aws-s3/README.md b/packages/@aws-cdk/aws-s3/README.md index 12ae88bb02d2e..d6a45e77cb7e1 100644 --- a/packages/@aws-cdk/aws-s3/README.md +++ b/packages/@aws-cdk/aws-s3/README.md @@ -120,6 +120,18 @@ bucket.grantReadWrite(lambda); Will give the Lambda's execution role permissions to read and write from the bucket. +## AWS Foundational Security Best Practices + +### Enforcing SSL + +To require all requests use Secure Socket Layer (SSL): + +```ts +const bucket = new Bucket(this, 'Bucket', { + enforceSSL: true +}); +``` + ## Sharing buckets between stacks To use a bucket in a different stack in the same CDK application, pass the object to the other stack: diff --git a/packages/@aws-cdk/aws-s3/lib/bucket.ts b/packages/@aws-cdk/aws-s3/lib/bucket.ts index 859f774565a93..1edbb9c7a5040 100644 --- a/packages/@aws-cdk/aws-s3/lib/bucket.ts +++ b/packages/@aws-cdk/aws-s3/lib/bucket.ts @@ -1061,6 +1061,14 @@ export interface BucketProps { */ readonly encryptionKey?: kms.IKey; + /** + * Enforces SSL for requests. S3.5 of the AWS Foundational Security Best Practices Regarding S3. + * @see https://docs.aws.amazon.com/config/latest/developerguide/s3-bucket-ssl-requests-only.html + * + * @default false + */ + readonly enforceSSL?: boolean; + /** * Specifies whether Amazon S3 should use an S3 Bucket Key with server-side * encryption using KMS (SSE-KMS) for new objects in the bucket. @@ -1161,8 +1169,8 @@ export interface BucketProps { * * @see https://docs.aws.amazon.com/AmazonS3/latest/dev/access-control-block-public-access.html * - * @default false New buckets and objects don't allow public access, but users can modify bucket - * policies or object permissions to allow public access. + * + * @default - CloudFormation defaults will apply. New buckets and objects don't allow public access, but users can modify bucket policies or object permissions to allow public access */ readonly blockPublicAccess?: BlockPublicAccess; @@ -1357,6 +1365,11 @@ export class Bucket extends BucketBase { this.disallowPublicAccess = props.blockPublicAccess && props.blockPublicAccess.blockPublicPolicy; this.accessControl = props.accessControl; + // Enforce AWS Foundational Security Best Practice + if (props.enforceSSL) { + this.enforceSSLStatement(); + } + if (props.serverAccessLogsBucket instanceof Bucket) { props.serverAccessLogsBucket.allowLogDelivery(); } @@ -1479,6 +1492,22 @@ export class Bucket extends BucketBase { this.inventories.push(inventory); } + /** + * Adds an iam statement to enforce SSL requests only. + */ + private enforceSSLStatement() { + const statement = new iam.PolicyStatement({ + actions: ['s3:*'], + conditions: { + Bool: { 'aws:SecureTransport': 'false' }, + }, + effect: iam.Effect.DENY, + resources: [this.arnForObjects('*')], + principals: [new iam.AnyPrincipal()], + }); + this.addToResourcePolicy(statement); + } + private validateBucketName(physicalName: string): void { const bucketName = physicalName; if (!bucketName || Token.isUnresolved(bucketName)) { diff --git a/packages/@aws-cdk/aws-s3/test/bucket.test.ts b/packages/@aws-cdk/aws-s3/test/bucket.test.ts index b54957f32d500..5a5f89a3eba94 100644 --- a/packages/@aws-cdk/aws-s3/test/bucket.test.ts +++ b/packages/@aws-cdk/aws-s3/test/bucket.test.ts @@ -277,6 +277,58 @@ describe('bucket', () => { }); + test('enforceSsl can be enabled', () => { + const stack = new cdk.Stack(); + new s3.Bucket(stack, 'MyBucket', { enforceSSL: true }); + + expect(stack).toMatchTemplate({ + 'Resources': { + 'MyBucketF68F3FF0': { + 'Type': 'AWS::S3::Bucket', + 'UpdateReplacePolicy': 'Retain', + 'DeletionPolicy': 'Retain', + }, + 'MyBucketPolicyE7FBAC7B': { + 'Type': 'AWS::S3::BucketPolicy', + 'Properties': { + 'Bucket': { + 'Ref': 'MyBucketF68F3FF0', + }, + 'PolicyDocument': { + 'Statement': [ + { + 'Action': 's3:*', + 'Condition': { + 'Bool': { + 'aws:SecureTransport': 'false', + }, + }, + 'Effect': 'Deny', + 'Principal': '*', + 'Resource': { + 'Fn::Join': [ + '', + [ + { + 'Fn::GetAtt': [ + 'MyBucketF68F3FF0', + 'Arn', + ], + }, + '/*', + ], + ], + }, + }, + ], + 'Version': '2012-10-17', + }, + }, + }, + }, + }); + }); + test('bucketKeyEnabled can be enabled', () => { const stack = new cdk.Stack(); @@ -2406,4 +2458,4 @@ describe('bucket', () => { autoDeleteObjects: true, })).toThrow(/Cannot use \'autoDeleteObjects\' property on a bucket without setting removal policy to \'DESTROY\'/); }); -}); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-sns-subscriptions/README.md b/packages/@aws-cdk/aws-sns-subscriptions/README.md index 3e047f2e802b6..c2bb95910d125 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/README.md +++ b/packages/@aws-cdk/aws-sns-subscriptions/README.md @@ -78,7 +78,7 @@ import * as subscriptions from '@aws-cdk/aws-sns-subscriptions'; const myFunction = new lambda.Function(this, 'Echo', { handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, + runtime: lambda.Runtime.NODEJS_12_X, code: lambda.Code.fromInline(`exports.handler = ${handler.toString()}`) }); diff --git a/packages/@aws-cdk/aws-sns-subscriptions/test/integ.sns-lambda.expected.json b/packages/@aws-cdk/aws-sns-subscriptions/test/integ.sns-lambda.expected.json index 38367e9204de2..d20fe9bf9a8db 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/test/integ.sns-lambda.expected.json +++ b/packages/@aws-cdk/aws-sns-subscriptions/test/integ.sns-lambda.expected.json @@ -40,13 +40,13 @@ "Code": { "ZipFile": "exports.handler = function handler(event, _context, callback) {\n /* eslint-disable no-console */\n console.log('====================================================');\n console.log(JSON.stringify(event, undefined, 2));\n console.log('====================================================');\n return callback(undefined, event);\n}" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "EchoServiceRoleBE28060B", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs10.x" }, "DependsOn": [ @@ -93,7 +93,9 @@ } }, "DeadLetterQueue9F481546": { - "Type": "AWS::SQS::Queue" + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "DeadLetterQueuePolicyB1FB890C": { "Type": "AWS::SQS::QueuePolicy", @@ -167,13 +169,13 @@ "Code": { "ZipFile": "exports.handler = function handler(event, _context, callback) {\n /* eslint-disable no-console */\n console.log('====================================================');\n console.log(JSON.stringify(event, undefined, 2));\n console.log('====================================================');\n return callback(undefined, event);\n}" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "FilteredServiceRole16D9DDC1", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs10.x" }, "DependsOn": [ diff --git a/packages/@aws-cdk/aws-sns-subscriptions/test/integ.sns-sqs.lit.expected.json b/packages/@aws-cdk/aws-sns-subscriptions/test/integ.sns-sqs.lit.expected.json index ea6b8345f0469..f9b68ad7da9ca 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/test/integ.sns-sqs.lit.expected.json +++ b/packages/@aws-cdk/aws-sns-subscriptions/test/integ.sns-sqs.lit.expected.json @@ -4,7 +4,9 @@ "Type": "AWS::SNS::Topic" }, "MyQueueE6CA6235": { - "Type": "AWS::SQS::Queue" + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "MyQueuePolicy6BBEDDAC": { "Type": "AWS::SQS::QueuePolicy", @@ -66,8 +68,8 @@ }, "DeadLetterQueue9F481546": { "Type": "AWS::SQS::Queue", - "Properties": { - } + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "DeadLetterQueuePolicyB1FB890C": { "Type": "AWS::SQS::QueuePolicy", diff --git a/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts b/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts index b2da0de8099b3..4bd8646176d08 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts +++ b/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts @@ -82,6 +82,8 @@ test('url subscription with user provided dlq', () => { }, 'DeadLetterQueue9F481546': { 'Type': 'AWS::SQS::Queue', + 'DeletionPolicy': 'Delete', + 'UpdateReplacePolicy': 'Delete', 'Properties': { 'MessageRetentionPeriod': 1209600, 'QueueName': 'MySubscription_DLQ', @@ -248,6 +250,8 @@ test('queue subscription', () => { }, 'MyQueueE6CA6235': { 'Type': 'AWS::SQS::Queue', + 'DeletionPolicy': 'Delete', + 'UpdateReplacePolicy': 'Delete', }, 'MyQueuePolicy6BBEDDAC': { 'Type': 'AWS::SQS::QueuePolicy', @@ -325,6 +329,8 @@ test('queue subscription with user provided dlq', () => { }, 'MyQueueE6CA6235': { 'Type': 'AWS::SQS::Queue', + 'DeletionPolicy': 'Delete', + 'UpdateReplacePolicy': 'Delete', }, 'MyQueuePolicy6BBEDDAC': { 'Type': 'AWS::SQS::QueuePolicy', @@ -386,6 +392,8 @@ test('queue subscription with user provided dlq', () => { }, 'DeadLetterQueue9F481546': { 'Type': 'AWS::SQS::Queue', + 'DeletionPolicy': 'Delete', + 'UpdateReplacePolicy': 'Delete', 'Properties': { 'MessageRetentionPeriod': 1209600, 'QueueName': 'MySubscription_DLQ', @@ -745,6 +753,8 @@ test('multiple subscriptions', () => { }, 'MyQueueE6CA6235': { 'Type': 'AWS::SQS::Queue', + 'DeletionPolicy': 'Delete', + 'UpdateReplacePolicy': 'Delete', }, 'MyQueuePolicy6BBEDDAC': { 'Type': 'AWS::SQS::QueuePolicy', diff --git a/packages/@aws-cdk/aws-sqs/lib/queue.ts b/packages/@aws-cdk/aws-sqs/lib/queue.ts index 63b466de84421..1c3067c7a70d6 100644 --- a/packages/@aws-cdk/aws-sqs/lib/queue.ts +++ b/packages/@aws-cdk/aws-sqs/lib/queue.ts @@ -1,5 +1,5 @@ import * as kms from '@aws-cdk/aws-kms'; -import { Duration, Stack, Token } from '@aws-cdk/core'; +import { Duration, RemovalPolicy, Stack, Token } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { IQueue, QueueAttributes, QueueBase } from './queue-base'; import { CfnQueue } from './sqs.generated'; @@ -137,6 +137,18 @@ export interface QueueProps { * @default false */ readonly contentBasedDeduplication?: boolean; + + /** + * Policy to apply when the user pool is removed from the stack + * + * Even though queues are technically stateful, their contents are transient and it + * is common to add and remove Queues while rearchitecting your application. The + * default is therefore `DESTROY`. Change it to `RETAIN` if the messages are so + * valuable that accidentally losing them would be unacceptable. + * + * @default RemovalPolicy.DESTROY + */ + readonly removalPolicy?: RemovalPolicy; } /** @@ -273,6 +285,7 @@ export class Queue extends QueueBase { receiveMessageWaitTimeSeconds: props.receiveMessageWaitTime && props.receiveMessageWaitTime.toSeconds(), visibilityTimeout: props.visibilityTimeout && props.visibilityTimeout.toSeconds(), }); + queue.applyRemovalPolicy(props.removalPolicy ?? RemovalPolicy.DESTROY); this.queueArn = this.getResourceArnAttribute(queue.attrArn, { service: 'sqs', diff --git a/packages/@aws-cdk/aws-sqs/test/integ.sqs.expected.json b/packages/@aws-cdk/aws-sqs/test/integ.sqs.expected.json index 30c3a8a66bfac..c310198cfcae6 100644 --- a/packages/@aws-cdk/aws-sqs/test/integ.sqs.expected.json +++ b/packages/@aws-cdk/aws-sqs/test/integ.sqs.expected.json @@ -1,7 +1,9 @@ { "Resources": { "DeadLetterQueue9F481546": { - "Type": "AWS::SQS::Queue" + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "Queue4A7E3555": { "Type": "AWS::SQS::Queue", @@ -16,7 +18,9 @@ }, "maxReceiveCount": 5 } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "EncryptionKey1B843E66": { "Type": "AWS::KMS::Key", @@ -63,7 +67,9 @@ "Arn" ] } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "Role1ABCC5F0": { "Type": "AWS::IAM::Role", diff --git a/packages/@aws-cdk/aws-sqs/test/test.sqs.ts b/packages/@aws-cdk/aws-sqs/test/test.sqs.ts index 87e38c2dcf2ca..ea0233578c5a6 100644 --- a/packages/@aws-cdk/aws-sqs/test/test.sqs.ts +++ b/packages/@aws-cdk/aws-sqs/test/test.sqs.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource, ResourcePart } from '@aws-cdk/assert'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import { CfnParameter, Duration, Stack, App } from '@aws-cdk/core'; @@ -18,10 +18,16 @@ export = { 'Resources': { 'Queue4A7E3555': { 'Type': 'AWS::SQS::Queue', + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', }, }, }); + expect(stack).to(haveResource('AWS::SQS::Queue', { + DeletionPolicy: 'Delete', + }, ResourcePart.CompleteDefinition)); + test.done(); }, 'with a dead letter queue'(test: Test) { @@ -33,6 +39,8 @@ export = { 'Resources': { 'DLQ581697C4': { 'Type': 'AWS::SQS::Queue', + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', }, 'Queue4A7E3555': { 'Type': 'AWS::SQS::Queue', @@ -47,6 +55,8 @@ export = { 'maxReceiveCount': 3, }, }, + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', }, }, }); @@ -99,6 +109,8 @@ export = { 'Ref': 'myretentionperiod', }, }, + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', }, }, }); @@ -119,6 +131,8 @@ export = { 'Resources': { 'MyQueueE6CA6235': { 'Type': 'AWS::SQS::Queue', + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', }, 'MyQueuePolicy6BBEDDAC': { 'Type': 'AWS::SQS::QueuePolicy', @@ -311,6 +325,8 @@ export = { 'Properties': { 'KmsMasterKeyId': 'alias/aws/sqs', }, + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', }, }, }); @@ -378,6 +394,8 @@ export = { 'QueueName': 'MyQueue.fifo', 'FifoQueue': true, }, + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', }, }, }); @@ -400,6 +418,8 @@ export = { 'Properties': { 'FifoQueue': true, }, + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', }, }, }); diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/README.md b/packages/@aws-cdk/aws-stepfunctions-tasks/README.md index 80e1dab5ef73f..3580e99d464d4 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/README.md +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/README.md @@ -54,6 +54,8 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aw - [Cancel Step](#cancel-step) - [Modify Instance Fleet](#modify-instance-fleet) - [Modify Instance Group](#modify-instance-group) +- [EKS](#eks) + - [Call](#call) - [Glue](#glue) - [Glue DataBrew](#glue-databrew) - [Lambda](#lambda) @@ -187,7 +189,7 @@ const convertToSeconds = new tasks.EvaluateExpression(this, 'Convert to seconds' const createMessage = new tasks.EvaluateExpression(this, 'Create message', { // Note: this is a string inside a string. expression: '`Now waiting ${$.waitSeconds} seconds...`', - runtime: lambda.Runtime.NODEJS_10_X, + runtime: lambda.Runtime.NODEJS_12_X, resultPath: '$.message', }); @@ -211,7 +213,7 @@ new sfn.StateMachine(this, 'StateMachine', { The `EvaluateExpression` supports a `runtime` prop to specify the Lambda runtime to use to evaluate the expression. Currently, the only runtime -supported is `lambda.Runtime.NODEJS_10_X`. +supported is `lambda.Runtime.NODEJS_12_X`. ## Athena @@ -664,6 +666,37 @@ new tasks.EmrModifyInstanceGroupByName(stack, 'Task', { }); ``` +## EKS + +Step Functions supports Amazon EKS through the service integration pattern. +The service integration APIs correspond to Amazon EKS APIs. + +[Read more](https://docs.aws.amazon.com/step-functions/latest/dg/connect-eks.html) about the differences when using these service integrations. + +### Call + +Read and write Kubernetes resource objects via a Kubernetes API endpoint. +Corresponds to the [`call`](https://docs.aws.amazon.com/step-functions/latest/dg/connect-eks.html) API in Step Functions Connector. + +The following code snippet includes a Task state that uses eks:call to list the pods. + +```ts +import * as eks from '@aws-cdk/aws-eks'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import * as tasks from '@aws-cdk/aws-stepfunctions-tasks'; + +const myEksCluster = new eks.Cluster(this, 'my sample cluster', { + version: eks.KubernetesVersion.V1_18, + clusterName: 'myEksCluster', + }); + +new tasks.EksCall(stack, 'Call a EKS Endpoint', { + cluster: myEksCluster, + httpMethod: MethodType.GET, + httpPath: '/api/v1/namespaces/default/pods', +}); +``` + ## Glue Step Functions supports [AWS Glue](https://docs.aws.amazon.com/step-functions/latest/dg/connect-glue.html) through the service integration pattern. @@ -811,7 +844,7 @@ Step Functions supports [AWS SageMaker](https://docs.aws.amazon.com/step-functio You can call the [`CreateTrainingJob`](https://docs.aws.amazon.com/sagemaker/latest/dg/API_CreateTrainingJob.html) API from a `Task` state. ```ts -new sfn.SagemakerTrainTask(this, 'TrainSagemaker', { +new sfn.SageMakerCreateTrainingJob(this, 'TrainSagemaker', { trainingJobName: sfn.JsonPath.stringAt('$.JobName'), role, algorithmSpecification: { @@ -846,7 +879,7 @@ new sfn.SagemakerTrainTask(this, 'TrainSagemaker', { You can call the [`CreateTransformJob`](https://docs.aws.amazon.com/sagemaker/latest/dg/API_CreateTransformJob.html) API from a `Task` state. ```ts -new sfn.SagemakerTransformTask(this, 'Batch Inference', { +new sfn.SageMakerCreateTransformJob(this, 'Batch Inference', { transformJobName: 'MyTransformJob', modelName: 'MyModelName', modelClientOptions: { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/eks/call.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/eks/call.ts new file mode 100644 index 0000000000000..8cbf3fcca5886 --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/eks/call.ts @@ -0,0 +1,137 @@ +import * as eks from '@aws-cdk/aws-eks'; +import * as iam from '@aws-cdk/aws-iam'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import { Construct } from 'constructs'; +import { integrationResourceArn, validatePatternSupported } from '../private/task-utils'; + +/** + * Properties for calling a EKS endpoint with EksCall + * @experimental + */ +export interface EksCallProps extends sfn.TaskStateBaseProps { + + /** + * The EKS cluster + */ + readonly cluster: eks.ICluster; + + /** + * HTTP method ("GET", "POST", "PUT", ...) part of HTTP request + */ + readonly httpMethod: HttpMethods; + + /** + * HTTP path of the Kubernetes REST API operation + * For example: /api/v1/namespaces/default/pods + */ + readonly httpPath: string; + + /** + * Query Parameters part of HTTP request + * @default - no query parameters + */ + readonly queryParameters?: { [key: string]: string[] }; + + /** + * Request body part of HTTP request + * @default - No request body + */ + readonly requestBody?: sfn.TaskInput; +} + +/** + * Call a EKS endpoint as a Task + * + * @see https://docs.aws.amazon.com/step-functions/latest/dg/connect-eks.html + * @experimental + */ +export class EksCall extends sfn.TaskStateBase { + + private static readonly SUPPORTED_INTEGRATION_PATTERNS: sfn.IntegrationPattern[] = [ + sfn.IntegrationPattern.REQUEST_RESPONSE, + ]; + + /** No policies are required due to eks:call is an Http service integration and does not call and EKS API directly + * @see https://docs.aws.amazon.com/step-functions/latest/dg/connect-eks.html#connect-eks-permissions + */ + protected readonly taskMetrics?: sfn.TaskMetricsConfig; + protected readonly taskPolicies?: iam.PolicyStatement[]; + + private readonly integrationPattern: sfn.IntegrationPattern; + + private readonly clusterEndpoint: string; + private readonly clusterCertificateAuthorityData: string; + + constructor(scope: Construct, id: string, private readonly props: EksCallProps) { + super(scope, id, props); + this.integrationPattern = props.integrationPattern ?? sfn.IntegrationPattern.REQUEST_RESPONSE; + + validatePatternSupported(this.integrationPattern, EksCall.SUPPORTED_INTEGRATION_PATTERNS); + + try { + this.clusterEndpoint = this.props.cluster.clusterEndpoint; + } catch (e) { + throw new Error('The "clusterEndpoint" property must be specified when using an imported Cluster.'); + } + + try { + this.clusterCertificateAuthorityData = this.props.cluster.clusterCertificateAuthorityData; + } catch (e) { + throw new Error('The "clusterCertificateAuthorityData" property must be specified when using an imported Cluster.'); + } + } + + /** + * Provides the EKS Call service integration task configuration + * @internal + */ + protected _renderTask(): any { + return { + Resource: integrationResourceArn('eks', 'call', this.integrationPattern), + Parameters: sfn.FieldUtils.renderObject({ + ClusterName: this.props.cluster.clusterName, + CertificateAuthority: this.clusterCertificateAuthorityData, + Endpoint: this.clusterEndpoint, + Method: this.props.httpMethod, + Path: this.props.httpPath, + QueryParameters: this.props.queryParameters, + RequestBody: this.props.requestBody?.value, + }), + }; + } +} + +/** + * Method type of a EKS call + */ +export enum HttpMethods { + /** + * Retrieve data from a server at the specified resource + */ + GET = 'GET', + + /** + * Send data to the API endpoint to create or update a resource + */ + POST = 'POST', + + /** + * Send data to the API endpoint to update or create a resource + */ + PUT = 'PUT', + + /** + * Delete the resource at the specified endpoint + */ + DELETE = 'DELETE', + + /** + * Apply partial modifications to the resource + */ + PATCH = 'PATCH', + + /** + * Retrieve data from a server at the specified resource without the response body + */ + HEAD = 'HEAD' +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/index.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/index.ts index 84b790beff216..32e684f6d1adf 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/index.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/index.ts @@ -44,3 +44,4 @@ export * from './athena/stop-query-execution'; export * from './athena/get-query-execution'; export * from './athena/get-query-results'; export * from './databrew/start-job-run'; +export * from './eks/call'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json index 63496e7c5fca5..a6137f570b1a3 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json @@ -81,6 +81,7 @@ "@aws-cdk/aws-ecr": "0.0.0", "@aws-cdk/aws-ecr-assets": "0.0.0", "@aws-cdk/aws-ecs": "0.0.0", + "@aws-cdk/aws-eks": "0.0.0", "@aws-cdk/aws-glue": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", @@ -103,6 +104,7 @@ "@aws-cdk/aws-ecr": "0.0.0", "@aws-cdk/aws-ecr-assets": "0.0.0", "@aws-cdk/aws-ecs": "0.0.0", + "@aws-cdk/aws-eks": "0.0.0", "@aws-cdk/aws-glue": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/call.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/call.test.ts new file mode 100644 index 0000000000000..fd7c9f7cb0dd7 --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/call.test.ts @@ -0,0 +1,234 @@ +import * as eks from '@aws-cdk/aws-eks'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import { Stack } from '@aws-cdk/core'; +import { EksCall, HttpMethods } from '../../lib/eks/call'; + +let stack: Stack; +let cluster: eks.Cluster; + +beforeEach(() => { + //GIVEN + stack = new Stack(); + cluster = new eks.Cluster(stack, 'Cluster', { + version: eks.KubernetesVersion.V1_18, + clusterName: 'eksCluster', + }); +}); + +test('Call an EKS endpoint', () => { + // WHEN + const task = new EksCall(stack, 'Call', { + cluster: cluster, + httpMethod: HttpMethods.GET, + httpPath: 'path', + requestBody: sfn.TaskInput.fromObject({ + Body: 'requestBody', + }), + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toEqual({ + Type: 'Task', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:::eks:call', + ], + ], + }, + End: true, + Parameters: { + ClusterName: { + Ref: 'Cluster9EE0221C', + }, + CertificateAuthority: { + 'Fn::GetAtt': [ + 'Cluster9EE0221C', + 'CertificateAuthorityData', + ], + }, + Endpoint: { + 'Fn::GetAtt': [ + 'Cluster9EE0221C', + 'Endpoint', + ], + }, + Method: 'GET', + Path: 'path', + RequestBody: { + Body: 'requestBody', + }, + }, + }); +}); + +test('Call an EKS endpoint with requestBody as a string', () => { + // WHEN + const task = new EksCall(stack, 'Call', { + cluster: cluster, + httpMethod: HttpMethods.GET, + httpPath: 'path', + requestBody: sfn.TaskInput.fromText('requestBody'), + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toEqual({ + Type: 'Task', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:::eks:call', + ], + ], + }, + End: true, + Parameters: { + ClusterName: { + Ref: 'Cluster9EE0221C', + }, + CertificateAuthority: { + 'Fn::GetAtt': [ + 'Cluster9EE0221C', + 'CertificateAuthorityData', + ], + }, + Endpoint: { + 'Fn::GetAtt': [ + 'Cluster9EE0221C', + 'Endpoint', + ], + }, + Method: 'GET', + Path: 'path', + RequestBody: 'requestBody', + }, + }); +}); + +test('Call an EKS endpoint with requestBody supply through path', () => { + // WHEN + const task = new EksCall(stack, 'Call', { + cluster: cluster, + httpMethod: HttpMethods.GET, + httpPath: 'path', + requestBody: sfn.TaskInput.fromJsonPathAt('$.Request.Body'), + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toEqual({ + Type: 'Task', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:::eks:call', + ], + ], + }, + End: true, + Parameters: { + 'ClusterName': { + Ref: 'Cluster9EE0221C', + }, + 'CertificateAuthority': { + 'Fn::GetAtt': [ + 'Cluster9EE0221C', + 'CertificateAuthorityData', + ], + }, + 'Endpoint': { + 'Fn::GetAtt': [ + 'Cluster9EE0221C', + 'Endpoint', + ], + }, + 'Method': 'GET', + 'Path': 'path', + 'RequestBody.$': '$.Request.Body', + }, + }); +}); + +test('Task throws if RUN_JOB is supplied as service integration pattern', () => { + expect(() => { + new EksCall(stack, 'Call', { + cluster: cluster, + httpMethod: HttpMethods.GET, + httpPath: 'path', + requestBody: sfn.TaskInput.fromObject({ + RequestBody: 'requestBody', + }), + integrationPattern: sfn.IntegrationPattern.RUN_JOB, + }); + }).toThrow( + /Unsupported service integration pattern. Supported Patterns: REQUEST_RESPONSE. Received: RUN_JOB/, + ); +}); + +test('Task throws if WAIT_FOR_TASK_TOKEN is supplied as service integration pattern', () => { + expect(() => { + new EksCall(stack, 'Call', { + cluster: cluster, + httpMethod: HttpMethods.GET, + httpPath: 'path', + requestBody: sfn.TaskInput.fromObject({ + RequestBody: 'requestBody', + }), + integrationPattern: sfn.IntegrationPattern.WAIT_FOR_TASK_TOKEN, + }); + }).toThrow( + /Unsupported service integration pattern. Supported Patterns: REQUEST_RESPONSE. Received: WAIT_FOR_TASK_TOKEN/, + ); +}); + +test('Task throws if cluster supplied does not have clusterEndpoint configured', () => { + const importedCluster = eks.Cluster.fromClusterAttributes(stack, 'InvalidCluster', { + clusterName: 'importedCluster', + clusterCertificateAuthorityData: 'clusterCertificateAuthorityData', + }); + expect(() => { + new EksCall(stack, 'Call', { + cluster: importedCluster, + httpMethod: HttpMethods.GET, + httpPath: 'path', + requestBody: sfn.TaskInput.fromObject({ + RequestBody: 'requestBody', + }), + }); + }).toThrow( + /The "clusterEndpoint" property must be specified when using an imported Cluster./, + ); +}); + +test('Task throws if cluster supplied does not have clusterCertificateAuthorityData configured', () => { + const importedCluster = eks.Cluster.fromClusterAttributes(stack, 'InvalidCluster', { + clusterName: 'importedCluster', + clusterEndpoint: 'clusterEndpoint', + }); + expect(() => { + new EksCall(stack, 'Call', { + cluster: importedCluster, + httpMethod: HttpMethods.GET, + httpPath: 'path', + requestBody: sfn.TaskInput.fromObject({ + RequestBody: 'requestBody', + }), + }); + }).toThrow( + /The "clusterCertificateAuthorityData" property must be specified when using an imported Cluster./, + ); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.expected.json new file mode 100644 index 0000000000000..23ad4160b9f7b --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.expected.json @@ -0,0 +1,1580 @@ +{ + "Resources": { + "EksClusterDefaultVpcB24550B2": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc" + } + ] + } + }, + "EksClusterDefaultVpcPublicSubnet1SubnetCB1D1047": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/19", + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PublicSubnet1" + } + ] + } + }, + "EksClusterDefaultVpcPublicSubnet1RouteTable163DE10A": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PublicSubnet1" + } + ] + } + }, + "EksClusterDefaultVpcPublicSubnet1RouteTableAssociation36D085C2": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "EksClusterDefaultVpcPublicSubnet1RouteTable163DE10A" + }, + "SubnetId": { + "Ref": "EksClusterDefaultVpcPublicSubnet1SubnetCB1D1047" + } + } + }, + "EksClusterDefaultVpcPublicSubnet1DefaultRouteCE5F6EF3": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "EksClusterDefaultVpcPublicSubnet1RouteTable163DE10A" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "EksClusterDefaultVpcIGWCA6A3220" + } + }, + "DependsOn": [ + "EksClusterDefaultVpcVPCGW0E4A5673" + ] + }, + "EksClusterDefaultVpcPublicSubnet1EIPF53713C9": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PublicSubnet1" + } + ] + } + }, + "EksClusterDefaultVpcPublicSubnet1NATGateway548C2CDF": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "EksClusterDefaultVpcPublicSubnet1EIPF53713C9", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "EksClusterDefaultVpcPublicSubnet1SubnetCB1D1047" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PublicSubnet1" + } + ] + } + }, + "EksClusterDefaultVpcPublicSubnet2SubnetA8FE675D": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.32.0/19", + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PublicSubnet2" + } + ] + } + }, + "EksClusterDefaultVpcPublicSubnet2RouteTable1027E4DE": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PublicSubnet2" + } + ] + } + }, + "EksClusterDefaultVpcPublicSubnet2RouteTableAssociation39E2ABB3": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "EksClusterDefaultVpcPublicSubnet2RouteTable1027E4DE" + }, + "SubnetId": { + "Ref": "EksClusterDefaultVpcPublicSubnet2SubnetA8FE675D" + } + } + }, + "EksClusterDefaultVpcPublicSubnet2DefaultRoute8B910E5C": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "EksClusterDefaultVpcPublicSubnet2RouteTable1027E4DE" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "EksClusterDefaultVpcIGWCA6A3220" + } + }, + "DependsOn": [ + "EksClusterDefaultVpcVPCGW0E4A5673" + ] + }, + "EksClusterDefaultVpcPublicSubnet2EIP16D41D80": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PublicSubnet2" + } + ] + } + }, + "EksClusterDefaultVpcPublicSubnet2NATGateway869DDCBF": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "EksClusterDefaultVpcPublicSubnet2EIP16D41D80", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "EksClusterDefaultVpcPublicSubnet2SubnetA8FE675D" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PublicSubnet2" + } + ] + } + }, + "EksClusterDefaultVpcPublicSubnet3SubnetA04EFFC1": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/19", + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + }, + "AvailabilityZone": "test-region-1c", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PublicSubnet3" + } + ] + } + }, + "EksClusterDefaultVpcPublicSubnet3RouteTableEBB51B8A": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PublicSubnet3" + } + ] + } + }, + "EksClusterDefaultVpcPublicSubnet3RouteTableAssociationFE466321": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "EksClusterDefaultVpcPublicSubnet3RouteTableEBB51B8A" + }, + "SubnetId": { + "Ref": "EksClusterDefaultVpcPublicSubnet3SubnetA04EFFC1" + } + } + }, + "EksClusterDefaultVpcPublicSubnet3DefaultRoute1F5BE861": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "EksClusterDefaultVpcPublicSubnet3RouteTableEBB51B8A" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "EksClusterDefaultVpcIGWCA6A3220" + } + }, + "DependsOn": [ + "EksClusterDefaultVpcVPCGW0E4A5673" + ] + }, + "EksClusterDefaultVpcPublicSubnet3EIPF8D34EDE": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PublicSubnet3" + } + ] + } + }, + "EksClusterDefaultVpcPublicSubnet3NATGatewayC35C74D3": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "EksClusterDefaultVpcPublicSubnet3EIPF8D34EDE", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "EksClusterDefaultVpcPublicSubnet3SubnetA04EFFC1" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PublicSubnet3" + } + ] + } + }, + "EksClusterDefaultVpcPrivateSubnet1Subnet4D665A2F": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.96.0/19", + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PrivateSubnet1" + } + ] + } + }, + "EksClusterDefaultVpcPrivateSubnet1RouteTable9104CFAB": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PrivateSubnet1" + } + ] + } + }, + "EksClusterDefaultVpcPrivateSubnet1RouteTableAssociationCC31B65B": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "EksClusterDefaultVpcPrivateSubnet1RouteTable9104CFAB" + }, + "SubnetId": { + "Ref": "EksClusterDefaultVpcPrivateSubnet1Subnet4D665A2F" + } + } + }, + "EksClusterDefaultVpcPrivateSubnet1DefaultRoute790DE5CF": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "EksClusterDefaultVpcPrivateSubnet1RouteTable9104CFAB" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "EksClusterDefaultVpcPublicSubnet1NATGateway548C2CDF" + } + } + }, + "EksClusterDefaultVpcPrivateSubnet2Subnet180B8A71": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/19", + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PrivateSubnet2" + } + ] + } + }, + "EksClusterDefaultVpcPrivateSubnet2RouteTable04B34031": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PrivateSubnet2" + } + ] + } + }, + "EksClusterDefaultVpcPrivateSubnet2RouteTableAssociation86243837": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "EksClusterDefaultVpcPrivateSubnet2RouteTable04B34031" + }, + "SubnetId": { + "Ref": "EksClusterDefaultVpcPrivateSubnet2Subnet180B8A71" + } + } + }, + "EksClusterDefaultVpcPrivateSubnet2DefaultRoute99A19B21": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "EksClusterDefaultVpcPrivateSubnet2RouteTable04B34031" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "EksClusterDefaultVpcPublicSubnet2NATGateway869DDCBF" + } + } + }, + "EksClusterDefaultVpcPrivateSubnet3Subnet6C4BFC07": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.160.0/19", + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + }, + "AvailabilityZone": "test-region-1c", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PrivateSubnet3" + } + ] + } + }, + "EksClusterDefaultVpcPrivateSubnet3RouteTableA8F449F1": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PrivateSubnet3" + } + ] + } + }, + "EksClusterDefaultVpcPrivateSubnet3RouteTableAssociationCE2741BE": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "EksClusterDefaultVpcPrivateSubnet3RouteTableA8F449F1" + }, + "SubnetId": { + "Ref": "EksClusterDefaultVpcPrivateSubnet3Subnet6C4BFC07" + } + } + }, + "EksClusterDefaultVpcPrivateSubnet3DefaultRouteDC2E9DE0": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "EksClusterDefaultVpcPrivateSubnet3RouteTableA8F449F1" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "EksClusterDefaultVpcPublicSubnet3NATGatewayC35C74D3" + } + } + }, + "EksClusterDefaultVpcIGWCA6A3220": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc" + } + ] + } + }, + "EksClusterDefaultVpcVPCGW0E4A5673": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + }, + "InternetGatewayId": { + "Ref": "EksClusterDefaultVpcIGWCA6A3220" + } + } + }, + "EksClusterRoleC84B376F": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "eks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/AmazonEKSClusterPolicy" + ] + ] + } + ] + } + }, + "EksClusterControlPlaneSecurityGroup9257A6D0": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "EKS Control Plane Security Group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + } + } + }, + "EksClusterCreationRole75AABE42": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + }, + "DependsOn": [ + "EksClusterDefaultVpcIGWCA6A3220", + "EksClusterDefaultVpcPrivateSubnet1DefaultRoute790DE5CF", + "EksClusterDefaultVpcPrivateSubnet1RouteTable9104CFAB", + "EksClusterDefaultVpcPrivateSubnet1RouteTableAssociationCC31B65B", + "EksClusterDefaultVpcPrivateSubnet1Subnet4D665A2F", + "EksClusterDefaultVpcPrivateSubnet2DefaultRoute99A19B21", + "EksClusterDefaultVpcPrivateSubnet2RouteTable04B34031", + "EksClusterDefaultVpcPrivateSubnet2RouteTableAssociation86243837", + "EksClusterDefaultVpcPrivateSubnet2Subnet180B8A71", + "EksClusterDefaultVpcPrivateSubnet3DefaultRouteDC2E9DE0", + "EksClusterDefaultVpcPrivateSubnet3RouteTableA8F449F1", + "EksClusterDefaultVpcPrivateSubnet3RouteTableAssociationCE2741BE", + "EksClusterDefaultVpcPrivateSubnet3Subnet6C4BFC07", + "EksClusterDefaultVpcPublicSubnet1DefaultRouteCE5F6EF3", + "EksClusterDefaultVpcPublicSubnet1EIPF53713C9", + "EksClusterDefaultVpcPublicSubnet1NATGateway548C2CDF", + "EksClusterDefaultVpcPublicSubnet1RouteTable163DE10A", + "EksClusterDefaultVpcPublicSubnet1RouteTableAssociation36D085C2", + "EksClusterDefaultVpcPublicSubnet1SubnetCB1D1047", + "EksClusterDefaultVpcPublicSubnet2DefaultRoute8B910E5C", + "EksClusterDefaultVpcPublicSubnet2EIP16D41D80", + "EksClusterDefaultVpcPublicSubnet2NATGateway869DDCBF", + "EksClusterDefaultVpcPublicSubnet2RouteTable1027E4DE", + "EksClusterDefaultVpcPublicSubnet2RouteTableAssociation39E2ABB3", + "EksClusterDefaultVpcPublicSubnet2SubnetA8FE675D", + "EksClusterDefaultVpcPublicSubnet3DefaultRoute1F5BE861", + "EksClusterDefaultVpcPublicSubnet3EIPF8D34EDE", + "EksClusterDefaultVpcPublicSubnet3NATGatewayC35C74D3", + "EksClusterDefaultVpcPublicSubnet3RouteTableEBB51B8A", + "EksClusterDefaultVpcPublicSubnet3RouteTableAssociationFE466321", + "EksClusterDefaultVpcPublicSubnet3SubnetA04EFFC1", + "EksClusterDefaultVpcB24550B2", + "EksClusterDefaultVpcVPCGW0E4A5673" + ] + }, + "EksClusterCreationRoleDefaultPolicy2DFE4D73": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "iam:PassRole", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "EksClusterRoleC84B376F", + "Arn" + ] + } + }, + { + "Action": [ + "eks:CreateCluster", + "eks:DescribeCluster", + "eks:DescribeUpdate", + "eks:DeleteCluster", + "eks:UpdateClusterVersion", + "eks:UpdateClusterConfig", + "eks:CreateFargateProfile", + "eks:TagResource", + "eks:UntagResource" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":eks:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":cluster/eksCluster" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":eks:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":cluster/eksCluster/*" + ] + ] + } + ] + }, + { + "Action": [ + "eks:DescribeFargateProfile", + "eks:DeleteFargateProfile" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":eks:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":fargateprofile/eksCluster/*" + ] + ] + } + }, + { + "Action": [ + "iam:GetRole", + "iam:listAttachedRolePolicies" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "iam:CreateServiceLinkedRole", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ec2:DescribeInstances", + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", + "ec2:DescribeRouteTables", + "ec2:DescribeDhcpOptions", + "ec2:DescribeVpcs" + ], + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "EksClusterCreationRoleDefaultPolicy2DFE4D73", + "Roles": [ + { + "Ref": "EksClusterCreationRole75AABE42" + } + ] + }, + "DependsOn": [ + "EksClusterDefaultVpcIGWCA6A3220", + "EksClusterDefaultVpcPrivateSubnet1DefaultRoute790DE5CF", + "EksClusterDefaultVpcPrivateSubnet1RouteTable9104CFAB", + "EksClusterDefaultVpcPrivateSubnet1RouteTableAssociationCC31B65B", + "EksClusterDefaultVpcPrivateSubnet1Subnet4D665A2F", + "EksClusterDefaultVpcPrivateSubnet2DefaultRoute99A19B21", + "EksClusterDefaultVpcPrivateSubnet2RouteTable04B34031", + "EksClusterDefaultVpcPrivateSubnet2RouteTableAssociation86243837", + "EksClusterDefaultVpcPrivateSubnet2Subnet180B8A71", + "EksClusterDefaultVpcPrivateSubnet3DefaultRouteDC2E9DE0", + "EksClusterDefaultVpcPrivateSubnet3RouteTableA8F449F1", + "EksClusterDefaultVpcPrivateSubnet3RouteTableAssociationCE2741BE", + "EksClusterDefaultVpcPrivateSubnet3Subnet6C4BFC07", + "EksClusterDefaultVpcPublicSubnet1DefaultRouteCE5F6EF3", + "EksClusterDefaultVpcPublicSubnet1EIPF53713C9", + "EksClusterDefaultVpcPublicSubnet1NATGateway548C2CDF", + "EksClusterDefaultVpcPublicSubnet1RouteTable163DE10A", + "EksClusterDefaultVpcPublicSubnet1RouteTableAssociation36D085C2", + "EksClusterDefaultVpcPublicSubnet1SubnetCB1D1047", + "EksClusterDefaultVpcPublicSubnet2DefaultRoute8B910E5C", + "EksClusterDefaultVpcPublicSubnet2EIP16D41D80", + "EksClusterDefaultVpcPublicSubnet2NATGateway869DDCBF", + "EksClusterDefaultVpcPublicSubnet2RouteTable1027E4DE", + "EksClusterDefaultVpcPublicSubnet2RouteTableAssociation39E2ABB3", + "EksClusterDefaultVpcPublicSubnet2SubnetA8FE675D", + "EksClusterDefaultVpcPublicSubnet3DefaultRoute1F5BE861", + "EksClusterDefaultVpcPublicSubnet3EIPF8D34EDE", + "EksClusterDefaultVpcPublicSubnet3NATGatewayC35C74D3", + "EksClusterDefaultVpcPublicSubnet3RouteTableEBB51B8A", + "EksClusterDefaultVpcPublicSubnet3RouteTableAssociationFE466321", + "EksClusterDefaultVpcPublicSubnet3SubnetA04EFFC1", + "EksClusterDefaultVpcB24550B2", + "EksClusterDefaultVpcVPCGW0E4A5673" + ] + }, + "EksClusterFAB68BDB": { + "Type": "Custom::AWSCDK-EKS-Cluster", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "awscdkawseksClusterResourceProviderNestedStackawscdkawseksClusterResourceProviderNestedStackResource9827C454", + "Outputs.awsstepfunctionstasksekscallintegawscdkawseksClusterResourceProviderframeworkonEvent5722A6A8Arn" + ] + }, + "Config": { + "name": "eksCluster", + "version": "1.18", + "roleArn": { + "Fn::GetAtt": [ + "EksClusterRoleC84B376F", + "Arn" + ] + }, + "resourcesVpcConfig": { + "subnetIds": [ + { + "Ref": "EksClusterDefaultVpcPublicSubnet1SubnetCB1D1047" + }, + { + "Ref": "EksClusterDefaultVpcPublicSubnet2SubnetA8FE675D" + }, + { + "Ref": "EksClusterDefaultVpcPublicSubnet3SubnetA04EFFC1" + }, + { + "Ref": "EksClusterDefaultVpcPrivateSubnet1Subnet4D665A2F" + }, + { + "Ref": "EksClusterDefaultVpcPrivateSubnet2Subnet180B8A71" + }, + { + "Ref": "EksClusterDefaultVpcPrivateSubnet3Subnet6C4BFC07" + } + ], + "securityGroupIds": [ + { + "Fn::GetAtt": [ + "EksClusterControlPlaneSecurityGroup9257A6D0", + "GroupId" + ] + } + ], + "endpointPublicAccess": true, + "endpointPrivateAccess": true + } + }, + "AssumeRoleArn": { + "Fn::GetAtt": [ + "EksClusterCreationRole75AABE42", + "Arn" + ] + }, + "AttributesRevision": 2 + }, + "DependsOn": [ + "EksClusterDefaultVpcIGWCA6A3220", + "EksClusterDefaultVpcPrivateSubnet1DefaultRoute790DE5CF", + "EksClusterDefaultVpcPrivateSubnet1RouteTable9104CFAB", + "EksClusterDefaultVpcPrivateSubnet1RouteTableAssociationCC31B65B", + "EksClusterDefaultVpcPrivateSubnet1Subnet4D665A2F", + "EksClusterDefaultVpcPrivateSubnet2DefaultRoute99A19B21", + "EksClusterDefaultVpcPrivateSubnet2RouteTable04B34031", + "EksClusterDefaultVpcPrivateSubnet2RouteTableAssociation86243837", + "EksClusterDefaultVpcPrivateSubnet2Subnet180B8A71", + "EksClusterDefaultVpcPrivateSubnet3DefaultRouteDC2E9DE0", + "EksClusterDefaultVpcPrivateSubnet3RouteTableA8F449F1", + "EksClusterDefaultVpcPrivateSubnet3RouteTableAssociationCE2741BE", + "EksClusterDefaultVpcPrivateSubnet3Subnet6C4BFC07", + "EksClusterDefaultVpcPublicSubnet1DefaultRouteCE5F6EF3", + "EksClusterDefaultVpcPublicSubnet1EIPF53713C9", + "EksClusterDefaultVpcPublicSubnet1NATGateway548C2CDF", + "EksClusterDefaultVpcPublicSubnet1RouteTable163DE10A", + "EksClusterDefaultVpcPublicSubnet1RouteTableAssociation36D085C2", + "EksClusterDefaultVpcPublicSubnet1SubnetCB1D1047", + "EksClusterDefaultVpcPublicSubnet2DefaultRoute8B910E5C", + "EksClusterDefaultVpcPublicSubnet2EIP16D41D80", + "EksClusterDefaultVpcPublicSubnet2NATGateway869DDCBF", + "EksClusterDefaultVpcPublicSubnet2RouteTable1027E4DE", + "EksClusterDefaultVpcPublicSubnet2RouteTableAssociation39E2ABB3", + "EksClusterDefaultVpcPublicSubnet2SubnetA8FE675D", + "EksClusterDefaultVpcPublicSubnet3DefaultRoute1F5BE861", + "EksClusterDefaultVpcPublicSubnet3EIPF8D34EDE", + "EksClusterDefaultVpcPublicSubnet3NATGatewayC35C74D3", + "EksClusterDefaultVpcPublicSubnet3RouteTableEBB51B8A", + "EksClusterDefaultVpcPublicSubnet3RouteTableAssociationFE466321", + "EksClusterDefaultVpcPublicSubnet3SubnetA04EFFC1", + "EksClusterDefaultVpcB24550B2", + "EksClusterDefaultVpcVPCGW0E4A5673", + "EksClusterCreationRoleDefaultPolicy2DFE4D73", + "EksClusterCreationRole75AABE42" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "EksClusterKubectlReadyBarrier502B0E83": { + "Type": "AWS::SSM::Parameter", + "Properties": { + "Type": "String", + "Value": "aws:cdk:eks:kubectl-ready" + }, + "DependsOn": [ + "EksClusterCreationRoleDefaultPolicy2DFE4D73", + "EksClusterCreationRole75AABE42", + "EksClusterFAB68BDB" + ] + }, + "EksClusterMastersRole3F49FAC3": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "EksClusterAwsAuthmanifest4F460A9B": { + "Type": "Custom::AWSCDK-EKS-KubernetesResource", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "awscdkawseksKubectlProviderNestedStackawscdkawseksKubectlProviderNestedStackResourceA7AEBA6B", + "Outputs.awsstepfunctionstasksekscallintegawscdkawseksKubectlProviderframeworkonEventAF076895Arn" + ] + }, + "Manifest": { + "Fn::Join": [ + "", + [ + "[{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"aws-auth\",\"namespace\":\"kube-system\",\"labels\":{\"aws.cdk.eks/prune-c8f58087a1a3e6c10f65d847befda9c1aa2145a8fc\":\"\"}},\"data\":{\"mapRoles\":\"[{\\\"rolearn\\\":\\\"", + { + "Fn::GetAtt": [ + "EksClusterMastersRole3F49FAC3", + "Arn" + ] + }, + "\\\",\\\"username\\\":\\\"", + { + "Fn::GetAtt": [ + "EksClusterMastersRole3F49FAC3", + "Arn" + ] + }, + "\\\",\\\"groups\\\":[\\\"system:masters\\\"]},{\\\"rolearn\\\":\\\"", + { + "Fn::GetAtt": [ + "EksClusterNodegroupDefaultCapacityNodeGroupRole70D09CEC", + "Arn" + ] + }, + "\\\",\\\"username\\\":\\\"system:node:{{EC2PrivateDNSName}}\\\",\\\"groups\\\":[\\\"system:bootstrappers\\\",\\\"system:nodes\\\"]},{\\\"rolearn\\\":\\\"", + { + "Fn::GetAtt": [ + "Role1ABCC5F0", + "Arn" + ] + }, + "\\\",\\\"username\\\":\\\"", + { + "Fn::GetAtt": [ + "Role1ABCC5F0", + "Arn" + ] + }, + "\\\",\\\"groups\\\":[\\\"system:masters\\\"]}]\",\"mapUsers\":\"[]\",\"mapAccounts\":\"[]\"}}]" + ] + ] + }, + "ClusterName": { + "Ref": "EksClusterFAB68BDB" + }, + "RoleArn": { + "Fn::GetAtt": [ + "EksClusterCreationRole75AABE42", + "Arn" + ] + }, + "PruneLabel": "aws.cdk.eks/prune-c8f58087a1a3e6c10f65d847befda9c1aa2145a8fc", + "Overwrite": true + }, + "DependsOn": [ + "EksClusterKubectlReadyBarrier502B0E83" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "EksClusterNodegroupDefaultCapacityNodeGroupRole70D09CEC": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ec2.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/AmazonEKSWorkerNodePolicy" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/AmazonEKS_CNI_Policy" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" + ] + ] + } + ] + } + }, + "EksClusterNodegroupDefaultCapacityA81E70F9": { + "Type": "AWS::EKS::Nodegroup", + "Properties": { + "ClusterName": { + "Ref": "EksClusterFAB68BDB" + }, + "NodeRole": { + "Fn::GetAtt": [ + "EksClusterNodegroupDefaultCapacityNodeGroupRole70D09CEC", + "Arn" + ] + }, + "Subnets": [ + { + "Ref": "EksClusterDefaultVpcPrivateSubnet1Subnet4D665A2F" + }, + { + "Ref": "EksClusterDefaultVpcPrivateSubnet2Subnet180B8A71" + }, + { + "Ref": "EksClusterDefaultVpcPrivateSubnet3Subnet6C4BFC07" + } + ], + "AmiType": "AL2_x86_64", + "ForceUpdateEnabled": true, + "InstanceTypes": [ + "m5.large" + ], + "ScalingConfig": { + "DesiredSize": 2, + "MaxSize": 2, + "MinSize": 2 + } + } + }, + "awscdkawseksClusterResourceProviderNestedStackawscdkawseksClusterResourceProviderNestedStackResource9827C454": { + "Type": "AWS::CloudFormation::Stack", + "Properties": { + "TemplateURL": { + "Fn::Join": [ + "", + [ + "https://s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "AssetParameters3aee2b76026cd725af3b14456bf03061e83d56cce0e0354c7c8e88ee1150e527S3Bucket7ED14FA7" + }, + "/", + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters3aee2b76026cd725af3b14456bf03061e83d56cce0e0354c7c8e88ee1150e527S3VersionKeyF4EF0775" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters3aee2b76026cd725af3b14456bf03061e83d56cce0e0354c7c8e88ee1150e527S3VersionKeyF4EF0775" + } + ] + } + ] + } + ] + ] + }, + "Parameters": { + "referencetoawsstepfunctionstasksekscallintegEksClusterCreationRole00B486C4Arn": { + "Fn::GetAtt": [ + "EksClusterCreationRole75AABE42", + "Arn" + ] + }, + "referencetoawsstepfunctionstasksekscallintegAssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket61AA45E5Ref": { + "Ref": "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket14D204F9" + }, + "referencetoawsstepfunctionstasksekscallintegAssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKey48ACDBCFRef": { + "Ref": "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyDE8A2F1F" + }, + "referencetoawsstepfunctionstasksekscallintegAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketCF9FB24DRef": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + }, + "referencetoawsstepfunctionstasksekscallintegAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey4B465A75Ref": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + } + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "awscdkawseksKubectlProviderNestedStackawscdkawseksKubectlProviderNestedStackResourceA7AEBA6B": { + "Type": "AWS::CloudFormation::Stack", + "Properties": { + "TemplateURL": { + "Fn::Join": [ + "", + [ + "https://s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "AssetParameterscad1ae036643e3cd17cd3b2b30a2f9e07c1aacaf5284314f41437e4c20447aeaS3BucketED16A657" + }, + "/", + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameterscad1ae036643e3cd17cd3b2b30a2f9e07c1aacaf5284314f41437e4c20447aeaS3VersionKey37A80BBF" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameterscad1ae036643e3cd17cd3b2b30a2f9e07c1aacaf5284314f41437e4c20447aeaS3VersionKey37A80BBF" + } + ] + } + ] + } + ] + ] + }, + "Parameters": { + "referencetoawsstepfunctionstasksekscallintegEksClusterCA674174Arn": { + "Fn::GetAtt": [ + "EksClusterFAB68BDB", + "Arn" + ] + }, + "referencetoawsstepfunctionstasksekscallintegEksClusterCreationRole00B486C4Arn": { + "Fn::GetAtt": [ + "EksClusterCreationRole75AABE42", + "Arn" + ] + }, + "referencetoawsstepfunctionstasksekscallintegAssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3BucketB45933E2Ref": { + "Ref": "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket008DBB35" + }, + "referencetoawsstepfunctionstasksekscallintegAssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey897E2F88Ref": { + "Ref": "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey97C3E1A0" + }, + "referencetoawsstepfunctionstasksekscallintegEksClusterDefaultVpcPrivateSubnet1Subnet3A6964EARef": { + "Ref": "EksClusterDefaultVpcPrivateSubnet1Subnet4D665A2F" + }, + "referencetoawsstepfunctionstasksekscallintegEksClusterDefaultVpcPrivateSubnet2Subnet08905A58Ref": { + "Ref": "EksClusterDefaultVpcPrivateSubnet2Subnet180B8A71" + }, + "referencetoawsstepfunctionstasksekscallintegEksClusterDefaultVpcPrivateSubnet3SubnetF3A2081ERef": { + "Ref": "EksClusterDefaultVpcPrivateSubnet3Subnet6C4BFC07" + }, + "referencetoawsstepfunctionstasksekscallintegEksClusterCA674174ClusterSecurityGroupId": { + "Fn::GetAtt": [ + "EksClusterFAB68BDB", + "ClusterSecurityGroupId" + ] + }, + "referencetoawsstepfunctionstasksekscallintegAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3Bucket3F56B6C0Ref": { + "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" + }, + "referencetoawsstepfunctionstasksekscallintegAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKey14F73D88Ref": { + "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" + }, + "referencetoawsstepfunctionstasksekscallintegAssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket82DB0998Ref": { + "Ref": "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket6ABE1927" + }, + "referencetoawsstepfunctionstasksekscallintegAssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKey5CB2DA63Ref": { + "Ref": "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyF55A2EA9" + }, + "referencetoawsstepfunctionstasksekscallintegAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketCF9FB24DRef": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + }, + "referencetoawsstepfunctionstasksekscallintegAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey4B465A75Ref": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + } + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "Role1ABCC5F0": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "states.", + { + "Ref": "AWS::Region" + }, + ".amazonaws.com" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + }, + "RoleName": "stateMachineExecutionRole" + } + }, + "StateMachine2E01A3A5": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "Role1ABCC5F0", + "Arn" + ] + }, + "DefinitionString": { + "Fn::Join": [ + "", + [ + "{\"StartAt\":\"Call a EKS Endpoint\",\"States\":{\"Call a EKS Endpoint\":{\"End\":true,\"Type\":\"Task\",\"Resource\":\"arn:", + { + "Ref": "AWS::Partition" + }, + ":states:::eks:call\",\"Parameters\":{\"ClusterName\":\"", + { + "Ref": "EksClusterFAB68BDB" + }, + "\",\"CertificateAuthority\":\"", + { + "Fn::GetAtt": [ + "EksClusterFAB68BDB", + "CertificateAuthorityData" + ] + }, + "\",\"Endpoint\":\"", + { + "Fn::GetAtt": [ + "EksClusterFAB68BDB", + "Endpoint" + ] + }, + "\",\"Method\":\"GET\",\"Path\":\"/api/v1/namespaces/default/pods\"}}},\"TimeoutSeconds\":30}" + ] + ] + } + }, + "DependsOn": [ + "Role1ABCC5F0" + ] + } + }, + "Outputs": { + "EksClusterConfigCommand2AE6ED67": { + "Value": { + "Fn::Join": [ + "", + [ + "aws eks update-kubeconfig --name ", + { + "Ref": "EksClusterFAB68BDB" + }, + " --region ", + { + "Ref": "AWS::Region" + }, + " --role-arn ", + { + "Fn::GetAtt": [ + "EksClusterMastersRole3F49FAC3", + "Arn" + ] + } + ] + ] + } + }, + "EksClusterGetTokenCommandDF0BEDB9": { + "Value": { + "Fn::Join": [ + "", + [ + "aws eks get-token --cluster-name ", + { + "Ref": "EksClusterFAB68BDB" + }, + " --region ", + { + "Ref": "AWS::Region" + }, + " --role-arn ", + { + "Fn::GetAtt": [ + "EksClusterMastersRole3F49FAC3", + "Arn" + ] + } + ] + ] + } + }, + "stateMachineArn": { + "Value": { + "Ref": "StateMachine2E01A3A5" + } + } + }, + "Parameters": { + "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket14D204F9": { + "Type": "String", + "Description": "S3 bucket for asset \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + }, + "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyDE8A2F1F": { + "Type": "String", + "Description": "S3 key for asset version \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + }, + "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaArtifactHash54822A43": { + "Type": "String", + "Description": "Artifact hash for asset \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + }, + "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { + "Type": "String", + "Description": "S3 bucket for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + }, + "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F": { + "Type": "String", + "Description": "S3 key for asset version \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + }, + "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1ArtifactHashA521A16F": { + "Type": "String", + "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + }, + "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket008DBB35": { + "Type": "String", + "Description": "S3 bucket for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + }, + "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey97C3E1A0": { + "Type": "String", + "Description": "S3 key for asset version \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + }, + "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757ArtifactHashF584A7D8": { + "Type": "String", + "Description": "Artifact hash for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + }, + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { + "Type": "String", + "Description": "S3 bucket for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + }, + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F": { + "Type": "String", + "Description": "S3 key for asset version \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + }, + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68ArtifactHashD9A515C3": { + "Type": "String", + "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + }, + "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket6ABE1927": { + "Type": "String", + "Description": "S3 bucket for asset \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" + }, + "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyF55A2EA9": { + "Type": "String", + "Description": "S3 key for asset version \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" + }, + "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0ArtifactHash1D7A2D6E": { + "Type": "String", + "Description": "Artifact hash for asset \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" + }, + "AssetParameters3aee2b76026cd725af3b14456bf03061e83d56cce0e0354c7c8e88ee1150e527S3Bucket7ED14FA7": { + "Type": "String", + "Description": "S3 bucket for asset \"3aee2b76026cd725af3b14456bf03061e83d56cce0e0354c7c8e88ee1150e527\"" + }, + "AssetParameters3aee2b76026cd725af3b14456bf03061e83d56cce0e0354c7c8e88ee1150e527S3VersionKeyF4EF0775": { + "Type": "String", + "Description": "S3 key for asset version \"3aee2b76026cd725af3b14456bf03061e83d56cce0e0354c7c8e88ee1150e527\"" + }, + "AssetParameters3aee2b76026cd725af3b14456bf03061e83d56cce0e0354c7c8e88ee1150e527ArtifactHash94EFED5E": { + "Type": "String", + "Description": "Artifact hash for asset \"3aee2b76026cd725af3b14456bf03061e83d56cce0e0354c7c8e88ee1150e527\"" + }, + "AssetParameterscad1ae036643e3cd17cd3b2b30a2f9e07c1aacaf5284314f41437e4c20447aeaS3BucketED16A657": { + "Type": "String", + "Description": "S3 bucket for asset \"cad1ae036643e3cd17cd3b2b30a2f9e07c1aacaf5284314f41437e4c20447aea\"" + }, + "AssetParameterscad1ae036643e3cd17cd3b2b30a2f9e07c1aacaf5284314f41437e4c20447aeaS3VersionKey37A80BBF": { + "Type": "String", + "Description": "S3 key for asset version \"cad1ae036643e3cd17cd3b2b30a2f9e07c1aacaf5284314f41437e4c20447aea\"" + }, + "AssetParameterscad1ae036643e3cd17cd3b2b30a2f9e07c1aacaf5284314f41437e4c20447aeaArtifactHash11CEC9E5": { + "Type": "String", + "Description": "Artifact hash for asset \"cad1ae036643e3cd17cd3b2b30a2f9e07c1aacaf5284314f41437e4c20447aea\"" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.ts new file mode 100644 index 0000000000000..7a3f0b70c8e9d --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.ts @@ -0,0 +1,52 @@ +import * as eks from '@aws-cdk/aws-eks'; +import * as iam from '@aws-cdk/aws-iam'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import * as cdk from '@aws-cdk/core'; +import { EksCall, HttpMethods } from '../../lib'; + +/* + * Create a state machine with a task state to use the Kubernetes API to read Kubernetes resource objects + * via a Kubernetes API endpoint. + * + * Stack verification steps: + * The generated State Machine can be executed from the CLI (or Step Functions console) + * and runs with an execution status of `Succeeded`. + * + * -- aws stepfunctions start-execution --state-machine-arn provides execution arn + * -- aws stepfunctions describe-execution --execution-arn returns a status of `Succeeded` + */ + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-stepfunctions-tasks-eks-call-integ'); + +const cluster = new eks.Cluster(stack, 'EksCluster', { + version: eks.KubernetesVersion.V1_18, + clusterName: 'eksCluster', +}); + +const executionRole = new iam.Role(stack, 'Role', { + roleName: 'stateMachineExecutionRole', + assumedBy: new iam.ServicePrincipal('states.amazonaws.com'), +}); + +cluster.awsAuth.addMastersRole(executionRole); + +const callJob = new EksCall(stack, 'Call a EKS Endpoint', { + cluster: cluster, + httpMethod: HttpMethods.GET, + httpPath: '/api/v1/namespaces/default/pods', +}); + +const chain = sfn.Chain.start(callJob); + +const sm = new sfn.StateMachine(stack, 'StateMachine', { + definition: chain, + role: executionRole, + timeout: cdk.Duration.seconds(30), +}); + +new cdk.CfnOutput(stack, 'stateMachineArn', { + value: sm.stateMachineArn, +}); + +app.synth(); diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sns/integ.publish.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sns/integ.publish.expected.json index bf407af2694d8..e5ac1d8ff84a7 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sns/integ.publish.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sns/integ.publish.expected.json @@ -4,7 +4,9 @@ "Type": "AWS::SNS::Topic" }, "showmethemessages8D16BBDB": { - "Type": "AWS::SQS::Queue" + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "showmethemessagesPolicyB08B04B0": { "Type": "AWS::SQS::QueuePolicy", @@ -110,6 +112,12 @@ "StateMachine2E01A3A5": { "Type": "AWS::StepFunctions::StateMachine", "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRoleB840431D", + "Arn" + ] + }, "DefinitionString": { "Fn::Join": [ "", @@ -125,12 +133,6 @@ "\",\"Message\":\"sending message over\"}},\"Final step\":{\"Type\":\"Pass\",\"End\":true}},\"TimeoutSeconds\":30}" ] ] - }, - "RoleArn": { - "Fn::GetAtt": [ - "StateMachineRoleB840431D", - "Arn" - ] } }, "DependsOn": [ diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sqs/integ.send-message.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sqs/integ.send-message.expected.json index 7465187d65c20..5d13c58fc0a5b 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sqs/integ.send-message.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sqs/integ.send-message.expected.json @@ -1,7 +1,9 @@ { "Resources": { "showmethemessages8D16BBDB": { - "Type": "AWS::SQS::Queue" + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "StateMachineRoleB840431D": { "Type": "AWS::IAM::Role", @@ -60,6 +62,12 @@ "StateMachine2E01A3A5": { "Type": "AWS::StepFunctions::StateMachine", "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRoleB840431D", + "Arn" + ] + }, "DefinitionString": { "Fn::Join": [ "", @@ -75,12 +83,6 @@ "\",\"MessageBody\":\"sending message over\"}},\"Final step\":{\"Type\":\"Pass\",\"End\":true}},\"TimeoutSeconds\":30}" ] ] - }, - "RoleArn": { - "Fn::GetAtt": [ - "StateMachineRoleB840431D", - "Arn" - ] } }, "DependsOn": [ diff --git a/packages/@aws-cdk/aws-synthetics/README.md b/packages/@aws-cdk/aws-synthetics/README.md index fd2310ecaacf3..80a6defd34848 100644 --- a/packages/@aws-cdk/aws-synthetics/README.md +++ b/packages/@aws-cdk/aws-synthetics/README.md @@ -44,7 +44,7 @@ const canary = new synthetics.Canary(this, 'MyCanary', { code: synthetics.Code.fromAsset(path.join(__dirname, 'canary')), handler: 'index.handler', }), - runtime: synthetics.Runtime.SYNTHETICS_NODEJS_2_2, + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_0, }); ``` @@ -107,7 +107,7 @@ const canary = new Canary(this, 'MyCanary', { code: synthetics.Code.fromInline('/* Synthetics handler code */'), handler: 'index.handler', // must be 'index.handler' }), - runtime: synthetics.Runtime.SYNTHETICS_NODEJS_2_2, + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_0, }); // To supply the code from your local filesystem: @@ -116,7 +116,7 @@ const canary = new Canary(this, 'MyCanary', { code: synthetics.Code.fromAsset(path.join(__dirname, 'canary')), handler: 'index.handler', // must end with '.handler' }), - runtime: synthetics.Runtime.SYNTHETICS_NODEJS_2_2, + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_0, }); // To supply the code from a S3 bucket: @@ -125,7 +125,7 @@ const canary = new Canary(this, 'MyCanary', { code: synthetics.Code.fromBucket(bucket, 'canary.zip'), handler: 'index.handler', // must end with '.handler' }), - runtime: synthetics.Runtime.SYNTHETICS_NODEJS_2_2, + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_0, }); ``` diff --git a/packages/@aws-cdk/aws-synthetics/lib/canary.ts b/packages/@aws-cdk/aws-synthetics/lib/canary.ts index 7e6d6c8b53b0f..72d4b311ce6e3 100644 --- a/packages/@aws-cdk/aws-synthetics/lib/canary.ts +++ b/packages/@aws-cdk/aws-synthetics/lib/canary.ts @@ -112,6 +112,16 @@ export class Runtime { */ public static readonly SYNTHETICS_NODEJS_2_2 = new Runtime('syn-nodejs-2.2'); + /** + * `syn-nodejs-puppeteer-3.0` includes the following: + * - Lambda runtime Node.js 12.x + * - Puppeteer-core version 5.5.0 + * - Chromium version 88.0.4298.0 + * + * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Library_nodejs_puppeteer.html#CloudWatch_Synthetics_runtimeversion-nodejs-puppeteer-3.0 + */ + public static readonly SYNTHETICS_NODEJS_PUPPETEER_3_0 = new Runtime('syn-nodejs-puppeteer-3.0'); + /** * @param name The name of the runtime version */ diff --git a/packages/@aws-cdk/aws-synthetics/test/canary.test.ts b/packages/@aws-cdk/aws-synthetics/test/canary.test.ts index d4a505e3a492b..bb5e479e7f7e9 100644 --- a/packages/@aws-cdk/aws-synthetics/test/canary.test.ts +++ b/packages/@aws-cdk/aws-synthetics/test/canary.test.ts @@ -44,7 +44,7 @@ test('Canary can have generated name', () => { handler: 'index.handler', code: synthetics.Code.fromInline('/* Synthetics handler code */'), }), - runtime: synthetics.Runtime.SYNTHETICS_NODEJS_2_0, + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_0, }); // THEN @@ -355,4 +355,4 @@ test('can specify custom test', () => { };`, }, }); -}); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/cfnspec/build-tools/build.ts b/packages/@aws-cdk/cfnspec/build-tools/build.ts index 913605461e224..a96688ecc36f1 100644 --- a/packages/@aws-cdk/cfnspec/build-tools/build.ts +++ b/packages/@aws-cdk/cfnspec/build-tools/build.ts @@ -13,8 +13,19 @@ import { decorateResourceTypes, forEachSection, massageSpec, merge, normalize, p async function main() { const inputDir = path.join(process.cwd(), 'spec-source'); - const files = await fs.readdir(inputDir); + const outDir = path.join(process.cwd(), 'spec'); + + await generateResourceSpecification(inputDir, path.join(outDir, 'specification.json')); + await mergeSpecificationFromDirs(path.join(inputDir, 'cfn-lint'), path.join(outDir, 'cfn-lint.json')); +} + +/** + * Generate CloudFormation resource specification from sources and patches + */ +async function generateResourceSpecification(inputDir: string, outFile: string) { const spec: schema.Specification = { PropertyTypes: {}, ResourceTypes: {}, Fingerprint: '' }; + + const files = await fs.readdir(inputDir); for (const file of files.filter(n => n.endsWith('.json')).sort()) { const data = await fs.readJson(path.join(inputDir, file)); if (file.indexOf('patch') === -1) { @@ -29,9 +40,49 @@ async function main() { spec.Fingerprint = md5(JSON.stringify(normalize(spec))); - const outDir = path.join(process.cwd(), 'spec'); - await fs.mkdirp(outDir); - await fs.writeJson(path.join(outDir, 'specification.json'), spec, { spaces: 2 }); + await fs.mkdirp(path.dirname(outFile)); + await fs.writeJson(outFile, spec, { spaces: 2 }); +} + +/** + * Generate Cfnlint spec annotations from sources and patches + */ +async function mergeSpecificationFromDirs(inputDir: string, outFile: string) { + const spec: any = {}; + + for (const child of await fs.readdir(inputDir)) { + const fullPath = path.join(inputDir, child); + if (!(await fs.stat(fullPath)).isDirectory()) { continue; } + + const subspec = await loadMergedSpec(fullPath); + spec[child] = subspec; + } + + await fs.mkdirp(path.dirname(outFile)); + await fs.writeJson(outFile, spec, { spaces: 2 }); +} + +/** + * Load all files in the given directory, merge them and apply patches in the order found + * + * The base structure is always an empty object + */ +async function loadMergedSpec(inputDir: string) { + const structure: any = {}; + + const files = await fs.readdir(inputDir); + for (const file of files.filter(n => n.endsWith('.json')).sort()) { + const data = await fs.readJson(path.join(inputDir, file)); + if (file.indexOf('patch') === -1) { + // Copy properties from current object into structure, adding/overwriting whatever is found + Object.assign(structure, data); + } else { + // Apply the loaded file as a patch onto the current structure + patch(structure, data); + } + } + + return structure; } main() diff --git a/packages/@aws-cdk/cfnspec/build-tools/update-cfnlint.sh b/packages/@aws-cdk/cfnspec/build-tools/update-cfnlint.sh new file mode 100755 index 0000000000000..594e7dd165b87 --- /dev/null +++ b/packages/@aws-cdk/cfnspec/build-tools/update-cfnlint.sh @@ -0,0 +1,18 @@ +#!/bin/bash +set -euo pipefail +scriptdir=$(cd $(dirname $0) && pwd) + +# Download (parts of) the cfn-lint repo that we use to enhance our model +intermediate="$(mktemp -d)/tmp.zip" + +url="https://github.com/aws-cloudformation/cfn-python-lint/archive/master.zip" +echo >&2 "Downloading from ${url}..." +curl -sSfL "${url}" -o ${intermediate} + +for file in StatefulResources; do + echo >&2 "${file}.json" + mkdir -p "spec-source/cfn-lint/${file}" + unzip -p "${intermediate}" cfn-python-lint-master/src/cfnlint/data/AdditionalSpecs/${file}.json > spec-source/cfn-lint/${file}/000.json +done + +echo >&2 "Done." diff --git a/packages/@aws-cdk/cfnspec/lib/_private_schema/cfn-lint.ts b/packages/@aws-cdk/cfnspec/lib/_private_schema/cfn-lint.ts new file mode 100644 index 0000000000000..4c11394888ec4 --- /dev/null +++ b/packages/@aws-cdk/cfnspec/lib/_private_schema/cfn-lint.ts @@ -0,0 +1,23 @@ +/** + * All annotations imported from cfn-lint + */ +export interface CfnLintFileSchema { + /** + * Resource types that are in this map are stateful + * + * There is more information in the structure this maps to. + */ + readonly StatefulResources: { readonly ResourceTypes: Record }; +} + +/** + * Extra information on stateful resource types + */ +export interface CfnLintStatefulSchema { + /** + * Whether or not a Delete operation requires the resource to be empty + * + * @default false + */ + readonly DeleteRequiresEmptyResource?: boolean; +} diff --git a/packages/@aws-cdk/cfnspec/lib/index.ts b/packages/@aws-cdk/cfnspec/lib/index.ts index 8584e6877ed62..6ab020d9580cc 100644 --- a/packages/@aws-cdk/cfnspec/lib/index.ts +++ b/packages/@aws-cdk/cfnspec/lib/index.ts @@ -1,4 +1,5 @@ import * as crypto from 'crypto'; +import { CfnLintFileSchema } from './_private_schema/cfn-lint'; import * as schema from './schema'; export { schema }; export * from './canned-metrics'; @@ -38,6 +39,19 @@ export function resourceAugmentation(typeName: string): schema.ResourceAugmentat } } +/** + * Get the resource augmentations for a given type + */ +export function cfnLintAnnotations(typeName: string): schema.CfnLintResourceAnnotations { + // eslint-disable-next-line @typescript-eslint/no-require-imports + const allAnnotations: CfnLintFileSchema = require('../spec/cfn-lint.json'); + + return { + stateful: !!allAnnotations.StatefulResources.ResourceTypes[typeName], + mustBeEmptyToDelete: allAnnotations.StatefulResources.ResourceTypes[typeName]?.DeleteRequiresEmptyResource ?? false, + }; +} + /** * Return the property specification for the given resource's property */ diff --git a/packages/@aws-cdk/cfnspec/lib/schema/cfn-lint.ts b/packages/@aws-cdk/cfnspec/lib/schema/cfn-lint.ts new file mode 100644 index 0000000000000..204892f173a95 --- /dev/null +++ b/packages/@aws-cdk/cfnspec/lib/schema/cfn-lint.ts @@ -0,0 +1,14 @@ +/** + * Additional resource information obtained from cfn-lint + */ +export interface CfnLintResourceAnnotations { + /** + * Whether or not the given resource is stateful + */ + readonly stateful: boolean; + + /** + * Whether or not a Delete operation requires the resource to be empty + */ + readonly mustBeEmptyToDelete: boolean; +} \ No newline at end of file diff --git a/packages/@aws-cdk/cfnspec/lib/schema/index.ts b/packages/@aws-cdk/cfnspec/lib/schema/index.ts index 250e5cc1edd96..e4f8720f79e82 100644 --- a/packages/@aws-cdk/cfnspec/lib/schema/index.ts +++ b/packages/@aws-cdk/cfnspec/lib/schema/index.ts @@ -3,3 +3,4 @@ export * from './property'; export * from './resource-type'; export * from './specification'; export * from './augmentation'; +export * from './cfn-lint'; diff --git a/packages/@aws-cdk/cfnspec/package.json b/packages/@aws-cdk/cfnspec/package.json index 3ab38256028bd..06c46cf79b839 100644 --- a/packages/@aws-cdk/cfnspec/package.json +++ b/packages/@aws-cdk/cfnspec/package.json @@ -3,7 +3,7 @@ "description": "The CloudFormation resource specification used by @aws-cdk packages", "version": "0.0.0", "scripts": { - "update": "cdk-build && /bin/bash build-tools/update.sh", + "update": "cdk-build && /bin/bash build-tools/update.sh && /bin/bash build-tools/update-cfnlint.sh", "update-metrics": "/bin/bash build-tools/update-metrics.sh", "build": "cdk-build && node build-tools/build", "watch": "cdk-watch", diff --git a/packages/@aws-cdk/cfnspec/spec-source/cfn-lint/StatefulResources/000.json b/packages/@aws-cdk/cfnspec/spec-source/cfn-lint/StatefulResources/000.json new file mode 100644 index 0000000000000..25c5e11c890ff --- /dev/null +++ b/packages/@aws-cdk/cfnspec/spec-source/cfn-lint/StatefulResources/000.json @@ -0,0 +1,30 @@ +{ + "ResourceTypes": { + "AWS::CloudFormation::Stack" : {}, + "AWS::Backup::BackupVault" : {}, + "AWS::Cognito::UserPool" : {}, + "AWS::DocDB::DBCluster" : {}, + "AWS::DocDB::DBInstance" : {}, + "AWS::DynamoDB::Table" : {}, + "AWS::EC2::Volume" : {}, + "AWS::EFS::FileSystem" : {}, + "AWS::EMR::Cluster" : {}, + "AWS::ElastiCache::CacheCluster" : {}, + "AWS::ElastiCache::ReplicationGroup" : {}, + "AWS::Elasticsearch::Domain" : {}, + "AWS::FSx::FileSystem" : {}, + "AWS::Logs::LogGroup" : {}, + "AWS::Neptune::DBCluster" : {}, + "AWS::Neptune::DBInstance" : {}, + "AWS::QLDB::Ledger" : {}, + "AWS::RDS::DBCluster" : {}, + "AWS::RDS::DBInstance" : {}, + "AWS::Redshift::Cluster" : {}, + "AWS::SDB::Domain" : {}, + "AWS::SQS::Queue" : {}, + "AWS::S3::Bucket" : { + "DeleteRequiresEmptyResource": true + } + } +} + diff --git a/packages/@aws-cdk/cfnspec/test/test.cfnlint-annotations.ts b/packages/@aws-cdk/cfnspec/test/test.cfnlint-annotations.ts new file mode 100644 index 0000000000000..04e0972893d12 --- /dev/null +++ b/packages/@aws-cdk/cfnspec/test/test.cfnlint-annotations.ts @@ -0,0 +1,28 @@ +import { Test } from 'nodeunit'; +import * as cfnspec from '../lib'; + +module.exports = { + 'spot-check Bucket statefulness'(test: Test) { + const anno = cfnspec.cfnLintAnnotations('AWS::S3::Bucket'); + test.equal(anno.stateful, true); + test.equal(anno.mustBeEmptyToDelete, true); + + test.done(); + }, + + 'spot-check Table statefulness'(test: Test) { + const anno = cfnspec.cfnLintAnnotations('AWS::DynamoDB::Table'); + test.equal(anno.stateful, true); + test.equal(anno.mustBeEmptyToDelete, false); + + test.done(); + }, + + 'spot-check MediaStore metrics'(test: Test) { + const anno = cfnspec.cfnLintAnnotations('AWS::MediaStore::Thingy'); + test.equal(anno.stateful, false); + + test.done(); + }, +}; + diff --git a/packages/@aws-cdk/core/lib/cfn-resource.ts b/packages/@aws-cdk/core/lib/cfn-resource.ts index c436e453cacac..9f9ee669374ed 100644 --- a/packages/@aws-cdk/core/lib/cfn-resource.ts +++ b/packages/@aws-cdk/core/lib/cfn-resource.ts @@ -320,13 +320,13 @@ export class CfnResource extends CfnRefElement { Description: this.cfnOptions.description, Metadata: ignoreEmpty(this.cfnOptions.metadata), Condition: this.cfnOptions.condition && this.cfnOptions.condition.logicalId, - }, props => { - const renderedProps = this.renderProperties(props.Properties || {}); + }, resourceDef => { + const renderedProps = this.renderProperties(resourceDef.Properties || {}); if (renderedProps) { const hasDefined = Object.values(renderedProps).find(v => v !== undefined); - props.Properties = hasDefined !== undefined ? renderedProps : undefined; + resourceDef.Properties = hasDefined !== undefined ? renderedProps : undefined; } - return deepMerge(props, this.rawOverrides); + return deepMerge(resourceDef, this.rawOverrides); }), }, }; diff --git a/packages/@aws-cdk/core/lib/construct-compat.ts b/packages/@aws-cdk/core/lib/construct-compat.ts index 76e95ad38071d..ac7873a837dde 100644 --- a/packages/@aws-cdk/core/lib/construct-compat.ts +++ b/packages/@aws-cdk/core/lib/construct-compat.ts @@ -472,6 +472,13 @@ export class ConstructNode { Aspects.of(this.host).add(aspect); } + /** + * Add a validator to this construct Node + */ + public addValidation(validation: constructs.IValidation) { + this._actualNode.addValidation(validation); + } + /** * All parent scopes of this construct. * diff --git a/packages/@aws-cdk/core/lib/nested-stack.ts b/packages/@aws-cdk/core/lib/nested-stack.ts index f130d00ded80b..648211aab22f0 100644 --- a/packages/@aws-cdk/core/lib/nested-stack.ts +++ b/packages/@aws-cdk/core/lib/nested-stack.ts @@ -8,6 +8,7 @@ import { CfnStack } from './cloudformation.generated'; import { Duration } from './duration'; import { Lazy } from './lazy'; import { Names } from './names'; +import { RemovalPolicy } from './removal-policy'; import { IResolveContext } from './resolvable'; import { Stack } from './stack'; import { NestedStackSynthesizer } from './stack-synthesizers'; @@ -60,6 +61,17 @@ export interface NestedStackProps { * @default - notifications are not sent for this stack. */ readonly notificationArns?: string[]; + + /** + * Policy to apply when the nested stack is removed + * + * The default is `Destroy`, because all Removal Policies of resources inside the + * Nested Stack should already have been set correctly. You normally should + * not need to set this value. + * + * @default RemovalPolicy.DESTROY + */ + readonly removalPolicy?: RemovalPolicy; } /** @@ -126,6 +138,7 @@ export class NestedStack extends Stack { notificationArns: props.notificationArns, timeoutInMinutes: props.timeout ? props.timeout.toMinutes() : undefined, }); + this.resource.applyRemovalPolicy(props.removalPolicy ?? RemovalPolicy.DESTROY); this.nestedStackResource = this.resource; diff --git a/packages/@aws-cdk/core/lib/private/synthesis.ts b/packages/@aws-cdk/core/lib/private/synthesis.ts index bcc6ddc94dbc8..737f11367e13f 100644 --- a/packages/@aws-cdk/core/lib/private/synthesis.ts +++ b/packages/@aws-cdk/core/lib/private/synthesis.ts @@ -171,11 +171,12 @@ function synthesizeTree(root: IConstruct, builder: cxapi.CloudAssemblyBuilder) { function validateTree(root: IConstruct) { const errors = new Array(); - visit(root, 'pre', construct => { - for (const message of construct.onValidate()) { - errors.push({ message, source: construct as unknown as Construct }); - } - }); + // Validations added through `node.addValidation()` + // This automatically also includes Ye Olde Method of validating, using + // the `protected validate()` methods. + errors.push(...constructs.Node.of(root).validate().map(e => ({ + message: e.message, source: e.source as unknown as Construct, + }))); if (errors.length > 0) { const errorList = errors.map(e => `[${e.source.node.path}] ${e.message}`).join('\n '); diff --git a/packages/@aws-cdk/core/lib/removal-policy.ts b/packages/@aws-cdk/core/lib/removal-policy.ts index 879a00f53b4f9..d815967fa2bf0 100644 --- a/packages/@aws-cdk/core/lib/removal-policy.ts +++ b/packages/@aws-cdk/core/lib/removal-policy.ts @@ -1,3 +1,28 @@ +/** + * Possible values for a resource's Removal Policy + * + * The removal policy controls what happens to the resource if it stops being + * managed by CloudFormation. This can happen in one of three situations: + * + * - The resource is removed from the template, so CloudFormation stops managing it; + * - A change to the resource is made that requires it to be replaced, so CloudFormation stops + * managing it; + * - The stack is deleted, so CloudFormation stops managing all resources in it. + * + * The Removal Policy applies to all above cases. + * + * Many stateful resources in the AWS Construct Library will accept a + * `removalPolicy` as a property, typically defaulting it to `RETAIN`. + * + * If the AWS Construct Library resource does not accept a `removalPolicy` + * argument, you can always configure it by using the escape hatch mechanism, + * as shown in the following example: + * + * ```ts + * const cfnBucket = bucket.node.findChild('Resource') as cdk.CfnResource; + * cfnBucket.applyRemovalPolicy(cdk.RemovalPolicy.DESTROY); + * ``` + */ export enum RemovalPolicy { /** * This is the default removal policy. It means that when the resource is diff --git a/packages/@aws-cdk/core/lib/resource.ts b/packages/@aws-cdk/core/lib/resource.ts index 6445fe718c547..a828f0d6cec98 100644 --- a/packages/@aws-cdk/core/lib/resource.ts +++ b/packages/@aws-cdk/core/lib/resource.ts @@ -1,15 +1,19 @@ -// v2 - leave this as a separate section so it reduces merge conflicts when compat is removed -// eslint-disable-next-line import/order -import { IConstruct, Construct as CoreConstruct } from './construct-compat'; - -import { Construct } from 'constructs'; import { ArnComponents } from './arn'; +import { CfnResource } from './cfn-resource'; +import { IConstruct, Construct as CoreConstruct } from './construct-compat'; import { IStringProducer, Lazy } from './lazy'; import { generatePhysicalName, isGeneratedWhenNeededMarker } from './private/physical-name-generator'; +import { Reference } from './reference'; +import { RemovalPolicy } from './removal-policy'; import { IResolveContext } from './resolvable'; import { Stack } from './stack'; import { Token, Tokenization } from './token'; -import { Reference } from './reference'; + +// v2 - leave this as a separate section so it reduces merge conflicts when compat is removed +// eslint-disable-next-line import/order +import { Construct } from 'constructs'; + +const RESOURCE_SYMBOL = Symbol.for('@aws-cdk/core.Resource'); /** * Represents the environment a given resource lives in. @@ -92,6 +96,13 @@ export interface ResourceProps { * A construct which represents an AWS resource. */ export abstract class Resource extends CoreConstruct implements IResource { + /** + * Check whether the given construct is a Resource + */ + public static isResource(construct: IConstruct): construct is CfnResource { + return construct !== null && typeof(construct) === 'object' && RESOURCE_SYMBOL in construct; + } + public readonly stack: Stack; public readonly env: ResourceEnvironment; @@ -115,6 +126,8 @@ export abstract class Resource extends CoreConstruct implements IResource { constructor(scope: Construct, id: string, props: ResourceProps = {}) { super(scope, id); + Object.defineProperty(this, RESOURCE_SYMBOL, { value: true }); + this.stack = Stack.of(this); this.env = { account: props.account ?? this.stack.account, @@ -165,6 +178,25 @@ export abstract class Resource extends CoreConstruct implements IResource { } } + /** + * Apply the given removal policy to this resource + * + * The Removal Policy controls what happens to this resource when it stops + * being managed by CloudFormation, either because you've removed it from the + * CDK application or because you've made a change that requires the resource + * to be replaced. + * + * The resource can be deleted (`RemovalPolicy.DELETE`), or left in your AWS + * account for data recovery and cleanup later (`RemovalPolicy.RETAIN`). + */ + public applyRemovalPolicy(policy: RemovalPolicy) { + const child = this.node.defaultChild; + if (!child || !CfnResource.isCfnResource(child)) { + throw new Error('Cannot apply RemovalPolicy: no child or not a CfnResource. Apply the removal policy on the CfnResource directly.'); + } + child.applyRemovalPolicy(policy); + } + protected generatePhysicalName(): string { return generatePhysicalName(this); } diff --git a/packages/@aws-cdk/core/test/stack.test.ts b/packages/@aws-cdk/core/test/stack.test.ts index 8891dbaa138c6..849ad10369147 100644 --- a/packages/@aws-cdk/core/test/stack.test.ts +++ b/packages/@aws-cdk/core/test/stack.test.ts @@ -640,7 +640,25 @@ describe('stack', () => { const assembly = app.synth(); expect(assembly.getStackByName(parentStack.stackName).template).toEqual({ Resources: { MyParentResource: { Type: 'Resource::Parent' } } }); expect(assembly.getStackByName(childStack.stackName).template).toEqual({ Resources: { MyChildResource: { Type: 'Resource::Child' } } }); + }); + + test('Nested Stacks are synthesized with DESTROY policy', () => { + const app = new App(); + // WHEN + const parentStack = new Stack(app, 'parent'); + const childStack = new NestedStack(parentStack, 'child'); + new CfnResource(childStack, 'ChildResource', { type: 'Resource::Child' }); + + const assembly = app.synth(); + expect(assembly.getStackByName(parentStack.stackName).template).toEqual(expect.objectContaining({ + Resources: { + childNestedStackchildNestedStackResource7408D03F: expect.objectContaining({ + Type: 'AWS::CloudFormation::Stack', + DeletionPolicy: 'Delete', + }), + }, + })); }); test('cross-stack reference (substack references parent stack)', () => { diff --git a/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts b/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts index 9da696f268b92..2139866ae3d06 100644 --- a/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts +++ b/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts @@ -93,6 +93,16 @@ export interface ProviderProps { */ readonly vpcSubnets?: ec2.SubnetSelection; + /** + * Security groups to attach to the provider functions. + * + * Only used if 'vpc' is supplied + * + * @default - If `vpc` is not supplied, no security groups are attached. Otherwise, a dedicated security + * group is created for each function. + */ + readonly securityGroups?: ec2.ISecurityGroup[]; + } /** @@ -122,6 +132,7 @@ export class Provider extends CoreConstruct implements cfn.ICustomResourceProvid private readonly logRetention?: logs.RetentionDays; private readonly vpc?: ec2.IVpc; private readonly vpcSubnets?: ec2.SubnetSelection; + private readonly securityGroups?: ec2.ISecurityGroup[]; constructor(scope: Construct, id: string, props: ProviderProps) { super(scope, id); @@ -137,6 +148,7 @@ export class Provider extends CoreConstruct implements cfn.ICustomResourceProvid this.logRetention = props.logRetention; this.vpc = props.vpc; this.vpcSubnets = props.vpcSubnets; + this.securityGroups = props.securityGroups; const onEventFunction = this.createFunction(consts.FRAMEWORK_ON_EVENT_HANDLER_NAME); @@ -182,6 +194,7 @@ export class Provider extends CoreConstruct implements cfn.ICustomResourceProvid logRetention: this.logRetention, vpc: this.vpc, vpcSubnets: this.vpcSubnets, + securityGroups: this.securityGroups, }); fn.addEnvironment(consts.USER_ON_EVENT_FUNCTION_ARN_ENV, this.onEventHandler.functionArn); diff --git a/packages/@aws-cdk/custom-resources/test/provider-framework/provider.test.ts b/packages/@aws-cdk/custom-resources/test/provider-framework/provider.test.ts index deed031d8909f..b60ef1a602431 100644 --- a/packages/@aws-cdk/custom-resources/test/provider-framework/provider.test.ts +++ b/packages/@aws-cdk/custom-resources/test/provider-framework/provider.test.ts @@ -8,6 +8,75 @@ import * as util from '../../lib/provider-framework/util'; import '@aws-cdk/assert/jest'; +test('security groups are applied to all framework functions', () => { + + // GIVEN + const stack = new Stack(); + + const vpc = new ec2.Vpc(stack, 'Vpc'); + const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup', { vpc }); + + // WHEN + new cr.Provider(stack, 'MyProvider', { + onEventHandler: new lambda.Function(stack, 'OnEvent', { + code: lambda.Code.fromInline('foo'), + handler: 'index.onEvent', + runtime: lambda.Runtime.NODEJS_10_X, + }), + isCompleteHandler: new lambda.Function(stack, 'IsComplete', { + code: lambda.Code.fromInline('foo'), + handler: 'index.isComplete', + runtime: lambda.Runtime.NODEJS_10_X, + }), + vpc: vpc, + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE }, + securityGroups: [securityGroup], + }); + + expect(stack).toHaveResourceLike('AWS::Lambda::Function', { + Handler: 'framework.onEvent', + VpcConfig: { + SecurityGroupIds: [ + { + 'Fn::GetAtt': [ + 'SecurityGroupDD263621', + 'GroupId', + ], + }, + ], + }, + }); + + expect(stack).toHaveResourceLike('AWS::Lambda::Function', { + Handler: 'framework.isComplete', + VpcConfig: { + SecurityGroupIds: [ + { + 'Fn::GetAtt': [ + 'SecurityGroupDD263621', + 'GroupId', + ], + }, + ], + }, + }); + + expect(stack).toHaveResourceLike('AWS::Lambda::Function', { + Handler: 'framework.onTimeout', + VpcConfig: { + SecurityGroupIds: [ + { + 'Fn::GetAtt': [ + 'SecurityGroupDD263621', + 'GroupId', + ], + }, + ], + }, + }); + +}); + test('vpc is applied to all framework functions', () => { // GIVEN diff --git a/packages/aws-cdk/README.md b/packages/aws-cdk/README.md index 71b05cc420eac..41dd4c75fbe2a 100644 --- a/packages/aws-cdk/README.md +++ b/packages/aws-cdk/README.md @@ -207,7 +207,7 @@ Usage of output in a CDK stack const fn = new lambda.Function(this, "fn", { handler: "index.handler", code: lambda.Code.fromInline(`exports.handler = \${handler.toString()}`), - runtime: lambda.Runtime.NODEJS_10_X + runtime: lambda.Runtime.NODEJS_12_X }); new cdk.CfnOutput(this, 'FunctionArn', { diff --git a/packages/decdk/test/__snapshots__/synth.test.js.snap b/packages/decdk/test/__snapshots__/synth.test.js.snap index 939497257dbc5..86a1fdd32f534 100644 --- a/packages/decdk/test/__snapshots__/synth.test.js.snap +++ b/packages/decdk/test/__snapshots__/synth.test.js.snap @@ -2735,7 +2735,9 @@ exports[`pure-cfn.json: pure-cfn 1`] = ` Object { "Resources": Object { "Hello4A628BD4": Object { + "DeletionPolicy": "Delete", "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", }, "MyLogGroup": Object { "Properties": Object { @@ -2753,6 +2755,7 @@ exports[`queue-kms.json: queue-kms 1`] = ` Object { "Resources": Object { "MyQueueE6CA6235": Object { + "DeletionPolicy": "Delete", "Properties": Object { "KmsMasterKeyId": Object { "Fn::GetAtt": Array [ @@ -2762,6 +2765,7 @@ Object { }, }, "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", }, "MyQueueKey6C31ABF3": Object { "DeletionPolicy": "Retain", diff --git a/packages/decdk/test/fixture/tsconfig.json b/packages/decdk/test/fixture/tsconfig.json index 44dbf4775b1a7..1b7d2bae0fab0 100644 --- a/packages/decdk/test/fixture/tsconfig.json +++ b/packages/decdk/test/fixture/tsconfig.json @@ -4,6 +4,7 @@ "charset": "utf8", "declaration": true, "experimentalDecorators": true, + "incremental": true, "inlineSourceMap": true, "inlineSources": true, "lib": [ @@ -22,8 +23,10 @@ "strict": true, "strictNullChecks": true, "strictPropertyInitialization": true, - "stripInternal": true, - "target": "ES2018" + "stripInternal": false, + "target": "ES2018", + "composite": false, + "tsBuildInfoFile": "tsconfig.tsbuildinfo" }, "include": [ "**/*.ts" diff --git a/tools/cfn2ts/lib/codegen.ts b/tools/cfn2ts/lib/codegen.ts index 08d0636a841f5..c06fce32e10ff 100644 --- a/tools/cfn2ts/lib/codegen.ts +++ b/tools/cfn2ts/lib/codegen.ts @@ -1,4 +1,4 @@ -import { schema } from '@aws-cdk/cfnspec'; +import { schema, cfnLintAnnotations } from '@aws-cdk/cfnspec'; import { CodeMaker } from 'codemaker'; import * as genspec from './genspec'; import { itemTypeNames, PropertyAttributeName, scalarTypeNames, SpecName } from './spec-utils'; @@ -125,7 +125,7 @@ export default class CodeGenerator { this.code.closeBlock(); this.code.line(); - this.emitValidator(resourceContext, name, spec.Properties, conversionTable); + this.emitPropertiesValidator(resourceContext, name, spec.Properties, conversionTable); this.code.line(); this.emitCloudFormationMapper(resourceContext, name, spec.Properties, conversionTable); this.emitFromCfnFactoryFunction(resourceContext, name, spec.Properties, conversionTable, false); @@ -343,6 +343,13 @@ export default class CodeGenerator { } } } + + // + // Validator + // + this.emitConstructValidator(resourceName); + + // End constructor this.code.closeBlock(); this.code.line(); @@ -385,6 +392,37 @@ export default class CodeGenerator { this.code.closeBlock(); } + /** + * Add validations for the given construct + * + * The generated code looks like this: + * + * ``` + * this.node.addValidation({ validate: () => /* validation code * / }); + * } + * ``` + */ + private emitConstructValidator(resourceType: genspec.CodeName) { + const cfnLint = cfnLintAnnotations(resourceType.specName?.fqn ?? ''); + + if (cfnLint.stateful) { + // Do a statefulness check. A deletionPolicy is required (and in normal operation an UpdateReplacePolicy + // would also be set if a user doesn't do complicated shenanigans, in which case they probably know what + // they're doing. + // + // Only do this for L1s embedded in L2s (to force L2 authors to add a way to set this policy). If we did it for all L1s: + // + // - users working at the L1 level would start getting synthesis failures when we add this feature + // - the `cloudformation-include` library that loads CFN templates to L1s would start failing when it loads + // templates that don't have DeletionPolicy set. + this.code.openBlock(`if (this.node.scope && ${CORE}.Resource.isResource(this.node.scope))`); + this.code.line('this.node.addValidation({ validate: () => this.cfnOptions.deletionPolicy === undefined'); + this.code.line(` ? [\'\\\'${resourceType.specName?.fqn}\\\' is a stateful resource type, and you must specify a Removal Policy for it. Call \\\'resource.applyRemovalPolicy()\\\'.\']`); + this.code.line(' : [] });'); + this.code.closeBlock(); + } + } + /** * Emit the function that is going to implement the IInspectable interface. * @@ -665,7 +703,7 @@ export default class CodeGenerator { * * Generated as a top-level function outside any namespace so we can hide it from library consumers. */ - private emitValidator( + private emitPropertiesValidator( resource: genspec.CodeName, typeName: genspec.CodeName, propSpecs: { [name: string]: schema.Property }, @@ -828,7 +866,7 @@ export default class CodeGenerator { this.endNamespace(typeName); this.code.line(); - this.emitValidator(resourceContext, typeName, propTypeSpec.Properties, conversionTable); + this.emitPropertiesValidator(resourceContext, typeName, propTypeSpec.Properties, conversionTable); this.code.line(); this.emitCloudFormationMapper(resourceContext, typeName, propTypeSpec.Properties, conversionTable); this.emitFromCfnFactoryFunction(resourceContext, typeName, propTypeSpec.Properties, conversionTable, true); diff --git a/yarn.lock b/yarn.lock index 1f1b95216371f..0044085ed9ce5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17,18 +17,18 @@ "@babel/highlight" "^7.12.13" "@babel/core@^7.1.0", "@babel/core@^7.7.5": - version "7.12.16" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.16.tgz#8c6ba456b23b680a6493ddcfcd9d3c3ad51cab7c" - integrity sha512-t/hHIB504wWceOeaOoONOhu+gX+hpjfeN6YRBT209X/4sibZQfSF1I0HFRRlBe97UZZosGx5XwUg1ZgNbelmNw== + version "7.12.17" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.17.tgz#993c5e893333107a2815d8e0d73a2c3755e280b2" + integrity sha512-V3CuX1aBywbJvV2yzJScRxeiiw0v2KZZYYE3giywxzFJL13RiyPjaaDwhDnxmgFTTS7FgvM2ijr4QmKNIu0AtQ== dependencies: "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.12.15" - "@babel/helper-module-transforms" "^7.12.13" - "@babel/helpers" "^7.12.13" - "@babel/parser" "^7.12.16" + "@babel/generator" "^7.12.17" + "@babel/helper-module-transforms" "^7.12.17" + "@babel/helpers" "^7.12.17" + "@babel/parser" "^7.12.17" "@babel/template" "^7.12.13" - "@babel/traverse" "^7.12.13" - "@babel/types" "^7.12.13" + "@babel/traverse" "^7.12.17" + "@babel/types" "^7.12.17" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.1" @@ -37,12 +37,12 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/generator@^7.12.13", "@babel/generator@^7.12.15", "@babel/generator@^7.4.0": - version "7.12.15" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.12.15.tgz#4617b5d0b25cc572474cc1aafee1edeaf9b5368f" - integrity sha512-6F2xHxBiFXWNSGb7vyCUTBF8RCLY66rS0zEPcP8t/nQyXjha5EuK4z7H5o7fWG8B4M7y6mqVWq1J+1PuwRhecQ== +"@babel/generator@^7.12.17", "@babel/generator@^7.4.0": + version "7.12.17" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.12.17.tgz#9ef1dd792d778b32284411df63f4f668a9957287" + integrity sha512-DSA7ruZrY4WI8VxuS1jWSRezFnghEoYEFrZcw9BizQRmOZiUsiHl59+qEARGPqPikwA/GPTyRCi7isuCK/oyqg== dependencies: - "@babel/types" "^7.12.13" + "@babel/types" "^7.12.17" jsesc "^2.5.1" source-map "^0.5.0" @@ -63,11 +63,11 @@ "@babel/types" "^7.12.13" "@babel/helper-member-expression-to-functions@^7.12.13": - version "7.12.16" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.16.tgz#41e0916b99f8d5f43da4f05d85f4930fa3d62b22" - integrity sha512-zYoZC1uvebBFmj1wFAlXwt35JLEgecefATtKp20xalwEK8vHAixLBXTGxNrVGEmTT+gzOThUgr8UEdgtalc1BQ== + version "7.12.17" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.17.tgz#f82838eb06e1235307b6d71457b6670ff71ee5ac" + integrity sha512-Bzv4p3ODgS/qpBE0DiJ9qf5WxSmrQ8gVTe8ClMfwwsY2x/rhykxxy3bXzG7AGTnPB2ij37zGJ/Q/6FruxHxsxg== dependencies: - "@babel/types" "^7.12.13" + "@babel/types" "^7.12.17" "@babel/helper-module-imports@^7.12.13": version "7.12.13" @@ -76,10 +76,10 @@ dependencies: "@babel/types" "^7.12.13" -"@babel/helper-module-transforms@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.12.13.tgz#01afb052dcad2044289b7b20beb3fa8bd0265bea" - integrity sha512-acKF7EjqOR67ASIlDTupwkKM1eUisNAjaSduo5Cz+793ikfnpe7p4Q7B7EWU2PCoSTPWsQkR7hRUWEIZPiVLGA== +"@babel/helper-module-transforms@^7.12.17": + version "7.12.17" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.12.17.tgz#7c75b987d6dfd5b48e575648f81eaac891539509" + integrity sha512-sFL+p6zOCQMm9vilo06M4VHuTxUAwa6IxgL56Tq1DVtA0ziAGTH1ThmJq7xwPqdQlgAbKX3fb0oZNbtRIyA5KQ== dependencies: "@babel/helper-module-imports" "^7.12.13" "@babel/helper-replace-supers" "^7.12.13" @@ -87,8 +87,8 @@ "@babel/helper-split-export-declaration" "^7.12.13" "@babel/helper-validator-identifier" "^7.12.11" "@babel/template" "^7.12.13" - "@babel/traverse" "^7.12.13" - "@babel/types" "^7.12.13" + "@babel/traverse" "^7.12.17" + "@babel/types" "^7.12.17" lodash "^4.17.19" "@babel/helper-optimise-call-expression@^7.12.13": @@ -132,14 +132,14 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== -"@babel/helpers@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.12.13.tgz#3c75e993632e4dadc0274eae219c73eb7645ba47" - integrity sha512-oohVzLRZ3GQEk4Cjhfs9YkJA4TdIDTObdBEZGrd6F/T0GPSnuV6l22eMcxlvcvzVIPH3VTtxbseudM1zIE+rPQ== +"@babel/helpers@^7.12.17": + version "7.12.17" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.12.17.tgz#71e03d2981a6b5ee16899964f4101dc8471d60bc" + integrity sha512-tEpjqSBGt/SFEsFikKds1sLNChKKGGR17flIgQKXH4fG6m9gTgl3gnOC1giHNyaBCSKuTfxaSzHi7UnvqiVKxg== dependencies: "@babel/template" "^7.12.13" - "@babel/traverse" "^7.12.13" - "@babel/types" "^7.12.13" + "@babel/traverse" "^7.12.17" + "@babel/types" "^7.12.17" "@babel/highlight@^7.10.4", "@babel/highlight@^7.12.13": version "7.12.13" @@ -150,10 +150,10 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.12.13", "@babel/parser@^7.12.16", "@babel/parser@^7.4.3": - version "7.12.16" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.16.tgz#cc31257419d2c3189d394081635703f549fc1ed4" - integrity sha512-c/+u9cqV6F0+4Hpq01jnJO+GLp2DdT63ppz9Xa+6cHaajM9VFzK/iDXiKK65YtpeVwu+ctfS6iqlMqRgQRzeCw== +"@babel/parser@^7.1.0", "@babel/parser@^7.12.13", "@babel/parser@^7.12.17", "@babel/parser@^7.4.3": + version "7.12.17" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.17.tgz#bc85d2d47db38094e5bb268fc761716e7d693848" + integrity sha512-r1yKkiUTYMQ8LiEI0UcQx5ETw5dpTLn9wijn9hk6KkTtOK95FndDN10M+8/s6k/Ymlbivw0Av9q4SlgF80PtHg== "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" @@ -248,25 +248,25 @@ "@babel/parser" "^7.12.13" "@babel/types" "^7.12.13" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.12.13", "@babel/traverse@^7.4.3": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.13.tgz#689f0e4b4c08587ad26622832632735fb8c4e0c0" - integrity sha512-3Zb4w7eE/OslI0fTp8c7b286/cQps3+vdLW3UcwC8VSJC6GbKn55aeVVu2QJNuCDoeKyptLOFrPq8WqZZBodyA== +"@babel/traverse@^7.1.0", "@babel/traverse@^7.12.13", "@babel/traverse@^7.12.17", "@babel/traverse@^7.4.3": + version "7.12.17" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.17.tgz#40ec8c7ffb502c4e54c7f95492dc11b88d718619" + integrity sha512-LGkTqDqdiwC6Q7fWSwQoas/oyiEYw6Hqjve5KOSykXkmFJFqzvGMb9niaUEag3Rlve492Mkye3gLw9FTv94fdQ== dependencies: "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.12.13" + "@babel/generator" "^7.12.17" "@babel/helper-function-name" "^7.12.13" "@babel/helper-split-export-declaration" "^7.12.13" - "@babel/parser" "^7.12.13" - "@babel/types" "^7.12.13" + "@babel/parser" "^7.12.17" + "@babel/types" "^7.12.17" debug "^4.1.0" globals "^11.1.0" lodash "^4.17.19" -"@babel/types@^7.0.0", "@babel/types@^7.12.13", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.0": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.13.tgz#8be1aa8f2c876da11a9cf650c0ecf656913ad611" - integrity sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ== +"@babel/types@^7.0.0", "@babel/types@^7.12.13", "@babel/types@^7.12.17", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.0": + version "7.12.17" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.17.tgz#9d711eb807e0934c90b8b1ca0eb1f7230d150963" + integrity sha512-tNMDjcv/4DIcHxErTgwB9q2ZcYyN0sUfgGKUK/mm1FJK7Wz+KstoEekxrl/tBiNDgLK1HGi+sppj1An/1DR4fQ== dependencies: "@babel/helper-validator-identifier" "^7.12.11" lodash "^4.17.19" @@ -1330,11 +1330,6 @@ "@octokit/types" "^6.0.3" universal-user-agent "^6.0.0" -"@octokit/openapi-types@^4.0.3": - version "4.0.4" - resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-4.0.4.tgz#96fcce11e929802898646205ac567e5df592f82b" - integrity sha512-31zY8JIuz3h6RAFOnyA8FbOwhILILiBu1qD81RyZZWY7oMBhIdBn6MaAmnnptLhB4jk0g50nkQkUVP4kUzppcA== - "@octokit/openapi-types@^5.1.0": version "5.1.0" resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-5.1.0.tgz#661fd03c7d55fbcb0a0937d3353d87dea012f52c" @@ -1353,11 +1348,11 @@ "@octokit/types" "^2.0.1" "@octokit/plugin-paginate-rest@^2.6.2": - version "2.9.1" - resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.9.1.tgz#e9bb34a89b7ed5b801f1c976feeb9b0078ecd201" - integrity sha512-8wnuWGjwDIEobbBet2xAjZwgiMVTgIer5wBsnGXzV3lJ4yqphLU2FEMpkhSrDx7y+WkZDfZ+V+1cFMZ1mAaFag== + version "2.10.0" + resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.10.0.tgz#5925156d809c94b7bfc47b28e17488415548fa67" + integrity sha512-71OsKBSMcQEu/6lfVbhv5C5ikU1rn10rKot/WiV7do7fyfElQ2eCUQFogHPbj0ci5lnKAjvahOiMAr6lcvL8Qw== dependencies: - "@octokit/types" "^6.8.0" + "@octokit/types" "^6.10.0" "@octokit/plugin-request-log@^1.0.0", "@octokit/plugin-request-log@^1.0.2": version "1.0.3" @@ -1451,14 +1446,7 @@ dependencies: "@types/node" ">= 8" -"@octokit/types@^6.0.3", "@octokit/types@^6.7.1", "@octokit/types@^6.8.0": - version "6.8.5" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.8.5.tgz#797dfdad8c75718e97dc687d4c9fc49200ca8d17" - integrity sha512-ZsQawftZoi0kSF2pCsdgLURbOjtVcHnBOXiSxBKSNF56CRjARt5rb/g8WJgqB8vv4lgUEHrv06EdDKYQ22vA9Q== - dependencies: - "@octokit/openapi-types" "^4.0.3" - -"@octokit/types@^6.10.0": +"@octokit/types@^6.0.3", "@octokit/types@^6.10.0", "@octokit/types@^6.7.1": version "6.10.0" resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.10.0.tgz#243faa864b0955f574012d52e179de38ac9ebafe" integrity sha512-aMDo10kglofejJ96edCBIgQLVuzMDyjxmhdgEcoUUD64PlHYSrNsAGqN0wZtoiX4/PCQ3JLA50IpkP1bcKD/cA== @@ -1657,9 +1645,9 @@ integrity sha1-m6It838H43gP/4Ux0aOOYz+UV6U= "@types/node@*", "@types/node@>= 8": - version "14.14.28" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.28.tgz#cade4b64f8438f588951a6b35843ce536853f25b" - integrity sha512-lg55ArB+ZiHHbBBttLpzD07akz0QPrZgUODNakeC09i62dnrywr9mFErHuaPlB6I7z+sEbK+IYmplahvplCj2g== + version "14.14.31" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.31.tgz#72286bd33d137aa0d152d47ec7c1762563d34055" + integrity sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g== "@types/node@^10.17.54": version "10.17.54" @@ -1950,9 +1938,9 @@ ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4: uri-js "^4.2.2" ajv@^7.0.2: - version "7.1.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-7.1.0.tgz#f982ea7933dc7f1012eae9eec5a86687d805421b" - integrity sha512-svS9uILze/cXbH0z2myCK2Brqprx/+JJYK5pHicT/GQiBfzzhUVAIT6MwqJg8y4xV/zoGsUeuPuwtoiKSGE15g== + version "7.1.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-7.1.1.tgz#1e6b37a454021fa9941713f38b952fc1c8d32a84" + integrity sha512-ga/aqDYnUy/o7vbsRTFhhTsNeXiYb5JWDIcRIeZfwRNCefwjNTVYCGdGSUrEmiu3yDK3vFvNbgJxvrQW4JXrYQ== dependencies: fast-deep-equal "^3.1.1" json-schema-traverse "^1.0.0" @@ -2031,6 +2019,11 @@ anymatch@^3.0.3: normalize-path "^3.0.0" picomatch "^2.0.4" +app-root-path@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.2.1.tgz#d0df4a682ee408273583d43f6f79e9892624bc9a" + integrity sha512-91IFKeKk7FjfmezPKkwtaRvSpnUc4gDwPAjA1YZ9Gn0q0PPeW+vbeUsZuyDwjI7+QTHhcLen2v25fi/AmhvbJA== + append-transform@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-1.0.0.tgz#046a52ae582a228bd72f58acfbe2967c678759ab" @@ -2150,14 +2143,14 @@ array-ify@^1.0.0: integrity sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4= array-includes@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.2.tgz#a8db03e0b88c8c6aeddc49cb132f9bcab4ebf9c8" - integrity sha512-w2GspexNQpx+PutG3QpT437/BenZBj0M/MZGn5mzv/MofYqo0xmRHzn4lFsoDlWJ+THYsGJmFlW68WlDFx7VRw== + version "3.1.3" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.3.tgz#c7f619b382ad2afaf5326cddfdc0afc61af7690a" + integrity sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A== dependencies: - call-bind "^1.0.0" + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" - get-intrinsic "^1.0.1" + es-abstract "^1.18.0-next.2" + get-intrinsic "^1.1.1" is-string "^1.0.5" array-union@^1.0.2: @@ -2271,7 +2264,7 @@ aws-sdk-mock@^5.1.0: sinon "^9.0.1" traverse "^0.6.6" -aws-sdk@^2.637.0, aws-sdk@^2.848.0: +aws-sdk@^2.596.0, aws-sdk@^2.637.0, aws-sdk@^2.848.0: version "2.848.0" resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.848.0.tgz#5e7706ddd30a55a2d5a5b64c29682a757607ee64" integrity sha512-c/e5kaEFl+9aYkrYDkmu5mSZlL+EfP6DnBOMD06fH12gIsaFSMBGtbsDTHABhvSu++LxeI1dJAD148O17MuZvg== @@ -2992,9 +2985,9 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= constructs@^3.2.0: - version "3.3.21" - resolved "https://registry.yarnpkg.com/constructs/-/constructs-3.3.21.tgz#1290fbebe8716e729a6ac2a47118b58b8f7c4461" - integrity sha512-FsdsSAJlmlWSiWWuKTTP/a0SpEtRMM2w0P5lsJxvP4/42AOJOSmqckDyrr9WkESiaX94WnnK9khoVWGlBzkvNA== + version "3.3.29" + resolved "https://registry.yarnpkg.com/constructs/-/constructs-3.3.29.tgz#42d2fbc0d872a47701a70583a0d4356a3f11955c" + integrity sha512-rGQzkq2M/qKZ0hMEtt4YPpsZKOwzmiyAQx3PqexXXsjdVnTqEfIwQuDpc+1jP6CtaBHl7rR6CxQcfsP5DmaERw== contains-path@^0.1.0: version "0.1.0" @@ -3171,15 +3164,15 @@ conventional-commits-filter@^2.0.2, conventional-commits-filter@^2.0.7: modify-values "^1.0.0" conventional-commits-parser@^3.0.3, conventional-commits-parser@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-3.2.0.tgz#9e261b139ca4b7b29bcebbc54460da36894004ca" - integrity sha512-XmJiXPxsF0JhAKyfA2Nn+rZwYKJ60nanlbSWwwkGwLQFbugsc0gv1rzc7VbbUWAzJfR1qR87/pNgv9NgmxtBMQ== + version "3.2.1" + resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-3.2.1.tgz#ba44f0b3b6588da2ee9fd8da508ebff50d116ce2" + integrity sha512-OG9kQtmMZBJD/32NEw5IhN5+HnBqVjy03eC+I71I0oQRFA5rOgA4OtPOYG7mz1GkCfCNxn3gKIX8EiHJYuf1cA== dependencies: JSONStream "^1.0.4" is-text-path "^1.0.1" lodash "^4.17.15" meow "^8.0.0" - split2 "^2.0.0" + split2 "^3.0.0" through2 "^4.0.0" trim-off-newlines "^1.0.0" @@ -3694,6 +3687,16 @@ dot-prop@^5.1.0: dependencies: is-obj "^2.0.0" +dotenv-json@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dotenv-json/-/dotenv-json-1.0.0.tgz#fc7f672aafea04bed33818733b9f94662332815c" + integrity sha512-jAssr+6r4nKhKRudQ0HOzMskOFFi9+ubXWwmrSGJFgTvpjyPXCXsCsYbjif6mXp7uxA7xY3/LGaiTQukZzSbOQ== + +dotenv@^8.0.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" + integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== + dotgitignore@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/dotgitignore/-/dotgitignore-2.1.0.tgz#a4b15a4e4ef3cf383598aaf1dfa4a04bcc089b7b" @@ -3865,10 +3868,10 @@ es6-promisify@^5.0.0: dependencies: es6-promise "^4.0.3" -esbuild@^0.8.49: - version "0.8.49" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.8.49.tgz#3d33f71b3966611f822cf4c838115f3fbd16def2" - integrity sha512-itiFVYv5UZz4NooO7/Y0bRGVDGz/M/cxKbl6zyNI5pnKaz1mZjvZXAFhhDVz6rGCmcdTKj5oag6rh8DaaSSmfQ== +esbuild@^0.8.50: + version "0.8.50" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.8.50.tgz#ebf24fde0cdad1a369789dd6fd7a820b0a01e46c" + integrity sha512-oidFLXssA7IccYzkqLVZSqNJDwDq8Mh/vqvrW+3fPWM7iUiC5O2bCllhnO8+K9LlyL/2Z6n+WwRJAz9fqSIVRg== escalade@^3.1.1: version "3.1.1" @@ -3902,6 +3905,11 @@ escodegen@^1.14.1, escodegen@^1.8.1: optionalDependencies: source-map "~0.6.1" +eslint-config-standard@^14.1.1: + version "14.1.1" + resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-14.1.1.tgz#830a8e44e7aef7de67464979ad06b406026c56ea" + integrity sha512-Z9B+VR+JIXRxz21udPTL9HpFMyoMUEeX1G251EQ6e05WD9aPVtVBn09XUmZ259wCMlCDmYDSZG62Hhm+ZTJcUg== + eslint-import-resolver-node@^0.3.4: version "0.3.4" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717" @@ -3929,6 +3937,14 @@ eslint-module-utils@^2.6.0: debug "^2.6.9" pkg-dir "^2.0.0" +eslint-plugin-es@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz#75a7cdfdccddc0589934aeeb384175f221c57893" + integrity sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ== + dependencies: + eslint-utils "^2.0.0" + regexpp "^3.0.0" + eslint-plugin-import@^2.22.1: version "2.22.1" resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz#0896c7e6a0cf44109a2d97b95903c2bb689d7702" @@ -3955,11 +3971,33 @@ eslint-plugin-jest@^24.1.5: dependencies: "@typescript-eslint/experimental-utils" "^4.0.1" +eslint-plugin-node@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz#c95544416ee4ada26740a30474eefc5402dc671d" + integrity sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g== + dependencies: + eslint-plugin-es "^3.0.0" + eslint-utils "^2.0.0" + ignore "^5.1.1" + minimatch "^3.0.4" + resolve "^1.10.1" + semver "^6.1.0" + +eslint-plugin-promise@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.3.1.tgz#61485df2a359e03149fdafc0a68b0e030ad2ac45" + integrity sha512-bY2sGqyptzFBDLh/GMbAxfdJC+b0f23ME63FOE4+Jao0oZ3E1LEwFtWJX/1pGMJLiTtrSSern2CRM/g+dfc0eQ== + eslint-plugin-rulesdir@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/eslint-plugin-rulesdir/-/eslint-plugin-rulesdir-0.1.0.tgz#ad144d7e98464fda82963eff3fab331aecb2bf08" integrity sha1-rRRNfphGT9qClj7/P6szGuyyvwg= +eslint-plugin-standard@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-4.1.0.tgz#0c3bf3a67e853f8bbbc580fb4945fbf16f41b7c5" + integrity sha512-ZL7+QRixjTR6/528YNGyDotyffm5OQst/sGxKDwGb9Uqs4In5Egi4+jbobhqJoyoCM6/7v/1A5fhQ7ScMtDjaQ== + eslint-scope@^5.0.0, eslint-scope@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" @@ -4309,9 +4347,9 @@ figures@^3.1.0: escape-string-regexp "^1.0.5" file-entry-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.0.tgz#7921a89c391c6d93efec2169ac6bf300c527ea0a" - integrity sha512-fqoO76jZ3ZnYrXLDRxBR1YvOvc0k844kcOg40bgsPrE25LAb/PDqTY+ho64Xh2c8ZXgIKldchCFHczG2UVRcWA== + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== dependencies: flat-cache "^3.0.4" @@ -4612,7 +4650,7 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.0.1, get-intrinsic@^1.0.2, get-intrinsic@^1.1.0: +get-intrinsic@^1.0.1, get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== @@ -5091,7 +5129,7 @@ ignore@^4.0.3, ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -ignore@^5.1.4, ignore@^5.1.8, ignore@~5.1.8: +ignore@^5.1.1, ignore@^5.1.4, ignore@^5.1.8, ignore@~5.1.8: version "5.1.8" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== @@ -6373,6 +6411,24 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== +lambda-leak@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lambda-leak/-/lambda-leak-2.0.0.tgz#771985d3628487f6e885afae2b54510dcfb2cd7e" + integrity sha1-dxmF02KEh/boha+uK1RRDc+yzX4= + +lambda-tester@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/lambda-tester/-/lambda-tester-3.6.0.tgz#ceb7d4f4f0da768487a05cff37dcd088508b5247" + integrity sha512-F2ZTGWCLyIR95o/jWK46V/WnOCFAEUG/m/V7/CLhPJ7PCM+pror1rZ6ujP3TkItSGxUfpJi0kqwidw+M/nEqWw== + dependencies: + app-root-path "^2.2.1" + dotenv "^8.0.0" + dotenv-json "^1.0.0" + lambda-leak "^2.0.0" + semver "^6.1.1" + uuid "^3.3.2" + vandium-utils "^1.1.1" + lazystream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4" @@ -6902,17 +6958,17 @@ micromatch@^4.0.2: braces "^3.0.1" picomatch "^2.0.5" -mime-db@1.45.0: - version "1.45.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.45.0.tgz#cceeda21ccd7c3a745eba2decd55d4b73e7879ea" - integrity sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w== +mime-db@1.46.0: + version "1.46.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.46.0.tgz#6267748a7f799594de3cbc8cde91def349661cee" + integrity sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ== mime-types@^2.1.12, mime-types@~2.1.19: - version "2.1.28" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.28.tgz#1160c4757eab2c5363888e005273ecf79d2a0ecd" - integrity sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ== + version "2.1.29" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.29.tgz#1d4ab77da64b91f5f72489df29236563754bb1b2" + integrity sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ== dependencies: - mime-db "1.45.0" + mime-db "1.46.0" mimic-fn@^1.0.0: version "1.2.0" @@ -7142,9 +7198,9 @@ nice-try@^1.0.4: integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== nise@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/nise/-/nise-4.0.4.tgz#d73dea3e5731e6561992b8f570be9e363c4512dd" - integrity sha512-bTTRUNlemx6deJa+ZyoCUTRvH3liK5+N6VQZ4NIw90AgDXY6iPnsqplNFf6STcj+ePk0H/xqxnP75Lr0J0Fq3A== + version "4.1.0" + resolved "https://registry.yarnpkg.com/nise/-/nise-4.1.0.tgz#8fb75a26e90b99202fa1e63f448f58efbcdedaf6" + integrity sha512-eQMEmGN/8arp0xsvGoQ+B1qvSkR73B1nWSCh7nOt5neMCtwcQVYQGdzQMhcNscktTsWB54xnlSQFzOAPJD8nXA== dependencies: "@sinonjs/commons" "^1.7.0" "@sinonjs/fake-timers" "^6.0.0" @@ -7457,11 +7513,11 @@ object-inspect@^1.9.0: integrity sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw== object-is@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.4.tgz#63d6c83c00a43f4cbc9434eb9757c8a5b8565068" - integrity sha512-1ZvAZ4wlF7IyPVOcE1Omikt7UpaFlOQq0HlSti+ZvDH3UiD2brwGMwDbyV43jao2bKJ+4+WdPJHSd7kgzKYVqg== + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== dependencies: - call-bind "^1.0.0" + call-bind "^1.0.2" define-properties "^1.1.3" object-keys@^1.0.12, object-keys@^1.1.1: @@ -7487,13 +7543,13 @@ object.assign@^4.1.2: object-keys "^1.1.1" object.getownpropertydescriptors@^2.0.3: - version "2.1.1" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.1.tgz#0dfda8d108074d9c563e80490c883b6661091544" - integrity sha512-6DtXgZ/lIZ9hqx4GtZETobXLR/ZLaa0aqV0kzbn80Rf8Z2e/XFnhA0I7p07N2wH8bBBltr2xQPi6sbKWAY2Eng== + version "2.1.2" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz#1bd63aeacf0d5d2d2f31b5e393b03a7c601a23f7" + integrity sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ== dependencies: - call-bind "^1.0.0" + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" + es-abstract "^1.18.0-next.2" object.pick@^1.3.0: version "1.3.0" @@ -8573,7 +8629,7 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.1.6, resolve@^1.10.0, resolve@^1.11.1, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.18.1: +resolve@^1.1.6, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.11.1, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.18.1: version "1.20.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== @@ -8727,7 +8783,7 @@ semver@7.x, semver@^7.1.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4: dependencies: lru-cache "^6.0.0" -semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: +semver@^6.0.0, semver@^6.1.0, semver@^6.1.1, semver@^6.2.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== @@ -10087,6 +10143,11 @@ validate-npm-package-name@^3.0.0: dependencies: builtins "^1.0.3" +vandium-utils@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/vandium-utils/-/vandium-utils-1.2.0.tgz#44735de4b7641a05de59ebe945f174e582db4f59" + integrity sha1-RHNd5LdkGgXeWevpRfF05YLbT1k= + verror@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" @@ -10430,9 +10491,9 @@ yapool@^1.0.0: integrity sha1-9pPymjFbUNmp2iZGp6ZkXJaYW2o= yargs-parser@20.x, yargs-parser@^20.2.2, yargs-parser@^20.2.3: - version "20.2.5" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.5.tgz#5d37729146d3f894f39fc94b6796f5b239513186" - integrity sha512-jYRGS3zWy20NtDtK2kBgo/TlAoy5YUuhD9/LZ7z7W4j1Fdw2cqD0xEEclf8fxc8xjD6X5Qr+qQQwCEsP8iRiYg== + version "20.2.6" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.6.tgz#69f920addf61aafc0b8b89002f5d66e28f2d8b20" + integrity sha512-AP1+fQIWSM/sMiET8fyayjx/J+JmTPt2Mr0FkrgqB4todtfa53sOsrSAcIrJRD5XS20bKUwaDIuMkWKCEiQLKA== yargs-parser@^13.0.0, yargs-parser@^13.1.2: version "13.1.2"