diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000000..ebbc970f83c09 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Stackoverflow + url: https://stackoverflow.com/questions/tagged/aws-cdk + about: Please ask and answer questions here. diff --git a/.github/ISSUE_TEMPLATE/doc.md b/.github/ISSUE_TEMPLATE/doc.md index 9f53191546602..942e2baa8f7fb 100644 --- a/.github/ISSUE_TEMPLATE/doc.md +++ b/.github/ISSUE_TEMPLATE/doc.md @@ -1,7 +1,7 @@ --- -name: "📕 Documentation issue" +name: "📕 Documentation Issue" about: Issue in the reference documentation or developer guide -labels: feature-request, needs-triage +labels: feature-request, documentation, needs-triage --- ### The Question diff --git a/.github/workflows/close-stale-issues.yml b/.github/workflows/close-stale-issues.yml index b5a04b5ca5370..a92dd4b594ad9 100644 --- a/.github/workflows/close-stale-issues.yml +++ b/.github/workflows/close-stale-issues.yml @@ -3,7 +3,7 @@ name: "Close Stale Issues" # Controls when the action will run. on: schedule: - - cron: "0 * * * *" + - cron: "0 6 * * *" jobs: cleanup: diff --git a/.gitignore b/.gitignore index 2f2092ed1a333..f8f8e687c6791 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ # VSCode extension +.vscode/ /.favorites.json # TypeScript incremental build states @@ -32,6 +33,3 @@ cdk.out/ # Yarn error log yarn-error.log - -# Generated jest config -jest.config.gen.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 676c7b4ff8b61..0000000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "eslint.workingDirectories": [ - { "pattern": "./packages/@aws-cdk/*" }, - { "pattern": "./packages/@monocdk-experiment/*" }, - { "pattern": "./packages/*" }, - { "pattern": "./tools/*" } - ] -} diff --git a/CHANGELOG.md b/CHANGELOG.md index 26222487d58a2..b62be7f8ca81c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,39 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.39.0](https://github.com/aws/aws-cdk/compare/v1.38.0...v1.39.0) (2020-05-15) + + +### ⚠ BREAKING CHANGES + +* **cognito:** An invalid template placeholder has been removed +from the default verification email body in a user pool. + +### Features + +* **apigateway:** create RestApi from an OpenAPI spec ([31014ca](https://github.com/aws/aws-cdk/commit/31014ca7c34b3efbf5dca159a1168d5fbce633ec)), closes [#4421](https://github.com/aws/aws-cdk/issues/4421) +* **apigateway:** import existing VpcLink ([#7811](https://github.com/aws/aws-cdk/issues/7811)) ([7b42f7f](https://github.com/aws/aws-cdk/commit/7b42f7f11030577d98714185259c3de210fff0e2)), closes [#4178](https://github.com/aws/aws-cdk/issues/4178) +* initial version of an improved CloudFormation template include experience ([0132251](https://github.com/aws/aws-cdk/commit/0132251e84a7d8dad747b4eb0661365414a114aa)), closes [#3537](https://github.com/aws/aws-cdk/issues/3537) +* **apigateway:** specify API key name and value in `addApiKey()` ([#7714](https://github.com/aws/aws-cdk/issues/7714)) ([e93da2c](https://github.com/aws/aws-cdk/commit/e93da2cf48a297b31f2ca0c1e96b905fc128914b)), closes [#3233](https://github.com/aws/aws-cdk/issues/3233) [#7767](https://github.com/aws/aws-cdk/issues/7767) +* **apigatewayv2:** HTTP API - configure CORS preflight ([#7923](https://github.com/aws/aws-cdk/issues/7923)) ([9f35104](https://github.com/aws/aws-cdk/commit/9f35104d2e6612032f2c6d8d7193baddceb30d15)), closes [#7922](https://github.com/aws/aws-cdk/issues/7922) +* **cognito:** user pool client - prevent user existence errors ([c7f15f2](https://github.com/aws/aws-cdk/commit/c7f15f255ede6411f4afb68f5b9f1d54abe47df3)), closes [#7406](https://github.com/aws/aws-cdk/issues/7406) +* **dynamodb:** support for Customer-managed CMK ([#7425](https://github.com/aws/aws-cdk/issues/7425)) ([ff8219b](https://github.com/aws/aws-cdk/commit/ff8219ba0e2582ec25d59498804073776d8ebf14)), closes [#7142](https://github.com/aws/aws-cdk/issues/7142) +* **ec2:** lookup available AZs for Interface Endpoints ([9fa3221](https://github.com/aws/aws-cdk/commit/9fa3221f7dbedb6e6fb388c97e21a4fdcfd9a892)) +* **events-targets:** support multiple security groups for an ECS task ([#7857](https://github.com/aws/aws-cdk/issues/7857)) ([c6504e6](https://github.com/aws/aws-cdk/commit/c6504e6433d540414a417b9fb23fb9950a44eb5c)), closes [#3312](https://github.com/aws/aws-cdk/issues/3312) +* **init/java:** model CDK version in property in Maven POMs ([#7931](https://github.com/aws/aws-cdk/issues/7931)) ([ce5b8fb](https://github.com/aws/aws-cdk/commit/ce5b8fbe77a4414b13b67845aca171aa00794d55)), closes [#7862](https://github.com/aws/aws-cdk/issues/7862) + + +### Bug Fixes + +* **cli:** cdk bootstrap cannot be used without supplying the --app argument ([#7970](https://github.com/aws/aws-cdk/issues/7970)) ([540a7e6](https://github.com/aws/aws-cdk/commit/540a7e6d020a2af867adbd9928d32bfec30c97ae)), closes [#7510](https://github.com/aws/aws-cdk/issues/7510) [#7906](https://github.com/aws/aws-cdk/issues/7906) +* **cognito:** invalid default for verification email ([#7790](https://github.com/aws/aws-cdk/issues/7790)) ([cb3c184](https://github.com/aws/aws-cdk/commit/cb3c184d41bcd5c995f9a01fe875fdbf15ce5564)), closes [#7597](https://github.com/aws/aws-cdk/issues/7597) +* **core:** consistent sorting of resource tags ([0105efd](https://github.com/aws/aws-cdk/commit/0105efdd22e6e24af0f1547d57e6528eee999155)), closes [#7707](https://github.com/aws/aws-cdk/issues/7707) +* **core:** hangs when used with yarn PnP ([8579100](https://github.com/aws/aws-cdk/commit/8579100db0de0b8ec78186caa82aa5e0432774db)), closes [yarnpkg/berry#1298](https://github.com/yarnpkg/berry/issues/1298) +* **elbv2:** race condition for Lambda backends ([1819a6b](https://github.com/aws/aws-cdk/commit/1819a6b5920bb22a60d09de870ea625455b90395)), closes [#4663](https://github.com/aws/aws-cdk/issues/4663) [#7236](https://github.com/aws/aws-cdk/issues/7236) +* **iot1click:** incorrect type for Project.deviceTemplates ([#8000](https://github.com/aws/aws-cdk/issues/8000)) ([338ef92](https://github.com/aws/aws-cdk/commit/338ef92ced25563a80fb93b90f75853fe29ce6b7)), closes [#8001](https://github.com/aws/aws-cdk/issues/8001) +* **lambda:** SingletonFunction ignores explicit declared dependencies ([#7997](https://github.com/aws/aws-cdk/issues/7997)) ([91f913f](https://github.com/aws/aws-cdk/commit/91f913f09cfe0ee402b5e6269a7cc8cbcb32d58b)), closes [#7568](https://github.com/aws/aws-cdk/issues/7568) +* **stepfunctions-tasks:** EvaluateExpression is limited to expressions that contain state paths ([#7774](https://github.com/aws/aws-cdk/issues/7774)) ([97f4f01](https://github.com/aws/aws-cdk/commit/97f4f019b8514bb9a2ce5d06237fb724d1b1ad84)), closes [#7655](https://github.com/aws/aws-cdk/issues/7655) + ## [1.38.0](https://github.com/aws/aws-cdk/compare/v1.37.0...v1.38.0) (2020-05-08) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a9bdea2c823e8..8600b28cba8f2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,12 +48,15 @@ and let us know if it's not up-to-date (even better, submit a PR with your corr ## Getting Started For day-to-day development and normal contributions, the following SDKs and tools are required: - - [Node.js 10.13.0](https://nodejs.org/download/release/latest-v10.x/) - - [Yarn >= 1.19.1](https://yarnpkg.com/lang/en/docs/install) - - [Java OpenJDK 8](http://openjdk.java.net/install/) - - [.NET Core SDK 3.1](https://www.microsoft.com/net/download) - - [Python 3.6.5](https://www.python.org/downloads/release/python-365/) - - [Ruby 2.5.1](https://www.ruby-lang.org/en/news/2018/03/28/ruby-2-5-1-released/) + +- [Node.js >= 10.13.0](https://nodejs.org/download/release/latest-v10.x/) + - We recommend using a version in [Active LTS](https://nodejs.org/en/about/releases/) + - ⚠️ versions `13.0.0` to `13.6.0` are not supported due to compatibility issues with our dependencies. +- [Yarn >= 1.19.1](https://yarnpkg.com/lang/en/docs/install) +- [Java OpenJDK 8](http://openjdk.java.net/install/) +- [.NET Core SDK 3.1](https://www.microsoft.com/net/download) +- [Python 3.6.5](https://www.python.org/downloads/release/python-365/) +- [Ruby 2.5.1](https://www.ruby-lang.org/en/news/2018/03/28/ruby-2-5-1-released/) The basic commands to get the repository cloned and built locally follow: @@ -292,9 +295,7 @@ All packages in the repo use a standard base configuration found at [eslintrc.js This can be customized for any package by modifying the `.eslintrc` file found at its root. If you're using the VS Code and would like to see eslint violations on it, install the [eslint -extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint). The VS Code setting [needed for -the extension to work](https://github.com/Microsoft/vscode-eslint#settings-options) on the monorepo is configured in -the [folder settings](https://code.visualstudio.com/docs/editor/multi-root-workspaces#_settings). +extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint). #### pkglint diff --git a/README.md b/README.md index 9db5621124d26..4d7778e5752ca 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,8 @@ infrastructure definition and share it without worrying about boilerplate logic. The CDK is available in the following languages: * JavaScript, TypeScript ([Node.js ≥ 10.13.0](https://nodejs.org/download/release/latest-v10.x/)) + - We recommend using a version in [Active LTS](https://nodejs.org/en/about/releases/) + - ⚠️ versions `13.0.0` to `13.6.0` are not supported due to compatibility issues with our dependencies. * Python ([Python ≥ 3.6](https://www.python.org/downloads/)) * Java ([Java ≥ 8](https://www.oracle.com/technetwork/java/javase/downloads/index.html) and [Maven ≥ 3.5.4](https://maven.apache.org/download.cgi)) * .NET ([.NET Core ≥ 3.1](https://dotnet.microsoft.com/download)) @@ -57,7 +59,8 @@ on AWS. ## At a glance -Install or update the [AWS CDK CLI] from npm (requires [Node.js ≥ 10.13.0](https://nodejs.org/download/release/latest-v10.x/)): +Install or update the [AWS CDK CLI] from npm (requires [Node.js ≥ 10.13.0](https://nodejs.org/download/release/latest-v10.x/)). We recommend using a version in [Active LTS](https://nodejs.org/en/about/releases/) +⚠️ versions `13.0.0` to `13.6.0` are not supported due to compatibility issues with our dependencies. ```bash $ npm i -g aws-cdk diff --git a/allowed-breaking-changes.txt b/allowed-breaking-changes.txt index 8a8b54410795f..0e03d2ce09560 100644 --- a/allowed-breaking-changes.txt +++ b/allowed-breaking-changes.txt @@ -49,6 +49,8 @@ incompatible-argument:@aws-cdk/aws-iam.PrincipalPolicyFragment. changed-type:@aws-cdk/aws-iam.FederatedPrincipal.conditions changed-type:@aws-cdk/aws-iam.PrincipalPolicyFragment.conditions changed-type:@aws-cdk/aws-iam.PrincipalWithConditions.conditions -# Changing untyped property blob into typed property blob -change-return-type:@aws-cdk/cloud-assembly-schema.Manifest.load +removed:@aws-cdk/cdk-assets-schema.Placeholders +# Following two are because we're turning: properties: {string=>any} into a union of typed interfaces +# Needs to be removed after next release. incompatible-argument:@aws-cdk/cloud-assembly-schema.Manifest.save +change-return-type:@aws-cdk/cloud-assembly-schema.Manifest.load diff --git a/build.sh b/build.sh index b58fa80e1c563..44c020454216a 100755 --- a/build.sh +++ b/build.sh @@ -60,6 +60,6 @@ echo "========================================================================== echo "building..." time lerna run $bail --stream $runtarget || fail -/bin/bash scripts/check-api-compatibility.sh +DOWNLOAD_LATEST=true /bin/bash scripts/check-api-compatibility.sh touch $BUILD_INDICATOR diff --git a/lerna.json b/lerna.json index 7b4d069f3a5ad..377d0713da5c1 100644 --- a/lerna.json +++ b/lerna.json @@ -10,5 +10,5 @@ "tools/*" ], "rejectCycles": "true", - "version": "1.38.0" + "version": "1.39.0" } diff --git a/package.json b/package.json index 38ceba57ec54e..1314742465e47 100644 --- a/package.json +++ b/package.json @@ -14,12 +14,12 @@ "build-all": "tsc -b" }, "devDependencies": { - "conventional-changelog-cli": "^2.0.31", + "conventional-changelog-cli": "^2.0.34", "fs-extra": "^8.1.0", "jsii-diff": "^1.5.0", "jsii-pacmak": "^1.5.0", "jsii-rosetta": "^1.5.0", - "lerna": "^3.20.2", + "lerna": "^3.21.0", "standard-version": "^8.0.0", "graceful-fs": "^4.2.4", "typescript": "~3.8.3" @@ -52,6 +52,8 @@ "@aws-cdk/cdk-assets-schema/semver/**", "@aws-cdk/core/minimatch", "@aws-cdk/core/minimatch/**", + "@aws-cdk/cloudformation-include/yaml", + "@aws-cdk/cloudformation-include/yaml/**", "@aws-cdk/aws-codepipeline-actions/case", "@aws-cdk/aws-codepipeline-actions/case/**", "@aws-cdk/aws-ecr-assets/minimatch", diff --git a/packages/@aws-cdk/alexa-ask/.eslintrc.js b/packages/@aws-cdk/alexa-ask/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/alexa-ask/.eslintrc.js +++ b/packages/@aws-cdk/alexa-ask/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/alexa-ask/.gitignore b/packages/@aws-cdk/alexa-ask/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/alexa-ask/.gitignore +++ b/packages/@aws-cdk/alexa-ask/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/alexa-ask/.npmignore b/packages/@aws-cdk/alexa-ask/.npmignore index dd7e4908d99e4..c0fc6f9e7667f 100644 --- a/packages/@aws-cdk/alexa-ask/.npmignore +++ b/packages/@aws-cdk/alexa-ask/.npmignore @@ -22,3 +22,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/alexa-ask/jest.config.js b/packages/@aws-cdk/alexa-ask/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/alexa-ask/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/alexa-ask/package.json b/packages/@aws-cdk/alexa-ask/package.json index 386883e20291a..b941255e02954 100644 --- a/packages/@aws-cdk/alexa-ask/package.json +++ b/packages/@aws-cdk/alexa-ask/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "Alexa::ASK" + "cloudformation": "Alexa::ASK", + "jest": true }, "keywords": [ "aws", @@ -61,23 +62,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "experimental", diff --git a/packages/@aws-cdk/app-delivery/.eslintrc.js b/packages/@aws-cdk/app-delivery/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/app-delivery/.eslintrc.js +++ b/packages/@aws-cdk/app-delivery/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/app-delivery/package.json b/packages/@aws-cdk/app-delivery/package.json index 0ffb5249a3621..db77409db42d4 100644 --- a/packages/@aws-cdk/app-delivery/package.json +++ b/packages/@aws-cdk/app-delivery/package.json @@ -54,7 +54,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "fast-check": "^1.24.2", @@ -90,7 +90,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "experimental", diff --git a/packages/@aws-cdk/assert/.eslintrc.js b/packages/@aws-cdk/assert/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/assert/.eslintrc.js +++ b/packages/@aws-cdk/assert/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/assert/.gitignore b/packages/@aws-cdk/assert/.gitignore index 892f05c6f236f..9d5b9f1ce1539 100644 --- a/packages/@aws-cdk/assert/.gitignore +++ b/packages/@aws-cdk/assert/.gitignore @@ -11,3 +11,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/assert/.npmignore b/packages/@aws-cdk/assert/.npmignore index f90c2f91756cb..18ab2081759df 100644 --- a/packages/@aws-cdk/assert/.npmignore +++ b/packages/@aws-cdk/assert/.npmignore @@ -14,3 +14,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/assert/jest.config.js b/packages/@aws-cdk/assert/jest.config.js new file mode 100644 index 0000000000000..f81b80f39a2aa --- /dev/null +++ b/packages/@aws-cdk/assert/jest.config.js @@ -0,0 +1,10 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = { + ...baseConfig, + coverageThreshold: { + global: { + statements: 75, + branches: 65, + }, + }, +}; diff --git a/packages/@aws-cdk/assert/package.json b/packages/@aws-cdk/assert/package.json index 2bad5d64de9cb..61fe0556b1d02 100644 --- a/packages/@aws-cdk/assert/package.json +++ b/packages/@aws-cdk/assert/package.json @@ -14,14 +14,6 @@ "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test" }, - "jest": { - "coverageThreshold": { - "global": { - "statements": 75, - "branches": 65 - } - } - }, "author": { "name": "Amazon Web Services", "url": "https://aws.amazon.com", @@ -29,11 +21,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^25.2.1", + "@types/jest": "^25.2.2", "cdk-build-tools": "0.0.0", "jest": "^25.5.4", "pkglint": "0.0.0", - "ts-jest": "^25.5.0" + "ts-jest": "^26.0.0" }, "dependencies": { "@aws-cdk/cloudformation-diff": "0.0.0", @@ -58,8 +50,11 @@ ], "homepage": "https://github.com/aws/aws-cdk", "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", - "maturity": "experimental" + "maturity": "experimental", + "cdk-build": { + "jest": true + } } diff --git a/packages/@aws-cdk/assets/.eslintrc.js b/packages/@aws-cdk/assets/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/assets/.eslintrc.js +++ b/packages/@aws-cdk/assets/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/assets/package.json b/packages/@aws-cdk/assets/package.json index 1032698bb86f9..2782349d3b020 100644 --- a/packages/@aws-cdk/assets/package.json +++ b/packages/@aws-cdk/assets/package.json @@ -64,8 +64,8 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", - "@types/sinon": "^9.0.0", + "@types/nodeunit": "^0.0.31", + "@types/sinon": "^9.0.1", "aws-cdk": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", @@ -86,7 +86,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "deprecated", "maturity": "deprecated", diff --git a/packages/@aws-cdk/aws-accessanalyzer/.eslintrc.js b/packages/@aws-cdk/aws-accessanalyzer/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-accessanalyzer/.eslintrc.js +++ b/packages/@aws-cdk/aws-accessanalyzer/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-accessanalyzer/.gitignore b/packages/@aws-cdk/aws-accessanalyzer/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-accessanalyzer/.gitignore +++ b/packages/@aws-cdk/aws-accessanalyzer/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-accessanalyzer/.npmignore b/packages/@aws-cdk/aws-accessanalyzer/.npmignore index d4f7bff69bdab..8ac959aca8fa5 100644 --- a/packages/@aws-cdk/aws-accessanalyzer/.npmignore +++ b/packages/@aws-cdk/aws-accessanalyzer/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json !.jsii .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-accessanalyzer/jest.config.js b/packages/@aws-cdk/aws-accessanalyzer/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-accessanalyzer/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-accessanalyzer/package.json b/packages/@aws-cdk/aws-accessanalyzer/package.json index 52aa0ee160d85..b513d3b0954a6 100644 --- a/packages/@aws-cdk/aws-accessanalyzer/package.json +++ b/packages/@aws-cdk/aws-accessanalyzer/package.json @@ -48,7 +48,8 @@ "build+test+package": "npm run build+test && npm run package" }, "cdk-build": { - "cloudformation": "AWS::AccessAnalyzer" + "cloudformation": "AWS::AccessAnalyzer", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -95,7 +79,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-acmpca/.eslintrc.js b/packages/@aws-cdk/aws-acmpca/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-acmpca/.eslintrc.js +++ b/packages/@aws-cdk/aws-acmpca/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-acmpca/.gitignore b/packages/@aws-cdk/aws-acmpca/.gitignore index 07160589a11df..6d1b46f871517 100644 --- a/packages/@aws-cdk/aws-acmpca/.gitignore +++ b/packages/@aws-cdk/aws-acmpca/.gitignore @@ -15,3 +15,4 @@ coverage .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-acmpca/.npmignore b/packages/@aws-cdk/aws-acmpca/.npmignore index e421b91419b9a..fb37683c5a457 100644 --- a/packages/@aws-cdk/aws-acmpca/.npmignore +++ b/packages/@aws-cdk/aws-acmpca/.npmignore @@ -20,3 +20,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-acmpca/jest.config.js b/packages/@aws-cdk/aws-acmpca/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-acmpca/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-acmpca/package.json b/packages/@aws-cdk/aws-acmpca/package.json index 3d9d5177a7e72..9a38379aa34c3 100644 --- a/packages/@aws-cdk/aws-acmpca/package.json +++ b/packages/@aws-cdk/aws-acmpca/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::ACMPCA" + "cloudformation": "AWS::ACMPCA", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -95,7 +79,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-amazonmq/.eslintrc.js b/packages/@aws-cdk/aws-amazonmq/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-amazonmq/.eslintrc.js +++ b/packages/@aws-cdk/aws-amazonmq/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-amazonmq/.gitignore b/packages/@aws-cdk/aws-amazonmq/.gitignore index 6ffc26f126c4a..adcba106db8d1 100644 --- a/packages/@aws-cdk/aws-amazonmq/.gitignore +++ b/packages/@aws-cdk/aws-amazonmq/.gitignore @@ -13,3 +13,4 @@ tsconfig.json *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-amazonmq/.npmignore b/packages/@aws-cdk/aws-amazonmq/.npmignore index 764850e022c5a..8afbe60698fb4 100644 --- a/packages/@aws-cdk/aws-amazonmq/.npmignore +++ b/packages/@aws-cdk/aws-amazonmq/.npmignore @@ -23,3 +23,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-amazonmq/jest.config.js b/packages/@aws-cdk/aws-amazonmq/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-amazonmq/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-amazonmq/package.json b/packages/@aws-cdk/aws-amazonmq/package.json index 303952f5f981a..4b1b93d7d268a 100644 --- a/packages/@aws-cdk/aws-amazonmq/package.json +++ b/packages/@aws-cdk/aws-amazonmq/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::AmazonMQ" + "cloudformation": "AWS::AmazonMQ", + "jest": true }, "keywords": [ "aws", @@ -61,23 +62,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-amplify/.eslintrc.js b/packages/@aws-cdk/aws-amplify/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-amplify/.eslintrc.js +++ b/packages/@aws-cdk/aws-amplify/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-amplify/.gitignore b/packages/@aws-cdk/aws-amplify/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-amplify/.gitignore +++ b/packages/@aws-cdk/aws-amplify/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-amplify/.npmignore b/packages/@aws-cdk/aws-amplify/.npmignore index 5f6bdce6a4315..2b093ce17a11b 100644 --- a/packages/@aws-cdk/aws-amplify/.npmignore +++ b/packages/@aws-cdk/aws-amplify/.npmignore @@ -23,3 +23,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-amplify/jest.config.js b/packages/@aws-cdk/aws-amplify/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-amplify/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-amplify/package.json b/packages/@aws-cdk/aws-amplify/package.json index c01cbde1c2ce3..db112e8886c5a 100644 --- a/packages/@aws-cdk/aws-amplify/package.json +++ b/packages/@aws-cdk/aws-amplify/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::Amplify" + "cloudformation": "AWS::Amplify", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 70, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -106,7 +90,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "experimental", diff --git a/packages/@aws-cdk/aws-apigateway/.eslintrc.js b/packages/@aws-cdk/aws-apigateway/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-apigateway/.eslintrc.js +++ b/packages/@aws-cdk/aws-apigateway/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-apigateway/README.md b/packages/@aws-cdk/aws-apigateway/README.md index d8361d290767a..3be9cea704d17 100644 --- a/packages/@aws-cdk/aws-apigateway/README.md +++ b/packages/@aws-cdk/aws-apigateway/README.md @@ -1,4 +1,5 @@ ## Amazon API Gateway Construct Library + --- @@ -31,9 +32,11 @@ running on AWS Lambda, or any web application. - [Deep dive: Invalidation of deployments](#deep-dive-invalidation-of-deployments) - [Custom Domains](#custom-domains) - [Access Logging](#access-logging) -- [Cross Origin Resource Sharing (CORS)](cross-origin-resource-sharing-cors) +- [Cross Origin Resource Sharing (CORS)](#cross-origin-resource-sharing-cors) - [Endpoint Configuration](#endpoint-configuration) +- [Private Integrations](#private-integrations) - [Gateway Response](#gateway-response) +- [OpenAPI Definition](#openapi-definition) - [APIGateway v2](#apigateway-v2) ## Defining APIs @@ -101,11 +104,11 @@ item.addMethod('DELETE', new apigateway.HttpIntegration('http://amazon.com')); Methods are associated with backend integrations, which are invoked when this method is called. API Gateway supports the following integrations: - * `MockIntegration` - can be used to test APIs. This is the default +* `MockIntegration` - can be used to test APIs. This is the default integration if one is not specified. - * `LambdaIntegration` - can be used to invoke an AWS Lambda function. - * `AwsIntegration` - can be used to invoke arbitrary AWS service APIs. - * `HttpIntegration` - can be used to invoke HTTP endpoints. +* `LambdaIntegration` - can be used to invoke an AWS Lambda function. +* `AwsIntegration` - can be used to invoke arbitrary AWS service APIs. +* `HttpIntegration` - can be used to invoke HTTP endpoints. The following example shows how to integrate the `GET /book/{book_id}` method to an AWS Lambda function: @@ -174,11 +177,22 @@ plan.addApiStage({ }); ``` +The name and value of the API Key can be specified at creation; if not +provided, a name and value will be automatically generated by API Gateway. + +```ts +const key = api.addApiKey('ApiKey', { + apiKeyName: 'myApiKey1', + value: 'MyApiKeyThatIsAtLeast20Characters', +}); +``` + In scenarios where you need to create a single api key and configure rate limiting for it, you can use `RateLimitedApiKey`. This construct lets you specify rate limiting properties which should be applied only to the api key being created. The API key created has the specified rate limits, such as quota and throttles, applied. 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, @@ -450,9 +464,9 @@ iamUser.attachInlinePolicy(new iam.Policy(this, 'AllowBooks', { API Gateway also allows [lambda functions to be used as authorizers](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html). This module provides support for token-based Lambda authorizers. When a client makes a request to an API's methods configured with such -an authorizer, API Gateway calls the Lambda authorizer, which takes the caller's identity as input and returns an IAM policy as output. +an authorizer, API Gateway calls the Lambda authorizer, which takes the caller's identity as input and returns an IAM policy as output. A token-based Lambda authorizer (also called a token authorizer) receives the caller's identity in a bearer token, such as -a JSON Web Token (JWT) or an OAuth token. +a JSON Web Token (JWT) or an OAuth token. API Gateway interacts with the authorizer Lambda function handler by passing input and expecting the output in a specific format. The event object that the handler is called with contains the `authorizationToken` and the `methodArn` from the request to the @@ -491,7 +505,7 @@ depending on where the defaults were specified. This module provides support for request-based Lambda authorizers. When a client makes a request to an API's methods configured with such an authorizer, API Gateway calls the Lambda authorizer, which takes specified parts of the request, known as identity sources, -as input and returns an IAM policy as output. A request-based Lambda authorizer (also called a request authorizer) receives +as input and returns an IAM policy as output. A request-based Lambda authorizer (also called a request authorizer) receives the identity sources in a series of values pulled from the request, from the headers, stage variables, query strings, and the context. API Gateway interacts with the authorizer Lambda function handler by passing input and expecting the output in a specific format. @@ -634,8 +648,8 @@ new apigw.DomainName(this, 'custom-domain', { ``` Once you have a domain, you can map base paths of the domain to APIs. -The following example will map the URL https://example.com/go-to-api1 -to the `api1` API and https://example.com/boom to the `api2` API. +The following example will map the URL +to the `api1` API and to the `api2` API. ```ts domain.addBasePathMapping(api1, { basePath: 'go-to-api1' }); @@ -643,7 +657,7 @@ domain.addBasePathMapping(api2, { basePath: 'boom' }); ``` You can specify the API `Stage` to which this base path URL will map to. By default, this will be the -`deploymentStage` of the `RestApi`. +`deploymentStage` of the `RestApi`. ```ts const betaDeploy = new Deployment(this, 'beta-deployment', { @@ -787,7 +801,7 @@ running at one origin, access to selected resources from a different origin. A web application executes a cross-origin HTTP request when it requests a resource that has a different origin (domain, protocol, or port) from its own. -You can add the CORS [preflight](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Preflighted_requests) OPTIONS +You can add the CORS [preflight](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Preflighted_requests) OPTIONS HTTP method to any API resource via the `defaultCorsPreflightOptions` option or by calling the `addCorsPreflight` on a specific resource. The following example will enable CORS for all methods and all origins on all resources of the API: @@ -802,7 +816,7 @@ new apigateway.RestApi(this, 'api', { ``` The following example will add an OPTIONS method to the `myResource` API resource, which -only allows GET and PUT HTTP requests from the origin https://amazon.com. +only allows GET and PUT HTTP requests from the origin ```ts myResource.addCorsPreflight({ @@ -833,8 +847,8 @@ features which are not yet supported. ## Endpoint Configuration -API gateway allows you to specify an -[API Endpoint Type](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-api-endpoint-types.html). +API gateway allows you to specify an +[API Endpoint Type](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-api-endpoint-types.html). To define an endpoint type for the API gateway, use `endpointConfiguration` property: ```ts @@ -868,6 +882,42 @@ By performing this association, we can invoke the API gateway using the followin https://{rest-api-id}-{vpce-id}.execute-api.{region}.amazonaws.com/{stage} ``` +## Private Integrations + +A private integration makes it simple to expose HTTP/HTTPS resources behind an +Amazon VPC for access by clients outside of the VPC. The private integration uses +an API Gateway resource of `VpcLink` to encapsulate connections between API +Gateway and targeted VPC resources. +The `VpcLink` is then attached to the `Integration` of a specific API Gateway +Method. The following code sets up a private integration with a network load +balancer - + +```ts +const vpc = new ec2.Vpc(stack, 'VPC'); +const nlb = new elbv2.NetworkLoadBalancer(stack, 'NLB', { + vpc, +}); +const link = new apigw.VpcLink(stack, 'link', { + targets: [nlb], +}); + +const integration = new apigw.Integration({ + type: apigw.IntegrationType.HTTP_PROXY, + options: { + connectionType: apigw.ConnectionType.VPC_LINK, + vpcLink: link, + }, +}); +``` + +Any existing `VpcLink` resource can be imported into the CDK app via the `VpcLink.fromVpcLinkId()`. + +```ts +const stack = new Stack(app, 'my-stack'); + +const awesomeLink = VpcLink.fromVpcLinkId(stack, 'awesome-vpc-link', 'us-east-1_oiuR12Abd'); +``` + ## Gateway response If the Rest API fails to process an incoming request, it returns to the client an error response without forwarding the @@ -894,6 +944,30 @@ api.addGatewayResponse('test-response', { }); ``` +## OpenAPI Definition + +CDK supports creating a REST API by importing an OpenAPI definition file. It currently supports OpenAPI v2.0 and OpenAPI +v3.0 definition files. Read more about [Configuring a REST API using +OpenAPI](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-import-api.html). + +The following code creates a REST API using an external OpenAPI definition JSON file - + +```ts +const api = new apigateway.SpecRestApi(this, 'books-api', { + apiDefinition: apigateway.ApiDefinition.fromAsset('path-to-file.json') +}); +``` + +There are a number of limitations in using OpenAPI definitions in API Gateway. Read the [Amazon API Gateway important +notes for REST APIs](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-known-issues.html#api-gateway-known-issues-rest-apis) +for more details. + +**Note:** When starting off with an OpenAPI definition using `SpecRestApi`, it is not possible to configure some +properties that can be configured directly in the OpenAPI specification file. This is to prevent people duplication +of these properties and potential confusion. +Further, it is currently also not possible to configure Methods and Resources in addition to the ones in the +specification file. + ## APIGateway v2 APIGateway v2 APIs are now moved to its own package named `aws-apigatewayv2`. For backwards compatibility, existing diff --git a/packages/@aws-cdk/aws-apigateway/lib/api-definition.ts b/packages/@aws-cdk/aws-apigateway/lib/api-definition.ts new file mode 100644 index 0000000000000..652c531de9c38 --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/lib/api-definition.ts @@ -0,0 +1,205 @@ +import * as s3 from '@aws-cdk/aws-s3'; +import * as s3_assets from '@aws-cdk/aws-s3-assets'; +import * as cdk from '@aws-cdk/core'; + +/** + * Represents an OpenAPI definition asset. + * @experimental + */ +export abstract class ApiDefinition { + /** + * Creates an API definition from a specification file in an S3 bucket + * @experimental + */ + public static fromBucket(bucket: s3.IBucket, key: string, objectVersion?: string): S3ApiDefinition { + return new S3ApiDefinition(bucket, key, objectVersion); + } + + /** + * Create an API definition from an inline object. The inline object must follow the + * schema of OpenAPI 2.0 or OpenAPI 3.0 + * + * @example + * ApiDefinition.fromInline({ + * openapi: '3.0.2', + * paths: { + * '/pets': { + * get: { + * 'responses': { + * 200: { + * content: { + * 'application/json': { + * schema: { + * $ref: '#/components/schemas/Empty', + * }, + * }, + * }, + * }, + * }, + * 'x-amazon-apigateway-integration': { + * responses: { + * default: { + * statusCode: '200', + * }, + * }, + * requestTemplates: { + * 'application/json': '{"statusCode": 200}', + * }, + * passthroughBehavior: 'when_no_match', + * type: 'mock', + * }, + * }, + * }, + * }, + * components: { + * schemas: { + * Empty: { + * title: 'Empty Schema', + * type: 'object', + * }, + * }, + * }, + * }); + */ + public static fromInline(definition: any): InlineApiDefinition { + return new InlineApiDefinition(definition); + } + + /** + * Loads the API specification from a local disk asset. + * @experimental + */ + public static fromAsset(file: string, options?: s3_assets.AssetOptions): AssetApiDefinition { + return new AssetApiDefinition(file, options); + } + + /** + * Called when the specification is initialized to allow this object to bind + * to the stack, add resources and have fun. + * + * @param scope The binding scope. Don't be smart about trying to down-cast or + * assume it's initialized. You may just use it as a construct scope. + */ + public abstract bind(scope: cdk.Construct): ApiDefinitionConfig; +} + +/** + * S3 location of the API definition file + * @experimental + */ +export interface ApiDefinitionS3Location { + /** The S3 bucket */ + readonly bucket: string; + /** The S3 key */ + readonly key: string; + /** + * An optional version + * @default - latest version + */ + readonly version?: string; +} + +/** + * Post-Binding Configuration for a CDK construct + * @experimental + */ +export interface ApiDefinitionConfig { + /** + * The location of the specification in S3 (mutually exclusive with `inlineDefinition`). + * + * @default - API definition is not an S3 location + */ + readonly s3Location?: ApiDefinitionS3Location; + + /** + * Inline specification (mutually exclusive with `s3Location`). + * + * @default - API definition is not defined inline + */ + readonly inlineDefinition?: any; +} + +/** + * OpenAPI specification from an S3 archive. + * @experimental + */ +export class S3ApiDefinition extends ApiDefinition { + private bucketName: string; + + constructor(bucket: s3.IBucket, private key: string, private objectVersion?: string) { + super(); + + if (!bucket.bucketName) { + throw new Error('bucketName is undefined for the provided bucket'); + } + + this.bucketName = bucket.bucketName; + } + + public bind(_scope: cdk.Construct): ApiDefinitionConfig { + return { + s3Location: { + bucket: this.bucketName, + key: this.key, + version: this.objectVersion, + }, + }; + } +} + +/** + * OpenAPI specification from an inline JSON object. + * @experimental + */ +export class InlineApiDefinition extends ApiDefinition { + constructor(private definition: any) { + super(); + + if (typeof(definition) !== 'object') { + throw new Error('definition should be of type object'); + } + + if (Object.keys(definition).length === 0) { + throw new Error('JSON definition cannot be empty'); + } + } + + public bind(_scope: cdk.Construct): ApiDefinitionConfig { + return { + inlineDefinition: this.definition, + }; + } +} + +/** + * OpenAPI specification from a local file. + * @experimental + */ +export class AssetApiDefinition extends ApiDefinition { + private asset?: s3_assets.Asset; + + constructor(private readonly path: string, private readonly options: s3_assets.AssetOptions = { }) { + super(); + } + + public bind(scope: cdk.Construct): ApiDefinitionConfig { + // If the same AssetAPIDefinition is used multiple times, retain only the first instantiation. + if (this.asset === undefined) { + this.asset = new s3_assets.Asset(scope, 'APIDefinition', { + path: this.path, + ...this.options, + }); + } + + if (this.asset.isZipArchive) { + throw new Error(`Asset cannot be a .zip file or a directory (${this.path})`); + } + + return { + s3Location: { + bucket: this.asset.s3BucketName, + key: this.asset.s3ObjectKey, + }, + }; + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apigateway/lib/api-key.ts b/packages/@aws-cdk/aws-apigateway/lib/api-key.ts index c94a67ead901c..172b77aa40309 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/api-key.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/api-key.ts @@ -15,10 +15,29 @@ export interface IApiKey extends IResourceBase { readonly keyId: string; } +/** + * The options for creating an API Key. + */ +export interface ApiKeyOptions extends ResourceOptions { + /** + * A name for the API key. If you don't specify a name, AWS CloudFormation generates a unique physical ID and uses that ID for the API key name. + * @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-apikey.html#cfn-apigateway-apikey-name + * @default automically generated name + */ + readonly apiKeyName?: string; + + /** + * The value of the API key. Must be at least 20 characters long. + * @link https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-apikey.html#cfn-apigateway-apikey-value + * @default none + */ + readonly value?: string; +} + /** * ApiKey Properties. */ -export interface ApiKeyProps extends ResourceOptions { +export interface ApiKeyProps extends ApiKeyOptions { /** * [disable-awslint:ref-via-interface] * A list of resources this api key is associated with. @@ -53,13 +72,6 @@ export interface ApiKeyProps extends ResourceOptions { * @default false */ readonly generateDistinctId?: boolean; - - /** - * A name for the API key. If you don't specify a name, AWS CloudFormation generates a unique physical ID and uses that ID for the API key name. - * @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-apikey.html#cfn-apigateway-apikey-name - * @default automically generated name - */ - readonly apiKeyName?: string; } /** @@ -83,6 +95,7 @@ export class ApiKey extends Resource implements IApiKey { generateDistinctId: props.generateDistinctId, name: this.physicalName, stageKeys: this.renderStageKeys(props.resources), + value: props.value, }); this.keyId = resource.ref; diff --git a/packages/@aws-cdk/aws-apigateway/lib/index.ts b/packages/@aws-cdk/aws-apigateway/lib/index.ts index a0b9c7529cde2..cdb63b19d2e07 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/index.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/index.ts @@ -20,6 +20,7 @@ export * from './base-path-mapping'; export * from './cors'; export * from './authorizers'; export * from './access-log'; +export * from './api-definition'; export * from './gateway-response'; // AWS::ApiGateway CloudFormation Resources: diff --git a/packages/@aws-cdk/aws-apigateway/lib/integration.ts b/packages/@aws-cdk/aws-apigateway/lib/integration.ts index 30561ba4ce061..05356a57a861e 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/integration.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/integration.ts @@ -1,6 +1,6 @@ import * as iam from '@aws-cdk/aws-iam'; import { Method } from './method'; -import { VpcLink } from './vpc-link'; +import { IVpcLink } from './vpc-link'; export interface IntegrationOptions { /** @@ -98,7 +98,7 @@ export interface IntegrationOptions { * The VpcLink used for the integration. * Required if connectionType is VPC_LINK */ - readonly vpcLink?: VpcLink; + readonly vpcLink?: IVpcLink; } export interface IntegrationProps { diff --git a/packages/@aws-cdk/aws-apigateway/lib/restapi.ts b/packages/@aws-cdk/aws-apigateway/lib/restapi.ts index 5785574023b17..5a43b562ff279 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/restapi.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/restapi.ts @@ -1,7 +1,8 @@ import { IVpcEndpoint } from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import { CfnOutput, Construct, IResource as IResourceBase, Resource, Stack } from '@aws-cdk/core'; -import { ApiKey, IApiKey } from './api-key'; +import { ApiDefinition } from './api-definition'; +import { ApiKey, ApiKeyOptions, IApiKey } from './api-key'; import { CfnAccount, CfnRestApi } from './apigateway.generated'; import { CorsOptions } from './cors'; import { Deployment } from './deployment'; @@ -23,7 +24,10 @@ export interface IRestApi extends IResourceBase { readonly restApiId: string; } -export interface RestApiProps extends ResourceOptions { +/** + * Represents the props that all Rest APIs share + */ +export interface RestApiOptions extends ResourceOptions { /** * Indicates if a Deployment should be automatically created for this API, * and recreated when the API model (resources, methods) changes. @@ -88,52 +92,53 @@ export interface RestApiProps extends ResourceOptions { readonly policy?: iam.PolicyDocument; /** - * A description of the purpose of this API Gateway RestApi resource. + * Indicates whether to roll back the resource if a warning occurs while API + * Gateway is creating the RestApi resource. * - * @default - No description. + * @default false */ - readonly description?: string; + readonly failOnWarnings?: boolean; /** - * The EndpointConfiguration property type specifies the endpoint types of a REST API - * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigateway-restapi-endpointconfiguration.html + * Configure a custom domain name and map it to this API. * - * @default - No endpoint configuration + * @default - no domain name is defined, use `addDomainName` or directly define a `DomainName`. */ - readonly endpointConfiguration?: EndpointConfiguration; + readonly domainName?: DomainNameOptions; /** - * A list of the endpoint types of the API. Use this property when creating - * an API. + * Automatically configure an AWS CloudWatch role for API Gateway. * - * @default - No endpoint types. - * @deprecated this property is deprecated, use endpointConfiguration instead + * @default true */ - readonly endpointTypes?: EndpointType[]; + readonly cloudWatchRole?: boolean; /** - * The source of the API key for metering requests according to a usage - * plan. + * Export name for the CfnOutput containing the API endpoint * - * @default - Metering is disabled. + * @default - when no export name is given, output will be created without export */ - readonly apiKeySourceType?: ApiKeySourceType; + readonly endpointExportName?: string; +} +/** + * Props to create a new instance of RestApi + */ +export interface RestApiProps extends RestApiOptions { /** - * The list of binary media mime-types that are supported by the RestApi - * resource, such as "image/png" or "application/octet-stream" + * A description of the purpose of this API Gateway RestApi resource. * - * @default - RestApi supports only UTF-8-encoded text payloads. + * @default - No description. */ - readonly binaryMediaTypes?: string[]; + readonly description?: string; /** - * Indicates whether to roll back the resource if a warning occurs while API - * Gateway is creating the RestApi resource. + * The list of binary media mime-types that are supported by the RestApi + * resource, such as "image/png" or "application/octet-stream" * - * @default false + * @default - RestApi supports only UTF-8-encoded text payloads. */ - readonly failOnWarnings?: boolean; + readonly binaryMediaTypes?: string[]; /** * A nullable integer that is used to enable compression (with non-negative @@ -155,65 +160,55 @@ export interface RestApiProps extends ResourceOptions { readonly cloneFrom?: IRestApi; /** - * Automatically configure an AWS CloudWatch role for API Gateway. + * The source of the API key for metering requests according to a usage + * plan. * - * @default true + * @default - Metering is disabled. */ - readonly cloudWatchRole?: boolean; + readonly apiKeySourceType?: ApiKeySourceType; /** - * Configure a custom domain name and map it to this API. + * The EndpointConfiguration property type specifies the endpoint types of a REST API + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigateway-restapi-endpointconfiguration.html * - * @default - no domain name is defined, use `addDomainName` or directly define a `DomainName`. + * @default - No endpoint configuration */ - readonly domainName?: DomainNameOptions; + readonly endpointConfiguration?: EndpointConfiguration; /** - * Export name for the CfnOutput containing the API endpoint + * A list of the endpoint types of the API. Use this property when creating + * an API. * - * @default - when no export name is given, output will be created without export + * @default - No endpoint types. + * @deprecated this property is deprecated, use endpointConfiguration instead */ - readonly endpointExportName?: string; + readonly endpointTypes?: EndpointType[]; } /** - * Represents a REST API in Amazon API Gateway. - * - * Use `addResource` and `addMethod` to configure the API model. - * - * By default, the API will automatically be deployed and accessible from a - * public endpoint. + * Props to instantiate a new SpecRestApi + * @experimental */ -export class RestApi extends Resource implements IRestApi { - - public static fromRestApiId(scope: Construct, id: string, restApiId: string): IRestApi { - class Import extends Resource implements IRestApi { - public readonly restApiId = restApiId; - } - - return new Import(scope, id); - } +export interface SpecRestApiProps extends RestApiOptions { + /** + * An OpenAPI definition compatible with API Gateway. + * @see https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-import-api.html + */ + readonly apiDefinition: ApiDefinition; +} +abstract class RestApiBase extends Resource implements IRestApi { /** * The ID of this API Gateway RestApi. */ - public readonly restApiId: string; + public abstract readonly restApiId: string; /** * The resource ID of the root resource. * * @attribute */ - public readonly restApiRootResourceId: string; - - /** - * Represents the root resource ("/") of this API. Use it to define the API model: - * - * api.root.addMethod('ANY', redirectToHomePage); // "ANY /" - * api.root.addResource('friends').addMethod('GET', getFriendsHandler); // "GET /friends" - * - */ - public readonly root: IResource; + public abstract readonly restApiRootResourceId: string; /** * API Gateway stage that points to the latest deployment (if defined). @@ -223,72 +218,13 @@ export class RestApi extends Resource implements IRestApi { */ public deploymentStage!: Stage; - /** - * The list of methods bound to this RestApi - */ - public readonly methods = new Array(); - + private _latestDeployment?: Deployment; private _domainName?: DomainName; - private _latestDeployment: Deployment | undefined; - constructor(scope: Construct, id: string, props: RestApiProps = { }) { + constructor(scope: Construct, id: string, props: RestApiOptions = { }) { super(scope, id, { physicalName: props.restApiName || id, }); - - const resource = new CfnRestApi(this, 'Resource', { - name: this.physicalName, - description: props.description, - policy: props.policy, - failOnWarnings: props.failOnWarnings, - minimumCompressionSize: props.minimumCompressionSize, - binaryMediaTypes: props.binaryMediaTypes, - endpointConfiguration: this.configureEndpoints(props), - apiKeySourceType: props.apiKeySourceType, - cloneFrom: props.cloneFrom ? props.cloneFrom.restApiId : undefined, - parameters: props.parameters, - }); - this.node.defaultChild = resource; - - this.restApiId = resource.ref; - - this.configureDeployment(props); - - const cloudWatchRole = props.cloudWatchRole !== undefined ? props.cloudWatchRole : true; - if (cloudWatchRole) { - this.configureCloudWatchRole(resource); - } - - this.root = new RootResource(this, props, resource.attrRootResourceId); - this.restApiRootResourceId = resource.attrRootResourceId; - - if (props.domainName) { - this.addDomainName('CustomDomain', props.domainName); - } - } - - /** - * The first domain name mapped to this API, if defined through the `domainName` - * configuration prop, or added via `addDomainName` - */ - public get domainName() { - return this._domainName; - } - - /** - * API Gateway deployment that represents the latest changes of the API. - * This resource will be automatically updated every time the REST API model changes. - * This will be undefined if `deploy` is false. - */ - public get latestDeployment() { - return this._latestDeployment; - } - - /** - * The deployed root URL of this REST API. - */ - public get url() { - return this.urlForPath(); } /** @@ -304,6 +240,15 @@ export class RestApi extends Resource implements IRestApi { return this.deploymentStage.urlForPath(path); } + /** + * API Gateway deployment that represents the latest changes of the API. + * This resource will be automatically updated every time the REST API model changes. + * This will be undefined if `deploy` is false. + */ + public get latestDeployment() { + return this._latestDeployment; + } + /** * Defines an API Gateway domain name and maps it to this API. * @param id The construct id @@ -328,35 +273,15 @@ export class RestApi extends Resource implements IRestApi { } /** - * Add an ApiKey - */ - public addApiKey(id: string): IApiKey { - return new ApiKey(this, id, { - resources: [this], - }); - } - - /** - * Adds a new model. - */ - public addModel(id: string, props: ModelOptions): Model { - return new Model(this, id, { - ...props, - restApi: this, - }); - } - - /** - * Adds a new request validator. + * The first domain name mapped to this API, if defined through the `domainName` + * configuration prop, or added via `addDomainName` */ - public addRequestValidator(id: string, props: RequestValidatorOptions): RequestValidator { - return new RequestValidator(this, id, { - ...props, - restApi: this, - }); + public get domainName() { + return this._domainName; } /** + * Gets the "execute-api" ARN * @returns The "execute-api" ARN. * @default "*" returns the execute API ARN for all methods/resources in * this API. @@ -381,16 +306,6 @@ export class RestApi extends Resource implements IRestApi { }); } - /** - * Internal API used by `Method` to keep an inventory of methods at the API - * level for validation purposes. - * - * @internal - */ - public _attachMethod(method: Method) { - this.methods.push(method); - } - /** * Adds a new gateway response. */ @@ -401,18 +316,20 @@ export class RestApi extends Resource implements IRestApi { }); } - /** - * Performs validation of the REST API. - */ - protected validate() { - if (this.methods.length === 0) { - return [ 'The REST API doesn\'t contain any methods' ]; - } + protected configureCloudWatchRole(apiResource: CfnRestApi) { + const role = new iam.Role(this, 'CloudWatchRole', { + assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonAPIGatewayPushToCloudWatchLogs')], + }); - return []; + const resource = new CfnAccount(this, 'Account', { + cloudWatchRoleArn: role.roleArn, + }); + + resource.node.addDependency(apiResource); } - private configureDeployment(props: RestApiProps) { + protected configureDeployment(props: RestApiOptions) { const deploy = props.deploy === undefined ? true : props.deploy; if (deploy) { @@ -438,18 +355,193 @@ export class RestApi extends Resource implements IRestApi { } } } +} - private configureCloudWatchRole(apiResource: CfnRestApi) { - const role = new iam.Role(this, 'CloudWatchRole', { - assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'), - managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonAPIGatewayPushToCloudWatchLogs')], +/** + * Represents a REST API in Amazon API Gateway, created with an OpenAPI specification. + * + * Some properties normally accessible on @see {@link RestApi} - such as the description - + * must be declared in the specification. All Resources and Methods need to be defined as + * part of the OpenAPI specification file, and cannot be added via the CDK. + * + * By default, the API will automatically be deployed and accessible from a + * public endpoint. + * + * @experimental + * + * @resource AWS::ApiGateway::RestApi + */ +export class SpecRestApi extends RestApiBase { + /** + * The ID of this API Gateway RestApi. + */ + public readonly restApiId: string; + + /** + * The resource ID of the root resource. + * + * @attribute + */ + public readonly restApiRootResourceId: string; + + constructor(scope: Construct, id: string, props: SpecRestApiProps) { + super(scope, id, props); + const apiDefConfig = props.apiDefinition.bind(this); + const resource = new CfnRestApi(this, 'Resource', { + name: this.physicalName, + policy: props.policy, + failOnWarnings: props.failOnWarnings, + body: apiDefConfig.inlineDefinition ? apiDefConfig.inlineDefinition : undefined, + bodyS3Location: apiDefConfig.inlineDefinition ? undefined : apiDefConfig.s3Location, + parameters: props.parameters, }); + this.node.defaultChild = resource; + this.restApiId = resource.ref; + this.restApiRootResourceId = resource.attrRootResourceId; - const resource = new CfnAccount(this, 'Account', { - cloudWatchRoleArn: role.roleArn, + this.configureDeployment(props); + if (props.domainName) { + this.addDomainName('CustomDomain', props.domainName); + } + + const cloudWatchRole = props.cloudWatchRole !== undefined ? props.cloudWatchRole : true; + if (cloudWatchRole) { + this.configureCloudWatchRole(resource); + } + } +} + +/** + * Represents a REST API in Amazon API Gateway. + * + * Use `addResource` and `addMethod` to configure the API model. + * + * By default, the API will automatically be deployed and accessible from a + * public endpoint. + */ +export class RestApi extends RestApiBase implements IRestApi { + public static fromRestApiId(scope: Construct, id: string, restApiId: string): IRestApi { + class Import extends Resource implements IRestApi { + public readonly restApiId = restApiId; + } + + return new Import(scope, id); + } + + /** + * The ID of this API Gateway RestApi. + */ + public readonly restApiId: string; + + /** + * Represents the root resource ("/") of this API. Use it to define the API model: + * + * api.root.addMethod('ANY', redirectToHomePage); // "ANY /" + * api.root.addResource('friends').addMethod('GET', getFriendsHandler); // "GET /friends" + * + */ + public readonly root: IResource; + + /** + * The resource ID of the root resource. + * + * @attribute + */ + public readonly restApiRootResourceId: string; + + /** + * The list of methods bound to this RestApi + */ + public readonly methods = new Array(); + + constructor(scope: Construct, id: string, props: RestApiProps = { }) { + super(scope, id, props); + + const resource = new CfnRestApi(this, 'Resource', { + name: this.physicalName, + description: props.description, + policy: props.policy, + failOnWarnings: props.failOnWarnings, + minimumCompressionSize: props.minimumCompressionSize, + binaryMediaTypes: props.binaryMediaTypes, + endpointConfiguration: this.configureEndpoints(props), + apiKeySourceType: props.apiKeySourceType, + cloneFrom: props.cloneFrom ? props.cloneFrom.restApiId : undefined, + parameters: props.parameters, }); + this.node.defaultChild = resource; + this.restApiId = resource.ref; - resource.node.addDependency(apiResource); + const cloudWatchRole = props.cloudWatchRole !== undefined ? props.cloudWatchRole : true; + if (cloudWatchRole) { + this.configureCloudWatchRole(resource); + } + + this.configureDeployment(props); + if (props.domainName) { + this.addDomainName('CustomDomain', props.domainName); + } + + this.root = new RootResource(this, props, resource.attrRootResourceId); + this.restApiRootResourceId = resource.attrRootResourceId; + } + + /** + * The deployed root URL of this REST API. + */ + public get url() { + return this.urlForPath(); + } + + /** + * Add an ApiKey + */ + public addApiKey(id: string, options?: ApiKeyOptions): IApiKey { + return new ApiKey(this, id, { + resources: [this], + ...options, + }); + } + + /** + * Adds a new model. + */ + public addModel(id: string, props: ModelOptions): Model { + return new Model(this, id, { + ...props, + restApi: this, + }); + } + + /** + * Adds a new request validator. + */ + public addRequestValidator(id: string, props: RequestValidatorOptions): RequestValidator { + return new RequestValidator(this, id, { + ...props, + restApi: this, + }); + } + + /** + * Internal API used by `Method` to keep an inventory of methods at the API + * level for validation purposes. + * + * @internal + */ + public _attachMethod(method: Method) { + this.methods.push(method); + } + + /** + * Performs validation of the REST API. + */ + protected validate() { + if (this.methods.length === 0) { + return [ "The REST API doesn't contain any methods" ]; + } + + return []; } private configureEndpoints(props: RestApiProps): CfnRestApi.EndpointConfigurationProperty | undefined { diff --git a/packages/@aws-cdk/aws-apigateway/lib/vpc-link.ts b/packages/@aws-cdk/aws-apigateway/lib/vpc-link.ts index 1c7737588f97a..81f6f843b97df 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/vpc-link.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/vpc-link.ts @@ -1,7 +1,18 @@ import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; -import { Construct, Lazy, Resource } from '@aws-cdk/core'; +import { Construct, IResource, Lazy, Resource } from '@aws-cdk/core'; import { CfnVpcLink } from './apigateway.generated'; +/** + * Represents an API Gateway VpcLink + */ +export interface IVpcLink extends IResource { + /** + * Physical ID of the VpcLink resource + * @attribute + */ + readonly vpcLinkId: string; +} + /** * Properties for a VpcLink */ @@ -31,7 +42,18 @@ export interface VpcLinkProps { * Define a new VPC Link * Specifies an API Gateway VPC link for a RestApi to access resources in an Amazon Virtual Private Cloud (VPC). */ -export class VpcLink extends Resource { +export class VpcLink extends Resource implements IVpcLink { + /** + * Import a VPC Link by its Id + */ + public static fromVpcLinkId(scope: Construct, id: string, vpcLinkId: string): IVpcLink { + class Import extends Resource implements IVpcLink { + public vpcLinkId = vpcLinkId; + } + + return new Import(scope, id); + } + /** * Physical ID of the VpcLink resource * @attribute diff --git a/packages/@aws-cdk/aws-apigateway/package.json b/packages/@aws-cdk/aws-apigateway/package.json index 3a0d997c6f292..c3003c458ea57 100644 --- a/packages/@aws-cdk/aws-apigateway/package.json +++ b/packages/@aws-cdk/aws-apigateway/package.json @@ -63,7 +63,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -71,28 +71,36 @@ "pkglint": "0.0.0" }, "dependencies": { + "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-certificatemanager": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", + "@aws-cdk/aws-s3": "0.0.0", + "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/core": "0.0.0", + "@aws-cdk/cx-api": "0.0.0", "constructs": "^3.0.2" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { + "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-certificatemanager": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", + "@aws-cdk/aws-s3": "0.0.0", + "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/core": "0.0.0", + "@aws-cdk/cx-api": "0.0.0", "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "nyc": { "exclude": [ diff --git a/packages/@aws-cdk/aws-apigateway/test/integ.api-definition.asset.expected.json b/packages/@aws-cdk/aws-apigateway/test/integ.api-definition.asset.expected.json new file mode 100644 index 0000000000000..71dd02f17ab9a --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/test/integ.api-definition.asset.expected.json @@ -0,0 +1,182 @@ +{ + "Resources": { + "myapi4C7BF186": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "BodyS3Location": { + "Bucket": { + "Ref": "AssetParameters68497ac876de4e963fc8f7b5f1b28844c18ecc95e3f7c6e9e0bf250e03c037fbS3Bucket42039E29" + }, + "Key": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters68497ac876de4e963fc8f7b5f1b28844c18ecc95e3f7c6e9e0bf250e03c037fbS3VersionKeyB590532F" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters68497ac876de4e963fc8f7b5f1b28844c18ecc95e3f7c6e9e0bf250e03c037fbS3VersionKeyB590532F" + } + ] + } + ] + } + ] + ] + } + }, + "Name": "my-api" + } + }, + "myapiDeployment92F2CB49": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "myapi4C7BF186" + }, + "Description": "Automatically created by the RestApi construct" + } + }, + "myapiDeploymentStageprod298F01AF": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "RestApiId": { + "Ref": "myapi4C7BF186" + }, + "DeploymentId": { + "Ref": "myapiDeployment92F2CB49" + }, + "StageName": "prod" + } + }, + "myapiCloudWatchRole095452E5": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "apigateway.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + ] + } + ] + } + }, + "myapiAccountEC421A0A": { + "Type": "AWS::ApiGateway::Account", + "Properties": { + "CloudWatchRoleArn": { + "Fn::GetAtt": [ + "myapiCloudWatchRole095452E5", + "Arn" + ] + } + }, + "DependsOn": [ + "myapi4C7BF186" + ] + } + }, + "Outputs": { + "myapiEndpoint3628AFE3": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Ref": "myapi4C7BF186" + }, + ".execute-api.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "myapiDeploymentStageprod298F01AF" + }, + "/" + ] + ] + } + }, + "PetsURL": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Ref": "myapi4C7BF186" + }, + ".execute-api.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "myapiDeploymentStageprod298F01AF" + }, + "/pets" + ] + ] + } + } + }, + "Parameters": { + "AssetParameters68497ac876de4e963fc8f7b5f1b28844c18ecc95e3f7c6e9e0bf250e03c037fbS3Bucket42039E29": { + "Type": "String", + "Description": "S3 bucket for asset \"68497ac876de4e963fc8f7b5f1b28844c18ecc95e3f7c6e9e0bf250e03c037fb\"" + }, + "AssetParameters68497ac876de4e963fc8f7b5f1b28844c18ecc95e3f7c6e9e0bf250e03c037fbS3VersionKeyB590532F": { + "Type": "String", + "Description": "S3 key for asset version \"68497ac876de4e963fc8f7b5f1b28844c18ecc95e3f7c6e9e0bf250e03c037fb\"" + }, + "AssetParameters68497ac876de4e963fc8f7b5f1b28844c18ecc95e3f7c6e9e0bf250e03c037fbArtifactHashA9C91B6D": { + "Type": "String", + "Description": "Artifact hash for asset \"68497ac876de4e963fc8f7b5f1b28844c18ecc95e3f7c6e9e0bf250e03c037fb\"" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apigateway/test/integ.api-definition.asset.ts b/packages/@aws-cdk/aws-apigateway/test/integ.api-definition.asset.ts new file mode 100644 index 0000000000000..1b8531ccad8d5 --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/test/integ.api-definition.asset.ts @@ -0,0 +1,21 @@ +import * as cdk from '@aws-cdk/core'; +import * as path from 'path'; +import * as apigateway from '../lib'; + +/* + * Stack verification steps: + * * `curl -i ` should return HTTP code 200 + */ + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'integtest-restapi-fromdefinition-asset'); + +const api = new apigateway.SpecRestApi(stack, 'my-api', { + apiDefinition: apigateway.ApiDefinition.fromAsset(path.join(__dirname, 'sample-definition.yaml')), +}); + +new cdk.CfnOutput(stack, 'PetsURL', { + value: api.urlForPath('/pets'), +}); + +app.synth(); diff --git a/packages/@aws-cdk/aws-apigateway/test/integ.api-definition.inline.expected.json b/packages/@aws-cdk/aws-apigateway/test/integ.api-definition.inline.expected.json new file mode 100644 index 0000000000000..3eaae1ff8fd58 --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/test/integ.api-definition.inline.expected.json @@ -0,0 +1,177 @@ +{ + "Resources": { + "myapi4C7BF186": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "openapi": "3.0.2", + "info": { + "version": "1.0.0", + "title": "Test API for CDK" + }, + "paths": { + "/pets": { + "get": { + "summary": "Test Method", + "operationId": "testMethod", + "responses": { + "200": { + "description": "A paged array of pets", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Empty" + } + } + } + } + }, + "x-amazon-apigateway-integration": { + "responses": { + "default": { + "statusCode": "200" + } + }, + "requestTemplates": { + "application/json": "{\"statusCode\": 200}" + }, + "passthroughBehavior": "when_no_match", + "type": "mock" + } + } + } + }, + "components": { + "schemas": { + "Empty": { + "title": "Empty Schema", + "type": "object" + } + } + } + }, + "Name": "my-api" + } + }, + "myapiDeployment92F2CB49": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "myapi4C7BF186" + }, + "Description": "Automatically created by the RestApi construct" + } + }, + "myapiDeploymentStageprod298F01AF": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "RestApiId": { + "Ref": "myapi4C7BF186" + }, + "DeploymentId": { + "Ref": "myapiDeployment92F2CB49" + }, + "StageName": "prod" + } + }, + "myapiCloudWatchRole095452E5": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "apigateway.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + ] + } + ] + } + }, + "myapiAccountEC421A0A": { + "Type": "AWS::ApiGateway::Account", + "Properties": { + "CloudWatchRoleArn": { + "Fn::GetAtt": [ + "myapiCloudWatchRole095452E5", + "Arn" + ] + } + }, + "DependsOn": [ + "myapi4C7BF186" + ] + } + }, + "Outputs": { + "myapiEndpoint3628AFE3": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Ref": "myapi4C7BF186" + }, + ".execute-api.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "myapiDeploymentStageprod298F01AF" + }, + "/" + ] + ] + } + }, + "PetsURL": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Ref": "myapi4C7BF186" + }, + ".execute-api.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "myapiDeploymentStageprod298F01AF" + }, + "/pets" + ] + ] + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apigateway/test/integ.api-definition.inline.ts b/packages/@aws-cdk/aws-apigateway/test/integ.api-definition.inline.ts new file mode 100644 index 0000000000000..4d9f3bcf76364 --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/test/integ.api-definition.inline.ts @@ -0,0 +1,66 @@ +import * as cdk from '@aws-cdk/core'; +import * as apigateway from '../lib'; + +/* + * Stack verification steps: + * * `curl -i ` should return HTTP code 200 + */ + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'integtest-restapi-fromdefinition-inline'); + +const api = new apigateway.SpecRestApi(stack, 'my-api', { + apiDefinition: apigateway.ApiDefinition.fromInline({ + openapi: '3.0.2', + info: { + version: '1.0.0', + title: 'Test API for CDK', + }, + paths: { + '/pets': { + get: { + 'summary': 'Test Method', + 'operationId': 'testMethod', + 'responses': { + 200: { + description: 'A paged array of pets', + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/Empty', + }, + }, + }, + }, + }, + 'x-amazon-apigateway-integration': { + responses: { + default: { + statusCode: '200', + }, + }, + requestTemplates: { + 'application/json': '{"statusCode": 200}', + }, + passthroughBehavior: 'when_no_match', + type: 'mock', + }, + }, + }, + }, + components: { + schemas: { + Empty: { + title: 'Empty Schema', + type: 'object', + }, + }, + }, + }), +}); + +new cdk.CfnOutput(stack, 'PetsURL', { + value: api.urlForPath('/pets'), +}); + +app.synth(); diff --git a/packages/@aws-cdk/aws-apigateway/test/integ.restapi.vpc-endpoint.expected.json b/packages/@aws-cdk/aws-apigateway/test/integ.restapi.vpc-endpoint.expected.json index 29958c39c2759..21b7c8298d601 100644 --- a/packages/@aws-cdk/aws-apigateway/test/integ.restapi.vpc-endpoint.expected.json +++ b/packages/@aws-cdk/aws-apigateway/test/integ.restapi.vpc-endpoint.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "test-apigateway-vpcendpoint/MyVpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "test-apigateway-vpcendpoint/MyVpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "test-apigateway-vpcendpoint/MyVpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "test-apigateway-vpcendpoint/MyVpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "test-apigateway-vpcendpoint/MyVpc/PublicSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "test-apigateway-vpcendpoint/MyVpc/PublicSubnet3" } ] } @@ -316,10 +316,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "test-apigateway-vpcendpoint/MyVpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -327,6 +323,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "test-apigateway-vpcendpoint/MyVpc/PrivateSubnet1" } ] } @@ -378,10 +378,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "test-apigateway-vpcendpoint/MyVpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -389,6 +385,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "test-apigateway-vpcendpoint/MyVpc/PrivateSubnet2" } ] } @@ -440,10 +440,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "test-apigateway-vpcendpoint/MyVpc/PrivateSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -451,6 +447,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "test-apigateway-vpcendpoint/MyVpc/PrivateSubnet3" } ] } diff --git a/packages/@aws-cdk/aws-apigateway/test/sample-definition.yaml b/packages/@aws-cdk/aws-apigateway/test/sample-definition.yaml new file mode 100644 index 0000000000000..a0dd197f67c37 --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/test/sample-definition.yaml @@ -0,0 +1,30 @@ +openapi: "3.0.2" +info: + version: 1.0.0 + title: Test API for CDK +paths: + /pets: + get: + summary: Test Method + operationId: testMethod + responses: + "200": + description: A paged array of pets + content: + application/json: + schema: + $ref: "#/components/schemas/Empty" + x-amazon-apigateway-integration: + responses: + default: + statusCode: "200" + requestTemplates: + application/json: "{\"statusCode\": 200}" + passthroughBehavior: when_no_match + type: mock + +components: + schemas: + Empty: + title: Empty Schema + type: object \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apigateway/test/test.api-definition.ts b/packages/@aws-cdk/aws-apigateway/test/test.api-definition.ts new file mode 100644 index 0000000000000..7753c83fe47a8 --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/test/test.api-definition.ts @@ -0,0 +1,102 @@ +import * as s3 from '@aws-cdk/aws-s3'; +import * as cdk from '@aws-cdk/core'; +import { Test } from 'nodeunit'; +import * as path from 'path'; +import * as apigw from '../lib'; + +export = { + 'apigateway.ApiDefinition.fromJson': { + 'happy case'(test: Test) { + const stack = new cdk.Stack(); + const definition = { + key1: 'val1', + }; + const config = apigw.ApiDefinition.fromInline(definition).bind(stack); + test.deepEqual(config.inlineDefinition, definition); + test.ok(config.s3Location === undefined); + test.done(); + }, + + 'fails if Json definition is empty'(test: Test) { + test.throws( + () => defineRestApi(apigw.ApiDefinition.fromInline({})), + /cannot be empty/); + test.done(); + }, + + 'fails if definition is not an object'(test: Test) { + test.throws( + () => defineRestApi(apigw.ApiDefinition.fromInline('not-json')), + /should be of type object/); + test.done(); + }, + }, + + 'apigateway.ApiDefinition.fromAsset': { + 'happy case'(test: Test) { + const stack = new cdk.Stack(); + const config = apigw.ApiDefinition.fromAsset(path.join(__dirname, 'sample-definition.yaml')).bind(stack); + test.ok(config.inlineDefinition === undefined); + test.ok(config.s3Location !== undefined); + test.deepEqual(stack.resolve(config.s3Location!.bucket), { + Ref: 'AssetParameters68497ac876de4e963fc8f7b5f1b28844c18ecc95e3f7c6e9e0bf250e03c037fbS3Bucket42039E29', + }); + test.done(); + }, + + 'fails if a directory is given for an asset'(test: Test) { + // GIVEN + const fileAsset = apigw.ApiDefinition.fromAsset(path.join(__dirname, 'authorizers')); + + // THEN + test.throws(() => defineRestApi(fileAsset), /Asset cannot be a \.zip file or a directory/); + test.done(); + }, + + 'only one Asset object gets created even if multiple functions use the same AssetApiDefinition'(test: Test) { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'MyStack'); + const directoryAsset = apigw.ApiDefinition.fromAsset(path.join(__dirname, 'sample-definition.yaml')); + + // WHEN + new apigw.SpecRestApi(stack, 'API1', { + apiDefinition: directoryAsset, + }); + + new apigw.SpecRestApi(stack, 'API2', { + apiDefinition: directoryAsset, + }); + + // THEN + const assembly = app.synth(); + const synthesized = assembly.stacks[0]; + + // API1 has an asset, API2 does not + test.deepEqual(synthesized.assets.length, 1); + test.done(); + }, + }, + + 'apigateway.ApiDefinition.fromBucket': { + 'happy case'(test: Test) { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'my-bucket'); + const config = apigw.ApiDefinition.fromBucket(bucket, 'my-key', 'my-version').bind(stack); + test.ok(config.inlineDefinition === undefined); + test.ok(config.s3Location !== undefined); + test.deepEqual(stack.resolve(config.s3Location!.bucket), { + Ref: 'mybucket15D133BF', + }); + test.equals(config.s3Location!.key, 'my-key'); + test.done(); + }, + }, +}; + +function defineRestApi(definition: apigw.ApiDefinition) { + const stack = new cdk.Stack(); + return new apigw.SpecRestApi(stack, 'API', { + apiDefinition: definition, + }); +} diff --git a/packages/@aws-cdk/aws-apigateway/test/test.restapi.ts b/packages/@aws-cdk/aws-apigateway/test/test.restapi.ts index 6997bcf31b220..d512b924cfe98 100644 --- a/packages/@aws-cdk/aws-apigateway/test/test.restapi.ts +++ b/packages/@aws-cdk/aws-apigateway/test/test.restapi.ts @@ -13,7 +13,7 @@ export = { // WHEN const api = new apigw.RestApi(stack, 'my-api'); - api.root.addMethod('GET'); // must have at least one method + api.root.addMethod('GET'); // must have at least one method or an API definition // THEN expect(stack).toMatch({ @@ -127,7 +127,7 @@ export = { test.done(); }, - 'fails in synthesis if there are no methods'(test: Test) { + 'fails in synthesis if there are no methods or definition'(test: Test) { // GIVEN const app = new App(); const stack = new Stack(app, 'my-stack'); @@ -679,6 +679,34 @@ export = { test.done(); }, + 'addApiKey is supported'(test: Test) { + // GIVEN + const stack = new Stack(); + const api = new apigw.RestApi(stack, 'myapi'); + api.root.addMethod('OPTIONS'); + + // WHEN + api.addApiKey('myapikey', { + apiKeyName: 'myApiKey1', + value: '01234567890ABCDEFabcdef', + }); + + // THEN + expect(stack).to(haveResource('AWS::ApiGateway::ApiKey', { + Enabled: true, + Name: 'myApiKey1', + StageKeys: [ + { + RestApiId: { Ref: 'myapi162F20B8' }, + StageName: { Ref: 'myapiDeploymentStageprod329F21FF' }, + }, + ], + Value: '01234567890ABCDEFabcdef', + })); + + test.done(); + }, + 'addModel is supported'(test: Test) { // GIVEN const stack = new Stack(); diff --git a/packages/@aws-cdk/aws-apigateway/test/test.vpc-link.ts b/packages/@aws-cdk/aws-apigateway/test/test.vpc-link.ts index 0ee88589fe435..331889ffbdf1e 100644 --- a/packages/@aws-cdk/aws-apigateway/test/test.vpc-link.ts +++ b/packages/@aws-cdk/aws-apigateway/test/test.vpc-link.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import * as cdk from '@aws-cdk/core'; @@ -59,6 +59,19 @@ export = { test.done(); }, + 'import'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + apigateway.VpcLink.fromVpcLinkId(stack, 'ImportedVpcLink', 'vpclink-id'); + + // THEN + expect(stack).notTo(haveResource('AWS::ApiGateway::VpcLink')); + + test.done(); + }, + 'validation error if vpc link is created and no targets are added'(test: Test) { // GIVEN const app = new cdk.App(); diff --git a/packages/@aws-cdk/aws-apigatewayv2/.eslintrc.js b/packages/@aws-cdk/aws-apigatewayv2/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/.eslintrc.js +++ b/packages/@aws-cdk/aws-apigatewayv2/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-apigatewayv2/.gitignore b/packages/@aws-cdk/aws-apigatewayv2/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/.gitignore +++ b/packages/@aws-cdk/aws-apigatewayv2/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-apigatewayv2/.npmignore b/packages/@aws-cdk/aws-apigatewayv2/.npmignore index d4f7bff69bdab..8ac959aca8fa5 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/.npmignore +++ b/packages/@aws-cdk/aws-apigatewayv2/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json !.jsii .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-apigatewayv2/README.md b/packages/@aws-cdk/aws-apigatewayv2/README.md index 49e9530404a56..a885fa9979695 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/README.md +++ b/packages/@aws-cdk/aws-apigatewayv2/README.md @@ -19,6 +19,7 @@ - [Introduction](#introduction) - [HTTP API](#http-api) - [Defining HTTP APIs](#defining-http-apis) + - [Cross Origin Resource Sharing (CORS)](#cross-origin-resource-sharing-cors) - [Publishing HTTP APIs](#publishing-http-apis) ## Introduction @@ -88,6 +89,31 @@ new HttpApi(stack, 'HttpProxyApi', { }); ``` +### Cross Origin Resource Sharing (CORS) + +[Cross-origin resource sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) is a browser security +feature that restricts HTTP requests that are initiated from scripts running in the browser. Enabling CORS will allow +requests to your API from a web application hosted in a domain different from your API domain. + +When configured CORS for an HTTP API, API Gateway automatically sends a response to preflight `OPTIONS` requests, even +if there isn't an `OPTIONS` route configured. Note that, when this option is used, API Gateway will ignore CORS headers +returned from your backend integration. Learn more about [Configuring CORS for an HTTP +API](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-cors.html). + +The `corsPreflight` option lets you specify a CORS configuration for an API. + +```ts +new HttpApi(stack, 'HttpProxyApi', { + corsPreflight: { + allowCredentials: true, + allowHeaders: ['Authorization'], + allowMethods: [HttpMethod.GET, HttpMethod.HEAD, HttpMethod.OPTIONS, HttpMethod.POST], + allowOrigins: ['*'], + maxAge: Duration.days(10), + }, +}); +``` + ### Publishing HTTP APIs A Stage is a logical reference to a lifecycle state of your API (for example, `dev`, `prod`, `beta`, or `v2`). API diff --git a/packages/@aws-cdk/aws-apigatewayv2/jest.config.js b/packages/@aws-cdk/aws-apigatewayv2/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-apigatewayv2/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts index c0ca922a69347..7856ff5f87bf7 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts @@ -1,4 +1,4 @@ -import { Construct, IResource, Resource } from '@aws-cdk/core'; +import { Construct, Duration, IResource, Resource } from '@aws-cdk/core'; import { CfnApi, CfnApiProps } from '../apigatewayv2.generated'; import { IHttpRouteIntegration } from './integration'; import { BatchHttpRouteOptions, HttpMethod, HttpRoute, HttpRouteKey } from './route'; @@ -36,6 +36,54 @@ export interface HttpApiProps { * @default true */ readonly createDefaultStage?: boolean; + + /** + * Specifies a CORS configuration for an API. + * @see https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-cors.html + * @default - CORS disabled. + */ + readonly corsPreflight?: CorsPreflightOptions; +} + +/** + * Options for the CORS Configuration + */ +export interface CorsPreflightOptions { + /** + * Specifies whether credentials are included in the CORS request. + * @default false + */ + readonly allowCredentials?: boolean; + + /** + * Represents a collection of allowed headers. + * @default - No Headers are allowed. + */ + readonly allowHeaders?: string[]; + + /** + * Represents a collection of allowed HTTP methods. + * @default - No Methods are allowed. + */ + readonly allowMethods?: HttpMethod[]; + + /** + * Represents a collection of allowed origins. + * @default - No Origins are allowed. + */ + readonly allowOrigins?: string[]; + + /** + * Represents a collection of exposed headers. + * @default - No Expose Headers are allowed. + */ + readonly exposeHeaders?: string[]; + + /** + * The duration that the browser should cache preflight request results. + * @default Duration.seconds(0) + */ + readonly maxAge?: Duration; } /** @@ -77,10 +125,32 @@ export class HttpApi extends Resource implements IHttpApi { const apiName = props?.apiName ?? id; + let corsConfiguration: CfnApi.CorsProperty | undefined; + if (props?.corsPreflight) { + const { + allowCredentials, + allowHeaders, + allowMethods, + allowOrigins, + exposeHeaders, + maxAge, + } = props.corsPreflight; + corsConfiguration = { + allowCredentials, + allowHeaders, + allowMethods, + allowOrigins, + exposeHeaders, + maxAge: maxAge?.toSeconds(), + }; + } + const apiProps: CfnApiProps = { name: apiName, protocolType: 'HTTP', + corsConfiguration, }; + const resource = new CfnApi(this, 'Resource', apiProps); this.httpApiId = resource.ref; @@ -130,4 +200,4 @@ export class HttpApi extends Resource implements IHttpApi { integration: options.integration, })); } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-apigatewayv2/package.json b/packages/@aws-cdk/aws-apigatewayv2/package.json index bfb1d13b0f29f..0920b42061902 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2/package.json @@ -48,7 +48,8 @@ "build+test+package": "npm run build+test && npm run package" }, "cdk-build": { - "cloudformation": "AWS::ApiGatewayV2" + "cloudformation": "AWS::ApiGatewayV2", + "jest": true }, "keywords": [ "aws", @@ -61,23 +62,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -99,7 +83,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/http/integrations/http.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/http/integrations/http.test.ts index a8d69ac1009d9..cc5ed64df20eb 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/http/integrations/http.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/http/integrations/http.test.ts @@ -1,5 +1,6 @@ +import { ABSENT } from '@aws-cdk/assert'; import '@aws-cdk/assert/jest'; -import { Stack } from '@aws-cdk/core'; +import { Duration, Stack } from '@aws-cdk/core'; import { HttpApi, HttpMethod, HttpProxyIntegration, HttpRoute, HttpRouteKey } from '../../../lib'; describe('HttpProxyIntegration', () => { @@ -38,4 +39,36 @@ describe('HttpProxyIntegration', () => { IntegrationMethod: 'PATCH', }); }); -}); \ No newline at end of file + + test('CORS Configuration is correctly configured.', () => { + const stack = new Stack(); + new HttpApi(stack, 'HttpApi', { + corsPreflight: { + allowCredentials: true, + allowHeaders: ['Authorization'], + allowMethods: [HttpMethod.GET, HttpMethod.HEAD, HttpMethod.OPTIONS, HttpMethod.POST], + allowOrigins: ['*'], + maxAge: Duration.seconds(36400), + }, + }); + + expect(stack).toHaveResource('AWS::ApiGatewayV2::Api', { + CorsConfiguration: { + AllowCredentials: true, + AllowHeaders: ['Authorization'], + AllowMethods: ['GET', 'HEAD', 'OPTIONS', 'POST'], + AllowOrigins: ['*'], + MaxAge: 36400, + }, + }); + }); + + test('CorsConfiguration is ABSENT when not specified.', () => { + const stack = new Stack(); + new HttpApi(stack, 'HttpApi'); + + expect(stack).toHaveResource('AWS::ApiGatewayV2::Api', { + CorsConfiguration: ABSENT, + }); + }); +}); diff --git a/packages/@aws-cdk/aws-appconfig/.eslintrc.js b/packages/@aws-cdk/aws-appconfig/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-appconfig/.eslintrc.js +++ b/packages/@aws-cdk/aws-appconfig/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appconfig/.gitignore b/packages/@aws-cdk/aws-appconfig/.gitignore index 033e4e5147d37..094eab59919f8 100644 --- a/packages/@aws-cdk/aws-appconfig/.gitignore +++ b/packages/@aws-cdk/aws-appconfig/.gitignore @@ -16,3 +16,4 @@ coverage nyc.config.js !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-appconfig/.npmignore b/packages/@aws-cdk/aws-appconfig/.npmignore index e421b91419b9a..fb37683c5a457 100644 --- a/packages/@aws-cdk/aws-appconfig/.npmignore +++ b/packages/@aws-cdk/aws-appconfig/.npmignore @@ -20,3 +20,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-appconfig/jest.config.js b/packages/@aws-cdk/aws-appconfig/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-appconfig/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appconfig/package.json b/packages/@aws-cdk/aws-appconfig/package.json index a95facf686866..075cbadd2b42d 100644 --- a/packages/@aws-cdk/aws-appconfig/package.json +++ b/packages/@aws-cdk/aws-appconfig/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::AppConfig" + "cloudformation": "AWS::AppConfig", + "jest": true }, "keywords": [ "aws", @@ -62,7 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": {}, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -79,7 +79,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-applicationautoscaling/.eslintrc.js b/packages/@aws-cdk/aws-applicationautoscaling/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/.eslintrc.js +++ b/packages/@aws-cdk/aws-applicationautoscaling/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-applicationautoscaling/lib/schedule.ts b/packages/@aws-cdk/aws-applicationautoscaling/lib/schedule.ts index 6ce1a80bf314e..c576e17453557 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/lib/schedule.ts +++ b/packages/@aws-cdk/aws-applicationautoscaling/lib/schedule.ts @@ -66,7 +66,7 @@ export abstract class Schedule { /** * Options to configure a cron expression * - * All fields are strings so you can use complex expresions. Absence of + * All fields are strings so you can use complex expressions. Absence of * a field implies '*' or '?', whichever one is appropriate. * * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/ScheduledEvents.html#CronExpressions @@ -156,4 +156,4 @@ function maybeRate(interval: number, singular: string) { */ function makeRate(interval: number, singular: string) { return interval === 1 ? `rate(1 ${singular})` : `rate(${interval} ${singular}s)`; -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-applicationautoscaling/package.json b/packages/@aws-cdk/aws-applicationautoscaling/package.json index 08aa342068974..5f4b909ff44b4 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/package.json +++ b/packages/@aws-cdk/aws-applicationautoscaling/package.json @@ -63,7 +63,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "fast-check": "^1.24.2", @@ -86,7 +86,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "nyc": { "branches": 65, diff --git a/packages/@aws-cdk/aws-appmesh/.eslintrc.js b/packages/@aws-cdk/aws-appmesh/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-appmesh/.eslintrc.js +++ b/packages/@aws-cdk/aws-appmesh/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appmesh/package.json b/packages/@aws-cdk/aws-appmesh/package.json index c4c6d2fc2fd7f..3bbc70c2941d8 100644 --- a/packages/@aws-cdk/aws-appmesh/package.json +++ b/packages/@aws-cdk/aws-appmesh/package.json @@ -68,7 +68,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -90,7 +90,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-appmesh/test/integ.mesh.expected.json b/packages/@aws-cdk/aws-appmesh/test/integ.mesh.expected.json index 877cf3f9205ed..8b85dbbd4c515 100644 --- a/packages/@aws-cdk/aws-appmesh/test/integ.mesh.expected.json +++ b/packages/@aws-cdk/aws-appmesh/test/integ.mesh.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "mesh-stack/vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "mesh-stack/vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "mesh-stack/vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "mesh-stack/vpc/PublicSubnet2" } ] } @@ -187,10 +187,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "mesh-stack/vpc/PublicSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -198,6 +194,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "mesh-stack/vpc/PublicSubnet3" } ] } @@ -252,10 +252,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "mesh-stack/vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -263,6 +259,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "mesh-stack/vpc/PrivateSubnet1" } ] } @@ -314,10 +314,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "mesh-stack/vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -325,6 +321,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "mesh-stack/vpc/PrivateSubnet2" } ] } @@ -376,10 +376,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "mesh-stack/vpc/PrivateSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -387,6 +383,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "mesh-stack/vpc/PrivateSubnet3" } ] } diff --git a/packages/@aws-cdk/aws-appstream/.eslintrc.js b/packages/@aws-cdk/aws-appstream/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-appstream/.eslintrc.js +++ b/packages/@aws-cdk/aws-appstream/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appstream/.gitignore b/packages/@aws-cdk/aws-appstream/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-appstream/.gitignore +++ b/packages/@aws-cdk/aws-appstream/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-appstream/.npmignore b/packages/@aws-cdk/aws-appstream/.npmignore index dd7e4908d99e4..c0fc6f9e7667f 100644 --- a/packages/@aws-cdk/aws-appstream/.npmignore +++ b/packages/@aws-cdk/aws-appstream/.npmignore @@ -22,3 +22,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-appstream/jest.config.js b/packages/@aws-cdk/aws-appstream/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-appstream/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appstream/package.json b/packages/@aws-cdk/aws-appstream/package.json index b02a85e77c16d..ace96ac5c84ce 100644 --- a/packages/@aws-cdk/aws-appstream/package.json +++ b/packages/@aws-cdk/aws-appstream/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::AppStream" + "cloudformation": "AWS::AppStream", + "jest": true }, "keywords": [ "aws", @@ -61,23 +62,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-appsync/.eslintrc.js b/packages/@aws-cdk/aws-appsync/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-appsync/.eslintrc.js +++ b/packages/@aws-cdk/aws-appsync/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appsync/.gitignore b/packages/@aws-cdk/aws-appsync/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-appsync/.gitignore +++ b/packages/@aws-cdk/aws-appsync/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-appsync/.npmignore b/packages/@aws-cdk/aws-appsync/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-appsync/.npmignore +++ b/packages/@aws-cdk/aws-appsync/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-appsync/jest.config.js b/packages/@aws-cdk/aws-appsync/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-appsync/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appsync/package.json b/packages/@aws-cdk/aws-appsync/package.json index fa9a4436730a0..9cc5bfa71f0e3 100644 --- a/packages/@aws-cdk/aws-appsync/package.json +++ b/packages/@aws-cdk/aws-appsync/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::AppSync" + "cloudformation": "AWS::AppSync", + "jest": true }, "keywords": [ "aws", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -103,7 +87,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ 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 5c97b96056905..f51065c3287c2 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.graphql.expected.json +++ b/packages/@aws-cdk/aws-appsync/test/integ.graphql.expected.json @@ -43,7 +43,7 @@ "AdminCreateUserConfig": { "AllowAdminCreateUserOnly": true }, - "EmailVerificationMessage": "Hello {username}, Your verification code is {####}", + "EmailVerificationMessage": "The verification code to your new account is {####}", "EmailVerificationSubject": "Verify your new account", "SmsConfiguration": { "ExternalId": "awsappsyncintegPool5D14B05B", @@ -58,7 +58,7 @@ "UserPoolName": "myPool", "VerificationMessageTemplate": { "DefaultEmailOption": "CONFIRM_WITH_CODE", - "EmailMessage": "Hello {username}, Your verification code is {####}", + "EmailMessage": "The verification code to your new account is {####}", "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } diff --git a/packages/@aws-cdk/aws-athena/.eslintrc.js b/packages/@aws-cdk/aws-athena/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-athena/.eslintrc.js +++ b/packages/@aws-cdk/aws-athena/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-athena/.gitignore b/packages/@aws-cdk/aws-athena/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-athena/.gitignore +++ b/packages/@aws-cdk/aws-athena/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-athena/.npmignore b/packages/@aws-cdk/aws-athena/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-athena/.npmignore +++ b/packages/@aws-cdk/aws-athena/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-athena/jest.config.js b/packages/@aws-cdk/aws-athena/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-athena/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-athena/package.json b/packages/@aws-cdk/aws-athena/package.json index 553b81434ab9d..51bc934c9fdac 100644 --- a/packages/@aws-cdk/aws-athena/package.json +++ b/packages/@aws-cdk/aws-athena/package.json @@ -28,7 +28,8 @@ } }, "cdk-build": { - "cloudformation": "AWS::Athena" + "cloudformation": "AWS::Athena", + "jest": true }, "repository": { "type": "git", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-autoscaling-common/.eslintrc.js b/packages/@aws-cdk/aws-autoscaling-common/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-autoscaling-common/.eslintrc.js +++ b/packages/@aws-cdk/aws-autoscaling-common/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-autoscaling-common/package.json b/packages/@aws-cdk/aws-autoscaling-common/package.json index 0203abc566d17..4c31c377051ca 100644 --- a/packages/@aws-cdk/aws-autoscaling-common/package.json +++ b/packages/@aws-cdk/aws-autoscaling-common/package.json @@ -59,7 +59,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "fast-check": "^1.24.2", @@ -99,7 +99,7 @@ ] }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "experimental", diff --git a/packages/@aws-cdk/aws-autoscaling-hooktargets/.eslintrc.js b/packages/@aws-cdk/aws-autoscaling-hooktargets/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-autoscaling-hooktargets/.eslintrc.js +++ b/packages/@aws-cdk/aws-autoscaling-hooktargets/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-autoscaling-hooktargets/.gitignore b/packages/@aws-cdk/aws-autoscaling-hooktargets/.gitignore index 32a10d785e8fb..23a79075f642c 100644 --- a/packages/@aws-cdk/aws-autoscaling-hooktargets/.gitignore +++ b/packages/@aws-cdk/aws-autoscaling-hooktargets/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-autoscaling-hooktargets/.npmignore b/packages/@aws-cdk/aws-autoscaling-hooktargets/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-autoscaling-hooktargets/.npmignore +++ b/packages/@aws-cdk/aws-autoscaling-hooktargets/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-autoscaling-hooktargets/jest.config.js b/packages/@aws-cdk/aws-autoscaling-hooktargets/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-autoscaling-hooktargets/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json b/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json index 7842d1619cd9e..6a8d4669fc8fc 100644 --- a/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json +++ b/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json @@ -57,23 +57,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 70, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -106,11 +89,14 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "stable", "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "cdk-build": { + "jest": true + } } diff --git a/packages/@aws-cdk/aws-autoscaling/.eslintrc.js b/packages/@aws-cdk/aws-autoscaling/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-autoscaling/.eslintrc.js +++ b/packages/@aws-cdk/aws-autoscaling/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-autoscaling/lib/schedule.ts b/packages/@aws-cdk/aws-autoscaling/lib/schedule.ts index 6c74ccdca5367..3525d9b6dee0e 100644 --- a/packages/@aws-cdk/aws-autoscaling/lib/schedule.ts +++ b/packages/@aws-cdk/aws-autoscaling/lib/schedule.ts @@ -41,7 +41,7 @@ export abstract class Schedule { /** * Options to configure a cron expression * - * All fields are strings so you can use complex expresions. Absence of + * All fields are strings so you can use complex expressions. Absence of * a field implies '*' or '?', whichever one is appropriate. * * @see http://crontab.org/ @@ -91,4 +91,4 @@ class LiteralSchedule extends Schedule { function fallback(x: T | undefined, def: T): T { return x === undefined ? def : x; -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-autoscaling/package.json b/packages/@aws-cdk/aws-autoscaling/package.json index c699180609d17..a7090a8e2284f 100644 --- a/packages/@aws-cdk/aws-autoscaling/package.json +++ b/packages/@aws-cdk/aws-autoscaling/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -96,7 +96,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-autoscaling/test/integ.amazonlinux2.expected.json b/packages/@aws-cdk/aws-autoscaling/test/integ.amazonlinux2.expected.json index 39c5bc0ffebd6..30fc6784c6c04 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/integ.amazonlinux2.expected.json +++ b/packages/@aws-cdk/aws-autoscaling/test/integ.amazonlinux2.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-autoscaling-integ/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-autoscaling-integ/VPC/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-autoscaling-integ/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-autoscaling-integ/VPC/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-autoscaling/test/integ.asg-w-classic-loadbalancer.expected.json b/packages/@aws-cdk/aws-autoscaling/test/integ.asg-w-classic-loadbalancer.expected.json index 7b9cd21bff4e7..5882016a8f8b2 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/integ.asg-w-classic-loadbalancer.expected.json +++ b/packages/@aws-cdk/aws-autoscaling/test/integ.asg-w-classic-loadbalancer.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-asg-integ/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-asg-integ/VPC/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-asg-integ/VPC/PublicSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet3" } ] } @@ -316,10 +316,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-asg-integ/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -327,6 +323,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PrivateSubnet1" } ] } @@ -378,10 +378,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-asg-integ/VPC/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -389,6 +385,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PrivateSubnet2" } ] } @@ -440,10 +440,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-asg-integ/VPC/PrivateSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -451,6 +447,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PrivateSubnet3" } ] } diff --git a/packages/@aws-cdk/aws-autoscaling/test/integ.asg-w-elbv2.expected.json b/packages/@aws-cdk/aws-autoscaling/test/integ.asg-w-elbv2.expected.json index 66f8ea0e2bdfe..813d994679d01 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/integ.asg-w-elbv2.expected.json +++ b/packages/@aws-cdk/aws-autoscaling/test/integ.asg-w-elbv2.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-asg-integ/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-asg-integ/VPC/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-asg-integ/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-asg-integ/VPC/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-autoscaling/test/integ.custom-scaling.expected.json b/packages/@aws-cdk/aws-autoscaling/test/integ.custom-scaling.expected.json index ce82a1f7be835..21457d1ea78e6 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/integ.custom-scaling.expected.json +++ b/packages/@aws-cdk/aws-autoscaling/test/integ.custom-scaling.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-autoscaling-integ/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-autoscaling-integ/VPC/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-autoscaling-integ/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-autoscaling-integ/VPC/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-autoscaling/test/integ.external-role.expected.json b/packages/@aws-cdk/aws-autoscaling/test/integ.external-role.expected.json index fc4a1ed60045b..49196dcc8ba93 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/integ.external-role.expected.json +++ b/packages/@aws-cdk/aws-autoscaling/test/integ.external-role.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "integ-iam-external-role/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "integ-iam-external-role/VPC/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "integ-iam-external-role/VPC/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "integ-iam-external-role/VPC/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "integ-iam-external-role/VPC/PublicSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "integ-iam-external-role/VPC/PublicSubnet3" } ] } @@ -316,10 +316,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "integ-iam-external-role/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -327,6 +323,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "integ-iam-external-role/VPC/PrivateSubnet1" } ] } @@ -378,10 +378,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "integ-iam-external-role/VPC/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -389,6 +385,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "integ-iam-external-role/VPC/PrivateSubnet2" } ] } @@ -440,10 +440,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "integ-iam-external-role/VPC/PrivateSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -451,6 +447,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "integ-iam-external-role/VPC/PrivateSubnet3" } ] } diff --git a/packages/@aws-cdk/aws-autoscaling/test/integ.spot-instances.expected.json b/packages/@aws-cdk/aws-autoscaling/test/integ.spot-instances.expected.json index 5a38a514b146c..709737be069fe 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/integ.spot-instances.expected.json +++ b/packages/@aws-cdk/aws-autoscaling/test/integ.spot-instances.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-autoscaling-integ/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-autoscaling-integ/VPC/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-autoscaling-integ/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-autoscaling-integ/VPC/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-autoscaling-integ/VPC/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-autoscaling/test/test.auto-scaling-group.ts b/packages/@aws-cdk/aws-autoscaling/test/test.auto-scaling-group.ts index 268399634c926..7c96ba6b461f6 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/test.auto-scaling-group.ts +++ b/packages/@aws-cdk/aws-autoscaling/test/test.auto-scaling-group.ts @@ -521,16 +521,16 @@ export = { PropagateAtLaunch: true, Value: 'MyFleet', }, - { - Key: 'superfood', - PropagateAtLaunch: true, - Value: 'acai', - }, { Key: 'notsuper', PropagateAtLaunch: false, Value: 'caramel', }, + { + Key: 'superfood', + PropagateAtLaunch: true, + Value: 'acai', + }, ], })); test.done(); diff --git a/packages/@aws-cdk/aws-autoscalingplans/.eslintrc.js b/packages/@aws-cdk/aws-autoscalingplans/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-autoscalingplans/.eslintrc.js +++ b/packages/@aws-cdk/aws-autoscalingplans/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-autoscalingplans/.gitignore b/packages/@aws-cdk/aws-autoscalingplans/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-autoscalingplans/.gitignore +++ b/packages/@aws-cdk/aws-autoscalingplans/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-autoscalingplans/.npmignore b/packages/@aws-cdk/aws-autoscalingplans/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-autoscalingplans/.npmignore +++ b/packages/@aws-cdk/aws-autoscalingplans/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-autoscalingplans/jest.config.js b/packages/@aws-cdk/aws-autoscalingplans/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-autoscalingplans/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-autoscalingplans/package.json b/packages/@aws-cdk/aws-autoscalingplans/package.json index 219e08a658bf6..fb38d6163ae88 100644 --- a/packages/@aws-cdk/aws-autoscalingplans/package.json +++ b/packages/@aws-cdk/aws-autoscalingplans/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::AutoScalingPlans" + "cloudformation": "AWS::AutoScalingPlans", + "jest": true }, "keywords": [ "aws", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-backup/.eslintrc.js b/packages/@aws-cdk/aws-backup/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-backup/.eslintrc.js +++ b/packages/@aws-cdk/aws-backup/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-backup/.gitignore b/packages/@aws-cdk/aws-backup/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-backup/.gitignore +++ b/packages/@aws-cdk/aws-backup/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-backup/.npmignore b/packages/@aws-cdk/aws-backup/.npmignore index 6b86843be50f7..d04d75fba5945 100644 --- a/packages/@aws-cdk/aws-backup/.npmignore +++ b/packages/@aws-cdk/aws-backup/.npmignore @@ -22,3 +22,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-backup/jest.config.js b/packages/@aws-cdk/aws-backup/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-backup/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-backup/package.json b/packages/@aws-cdk/aws-backup/package.json index 485daed471a28..ce47e6dc2b249 100644 --- a/packages/@aws-cdk/aws-backup/package.json +++ b/packages/@aws-cdk/aws-backup/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::Backup" + "cloudformation": "AWS::Backup", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -112,7 +96,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-batch/.eslintrc.js b/packages/@aws-cdk/aws-batch/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-batch/.eslintrc.js +++ b/packages/@aws-cdk/aws-batch/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-batch/.gitignore b/packages/@aws-cdk/aws-batch/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-batch/.gitignore +++ b/packages/@aws-cdk/aws-batch/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-batch/.npmignore b/packages/@aws-cdk/aws-batch/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-batch/.npmignore +++ b/packages/@aws-cdk/aws-batch/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-batch/jest.config.js b/packages/@aws-cdk/aws-batch/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-batch/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-batch/package.json b/packages/@aws-cdk/aws-batch/package.json index 72b87a3f46aa3..958c8a3b3ab96 100644 --- a/packages/@aws-cdk/aws-batch/package.json +++ b/packages/@aws-cdk/aws-batch/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::Batch" + "cloudformation": "AWS::Batch", + "jest": true }, "keywords": [ "aws", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 60 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -104,7 +88,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "experimental", diff --git a/packages/@aws-cdk/aws-batch/test/integ.batch.expected.json b/packages/@aws-cdk/aws-batch/test/integ.batch.expected.json index 6519a5c34bb36..b1e7863929d12 100644 --- a/packages/@aws-cdk/aws-batch/test/integ.batch.expected.json +++ b/packages/@aws-cdk/aws-batch/test/integ.batch.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "batch-stack/vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "batch-stack/vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "batch-stack/vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "batch-stack/vpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "batch-stack/vpc/PublicSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "batch-stack/vpc/PublicSubnet3" } ] } @@ -316,10 +316,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "batch-stack/vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -327,6 +323,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "batch-stack/vpc/PrivateSubnet1" } ] } @@ -378,10 +378,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "batch-stack/vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -389,6 +385,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "batch-stack/vpc/PrivateSubnet2" } ] } @@ -440,10 +440,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "batch-stack/vpc/PrivateSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -451,6 +447,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "batch-stack/vpc/PrivateSubnet3" } ] } diff --git a/packages/@aws-cdk/aws-budgets/.eslintrc.js b/packages/@aws-cdk/aws-budgets/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-budgets/.eslintrc.js +++ b/packages/@aws-cdk/aws-budgets/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-budgets/.gitignore b/packages/@aws-cdk/aws-budgets/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-budgets/.gitignore +++ b/packages/@aws-cdk/aws-budgets/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-budgets/.npmignore b/packages/@aws-cdk/aws-budgets/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-budgets/.npmignore +++ b/packages/@aws-cdk/aws-budgets/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-budgets/jest.config.js b/packages/@aws-cdk/aws-budgets/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-budgets/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-budgets/package.json b/packages/@aws-cdk/aws-budgets/package.json index c6dfa0b475ad9..72264798000e0 100644 --- a/packages/@aws-cdk/aws-budgets/package.json +++ b/packages/@aws-cdk/aws-budgets/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::Budgets" + "cloudformation": "AWS::Budgets", + "jest": true }, "keywords": [ "aws", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-cassandra/.eslintrc.js b/packages/@aws-cdk/aws-cassandra/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-cassandra/.eslintrc.js +++ b/packages/@aws-cdk/aws-cassandra/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cassandra/.gitignore b/packages/@aws-cdk/aws-cassandra/.gitignore index 6031555a5720f..d57af28d42320 100644 --- a/packages/@aws-cdk/aws-cassandra/.gitignore +++ b/packages/@aws-cdk/aws-cassandra/.gitignore @@ -15,3 +15,4 @@ coverage *.snk nyc.config.js !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-cassandra/.npmignore b/packages/@aws-cdk/aws-cassandra/.npmignore index e421b91419b9a..fb37683c5a457 100644 --- a/packages/@aws-cdk/aws-cassandra/.npmignore +++ b/packages/@aws-cdk/aws-cassandra/.npmignore @@ -20,3 +20,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-cassandra/jest.config.js b/packages/@aws-cdk/aws-cassandra/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-cassandra/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cassandra/package.json b/packages/@aws-cdk/aws-cassandra/package.json index 7f629766ed2c7..d3fcec51cfd72 100644 --- a/packages/@aws-cdk/aws-cassandra/package.json +++ b/packages/@aws-cdk/aws-cassandra/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::Cassandra" + "cloudformation": "AWS::Cassandra", + "jest": true }, "keywords": [ "aws", @@ -62,7 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": {}, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -77,7 +77,7 @@ "@aws-cdk/core": "0.0.0" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-ce/.eslintrc.js b/packages/@aws-cdk/aws-ce/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-ce/.eslintrc.js +++ b/packages/@aws-cdk/aws-ce/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ce/.gitignore b/packages/@aws-cdk/aws-ce/.gitignore index 1d72e2af4beb4..e9fee23607e76 100644 --- a/packages/@aws-cdk/aws-ce/.gitignore +++ b/packages/@aws-cdk/aws-ce/.gitignore @@ -16,3 +16,4 @@ coverage *.snk nyc.config.js !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-ce/.npmignore b/packages/@aws-cdk/aws-ce/.npmignore index e421b91419b9a..fb37683c5a457 100644 --- a/packages/@aws-cdk/aws-ce/.npmignore +++ b/packages/@aws-cdk/aws-ce/.npmignore @@ -20,3 +20,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-ce/jest.config.js b/packages/@aws-cdk/aws-ce/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-ce/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ce/package.json b/packages/@aws-cdk/aws-ce/package.json index 96ddba1adbb22..a3ca1ae162847 100644 --- a/packages/@aws-cdk/aws-ce/package.json +++ b/packages/@aws-cdk/aws-ce/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::CE" + "cloudformation": "AWS::CE", + "jest": true }, "keywords": [ "aws", @@ -62,7 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": {}, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -77,7 +77,7 @@ "@aws-cdk/core": "0.0.0" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-certificatemanager/.eslintrc.js b/packages/@aws-cdk/aws-certificatemanager/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-certificatemanager/.eslintrc.js +++ b/packages/@aws-cdk/aws-certificatemanager/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-certificatemanager/package.json b/packages/@aws-cdk/aws-certificatemanager/package.json index f1ab9b89ea790..5a49b7e2639c5 100644 --- a/packages/@aws-cdk/aws-certificatemanager/package.json +++ b/packages/@aws-cdk/aws-certificatemanager/package.json @@ -63,7 +63,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "nodeunit": "^0.11.3", @@ -85,7 +85,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-chatbot/.eslintrc.js b/packages/@aws-cdk/aws-chatbot/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-chatbot/.eslintrc.js +++ b/packages/@aws-cdk/aws-chatbot/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-chatbot/.gitignore b/packages/@aws-cdk/aws-chatbot/.gitignore index 6031555a5720f..d57af28d42320 100644 --- a/packages/@aws-cdk/aws-chatbot/.gitignore +++ b/packages/@aws-cdk/aws-chatbot/.gitignore @@ -15,3 +15,4 @@ coverage *.snk nyc.config.js !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-chatbot/.npmignore b/packages/@aws-cdk/aws-chatbot/.npmignore index e421b91419b9a..fb37683c5a457 100644 --- a/packages/@aws-cdk/aws-chatbot/.npmignore +++ b/packages/@aws-cdk/aws-chatbot/.npmignore @@ -20,3 +20,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-chatbot/jest.config.js b/packages/@aws-cdk/aws-chatbot/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-chatbot/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-chatbot/package.json b/packages/@aws-cdk/aws-chatbot/package.json index c5ab42c954fbf..a2e805d6dea09 100644 --- a/packages/@aws-cdk/aws-chatbot/package.json +++ b/packages/@aws-cdk/aws-chatbot/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::Chatbot" + "cloudformation": "AWS::Chatbot", + "jest": true }, "keywords": [ "aws", @@ -62,7 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": {}, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -77,7 +77,7 @@ "@aws-cdk/core": "0.0.0" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-cloud9/.eslintrc.js b/packages/@aws-cdk/aws-cloud9/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-cloud9/.eslintrc.js +++ b/packages/@aws-cdk/aws-cloud9/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloud9/.gitignore b/packages/@aws-cdk/aws-cloud9/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-cloud9/.gitignore +++ b/packages/@aws-cdk/aws-cloud9/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-cloud9/.npmignore b/packages/@aws-cdk/aws-cloud9/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-cloud9/.npmignore +++ b/packages/@aws-cdk/aws-cloud9/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-cloud9/jest.config.js b/packages/@aws-cdk/aws-cloud9/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-cloud9/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloud9/package.json b/packages/@aws-cdk/aws-cloud9/package.json index 1f0189feabeca..4e5ce1f32e1e3 100644 --- a/packages/@aws-cdk/aws-cloud9/package.json +++ b/packages/@aws-cdk/aws-cloud9/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::Cloud9" + "cloudformation": "AWS::Cloud9", + "jest": true }, "keywords": [ "aws", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -97,7 +81,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-cloud9/test/integ.cloud9.expected.json b/packages/@aws-cdk/aws-cloud9/test/integ.cloud9.expected.json index acb59e3a7705f..13431fa4c95fb 100644 --- a/packages/@aws-cdk/aws-cloud9/test/integ.cloud9.expected.json +++ b/packages/@aws-cdk/aws-cloud9/test/integ.cloud9.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "C9Stack/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "C9Stack/VPC/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "C9Stack/VPC/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "C9Stack/VPC/PublicSubnet2" } ] } @@ -187,10 +187,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "C9Stack/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -198,6 +194,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "C9Stack/VPC/PrivateSubnet1" } ] } @@ -249,10 +249,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "C9Stack/VPC/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -260,6 +256,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "C9Stack/VPC/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-cloudformation/.eslintrc.js b/packages/@aws-cdk/aws-cloudformation/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-cloudformation/.eslintrc.js +++ b/packages/@aws-cdk/aws-cloudformation/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudformation/package.json b/packages/@aws-cdk/aws-cloudformation/package.json index ea193392b1ffd..f458900221640 100644 --- a/packages/@aws-cdk/aws-cloudformation/package.json +++ b/packages/@aws-cdk/aws-cloudformation/package.json @@ -69,7 +69,7 @@ "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", "@types/aws-lambda": "^8.10.39", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -96,7 +96,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-cloudfront/.eslintrc.js b/packages/@aws-cdk/aws-cloudfront/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-cloudfront/.eslintrc.js +++ b/packages/@aws-cdk/aws-cloudfront/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts index 6b7a530173c2d..ab5eda0eb0834 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts @@ -575,7 +575,7 @@ export interface CloudFrontWebDistributionProps { /** * The price class for the distribution (this impacts how many locations CloudFront uses for your distribution, and billing) * - * @default PriceClass.PriceClass100 the cheapest option for CloudFront is picked by default. + * @default PriceClass.PRICE_CLASS_100 the cheapest option for CloudFront is picked by default. */ readonly priceClass?: PriceClass; diff --git a/packages/@aws-cdk/aws-cloudfront/package.json b/packages/@aws-cdk/aws-cloudfront/package.json index 3df3ce2f1a7c3..0a7bb14bfb821 100644 --- a/packages/@aws-cdk/aws-cloudfront/package.json +++ b/packages/@aws-cdk/aws-cloudfront/package.json @@ -63,8 +63,8 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.672.0", + "@types/nodeunit": "^0.0.31", + "aws-sdk": "^2.678.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -91,7 +91,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "experimental", diff --git a/packages/@aws-cdk/aws-cloudtrail/.eslintrc.js b/packages/@aws-cdk/aws-cloudtrail/.eslintrc.js index 1b28bad193ceb..d8fd56c07016a 100644 --- a/packages/@aws-cdk/aws-cloudtrail/.eslintrc.js +++ b/packages/@aws-cdk/aws-cloudtrail/.eslintrc.js @@ -1,2 +1,4 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; + diff --git a/packages/@aws-cdk/aws-cloudtrail/package.json b/packages/@aws-cdk/aws-cloudtrail/package.json index 18ceeb21c90c2..91f78c400c1b8 100644 --- a/packages/@aws-cdk/aws-cloudtrail/package.json +++ b/packages/@aws-cdk/aws-cloudtrail/package.json @@ -63,8 +63,8 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.672.0", + "@types/nodeunit": "^0.0.31", + "aws-sdk": "^2.678.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -94,7 +94,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "experimental", diff --git a/packages/@aws-cdk/aws-cloudwatch-actions/.eslintrc.js b/packages/@aws-cdk/aws-cloudwatch-actions/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-cloudwatch-actions/.eslintrc.js +++ b/packages/@aws-cdk/aws-cloudwatch-actions/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudwatch-actions/.gitignore b/packages/@aws-cdk/aws-cloudwatch-actions/.gitignore index 32a10d785e8fb..23a79075f642c 100644 --- a/packages/@aws-cdk/aws-cloudwatch-actions/.gitignore +++ b/packages/@aws-cdk/aws-cloudwatch-actions/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-cloudwatch-actions/.npmignore b/packages/@aws-cdk/aws-cloudwatch-actions/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-cloudwatch-actions/.npmignore +++ b/packages/@aws-cdk/aws-cloudwatch-actions/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-cloudwatch-actions/jest.config.js b/packages/@aws-cdk/aws-cloudwatch-actions/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudwatch-actions/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudwatch-actions/package.json b/packages/@aws-cdk/aws-cloudwatch-actions/package.json index 6fbb4ee0989af..eefec8c4a581d 100644 --- a/packages/@aws-cdk/aws-cloudwatch-actions/package.json +++ b/packages/@aws-cdk/aws-cloudwatch-actions/package.json @@ -57,23 +57,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 70, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -104,7 +87,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "stable", "awslint": { @@ -117,5 +100,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "cdk-build": { + "jest": true + } } diff --git a/packages/@aws-cdk/aws-cloudwatch/.eslintrc.js b/packages/@aws-cdk/aws-cloudwatch/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-cloudwatch/.eslintrc.js +++ b/packages/@aws-cdk/aws-cloudwatch/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudwatch/package.json b/packages/@aws-cdk/aws-cloudwatch/package.json index b301ce00af9fc..2f4d2e1fe139d 100644 --- a/packages/@aws-cdk/aws-cloudwatch/package.json +++ b/packages/@aws-cdk/aws-cloudwatch/package.json @@ -63,7 +63,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -103,7 +103,7 @@ ] }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "stable", "awscdkio": { diff --git a/packages/@aws-cdk/aws-codebuild/.eslintrc.js b/packages/@aws-cdk/aws-codebuild/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-codebuild/.eslintrc.js +++ b/packages/@aws-cdk/aws-codebuild/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codebuild/package.json b/packages/@aws-cdk/aws-codebuild/package.json index 23017a58a7430..77829647d1092 100644 --- a/packages/@aws-cdk/aws-codebuild/package.json +++ b/packages/@aws-cdk/aws-codebuild/package.json @@ -69,8 +69,8 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", - "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.672.0", + "@types/nodeunit": "^0.0.31", + "aws-sdk": "^2.678.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -111,7 +111,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.project-file-system-location.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.project-file-system-location.expected.json index 5e52b1ef3dedd..c23bcab0e013a 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.project-file-system-location.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.project-file-system-location.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-codebuild-file-system-locations/MyVPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-codebuild-file-system-locations/MyVPC/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-codebuild-file-system-locations/MyVPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-codebuild-file-system-locations/MyVPC/PrivateSubnet1" } ] } diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.project-vpc.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.project-vpc.expected.json index 24c0355839d69..2e46025573d0b 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.project-vpc.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.project-vpc.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-codebuild-project-vpc/MyVPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-codebuild-project-vpc/MyVPC/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-codebuild-project-vpc/MyVPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-codebuild-project-vpc/MyVPC/PrivateSubnet1" } ] } diff --git a/packages/@aws-cdk/aws-codecommit/.eslintrc.js b/packages/@aws-cdk/aws-codecommit/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-codecommit/.eslintrc.js +++ b/packages/@aws-cdk/aws-codecommit/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codecommit/package.json b/packages/@aws-cdk/aws-codecommit/package.json index affeceeeca8a9..41b634411314f 100644 --- a/packages/@aws-cdk/aws-codecommit/package.json +++ b/packages/@aws-cdk/aws-codecommit/package.json @@ -69,8 +69,8 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", - "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.672.0", + "@types/nodeunit": "^0.0.31", + "aws-sdk": "^2.678.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -91,7 +91,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "stable", "awslint": { diff --git a/packages/@aws-cdk/aws-codedeploy/.eslintrc.js b/packages/@aws-cdk/aws-codedeploy/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-codedeploy/.eslintrc.js +++ b/packages/@aws-cdk/aws-codedeploy/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codedeploy/package.json b/packages/@aws-cdk/aws-codedeploy/package.json index cca5d4dee2f00..65599aa94455b 100644 --- a/packages/@aws-cdk/aws-codedeploy/package.json +++ b/packages/@aws-cdk/aws-codedeploy/package.json @@ -66,7 +66,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -99,7 +99,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-codedeploy/test/server/integ.deployment-group.expected.json b/packages/@aws-cdk/aws-codedeploy/test/server/integ.deployment-group.expected.json index 002dd0df2e6f9..c463bc84e8df3 100644 --- a/packages/@aws-cdk/aws-codedeploy/test/server/integ.deployment-group.expected.json +++ b/packages/@aws-cdk/aws-codedeploy/test/server/integ.deployment-group.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-codedeploy-server-dg/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-codedeploy-server-dg/VPC/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-codedeploy-server-dg/VPC/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-codedeploy-server-dg/VPC/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-codedeploy-server-dg/VPC/PublicSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-codedeploy-server-dg/VPC/PublicSubnet3" } ] } @@ -316,10 +316,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-codedeploy-server-dg/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -327,6 +323,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-codedeploy-server-dg/VPC/PrivateSubnet1" } ] } @@ -378,10 +378,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-codedeploy-server-dg/VPC/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -389,6 +385,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-codedeploy-server-dg/VPC/PrivateSubnet2" } ] } @@ -440,10 +440,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-codedeploy-server-dg/VPC/PrivateSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -451,6 +447,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-codedeploy-server-dg/VPC/PrivateSubnet3" } ] } diff --git a/packages/@aws-cdk/aws-codeguruprofiler/.eslintrc.js b/packages/@aws-cdk/aws-codeguruprofiler/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-codeguruprofiler/.eslintrc.js +++ b/packages/@aws-cdk/aws-codeguruprofiler/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codeguruprofiler/.gitignore b/packages/@aws-cdk/aws-codeguruprofiler/.gitignore index 6031555a5720f..d57af28d42320 100644 --- a/packages/@aws-cdk/aws-codeguruprofiler/.gitignore +++ b/packages/@aws-cdk/aws-codeguruprofiler/.gitignore @@ -15,3 +15,4 @@ coverage *.snk nyc.config.js !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-codeguruprofiler/.npmignore b/packages/@aws-cdk/aws-codeguruprofiler/.npmignore index e421b91419b9a..fb37683c5a457 100644 --- a/packages/@aws-cdk/aws-codeguruprofiler/.npmignore +++ b/packages/@aws-cdk/aws-codeguruprofiler/.npmignore @@ -20,3 +20,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-codeguruprofiler/jest.config.js b/packages/@aws-cdk/aws-codeguruprofiler/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-codeguruprofiler/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codeguruprofiler/package.json b/packages/@aws-cdk/aws-codeguruprofiler/package.json index 6abb9a28a4273..71efbaf81a1d0 100644 --- a/packages/@aws-cdk/aws-codeguruprofiler/package.json +++ b/packages/@aws-cdk/aws-codeguruprofiler/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::CodeGuruProfiler" + "cloudformation": "AWS::CodeGuruProfiler", + "jest": true }, "keywords": [ "aws", @@ -62,7 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": {}, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -77,7 +77,7 @@ "@aws-cdk/core": "0.0.0" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-codepipeline-actions/.eslintrc.js b/packages/@aws-cdk/aws-codepipeline-actions/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/.eslintrc.js +++ b/packages/@aws-cdk/aws-codepipeline-actions/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codepipeline-actions/package.json b/packages/@aws-cdk/aws-codepipeline-actions/package.json index 70d8ff02b9ba4..95b7d17c69e87 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/package.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/package.json @@ -64,8 +64,8 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-cloudtrail": "0.0.0", - "@types/lodash": "^4.14.150", - "@types/nodeunit": "^0.0.30", + "@types/lodash": "^4.14.151", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "lodash": "^4.17.15", @@ -116,7 +116,7 @@ "case" ], "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "stable", "awslint": { diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecs-deploy.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecs-deploy.expected.json index bb730aef79421..34a425b48a1a6 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecs-deploy.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecs-deploy.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-codepipeline-ecs-deploy/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-codepipeline-ecs-deploy/VPC/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-codepipeline-ecs-deploy/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-codepipeline-ecs-deploy/VPC/PrivateSubnet1" } ] } diff --git a/packages/@aws-cdk/aws-codepipeline/.eslintrc.js b/packages/@aws-cdk/aws-codepipeline/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-codepipeline/.eslintrc.js +++ b/packages/@aws-cdk/aws-codepipeline/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codepipeline/package.json b/packages/@aws-cdk/aws-codepipeline/package.json index 50bae2c548457..36154be191da0 100644 --- a/packages/@aws-cdk/aws-codepipeline/package.json +++ b/packages/@aws-cdk/aws-codepipeline/package.json @@ -68,7 +68,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -93,7 +93,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-codestar/.eslintrc.js b/packages/@aws-cdk/aws-codestar/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-codestar/.eslintrc.js +++ b/packages/@aws-cdk/aws-codestar/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codestar/.gitignore b/packages/@aws-cdk/aws-codestar/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-codestar/.gitignore +++ b/packages/@aws-cdk/aws-codestar/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-codestar/.npmignore b/packages/@aws-cdk/aws-codestar/.npmignore index 6b86843be50f7..d04d75fba5945 100644 --- a/packages/@aws-cdk/aws-codestar/.npmignore +++ b/packages/@aws-cdk/aws-codestar/.npmignore @@ -22,3 +22,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-codestar/jest.config.js b/packages/@aws-cdk/aws-codestar/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-codestar/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codestar/package.json b/packages/@aws-cdk/aws-codestar/package.json index d91796650b705..d0c07ad1c6489 100644 --- a/packages/@aws-cdk/aws-codestar/package.json +++ b/packages/@aws-cdk/aws-codestar/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::CodeStar" + "cloudformation": "AWS::CodeStar", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -95,7 +79,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-codestarconnections/.eslintrc.js b/packages/@aws-cdk/aws-codestarconnections/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-codestarconnections/.eslintrc.js +++ b/packages/@aws-cdk/aws-codestarconnections/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codestarconnections/.gitignore b/packages/@aws-cdk/aws-codestarconnections/.gitignore index 6031555a5720f..d57af28d42320 100644 --- a/packages/@aws-cdk/aws-codestarconnections/.gitignore +++ b/packages/@aws-cdk/aws-codestarconnections/.gitignore @@ -15,3 +15,4 @@ coverage *.snk nyc.config.js !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-codestarconnections/.npmignore b/packages/@aws-cdk/aws-codestarconnections/.npmignore index e421b91419b9a..fb37683c5a457 100644 --- a/packages/@aws-cdk/aws-codestarconnections/.npmignore +++ b/packages/@aws-cdk/aws-codestarconnections/.npmignore @@ -20,3 +20,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-codestarconnections/jest.config.js b/packages/@aws-cdk/aws-codestarconnections/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-codestarconnections/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codestarconnections/package.json b/packages/@aws-cdk/aws-codestarconnections/package.json index 0dd0bda80fb38..f00755a028d27 100644 --- a/packages/@aws-cdk/aws-codestarconnections/package.json +++ b/packages/@aws-cdk/aws-codestarconnections/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::CodeStarConnections" + "cloudformation": "AWS::CodeStarConnections", + "jest": true }, "keywords": [ "aws", @@ -62,7 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": {}, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -77,7 +77,7 @@ "@aws-cdk/core": "0.0.0" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-codestarnotifications/.eslintrc.js b/packages/@aws-cdk/aws-codestarnotifications/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-codestarnotifications/.eslintrc.js +++ b/packages/@aws-cdk/aws-codestarnotifications/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codestarnotifications/.gitignore b/packages/@aws-cdk/aws-codestarnotifications/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-codestarnotifications/.gitignore +++ b/packages/@aws-cdk/aws-codestarnotifications/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-codestarnotifications/.npmignore b/packages/@aws-cdk/aws-codestarnotifications/.npmignore index d4f7bff69bdab..8ac959aca8fa5 100644 --- a/packages/@aws-cdk/aws-codestarnotifications/.npmignore +++ b/packages/@aws-cdk/aws-codestarnotifications/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json !.jsii .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-codestarnotifications/jest.config.js b/packages/@aws-cdk/aws-codestarnotifications/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-codestarnotifications/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codestarnotifications/package.json b/packages/@aws-cdk/aws-codestarnotifications/package.json index 4e02146eddb84..fc2af8c156c95 100644 --- a/packages/@aws-cdk/aws-codestarnotifications/package.json +++ b/packages/@aws-cdk/aws-codestarnotifications/package.json @@ -48,7 +48,8 @@ "build+test+package": "npm run build+test && npm run package" }, "cdk-build": { - "cloudformation": "AWS::CodeStarNotifications" + "cloudformation": "AWS::CodeStarNotifications", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -95,7 +79,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-cognito/.eslintrc.js b/packages/@aws-cdk/aws-cognito/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-cognito/.eslintrc.js +++ b/packages/@aws-cdk/aws-cognito/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cognito/.gitignore b/packages/@aws-cdk/aws-cognito/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-cognito/.gitignore +++ b/packages/@aws-cdk/aws-cognito/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-cognito/.npmignore b/packages/@aws-cdk/aws-cognito/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-cognito/.npmignore +++ b/packages/@aws-cdk/aws-cognito/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-cognito/README.md b/packages/@aws-cdk/aws-cognito/README.md index 4c9a5c60ea77f..9886fdbbd2442 100644 --- a/packages/@aws-cdk/aws-cognito/README.md +++ b/packages/@aws-cdk/aws-cognito/README.md @@ -400,6 +400,20 @@ pool.addClient('app-client', { }); ``` +An app client can be configured to prevent user existence errors. This +instructs the Cognito authentication API to return generic authentication +failure responses instead of an UserNotFoundException. By default, the flag +is not set, which means different things for existing and new stacks. See the +[documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pool-managing-errors.html) +for the full details on the behavior of this flag. + +```ts +const pool = new UserPool(this, 'Pool'); +pool.addClient('app-client', { + preventUserExistenceErrors: true, +}); +``` + ### Domains After setting up an [app client](#app-clients), the address for the user pool's sign-up and sign-in webpages can be @@ -429,4 +443,4 @@ pool.addDomain('CustomDomain', { Read more about [Using the Amazon Cognito Domain](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-assign-domain-prefix.html) and [Using Your Own -Domain](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-add-custom-domain.html). \ No newline at end of file +Domain](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-add-custom-domain.html). diff --git a/packages/@aws-cdk/aws-cognito/jest.config.js b/packages/@aws-cdk/aws-cognito/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-cognito/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts index cde6bf72191ca..039c17376b8fe 100644 --- a/packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts @@ -173,6 +173,15 @@ export interface UserPoolClientOptions { * @default - see defaults in `OAuthSettings` */ readonly oAuth?: OAuthSettings; + + /** + * Whether Cognito returns a UserNotFoundException exception when the + * user does not exist in the user pool (false), or whether it returns + * another type of error that doesn't reveal the user's absence. + * @see https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pool-managing-errors.html + * @default true for new stacks + */ + readonly preventUserExistenceErrors?: boolean; } /** @@ -234,6 +243,7 @@ export class UserPoolClient extends Resource implements IUserPoolClient { allowedOAuthScopes: this.configureOAuthScopes(props.oAuth), callbackUrLs: (props.oAuth?.callbackUrls && props.oAuth?.callbackUrls.length > 0) ? props.oAuth?.callbackUrls : undefined, allowedOAuthFlowsUserPoolClient: props.oAuth ? true : undefined, + preventUserExistenceErrors: this.configurePreventUserExistenceErrors(props.preventUserExistenceErrors), }); this.userPoolClientId = resource.ref; @@ -297,4 +307,11 @@ export class UserPoolClient extends Resource implements IUserPoolClient { } return undefined; } + + private configurePreventUserExistenceErrors(prevent?: boolean): string | undefined { + if (prevent === undefined) { + return undefined; + } + return prevent ? 'ENABLED' : 'LEGACY'; + } } diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts index b8ba8176be0a9..38b89abf288d5 100644 --- a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts @@ -243,8 +243,8 @@ export interface UserVerificationConfig { * See https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pool-settings-message-templates.html to * learn more about message templates. * - * @default - 'Hello {username}, Your verification code is {####}' if VerificationEmailStyle.CODE is chosen, - * 'Hello {username}, Verify your account by clicking on {##Verify Email##}' if VerificationEmailStyle.LINK is chosen. + * @default - 'The verification code to your new account is {####}' if VerificationEmailStyle.CODE is chosen, + * 'Verify your account by clicking on {##Verify Email##}' if VerificationEmailStyle.LINK is chosen. */ readonly emailBody?: string; @@ -690,7 +690,6 @@ export class UserPool extends Resource implements IUserPool { } private verificationMessageConfiguration(props: UserPoolProps): CfnUserPool.VerificationMessageTemplateProperty { - const USERNAME_TEMPLATE = '{username}'; const CODE_TEMPLATE = '{####}'; const VERIFY_EMAIL_TEMPLATE = '{##Verify Email##}'; @@ -699,7 +698,7 @@ export class UserPool extends Resource implements IUserPool { const smsMessage = props.userVerification?.smsMessage ?? `The verification code to your new account is ${CODE_TEMPLATE}`; if (emailStyle === VerificationEmailStyle.CODE) { - const emailMessage = props.userVerification?.emailBody ?? `Hello ${USERNAME_TEMPLATE}, Your verification code is ${CODE_TEMPLATE}`; + const emailMessage = props.userVerification?.emailBody ?? `The verification code to your new account is ${CODE_TEMPLATE}`; if (emailMessage.indexOf(CODE_TEMPLATE) < 0) { throw new Error(`Verification email body must contain the template string '${CODE_TEMPLATE}'`); } @@ -714,7 +713,7 @@ export class UserPool extends Resource implements IUserPool { }; } else { const emailMessage = props.userVerification?.emailBody ?? - `Hello ${USERNAME_TEMPLATE}, Verify your account by clicking on ${VERIFY_EMAIL_TEMPLATE}`; + `Verify your account by clicking on ${VERIFY_EMAIL_TEMPLATE}`; if (emailMessage.indexOf(VERIFY_EMAIL_TEMPLATE) < 0) { throw new Error(`Verification email body must contain the template string '${VERIFY_EMAIL_TEMPLATE}'`); } diff --git a/packages/@aws-cdk/aws-cognito/package.json b/packages/@aws-cdk/aws-cognito/package.json index aca0c4ece946d..d3f83d76fcb5c 100644 --- a/packages/@aws-cdk/aws-cognito/package.json +++ b/packages/@aws-cdk/aws-cognito/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::Cognito" + "cloudformation": "AWS::Cognito", + "jest": true }, "keywords": [ "aws", @@ -63,7 +64,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -88,9 +89,8 @@ "@aws-cdk/custom-resources": "0.0.0", "constructs": "^3.0.2" }, - "jest": {}, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ 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 f3da0535c775d..63556451e98ff 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 @@ -43,7 +43,7 @@ "AdminCreateUserConfig": { "AllowAdminCreateUserOnly": true }, - "EmailVerificationMessage": "Hello {username}, Your verification code is {####}", + "EmailVerificationMessage": "The verification code to your new account is {####}", "EmailVerificationSubject": "Verify your new account", "SmsConfiguration": { "ExternalId": "integuserpoolclientexplicitpropsmyuserpoolFC6541FF", @@ -57,7 +57,7 @@ "SmsVerificationMessage": "The verification code to your new account is {####}", "VerificationMessageTemplate": { "DefaultEmailOption": "CONFIRM_WITH_CODE", - "EmailMessage": "Hello {username}, Your verification code is {####}", + "EmailMessage": "The verification code to your new account is {####}", "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } @@ -93,8 +93,9 @@ "ALLOW_USER_SRP_AUTH", "ALLOW_REFRESH_TOKEN_AUTH" ], - "GenerateSecret": true + "GenerateSecret": true, + "PreventUserExistenceErrors": "ENABLED" } } } -} \ No newline at end of file +} 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 4870ab2276738..92a8bd8f19321 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 @@ -31,4 +31,5 @@ userpool.addClient('myuserpoolclient', { ], callbackUrls: [ 'https://redirect-here.myapp.com' ], }, -}); \ No newline at end of file + preventUserExistenceErrors: true, +}); 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 b1e726042529a..15fd0ce903e93 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 @@ -43,7 +43,7 @@ "AdminCreateUserConfig": { "AllowAdminCreateUserOnly": true }, - "EmailVerificationMessage": "Hello {username}, Your verification code is {####}", + "EmailVerificationMessage": "The verification code to your new account is {####}", "EmailVerificationSubject": "Verify your new account", "SmsConfiguration": { "ExternalId": "integuserpooldomaincfdistUserPool17475E8A", @@ -57,7 +57,7 @@ "SmsVerificationMessage": "The verification code to your new account is {####}", "VerificationMessageTemplate": { "DefaultEmailOption": "CONFIRM_WITH_CODE", - "EmailMessage": "Hello {username}, Your verification code is {####}", + "EmailMessage": "The verification code to your new account is {####}", "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } 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 712d5ca0de932..075fb3542f6ad 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 @@ -43,7 +43,7 @@ "AdminCreateUserConfig": { "AllowAdminCreateUserOnly": true }, - "EmailVerificationMessage": "Hello {username}, Your verification code is {####}", + "EmailVerificationMessage": "The verification code to your new account is {####}", "EmailVerificationSubject": "Verify your new account", "SmsConfiguration": { "ExternalId": "integuserpoolmyuserpoolDA38443C", @@ -58,7 +58,7 @@ "UserPoolName": "MyUserPool", "VerificationMessageTemplate": { "DefaultEmailOption": "CONFIRM_WITH_CODE", - "EmailMessage": "Hello {username}, Your verification code is {####}", + "EmailMessage": "The verification code to your new account is {####}", "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } diff --git a/packages/@aws-cdk/aws-cognito/test/user-pool-client.test.ts b/packages/@aws-cdk/aws-cognito/test/user-pool-client.test.ts index d309f379611a2..d1e0862df0a50 100644 --- a/packages/@aws-cdk/aws-cognito/test/user-pool-client.test.ts +++ b/packages/@aws-cdk/aws-cognito/test/user-pool-client.test.ts @@ -283,4 +283,57 @@ describe('User Pool Client', () => { AllowedOAuthScopes: [ 'aws.cognito.signin.user.admin' ], }); }); + + test('enable user existence errors prevention', () => { + // GIVEN + const stack = new Stack(); + const pool = new UserPool(stack, 'Pool'); + + // WHEN + new UserPoolClient(stack, 'Client', { + userPool: pool, + preventUserExistenceErrors: true, + }); + + // THEN + expect(stack).toHaveResource('AWS::Cognito::UserPoolClient', { + UserPoolId: stack.resolve(pool.userPoolId), + PreventUserExistenceErrors: 'ENABLED', + }); + }); + + test('disable user existence errors prevention', () => { + // GIVEN + const stack = new Stack(); + const pool = new UserPool(stack, 'Pool'); + + // WHEN + new UserPoolClient(stack, 'Client', { + userPool: pool, + preventUserExistenceErrors: false, + }); + + // THEN + expect(stack).toHaveResource('AWS::Cognito::UserPoolClient', { + UserPoolId: stack.resolve(pool.userPoolId), + PreventUserExistenceErrors: 'LEGACY', + }); + }); + + test('user existence errors prevention is absent by default', () => { + // GIVEN + const stack = new Stack(); + const pool = new UserPool(stack, 'Pool'); + + // WHEN + new UserPoolClient(stack, 'Client', { + userPool: pool, + }); + + // THEN + expect(stack).toHaveResource('AWS::Cognito::UserPoolClient', { + UserPoolId: stack.resolve(pool.userPoolId), + PreventUserExistenceErrors: ABSENT, + }); + }); }); \ No newline at end of file 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 904c5823302ea..449aa27403acb 100644 --- a/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts +++ b/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts @@ -19,12 +19,12 @@ describe('User Pool', () => { AllowAdminCreateUserOnly: true, InviteMessageTemplate: ABSENT, }, - EmailVerificationMessage: 'Hello {username}, Your verification code is {####}', + EmailVerificationMessage: 'The verification code to your new account is {####}', EmailVerificationSubject: 'Verify your new account', SmsVerificationMessage: 'The verification code to your new account is {####}', VerificationMessageTemplate: { DefaultEmailOption: 'CONFIRM_WITH_CODE', - EmailMessage: 'Hello {username}, Your verification code is {####}', + EmailMessage: 'The verification code to your new account is {####}', EmailSubject: 'Verify your new account', SmsMessage: 'The verification code to your new account is {####}', }, @@ -108,7 +108,7 @@ describe('User Pool', () => { SmsVerificationMessage: 'The verification code to your new account is {####}', VerificationMessageTemplate: { DefaultEmailOption: 'CONFIRM_WITH_LINK', - EmailMessageByLink: 'Hello {username}, Verify your account by clicking on {##Verify Email##}', + EmailMessageByLink: 'Verify your account by clicking on {##Verify Email##}', EmailSubjectByLink: 'Verify your new account', SmsMessage: 'The verification code to your new account is {####}', }, diff --git a/packages/@aws-cdk/aws-config/.eslintrc.js b/packages/@aws-cdk/aws-config/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-config/.eslintrc.js +++ b/packages/@aws-cdk/aws-config/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-config/package.json b/packages/@aws-cdk/aws-config/package.json index 283ada15a91fb..7f12b80773cb3 100644 --- a/packages/@aws-cdk/aws-config/package.json +++ b/packages/@aws-cdk/aws-config/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-events-targets": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -89,7 +89,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "developer-preview", diff --git a/packages/@aws-cdk/aws-datapipeline/.eslintrc.js b/packages/@aws-cdk/aws-datapipeline/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-datapipeline/.eslintrc.js +++ b/packages/@aws-cdk/aws-datapipeline/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-datapipeline/.gitignore b/packages/@aws-cdk/aws-datapipeline/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-datapipeline/.gitignore +++ b/packages/@aws-cdk/aws-datapipeline/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-datapipeline/.npmignore b/packages/@aws-cdk/aws-datapipeline/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-datapipeline/.npmignore +++ b/packages/@aws-cdk/aws-datapipeline/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-datapipeline/jest.config.js b/packages/@aws-cdk/aws-datapipeline/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-datapipeline/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-datapipeline/package.json b/packages/@aws-cdk/aws-datapipeline/package.json index d5cd0365b585d..0c3c5712c7919 100644 --- a/packages/@aws-cdk/aws-datapipeline/package.json +++ b/packages/@aws-cdk/aws-datapipeline/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::DataPipeline" + "cloudformation": "AWS::DataPipeline", + "jest": true }, "keywords": [ "aws", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-dax/.eslintrc.js b/packages/@aws-cdk/aws-dax/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-dax/.eslintrc.js +++ b/packages/@aws-cdk/aws-dax/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dax/.gitignore b/packages/@aws-cdk/aws-dax/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-dax/.gitignore +++ b/packages/@aws-cdk/aws-dax/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-dax/.npmignore b/packages/@aws-cdk/aws-dax/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-dax/.npmignore +++ b/packages/@aws-cdk/aws-dax/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-dax/jest.config.js b/packages/@aws-cdk/aws-dax/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-dax/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dax/package.json b/packages/@aws-cdk/aws-dax/package.json index 341082aed5498..7fe462acd30c6 100644 --- a/packages/@aws-cdk/aws-dax/package.json +++ b/packages/@aws-cdk/aws-dax/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::DAX" + "cloudformation": "AWS::DAX", + "jest": true }, "keywords": [ "aws", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-detective/.eslintrc.js b/packages/@aws-cdk/aws-detective/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-detective/.eslintrc.js +++ b/packages/@aws-cdk/aws-detective/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-detective/.gitignore b/packages/@aws-cdk/aws-detective/.gitignore index 1d72e2af4beb4..e9fee23607e76 100644 --- a/packages/@aws-cdk/aws-detective/.gitignore +++ b/packages/@aws-cdk/aws-detective/.gitignore @@ -16,3 +16,4 @@ coverage *.snk nyc.config.js !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-detective/.npmignore b/packages/@aws-cdk/aws-detective/.npmignore index e421b91419b9a..fb37683c5a457 100644 --- a/packages/@aws-cdk/aws-detective/.npmignore +++ b/packages/@aws-cdk/aws-detective/.npmignore @@ -20,3 +20,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-detective/jest.config.js b/packages/@aws-cdk/aws-detective/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-detective/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-detective/package.json b/packages/@aws-cdk/aws-detective/package.json index 0022c783802fe..e8a168b25ca28 100644 --- a/packages/@aws-cdk/aws-detective/package.json +++ b/packages/@aws-cdk/aws-detective/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::Detective" + "cloudformation": "AWS::Detective", + "jest": true }, "keywords": [ "aws", @@ -62,7 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": {}, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -77,7 +77,7 @@ "@aws-cdk/core": "0.0.0" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "awscdkio": { diff --git a/packages/@aws-cdk/aws-directoryservice/.eslintrc.js b/packages/@aws-cdk/aws-directoryservice/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-directoryservice/.eslintrc.js +++ b/packages/@aws-cdk/aws-directoryservice/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-directoryservice/.gitignore b/packages/@aws-cdk/aws-directoryservice/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-directoryservice/.gitignore +++ b/packages/@aws-cdk/aws-directoryservice/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-directoryservice/.npmignore b/packages/@aws-cdk/aws-directoryservice/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-directoryservice/.npmignore +++ b/packages/@aws-cdk/aws-directoryservice/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-directoryservice/jest.config.js b/packages/@aws-cdk/aws-directoryservice/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-directoryservice/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-directoryservice/package.json b/packages/@aws-cdk/aws-directoryservice/package.json index faa7bcc493b8d..462f8cdfcdf8d 100644 --- a/packages/@aws-cdk/aws-directoryservice/package.json +++ b/packages/@aws-cdk/aws-directoryservice/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::DirectoryService" + "cloudformation": "AWS::DirectoryService", + "jest": true }, "keywords": [ "aws", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-dlm/.eslintrc.js b/packages/@aws-cdk/aws-dlm/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-dlm/.eslintrc.js +++ b/packages/@aws-cdk/aws-dlm/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dlm/.gitignore b/packages/@aws-cdk/aws-dlm/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-dlm/.gitignore +++ b/packages/@aws-cdk/aws-dlm/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-dlm/.npmignore b/packages/@aws-cdk/aws-dlm/.npmignore index dd7e4908d99e4..c0fc6f9e7667f 100644 --- a/packages/@aws-cdk/aws-dlm/.npmignore +++ b/packages/@aws-cdk/aws-dlm/.npmignore @@ -22,3 +22,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-dlm/jest.config.js b/packages/@aws-cdk/aws-dlm/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-dlm/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dlm/package.json b/packages/@aws-cdk/aws-dlm/package.json index eaa009fcf1384..52e12eb311682 100644 --- a/packages/@aws-cdk/aws-dlm/package.json +++ b/packages/@aws-cdk/aws-dlm/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::DLM" + "cloudformation": "AWS::DLM", + "jest": true }, "keywords": [ "aws", @@ -61,23 +62,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-dms/.eslintrc.js b/packages/@aws-cdk/aws-dms/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-dms/.eslintrc.js +++ b/packages/@aws-cdk/aws-dms/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dms/.gitignore b/packages/@aws-cdk/aws-dms/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-dms/.gitignore +++ b/packages/@aws-cdk/aws-dms/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-dms/.npmignore b/packages/@aws-cdk/aws-dms/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-dms/.npmignore +++ b/packages/@aws-cdk/aws-dms/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-dms/jest.config.js b/packages/@aws-cdk/aws-dms/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-dms/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dms/package.json b/packages/@aws-cdk/aws-dms/package.json index 21ee20a03e810..901a5631b8aba 100644 --- a/packages/@aws-cdk/aws-dms/package.json +++ b/packages/@aws-cdk/aws-dms/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::DMS" + "cloudformation": "AWS::DMS", + "jest": true }, "keywords": [ "aws", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-docdb/.eslintrc.js b/packages/@aws-cdk/aws-docdb/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-docdb/.eslintrc.js +++ b/packages/@aws-cdk/aws-docdb/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-docdb/.gitignore b/packages/@aws-cdk/aws-docdb/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-docdb/.gitignore +++ b/packages/@aws-cdk/aws-docdb/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-docdb/.npmignore b/packages/@aws-cdk/aws-docdb/.npmignore index dd7e4908d99e4..c0fc6f9e7667f 100644 --- a/packages/@aws-cdk/aws-docdb/.npmignore +++ b/packages/@aws-cdk/aws-docdb/.npmignore @@ -22,3 +22,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-docdb/README.md b/packages/@aws-cdk/aws-docdb/README.md index 0792cace4242f..a2d38da952212 100644 --- a/packages/@aws-cdk/aws-docdb/README.md +++ b/packages/@aws-cdk/aws-docdb/README.md @@ -6,11 +6,81 @@ > All classes with the `Cfn` prefix in this module ([CFN Resources](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) are always stable and safe to use. +![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge) + +> The APIs of higher level constructs in this module are experimental and under active development. They are subject to non-backward compatible changes or removal in any future version. These are not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be announced in the release notes. This means that while you may use them, you may need to update your source code when upgrading to a newer version of this package. + --- -This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. +### Starting a Clustered Database + +To set up a clustered DocumentDB database, define a `DatabaseCluster`. You must +always launch a database in a VPC. Use the `vpcSubnets` attribute to control whether +your instances will be launched privately or publicly: + +```ts +const cluster = new DatabaseCluster(this, 'Database', { + masterUser: { + username: 'admin' + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.LARGE), + vpcSubnets: { + subnetType: ec2.SubnetType.PUBLIC, + }, + vpc + } +}); +``` +By default, the master password will be generated and stored in AWS Secrets Manager with auto-generated description. + +Your cluster will be empty by default. + +### Connecting + +To control who can access the cluster, use the `.connections` attribute. DocumentDB databases have a default port, so +you don't need to specify the port: + +```ts +cluster.connections.allowDefaultPortFromAnyIpv4('Open to the world'); +``` + +The endpoints to access your database cluster will be available as the `.clusterEndpoint` and `.clusterReadEndpoint` +attributes: ```ts -import * as docdb from '@aws-cdk/aws-docdb'; +const writeAddress = cluster.clusterEndpoint.socketAddress; // "HOSTNAME:PORT" ``` + +### Rotating credentials +When the master password is generated and stored in AWS Secrets Manager, it can be rotated automatically: +```ts +cluster.addRotationSingleUser(); // Will rotate automatically after 30 days +``` + +[example of setting up master password rotation for a cluster](test/integ.cluster-rotation.lit.ts) + +The multi user rotation scheme is also available: +```ts +cluster.addRotationMultiUser('MyUser', { + secret: myImportedSecret // This secret must have the `masterarn` key +}); +``` + +It's also possible to create user credentials together with the cluster and add rotation: +```ts +const myUserSecret = new docdb.DatabaseSecret(this, 'MyUserSecret', { + username: 'myuser', + masterSecret: cluster.secret +}); +const myUserSecretAttached = myUserSecret.attach(cluster); // Adds DB connections information in the secret + +cluster.addRotationMultiUser('MyUser', { // Add rotation using the multi user scheme + secret: myUserSecretAttached // This secret must have the `masterarn` key +}); +``` +**Note**: This user must be created manually in the database using the master credentials. +The rotation will start as soon as this user exists. + +See also [@aws-cdk/aws-secretsmanager](https://github.com/aws/aws-cdk/blob/master/packages/%40aws-cdk/aws-secretsmanager/README.md) for credentials rotation of existing clusters. diff --git a/packages/@aws-cdk/aws-docdb/jest.config.js b/packages/@aws-cdk/aws-docdb/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-docdb/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-docdb/lib/cluster-ref.ts b/packages/@aws-cdk/aws-docdb/lib/cluster-ref.ts new file mode 100644 index 0000000000000..9723da3d3acce --- /dev/null +++ b/packages/@aws-cdk/aws-docdb/lib/cluster-ref.ts @@ -0,0 +1,82 @@ +import { IConnectable, ISecurityGroup } from '@aws-cdk/aws-ec2'; +import { ISecretAttachmentTarget } from '@aws-cdk/aws-secretsmanager'; +import { IResource } from '@aws-cdk/core'; +import { Endpoint } from './endpoint'; + +/** + * Create a clustered database with a given number of instances. + */ +export interface IDatabaseCluster extends IResource, IConnectable, ISecretAttachmentTarget { + /** + * Identifier of the cluster + */ + readonly clusterIdentifier: string; + + /** + * Identifiers of the replicas + */ + readonly instanceIdentifiers: string[]; + + /** + * The endpoint to use for read/write operations + * @attribute Endpoint,Port + */ + readonly clusterEndpoint: Endpoint; + + /** + * Endpoint to use for load-balanced read-only operations. + * @attribute ReadEndpoint + */ + readonly clusterReadEndpoint: Endpoint; + + /** + * Endpoints which address each individual replica. + */ + readonly instanceEndpoints: Endpoint[]; + + /** + * The security group for this database cluster + */ + readonly securityGroupId: string; +} + +/** + * Properties that describe an existing cluster instance + */ +export interface DatabaseClusterAttributes { + /** + * The database port + */ + readonly port: number; + + /** + * The security group of the database cluster + */ + readonly securityGroup: ISecurityGroup; + + /** + * Identifier for the cluster + */ + readonly clusterIdentifier: string; + + /** + * Identifier for the instances + */ + readonly instanceIdentifiers: string[]; + // Actual underlying type: DBInstanceId[], but we have to type it more loosely for Java's benefit. + + /** + * Cluster endpoint address + */ + readonly clusterEndpointAddress: string; + + /** + * Reader endpoint address + */ + readonly readerEndpointAddress: string; + + /** + * Endpoint addresses of individual instances + */ + readonly instanceEndpointAddresses: string[]; +} diff --git a/packages/@aws-cdk/aws-docdb/lib/cluster.ts b/packages/@aws-cdk/aws-docdb/lib/cluster.ts new file mode 100644 index 0000000000000..339ef8f0b51a0 --- /dev/null +++ b/packages/@aws-cdk/aws-docdb/lib/cluster.ts @@ -0,0 +1,455 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as kms from '@aws-cdk/aws-kms'; +import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; +import { CfnResource, Construct, Duration, RemovalPolicy, Resource, Token } from '@aws-cdk/core'; +import { DatabaseClusterAttributes, IDatabaseCluster } from './cluster-ref'; +import { DatabaseSecret } from './database-secret'; +import { CfnDBCluster, CfnDBInstance, CfnDBSubnetGroup } from './docdb.generated'; +import { Endpoint } from './endpoint'; +import { IClusterParameterGroup } from './parameter-group'; +import { BackupProps, InstanceProps, Login, RotationMultiUserOptions } from './props'; + +/** + * Properties for a new database cluster + */ +export interface DatabaseClusterProps { + /** + * What version of the database to start + * + * @default - The default engine version. + */ + readonly engineVersion?: string; + + /** + * The port the DocumentDB cluster will listen on + * + * @default DatabaseCluster.DEFAULT_PORT + */ + readonly port?: number; + + /** + * Username and password for the administrative user + */ + readonly masterUser: Login; + + /** + * Backup settings + * + * @default - Backup retention period for automated backups is 1 day. + * Backup preferred window is set to a 30-minute window selected at random from an + * 8-hour block of time for each AWS Region, occurring on a random day of the week. + * @see https://docs.aws.amazon.com/documentdb/latest/developerguide/backup-restore.db-cluster-snapshots.html#backup-restore.backup-window + */ + readonly backup?: BackupProps; + + /** + * The KMS key for storage encryption. + * + * @default - default master key. + */ + readonly kmsKey?: kms.IKey; + + /** + * Whether to enable storage encryption + * + * @default true + */ + readonly storageEncrypted?: boolean; + + /** + * Number of DocDB compute instances + * + * @default 1 + */ + readonly instances?: number; + + /** + * An optional identifier for the cluster + * + * @default - A name is automatically generated. + */ + readonly dbClusterName?: string; + + /** + * Base identifier for instances + * + * Every replica is named by appending the replica number to this string, 1-based. + * + * @default - `dbClusterName` is used with the word "Instance" appended. If `dbClusterName` is not provided, the + * identifier is automatically generated. + */ + readonly instanceIdentifierBase?: string; + + /** + * Settings for the individual instances that are launched + */ + readonly instanceProps: InstanceProps; + + /** + * A weekly time range in which maintenance should preferably execute. + * + * Must be at least 30 minutes long. + * + * Example: 'tue:04:17-tue:04:47' + * + * @default - 30-minute window selected at random from an 8-hour block of time for + * each AWS Region, occurring on a random day of the week. + * @see https://docs.aws.amazon.com/documentdb/latest/developerguide/db-instance-maintain.html#maintenance-window + */ + readonly preferredMaintenanceWindow?: string; + + /** + * Additional parameters to pass to the database engine + * + * @default - No parameter group. + */ + readonly parameterGroup?: IClusterParameterGroup; + + /** + * The removal policy to apply when the cluster and its instances are removed + * or replaced during a stack update, or when the stack is deleted. This + * removal policy also applies to the implicit security group created for the + * cluster if one is not supplied as a parameter. + * + * @default - Retain cluster. + */ + readonly removalPolicy?: RemovalPolicy +} + +/** + * A new or imported clustered database. + */ +abstract class DatabaseClusterBase extends Resource implements IDatabaseCluster { + /** + * Identifier of the cluster + */ + public abstract readonly clusterIdentifier: string; + /** + * Identifiers of the replicas + */ + public abstract readonly instanceIdentifiers: string[]; + + /** + * The endpoint to use for read/write operations + */ + public abstract readonly clusterEndpoint: Endpoint; + + /** + * Endpoint to use for load-balanced read-only operations. + */ + public abstract readonly clusterReadEndpoint: Endpoint; + + /** + * Endpoints which address each individual replica. + */ + public abstract readonly instanceEndpoints: Endpoint[]; + + /** + * Access to the network connections + */ + public abstract readonly connections: ec2.Connections; + + /** + * Security group identifier of this database + */ + public abstract readonly securityGroupId: string; + + /** + * Renders the secret attachment target specifications. + */ + public asSecretAttachmentTarget(): secretsmanager.SecretAttachmentTargetProps { + return { + targetId: this.clusterIdentifier, + targetType: secretsmanager.AttachmentTargetType.DOCDB_DB_CLUSTER, + }; + } +} + +/** + * Create a clustered database with a given number of instances. + * + * @resource AWS::DocDB::DBCluster + */ +export class DatabaseCluster extends DatabaseClusterBase { + + /** + * The default number of instances in the DocDB cluster if none are + * specified + */ + public static readonly DEFAULT_NUM_INSTANCES = 1; + + /** + * The default port Document DB listens on + */ + public static readonly DEFAULT_PORT = 27017; + + /** + * Import an existing DatabaseCluster from properties + */ + public static fromDatabaseClusterAttributes(scope: Construct, id: string, attrs: DatabaseClusterAttributes): IDatabaseCluster { + class Import extends DatabaseClusterBase implements IDatabaseCluster { + public readonly defaultPort = ec2.Port.tcp(attrs.port); + public readonly connections = new ec2.Connections({ + securityGroups: [attrs.securityGroup], + defaultPort: this.defaultPort, + }); + public readonly clusterIdentifier = attrs.clusterIdentifier; + public readonly instanceIdentifiers = attrs.instanceIdentifiers; + public readonly clusterEndpoint = new Endpoint(attrs.clusterEndpointAddress, attrs.port); + public readonly clusterReadEndpoint = new Endpoint(attrs.readerEndpointAddress, attrs.port); + public readonly instanceEndpoints = attrs.instanceEndpointAddresses.map(a => new Endpoint(a, attrs.port)); + public readonly securityGroupId = attrs.securityGroup.securityGroupId; + } + + return new Import(scope, id); + } + + /** + * The single user secret rotation application. + */ + private static readonly SINGLE_USER_ROTATION_APPLICATION = secretsmanager.SecretRotationApplication.MONGODB_ROTATION_SINGLE_USER; + + /** + * The multi user secret rotation application. + */ + private static readonly MULTI_USER_ROTATION_APPLICATION = secretsmanager.SecretRotationApplication.MONGODB_ROTATION_MULTI_USER; + + /** + * Identifier of the cluster + */ + public readonly clusterIdentifier: string; + + /** + * The endpoint to use for read/write operations + */ + public readonly clusterEndpoint: Endpoint; + + /** + * Endpoint to use for load-balanced read-only operations. + */ + public readonly clusterReadEndpoint: Endpoint; + + /** + * The resource id for the cluster; for example: cluster-ABCD1234EFGH5678IJKL90MNOP. The cluster ID uniquely + * identifies the cluster and is used in things like IAM authentication policies. + * @attribute ClusterResourceId + */ + public readonly clusterResourceIdentifier: string; + + /** + * The connections object to implement IConectable + */ + public readonly connections: ec2.Connections; + + /** + * Identifiers of the replicas + */ + public readonly instanceIdentifiers: string[] = []; + + /** + * Endpoints which address each individual replica. + */ + public readonly instanceEndpoints: Endpoint[] = []; + + /** + * Security group identifier of this database + */ + public readonly securityGroupId: string; + + /** + * The secret attached to this cluster + */ + public readonly secret?: secretsmanager.ISecret; + + /** + * The VPC where the DB subnet group is created. + */ + private readonly vpc: ec2.IVpc; + + /** + * The subnets used by the DB subnet group. + */ + private readonly vpcSubnets?: ec2.SubnetSelection; + + constructor(scope: Construct, id: string, props: DatabaseClusterProps) { + super(scope, id); + + this.vpc = props.instanceProps.vpc; + this.vpcSubnets = props.instanceProps.vpcSubnets; + + // Determine the subnet(s) to deploy the DocDB cluster to + const { subnetIds, internetConnectivityEstablished } = this.vpc.selectSubnets(this.vpcSubnets); + + // DocDB clusters require a subnet group with subnets from at least two AZs. + // We cannot test whether the subnets are in different AZs, but at least we can test the amount. + // See https://docs.aws.amazon.com/documentdb/latest/developerguide/replication.html#replication.high-availability + if (subnetIds.length < 2) { + throw new Error(`Cluster requires at least 2 subnets, got ${subnetIds.length}`); + } + + const subnetGroup = new CfnDBSubnetGroup(this, 'Subnets', { + dbSubnetGroupDescription: `Subnets for ${id} database`, + subnetIds, + }); + + // Create the security group for the DB cluster + let securityGroup: ec2.ISecurityGroup; + if (props.instanceProps.securityGroup) { + securityGroup = props.instanceProps.securityGroup; + } else { + securityGroup = new ec2.SecurityGroup(this, 'SecurityGroup', { + description: 'DocumentDB security group', + vpc: this.vpc, + }); + // HACK: Use an escape-hatch to apply a consistent removal policy to the + // security group so we don't get errors when trying to delete the stack + (securityGroup.node.defaultChild as CfnResource).applyRemovalPolicy(props.removalPolicy, { + applyToUpdateReplacePolicy: true, + }); + } + this.securityGroupId = securityGroup.securityGroupId; + + // Create the secret manager secret if no password is specified + let secret: DatabaseSecret | undefined; + if (!props.masterUser.password) { + secret = new DatabaseSecret(this, 'Secret', { + username: props.masterUser.username, + encryptionKey: props.masterUser.kmsKey, + }); + } + + // Default to encrypted storage + const storageEncrypted = props.storageEncrypted ?? true; + + if (props.kmsKey && !storageEncrypted) { + throw new Error('KMS key supplied but storageEncrypted is false'); + } + + // Create the DocDB cluster + const cluster = new CfnDBCluster(this, 'Resource', { + // Basic + engineVersion: props.engineVersion, + dbClusterIdentifier: props.dbClusterName, + dbSubnetGroupName: subnetGroup.ref, + port: props.port, + vpcSecurityGroupIds: [this.securityGroupId], + dbClusterParameterGroupName: props.parameterGroup?.parameterGroupName, + // Admin + masterUsername: secret ? secret.secretValueFromJson('username').toString() : props.masterUser.username, + masterUserPassword: secret + ? secret.secretValueFromJson('password').toString() + : props.masterUser.password!.toString(), + // Backup + backupRetentionPeriod: props.backup?.retention?.toDays(), + preferredBackupWindow: props.backup?.preferredWindow, + preferredMaintenanceWindow: props.preferredMaintenanceWindow, + // Encryption + kmsKeyId: props.kmsKey?.keyArn, + storageEncrypted, + }); + + cluster.applyRemovalPolicy(props.removalPolicy, { + applyToUpdateReplacePolicy: true, + }); + + this.clusterIdentifier = cluster.ref; + this.clusterResourceIdentifier = cluster.attrClusterResourceId; + + const port = Token.asNumber(cluster.attrPort); + this.clusterEndpoint = new Endpoint(cluster.attrEndpoint, port); + this.clusterReadEndpoint = new Endpoint(cluster.attrReadEndpoint, port); + + if (secret) { + this.secret = secret.attach(this); + } + + // Create the instances + const instanceCount = props.instances ?? DatabaseCluster.DEFAULT_NUM_INSTANCES; + if (instanceCount < 1) { + throw new Error('At least one instance is required'); + } + + for (let i = 0; i < instanceCount; i++) { + const instanceIndex = i + 1; + + const instanceIdentifier = props.instanceIdentifierBase != null ? `${props.instanceIdentifierBase}${instanceIndex}` + : props.dbClusterName != null ? `${props.dbClusterName}instance${instanceIndex}` : undefined; + + const instance = new CfnDBInstance(this, `Instance${instanceIndex}`, { + // Link to cluster + dbClusterIdentifier: cluster.ref, + dbInstanceIdentifier: instanceIdentifier, + // Instance properties + dbInstanceClass: databaseInstanceType(props.instanceProps.instanceType), + }); + + instance.applyRemovalPolicy(props.removalPolicy, { + applyToUpdateReplacePolicy: true, + }); + + // We must have a dependency on the NAT gateway provider here to create + // things in the right order. + instance.node.addDependency(internetConnectivityEstablished); + + this.instanceIdentifiers.push(instance.ref); + this.instanceEndpoints.push(new Endpoint(instance.attrEndpoint, port)); + } + + this.connections = new ec2.Connections({ + defaultPort: ec2.Port.tcp(port), + securityGroups: [securityGroup], + }); + } + + /** + * Adds the single user rotation of the master password to this cluster. + * + * @param [automaticallyAfter=Duration.days(30)] Specifies the number of days after the previous rotation + * before Secrets Manager triggers the next automatic rotation. + */ + public addRotationSingleUser(automaticallyAfter?: Duration): secretsmanager.SecretRotation { + if (!this.secret) { + throw new Error('Cannot add single user rotation for a cluster without secret.'); + } + + const id = 'RotationSingleUser'; + const existing = this.node.tryFindChild(id); + if (existing) { + throw new Error('A single user rotation was already added to this cluster.'); + } + + return new secretsmanager.SecretRotation(this, id, { + secret: this.secret, + automaticallyAfter, + application: DatabaseCluster.SINGLE_USER_ROTATION_APPLICATION, + vpc: this.vpc, + vpcSubnets: this.vpcSubnets, + target: this, + }); + } + + /** + * Adds the multi user rotation to this cluster. + */ + public addRotationMultiUser(id: string, options: RotationMultiUserOptions): secretsmanager.SecretRotation { + if (!this.secret) { + throw new Error('Cannot add multi user rotation for a cluster without secret.'); + } + return new secretsmanager.SecretRotation(this, id, { + secret: options.secret, + masterSecret: this.secret, + automaticallyAfter: options.automaticallyAfter, + application: DatabaseCluster.MULTI_USER_ROTATION_APPLICATION, + vpc: this.vpc, + vpcSubnets: this.vpcSubnets, + target: this, + }); + } +} + +/** + * Turn a regular instance type into a database instance type + */ +function databaseInstanceType(instanceType: ec2.InstanceType) { + return 'db.' + instanceType.toString(); +} diff --git a/packages/@aws-cdk/aws-docdb/lib/database-secret.ts b/packages/@aws-cdk/aws-docdb/lib/database-secret.ts new file mode 100644 index 0000000000000..25a94410674aa --- /dev/null +++ b/packages/@aws-cdk/aws-docdb/lib/database-secret.ts @@ -0,0 +1,67 @@ +import { IKey } from '@aws-cdk/aws-kms'; +import { ISecret, Secret } from '@aws-cdk/aws-secretsmanager'; +import { Aws, Construct } from '@aws-cdk/core'; + +/** + * Construction properties for a DatabaseSecret. + */ +export interface DatabaseSecretProps { + /** + * The username. + */ + readonly username: string; + + /** + * The KMS key to use to encrypt the secret. + * + * @default default master key + */ + readonly encryptionKey?: IKey; + + /** + * The physical name of the secret + * + * @default Secretsmanager will generate a physical name for the secret + */ + readonly secretName?: string; + + /** + * The master secret which will be used to rotate this secret. + * + * @default - no master secret information will be included + */ + readonly masterSecret?: ISecret; +} + +/** + * + * A database secret. + * + * @resource AWS::SecretsManager::Secret + */ +export class DatabaseSecret extends Secret { + constructor(scope: Construct, id: string, props: DatabaseSecretProps) { + super(scope, id, { + secretName: props.secretName, + description: `Generated by the CDK for stack: ${Aws.STACK_NAME}`, + encryptionKey: props.encryptionKey, + // The CloudFormation resource provider for AWS::DocDB::DBCluster currently limits the DocDB master password to + // 41 characters when pulling the password from secrets manager using a CloudFormation reference. This does not + // line up with the CloudFormation resource specification which states a maximum of 100 characters: + // + // https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-docdb-dbcluster.html#cfn-docdb-dbcluster-masteruserpassword + // + // When attempting to exceed 41 characters, a deployment fails with the message: + // Length of value for property {/MasterUserPassword} is greater than maximum allowed length {41} + generateSecretString: { + passwordLength: 41, + secretStringTemplate: JSON.stringify({ + username: props.username, + masterarn: props.masterSecret?.secretArn, + }), + generateStringKey: 'password', + excludeCharacters: '"@/', + }, + }); + } +} diff --git a/packages/@aws-cdk/aws-docdb/lib/endpoint.ts b/packages/@aws-cdk/aws-docdb/lib/endpoint.ts new file mode 100644 index 0000000000000..229a0bf7f0e70 --- /dev/null +++ b/packages/@aws-cdk/aws-docdb/lib/endpoint.ts @@ -0,0 +1,81 @@ +import { Token } from '@aws-cdk/core'; + +/** + * Connection endpoint of a database cluster or instance + * + * Consists of a combination of hostname and port. + */ +export class Endpoint { + /** + * The minimum port value + */ + private static readonly MIN_PORT = 1; + + /** + * The maximum port value + */ + private static readonly MAX_PORT = 65535; + + /** + * Determines if a port is valid + * + * @param port: The port number + * @returns boolean whether the port is valid + */ + private static isValidPort(port: number): boolean { + return Number.isInteger(port) && port >= Endpoint.MIN_PORT && port <= Endpoint.MAX_PORT; + } + + /** + * The hostname of the endpoint + */ + public readonly hostname: string; + + /** + * The port number of the endpoint. + * + * This can potentially be a CDK token. If you need to embed the port in a string (e.g. instance user data script), + * use {@link Endpoint.portAsString}. + */ + public readonly port: number; + + /** + * The combination of "HOSTNAME:PORT" for this endpoint + */ + public readonly socketAddress: string; + + /** + * Constructs an Endpoint instance. + * + * @param address - The hostname or address of the endpoint + * @param port - The port number of the endpoint + */ + constructor(address: string, port: number) { + if (!Token.isUnresolved(port) && !Endpoint.isValidPort(port)) { + throw new Error(`Port must be an integer between [${Endpoint.MIN_PORT}, ${Endpoint.MAX_PORT}] but got: ${port}`); + } + + this.hostname = address; + this.port = port; + + const portDesc = Token.isUnresolved(port) ? Token.asString(port) : port; + this.socketAddress = `${address}:${portDesc}`; + } + + /** + * Returns the port number as a string representation that can be used for embedding within other strings. + * + * This is intended to deal with CDK's token system. Numeric CDK tokens are not expanded when their string + * representation is embedded in a string. This function returns the port either as an unresolved string token or + * as a resolved string representation of the port value. + * + * @returns {string} An (un)resolved string representation of the endpoint's port number + */ + public portAsString(): string { + if (Token.isUnresolved(this.port)) { + return Token.asString(this.port); + } else { + return this.port.toString(); + } + } +} diff --git a/packages/@aws-cdk/aws-docdb/lib/index.ts b/packages/@aws-cdk/aws-docdb/lib/index.ts index 5d0e650430f1f..1bfcc3716caaf 100644 --- a/packages/@aws-cdk/aws-docdb/lib/index.ts +++ b/packages/@aws-cdk/aws-docdb/lib/index.ts @@ -1,2 +1,10 @@ +export * from './cluster'; +export * from './cluster-ref'; +export * from './database-secret'; +export * from './endpoint'; +export * from './instance'; +export * from './parameter-group'; +export * from './props'; + // AWS::DocDB CloudFormation Resources: -export * from './docdb.generated'; +export * from './docdb.generated'; \ No newline at end of file diff --git a/packages/@aws-cdk/aws-docdb/lib/instance.ts b/packages/@aws-cdk/aws-docdb/lib/instance.ts new file mode 100644 index 0000000000000..ab6400f5480e4 --- /dev/null +++ b/packages/@aws-cdk/aws-docdb/lib/instance.ts @@ -0,0 +1,227 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as cdk from '@aws-cdk/core'; + +import { IDatabaseCluster } from './cluster-ref'; +import { CfnDBInstance } from './docdb.generated'; +import { Endpoint } from './endpoint'; + +/** + * A database instance + */ +export interface IDatabaseInstance extends cdk.IResource { + /** + * The instance identifier. + */ + readonly instanceIdentifier: string; + + /** + * The instance arn. + */ + readonly instanceArn: string; + + /** + * The instance endpoint address. + * + * @attribute Endpoint + */ + readonly dbInstanceEndpointAddress: string; + + /** + * The instance endpoint port. + * + * @attribute Port + */ + readonly dbInstanceEndpointPort: string; + + /** + * The instance endpoint. + */ + readonly instanceEndpoint: Endpoint; +} + +/** + * Properties that describe an existing instance + */ +export interface DatabaseInstanceAttributes { + /** + * The instance identifier. + */ + readonly instanceIdentifier: string; + + /** + * The endpoint address. + */ + readonly instanceEndpointAddress: string; + + /** + * The database port. + */ + readonly port: number; +} + +/** + * A new or imported database instance. + */ +abstract class DatabaseInstanceBase extends cdk.Resource implements IDatabaseInstance { + /** + * Import an existing database instance. + */ + public static fromDatabaseInstanceAttributes(scope: cdk.Construct, id: string, attrs: DatabaseInstanceAttributes): IDatabaseInstance { + class Import extends DatabaseInstanceBase implements IDatabaseInstance { + public readonly defaultPort = ec2.Port.tcp(attrs.port); + public readonly instanceIdentifier = attrs.instanceIdentifier; + public readonly dbInstanceEndpointAddress = attrs.instanceEndpointAddress; + public readonly dbInstanceEndpointPort = attrs.port.toString(); + public readonly instanceEndpoint = new Endpoint(attrs.instanceEndpointAddress, attrs.port); + } + + return new Import(scope, id); + } + + /** + * @inheritdoc + */ + public abstract readonly instanceIdentifier: string; + /** + * @inheritdoc + */ + public abstract readonly dbInstanceEndpointAddress: string; + /** + * @inheritdoc + */ + public abstract readonly dbInstanceEndpointPort: string; + /** + * @inheritdoc + */ + public abstract readonly instanceEndpoint: Endpoint; + + /** + * The instance arn. + */ + public get instanceArn(): string { + return cdk.Stack.of(this).formatArn({ + service: 'docdb', + resource: 'db', + sep: ':', + resourceName: this.instanceIdentifier, + }); + } +} + +/** + * Construction properties for a DatabaseInstanceNew + */ +export interface DatabaseInstanceProps { + /** + * The DocumentDB database cluster the instance should launch into. + */ + readonly cluster: IDatabaseCluster; + + /** + * The name of the compute and memory capacity classes. + */ + readonly instanceClass: ec2.InstanceType; + + /** + * The name of the Availability Zone where the DB instance will be located. + * + * @default - no preference + */ + readonly availabilityZone?: string; + + /** + * A name for the DB instance. If you specify a name, AWS CloudFormation + * converts it to lowercase. + * + * @default - a CloudFormation generated name + */ + readonly dbInstanceName?: string; + + /** + * Indicates that minor engine upgrades are applied automatically to the + * DB instance during the maintenance window. + * + * @default true + */ + readonly autoMinorVersionUpgrade?: boolean; + + // tslint:disable:max-line-length + /** + * The weekly time range (in UTC) during which system maintenance can occur. + * + * Format: `ddd:hh24:mi-ddd:hh24:mi` + * Constraint: Minimum 30-minute window + * + * @default - a 30-minute window selected at random from an 8-hour block of + * time for each AWS Region, occurring on a random day of the week. To see + * the time blocks available, see https://docs.aws.amazon.com/documentdb/latest/developerguide/db-instance-maintain.html#maintenance-window + */ + // tslint:enable:max-line-length + readonly preferredMaintenanceWindow?: string; + + /** + * The CloudFormation policy to apply when the instance is removed from the + * stack or replaced during an update. + * + * @default RemovalPolicy.Retain + */ + readonly removalPolicy?: cdk.RemovalPolicy +} + +/** + * A database instance + * + * @resource AWS::DocDB::DBInstance + */ +export class DatabaseInstance extends DatabaseInstanceBase implements IDatabaseInstance { + /** + * The instance's database cluster + */ + public readonly cluster: IDatabaseCluster; + + /** + * @inheritdoc + */ + public readonly instanceIdentifier: string; + + /** + * @inheritdoc + */ + public readonly dbInstanceEndpointAddress: string; + + /** + * @inheritdoc + */ + public readonly dbInstanceEndpointPort: string; + + /** + * @inheritdoc + */ + public readonly instanceEndpoint: Endpoint; + + constructor(scope: cdk.Construct, id: string, props: DatabaseInstanceProps) { + super(scope, id); + + const instance = new CfnDBInstance(this, 'Resource', { + dbClusterIdentifier: props.cluster.clusterIdentifier, + dbInstanceClass: `db.${props.instanceClass}`, + autoMinorVersionUpgrade: props.autoMinorVersionUpgrade, + availabilityZone: props.availabilityZone, + dbInstanceIdentifier: props.dbInstanceName, + preferredMaintenanceWindow: props.preferredMaintenanceWindow, + }); + + this.cluster = props.cluster; + this.instanceIdentifier = instance.ref; + this.dbInstanceEndpointAddress = instance.attrEndpoint; + this.dbInstanceEndpointPort = instance.attrPort; + + // create a number token that represents the port of the instance + const portAttribute = cdk.Token.asNumber(instance.attrPort); + this.instanceEndpoint = new Endpoint(instance.attrEndpoint, portAttribute); + + instance.applyRemovalPolicy(props.removalPolicy, { + applyToUpdateReplacePolicy: true, + }); + } +} diff --git a/packages/@aws-cdk/aws-docdb/lib/parameter-group.ts b/packages/@aws-cdk/aws-docdb/lib/parameter-group.ts new file mode 100644 index 0000000000000..f98c74cbcf403 --- /dev/null +++ b/packages/@aws-cdk/aws-docdb/lib/parameter-group.ts @@ -0,0 +1,86 @@ +import { Construct, IResource, Resource } from '@aws-cdk/core'; +import { CfnDBClusterParameterGroup } from './docdb.generated'; + +/** + * A parameter group + */ +export interface IClusterParameterGroup extends IResource { + /** + * The name of this parameter group + */ + readonly parameterGroupName: string; +} + +/** + * A new cluster or instance parameter group + */ +abstract class ClusterParameterGroupBase extends Resource implements IClusterParameterGroup { + /** + * Imports a parameter group + */ + public static fromParameterGroupName(scope: Construct, id: string, parameterGroupName: string): IClusterParameterGroup { + class Import extends Resource implements IClusterParameterGroup { + public readonly parameterGroupName = parameterGroupName; + } + return new Import(scope, id); + } + + /** + * The name of the parameter group + */ + public abstract readonly parameterGroupName: string; +} + +/** + * Properties for a cluster parameter group + */ +export interface ClusterParameterGroupProps { + /** + * Description for this parameter group + * + * @default a CDK generated description + */ + readonly description?: string; + + /** + * Database family of this parameter group + */ + readonly family: string; + + /** + * The name of the cluster parameter group + * + * @default A CDK generated name for the cluster parameter group + */ + readonly dbClusterParameterGroupName?: string; + + /** + * The parameters in this parameter group + */ + readonly parameters: { [key: string]: string }; +} + +/** + * A cluster parameter group + * + * @resource AWS::DocDB::DBClusterParameterGroup + */ +export class ClusterParameterGroup extends ClusterParameterGroupBase implements IClusterParameterGroup { + /** + * The name of the parameter group + */ + public readonly parameterGroupName: string; + + constructor(scope: Construct, id: string, props: ClusterParameterGroupProps) { + super(scope, id); + + const resource = new CfnDBClusterParameterGroup(this, 'Resource', { + name: props.dbClusterParameterGroupName, + description: props.description || `Cluster parameter group for ${props.family}`, + family: props.family, + parameters: props.parameters, + }); + + this.parameterGroupName = resource.ref; + } +} diff --git a/packages/@aws-cdk/aws-docdb/lib/props.ts b/packages/@aws-cdk/aws-docdb/lib/props.ts new file mode 100644 index 0000000000000..270bc51cdc203 --- /dev/null +++ b/packages/@aws-cdk/aws-docdb/lib/props.ts @@ -0,0 +1,127 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as kms from '@aws-cdk/aws-kms'; +import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; +import { Duration, SecretValue } from '@aws-cdk/core'; +import { IClusterParameterGroup } from './parameter-group'; + +/** + * Backup configuration for DocumentDB databases + * + * @default - The retention period for automated backups is 1 day. + * The preferred backup window will be a 30-minute window selected at random + * from an 8-hour block of time for each AWS Region. + * @see https://docs.aws.amazon.com/documentdb/latest/developerguide/backup-restore.db-cluster-snapshots.html#backup-restore.backup-window + */ +export interface BackupProps { + + /** + * How many days to retain the backup + */ + readonly retention: Duration; + + /** + * A daily time range in 24-hours UTC format in which backups preferably execute. + * + * Must be at least 30 minutes long. + * + * Example: '01:00-02:00' + * + * @default - a 30-minute window selected at random from an 8-hour block of + * time for each AWS Region. To see the time blocks available, see + * https://docs.aws.amazon.com/documentdb/latest/developerguide/backup-restore.db-cluster-snapshots.html#backup-restore.backup-window + */ + readonly preferredWindow?: string; +} + +/** + * Login credentials for a database cluster + */ +export interface Login { + /** + * Username + */ + readonly username: string; + /** + * Password + * + * Do not put passwords in your CDK code directly. + * + * @default a Secrets Manager generated password + */ + readonly password?: SecretValue; + /** + * KMS encryption key to encrypt the generated secret. + * + * @default default master key + */ + readonly kmsKey?: kms.IKey; +} + +/** + * Instance properties for database instances + */ +export interface InstanceProps { + /** + * What type of instance to start for the replicas + */ + readonly instanceType: ec2.InstanceType; + + /** + * What subnets to run the DocumentDB instances in. + * + * Must be at least 2 subnets in two different AZs. + */ + readonly vpc: ec2.IVpc; + + /** + * Where to place the instances within the VPC + * + * @default private subnets + */ + readonly vpcSubnets?: ec2.SubnetSelection; + + /** + * Security group. + * + * @default a new security group is created. + */ + readonly securityGroup?: ec2.ISecurityGroup; + + /** + * The DB parameter group to associate with the instance. + * + * @default no parameter group + */ + readonly parameterGroup?: IClusterParameterGroup; +} + +/** + * Options to add the multi user rotation + */ +export interface RotationMultiUserOptions { + /** + * The secret to rotate. It must be a JSON string with the following format: + * ``` + * { + * "engine": , + * "host": , + * "username": , + * "password": , + * "dbname": , + * "port": , + * "masterarn": + * "ssl": + * } + * ``` + */ + readonly secret: secretsmanager.ISecret; + + /** + * Specifies the number of days after the previous rotation before + * Secrets Manager triggers the next automatic rotation. + * + * @default Duration.days(30) + */ + readonly automaticallyAfter?: Duration; +} diff --git a/packages/@aws-cdk/aws-docdb/package.json b/packages/@aws-cdk/aws-docdb/package.json index 8c1d4fb92e23d..cde479290182a 100644 --- a/packages/@aws-cdk/aws-docdb/package.json +++ b/packages/@aws-cdk/aws-docdb/package.json @@ -48,9 +48,10 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::DocDB" + "cloudformation": "AWS::DocDB", + "jest": true }, - "keywords": [ +"keywords": [ "aws", "cdk", "constructs", @@ -62,43 +63,35 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", "cdk-build-tools": "0.0.0", + "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0" }, "dependencies": { + "@aws-cdk/aws-efs": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-kms": "0.0.0", + "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.0.2" }, "peerDependencies": { + "@aws-cdk/aws-efs": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-kms": "0.0.0", + "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", - "maturity": "cfn-only", + "maturity": "experimental", "awscdkio": { "announce": false } diff --git a/packages/@aws-cdk/aws-docdb/test/cluster.test.ts b/packages/@aws-cdk/aws-docdb/test/cluster.test.ts new file mode 100644 index 0000000000000..957ea0bd40a85 --- /dev/null +++ b/packages/@aws-cdk/aws-docdb/test/cluster.test.ts @@ -0,0 +1,780 @@ +import { expect as expectCDK, haveResource, ResourcePart } from '@aws-cdk/assert'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as kms from '@aws-cdk/aws-kms'; +import * as cdk from '@aws-cdk/core'; + +import { ClusterParameterGroup, DatabaseCluster, DatabaseSecret } from '../lib'; + +describe('DatabaseCluster', () => { + + test('check that instantiation works', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + masterUser: { + username: 'admin', + password: cdk.SecretValue.plainText('tooshort'), + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + }, + }); + + // THEN + expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + Properties: { + DBSubnetGroupName: { Ref: 'DatabaseSubnets56F17B9A' }, + MasterUsername: 'admin', + MasterUserPassword: 'tooshort', + VpcSecurityGroupIds: [ {'Fn::GetAtt': ['DatabaseSecurityGroup5C91FDCB', 'GroupId']}], + StorageEncrypted: true, + }, + DeletionPolicy: 'Retain', + UpdateReplacePolicy: 'Retain', + }, ResourcePart.CompleteDefinition)); + + expectCDK(stack).to(haveResource('AWS::DocDB::DBInstance', { + DeletionPolicy: 'Retain', + UpdateReplacePolicy: 'Retain', + }, ResourcePart.CompleteDefinition)); + + expectCDK(stack).to(haveResource('AWS::DocDB::DBSubnetGroup', { + SubnetIds: [ + { Ref: 'VPCPrivateSubnet1Subnet8BCA10E0' }, + { Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A' }, + { Ref: 'VPCPrivateSubnet3Subnet3EDCD457' }, + ], + })); + }); + + test('can create a cluster with a single instance', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + instances: 1, + masterUser: { + username: 'admin', + password: cdk.SecretValue.plainText('tooshort'), + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + }, + }); + + // THEN + expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + DBSubnetGroupName: { Ref: 'DatabaseSubnets56F17B9A' }, + MasterUsername: 'admin', + MasterUserPassword: 'tooshort', + VpcSecurityGroupIds: [ {'Fn::GetAtt': ['DatabaseSecurityGroup5C91FDCB', 'GroupId']}], + })); + }); + + test('errors when less than one instance is specified', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + expect(() => { + new DatabaseCluster(stack, 'Database', { + instances: 0, + masterUser: { + username: 'admin', + }, + instanceProps: { + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.LARGE), + }, + }); + }).toThrowError('At least one instance is required'); + }); + + test('errors when only one subnet is specified', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC', { + maxAzs: 1, + }); + + // WHEN + expect(() => { + new DatabaseCluster(stack, 'Database', { + instances: 1, + masterUser: { + username: 'admin', + }, + instanceProps: { + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.LARGE), + vpcSubnets: { + subnetType: ec2.SubnetType.PRIVATE, + }, + }, + }); + }).toThrowError('Cluster requires at least 2 subnets, got 1'); + }); + + test('secret attachment target type is correct', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + instances: 1, + masterUser: { + username: 'admin', + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + }, + }); + + // THEN + expectCDK(stack).to(haveResource('AWS::SecretsManager::SecretTargetAttachment', { + SecretId: { Ref: 'DatabaseSecret3B817195' }, + TargetId: { Ref: 'DatabaseB269D8BB' }, + TargetType: 'AWS::DocDB::DBCluster', + })); + }); + + test('can create a cluster with imported vpc and security group', () => { + // GIVEN + const stack = testStack(); + const vpc = ec2.Vpc.fromLookup(stack, 'VPC', { + vpcId: 'VPC12345', + }); + const sg = ec2.SecurityGroup.fromSecurityGroupId(stack, 'SG', 'SecurityGroupId12345'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + instances: 1, + masterUser: { + username: 'admin', + password: cdk.SecretValue.plainText('tooshort'), + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + securityGroup: sg, + }, + }); + + // THEN + expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + DBSubnetGroupName: { Ref: 'DatabaseSubnets56F17B9A' }, + MasterUsername: 'admin', + MasterUserPassword: 'tooshort', + VpcSecurityGroupIds: [ 'SecurityGroupId12345' ], + })); + }); + + test('cluster with parameter group', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + const group = new ClusterParameterGroup(stack, 'Params', { + family: 'hello', + description: 'bye', + parameters: { + param: 'value', + }, + }); + new DatabaseCluster(stack, 'Database', { + masterUser: { + username: 'admin', + password: cdk.SecretValue.plainText('tooshort'), + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + }, + parameterGroup: group, + }); + + // THEN + expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + DBClusterParameterGroupName: { Ref: 'ParamsA8366201' }, + })); + }); + + test('cluster with imported parameter group', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + const group = ClusterParameterGroup.fromParameterGroupName(stack, 'Params', 'ParamGroupName'); + + new DatabaseCluster(stack, 'Database', { + masterUser: { + username: 'admin', + password: cdk.SecretValue.plainText('tooshort'), + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + }, + parameterGroup: group, + }); + + // THEN + expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + DBClusterParameterGroupName: 'ParamGroupName', + })); + }); + + test('creates a secret when master credentials are not specified', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + masterUser: { + username: 'admin', + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + }, + }); + + // THEN + expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + MasterUsername: { + 'Fn::Join': [ + '', + [ + '{{resolve:secretsmanager:', + { + Ref: 'DatabaseSecret3B817195', + }, + ':SecretString:username::}}', + ], + ], + }, + MasterUserPassword: { + 'Fn::Join': [ + '', + [ + '{{resolve:secretsmanager:', + { + Ref: 'DatabaseSecret3B817195', + }, + ':SecretString:password::}}', + ], + ], + }, + })); + + expectCDK(stack).to(haveResource('AWS::SecretsManager::Secret', { + GenerateSecretString: { + ExcludeCharacters: '\"@/', + GenerateStringKey: 'password', + PasswordLength: 41, + SecretStringTemplate: '{"username":"admin"}', + }, + })); + }); + + test('create an encrypted cluster with custom KMS key', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + masterUser: { + username: 'admin', + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + }, + kmsKey: new kms.Key(stack, 'Key'), + }); + + // THEN + expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + KmsKeyId: { + 'Fn::GetAtt': [ + 'Key961B73FD', + 'Arn', + ], + }, + StorageEncrypted: true, + })); + }); + + test('creating a cluster defaults to using encryption', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + masterUser: { + username: 'admin', + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + }, + }); + + // THEN + expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + StorageEncrypted: true, + })); + }); + + test('supplying a KMS key with storageEncryption false throws an error', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + function action() { + new DatabaseCluster(stack, 'Database', { + masterUser: { + username: 'admin', + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + }, + kmsKey: new kms.Key(stack, 'Key'), + storageEncrypted: false, + }); + } + + // THEN + expect(action).toThrow(); + }); + + test('cluster exposes different read and write endpoints', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + const cluster = new DatabaseCluster(stack, 'Database', { + masterUser: { + username: 'admin', + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + }, + }); + + // THEN + expect(stack.resolve(cluster.clusterEndpoint)).not.toBe(stack.resolve(cluster.clusterReadEndpoint)); + }); + + test('instance identifier used when present', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + const instanceIdentifierBase = 'instanceidentifierbase-'; + new DatabaseCluster(stack, 'Database', { + masterUser: { + username: 'admin', + }, + instanceProps: { + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), + }, + instanceIdentifierBase, + }); + + // THEN + expectCDK(stack).to(haveResource('AWS::DocDB::DBInstance', { + DBInstanceIdentifier: `${instanceIdentifierBase}1`, + })); + }); + + test('cluster identifier used', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + const clusterIdentifier = 'clusteridentifier-'; + new DatabaseCluster(stack, 'Database', { + masterUser: { + username: 'admin', + }, + instanceProps: { + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), + }, + dbClusterName: clusterIdentifier, + }); + + // THEN + expectCDK(stack).to(haveResource('AWS::DocDB::DBInstance', { + DBInstanceIdentifier: `${clusterIdentifier}instance1`, + })); + }); + + test('imported cluster has supplied attributes', () => { + // GIVEN + const stack = testStack(); + + // WHEN + const cluster = DatabaseCluster.fromDatabaseClusterAttributes(stack, 'Database', { + clusterEndpointAddress: 'addr', + clusterIdentifier: 'identifier', + instanceEndpointAddresses: ['addr'], + instanceIdentifiers: ['identifier'], + port: 3306, + readerEndpointAddress: 'reader-address', + securityGroup: ec2.SecurityGroup.fromSecurityGroupId(stack, 'SG', 'sg-123456789', { + allowAllOutbound: false, + }), + }); + + // THEN + expect(cluster.clusterEndpoint.hostname).toEqual('addr'); + expect(cluster.clusterEndpoint.port).toEqual(3306); + expect(cluster.clusterIdentifier).toEqual('identifier'); + expect(cluster.instanceIdentifiers).toEqual(['identifier']); + expect(cluster.clusterReadEndpoint.hostname).toEqual('reader-address'); + expect(cluster.securityGroupId).toEqual('sg-123456789'); + }); + + test('imported cluster with imported security group honors allowAllOutbound', () => { + // GIVEN + const stack = testStack(); + + const cluster = DatabaseCluster.fromDatabaseClusterAttributes(stack, 'Database', { + clusterEndpointAddress: 'addr', + clusterIdentifier: 'identifier', + instanceEndpointAddresses: ['addr'], + instanceIdentifiers: ['identifier'], + port: 3306, + readerEndpointAddress: 'reader-address', + securityGroup: ec2.SecurityGroup.fromSecurityGroupId(stack, 'SG', 'sg-123456789', { + allowAllOutbound: false, + }), + }); + + // WHEN + cluster.connections.allowToAnyIpv4(ec2.Port.tcp(443)); + + // THEN + expectCDK(stack).to(haveResource('AWS::EC2::SecurityGroupEgress', { + GroupId: 'sg-123456789', + })); + }); + + test('backup retention period respected', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + masterUser: { + username: 'admin', + }, + instanceProps: { + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), + }, + backup: { + retention: cdk.Duration.days(20), + }, + }); + + // THEN + expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + BackupRetentionPeriod: 20, + })); + }); + + test('backup maintenance window respected', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + masterUser: { + username: 'admin', + }, + instanceProps: { + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), + }, + backup: { + retention: cdk.Duration.days(20), + preferredWindow: '07:34-08:04', + }, + }); + + // THEN + expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + BackupRetentionPeriod: 20, + PreferredBackupWindow: '07:34-08:04', + })); + }); + + test('regular maintenance window respected', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + masterUser: { + username: 'admin', + }, + instanceProps: { + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), + }, + preferredMaintenanceWindow: '07:34-08:04', + }); + + // THEN + expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + PreferredMaintenanceWindow: '07:34-08:04', + })); + }); + + test('single user rotation', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new DatabaseCluster(stack, 'Database', { + masterUser: { + username: 'admin', + }, + instanceProps: { + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), + }, + }); + + // WHEN + cluster.addRotationSingleUser(cdk.Duration.days(5)); + + // THEN + expectCDK(stack).to(haveResource('AWS::Serverless::Application', { + Location: { + ApplicationId: 'arn:aws:serverlessrepo:us-east-1:297356227824:applications/SecretsManagerMongoDBRotationSingleUser', + SemanticVersion: '1.1.3', + }, + Parameters: { + endpoint: { + 'Fn::Join': [ + '', + [ + 'https://secretsmanager.us-test-1.', + { Ref: 'AWS::URLSuffix' }, + ], + ], + }, + functionName: 'DatabaseRotationSingleUser458A45BE', + vpcSubnetIds: { + 'Fn::Join': [ + '', + [ + { Ref: 'VPCPrivateSubnet1Subnet8BCA10E0' }, + ',', + { Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A' }, + ',', + { Ref: 'VPCPrivateSubnet3Subnet3EDCD457' }, + ], + ], + }, + vpcSecurityGroupIds: { + 'Fn::GetAtt': [ 'DatabaseRotationSingleUserSecurityGroupAC6E0E73', 'GroupId' ], + }, + }, + })); + expectCDK(stack).to(haveResource('AWS::SecretsManager::RotationSchedule', { + SecretId: { Ref: 'DatabaseSecretAttachmentE5D1B020' }, + RotationLambdaARN: { + 'Fn::GetAtt': [ 'DatabaseRotationSingleUser65F55654', 'Outputs.RotationLambdaARN' ], + }, + RotationRules: { + AutomaticallyAfterDays: 5, + }, + })); + }); + + test('single user rotation requires secret', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new DatabaseCluster(stack, 'Database', { + masterUser: { + username: 'admin', + password: cdk.SecretValue.plainText('secret'), + }, + instanceProps: { + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), + }, + }); + + // WHEN + function addSingleUserRotation() { + cluster.addRotationSingleUser(cdk.Duration.days(10)); + } + + // THEN + expect(addSingleUserRotation).toThrow(); + }); + + test('no multiple single user rotations', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new DatabaseCluster(stack, 'Database', { + masterUser: { + username: 'admin', + }, + instanceProps: { + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), + }, + }); + + // WHEN + cluster.addRotationSingleUser(cdk.Duration.days(5)); + function addSecondRotation() { + cluster.addRotationSingleUser(cdk.Duration.days(10)); + } + + // THEN + expect(addSecondRotation).toThrow(); + }); + + test('multi user rotation', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new DatabaseCluster(stack, 'Database', { + masterUser: { + username: 'admin', + }, + instanceProps: { + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), + }, + }); + const userSecret = new DatabaseSecret(stack, 'UserSecret', { + username: 'seconduser', + masterSecret: cluster.secret, + }); + userSecret.attach(cluster); + + // WHEN + cluster.addRotationMultiUser('Rotation', { + secret: userSecret, + automaticallyAfter: cdk.Duration.days(5), + }); + + // THEN + expectCDK(stack).to(haveResource('AWS::Serverless::Application', { + Location: { + ApplicationId: 'arn:aws:serverlessrepo:us-east-1:297356227824:applications/SecretsManagerMongoDBRotationMultiUser', + SemanticVersion: '1.1.3', + }, + Parameters: { + endpoint: { + 'Fn::Join': [ + '', + [ + 'https://secretsmanager.us-test-1.', + { Ref: 'AWS::URLSuffix' }, + ], + ], + }, + functionName: 'DatabaseRotation0D47EBD2', + vpcSubnetIds: { + 'Fn::Join': [ + '', + [ + { Ref: 'VPCPrivateSubnet1Subnet8BCA10E0' }, + ',', + { Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A' }, + ',', + { Ref: 'VPCPrivateSubnet3Subnet3EDCD457' }, + ], + ], + }, + vpcSecurityGroupIds: { + 'Fn::GetAtt': [ 'DatabaseRotationSecurityGroup17736B63', 'GroupId' ], + }, + masterSecretArn: { Ref: 'DatabaseSecretAttachmentE5D1B020' }, + }, + })); + expectCDK(stack).to(haveResource('AWS::SecretsManager::RotationSchedule', { + SecretId: { Ref: 'UserSecret0463E4F5' }, + RotationLambdaARN: { + 'Fn::GetAtt': [ 'DatabaseRotation6B6E1D86', 'Outputs.RotationLambdaARN' ], + }, + RotationRules: { + AutomaticallyAfterDays: 5, + }, + })); + }); + + test('multi user rotation requires secret', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new DatabaseCluster(stack, 'Database', { + masterUser: { + username: 'admin', + password: cdk.SecretValue.plainText('secret'), + }, + instanceProps: { + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), + }, + }); + const userSecret = new DatabaseSecret(stack, 'UserSecret', { + username: 'seconduser', + masterSecret: cluster.secret, + }); + userSecret.attach(cluster); + + // WHEN + function addMultiUserRotation() { + cluster.addRotationMultiUser('Rotation', { + secret: userSecret, + }); + } + + // THEN + expect(addMultiUserRotation).toThrow(); + }); + +}); + +function testStack() { + const stack = new cdk.Stack(undefined, 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-docdb/test/docdb.test.ts b/packages/@aws-cdk/aws-docdb/test/docdb.test.ts deleted file mode 100644 index e394ef336bfb4..0000000000000 --- a/packages/@aws-cdk/aws-docdb/test/docdb.test.ts +++ /dev/null @@ -1,6 +0,0 @@ -import '@aws-cdk/assert/jest'; -import {} from '../lib'; - -test('No tests are specified for this package', () => { - expect(true).toBe(true); -}); diff --git a/packages/@aws-cdk/aws-docdb/test/endpoint.test.ts b/packages/@aws-cdk/aws-docdb/test/endpoint.test.ts new file mode 100644 index 0000000000000..72a1b699779ce --- /dev/null +++ b/packages/@aws-cdk/aws-docdb/test/endpoint.test.ts @@ -0,0 +1,100 @@ +import { Token } from '@aws-cdk/core'; +import { Endpoint } from '../lib'; + +// A numeric CDK token (see: https://docs.aws.amazon.com/cdk/latest/guide/tokens.html#tokens_number) +const CDK_NUMERIC_TOKEN = -1.8881545897087626e+289; + +describe('Endpoint', () => { + test('accepts tokens for the port value', () => { + // GIVEN + const token = CDK_NUMERIC_TOKEN; + + // WHEN + const endpoint = new Endpoint('127.0.0.1', token); + + // THEN + expect(endpoint.port).toBe(token); + }); + + test('accepts valid port string numbers', () => { + // GIVEN + for (const port of [1, 50, 65535]) { + // WHEN + const endpoint = new Endpoint('127.0.0.1', port); + + // THEN + expect(endpoint.port).toBe(port); + } + }); + + test('throws an exception for port numbers below the minimum', () => { + // GIVEN + const port = 0; + + // WHEN + function createInvalidEnpoint() { + new Endpoint('127.0.0.1', port); + } + + // THEN + expect(createInvalidEnpoint) + .toThrow(); + }); + + test('throws an exception for port numbers above the maximum', () => { + // GIVEN + const port = 65536; + + // WHEN + function createInvalidEnpoint() { + new Endpoint('127.0.0.1', port); + } + + // THEN + expect(createInvalidEnpoint) + .toThrow(); + }); + + test('throws an exception for floating-point port numbers', () => { + // GIVEN + const port = 1.5; + + // WHEN + function createInvalidEnpoint() { + new Endpoint('127.0.0.1', port); + } + + // THEN + expect(createInvalidEnpoint) + .toThrow(); + }); + + describe('.portAsString()', () => { + test('converts port tokens to string tokens', () => { + // GIVEN + const port = CDK_NUMERIC_TOKEN; + const endpoint = new Endpoint('127.0.0.1', port); + + // WHEN + const result = endpoint.portAsString(); + + // THEN + // Should return a string token + expect(Token.isUnresolved(result)).toBeTruthy(); + // It should not just be the string representation of the numeric token + expect(result).not.toBe(port.toString()); + }); + + test('converts resolved port numbers to string representation', () => { + // GIVEN + const port = 1500; + const endpoint = new Endpoint('127.0.0.1', port); + + // WHEN + const result = endpoint.portAsString(); + + // THEN + expect(result).toBe(port.toString()); + }); + }); +}); diff --git a/packages/@aws-cdk/aws-docdb/test/instance.test.ts b/packages/@aws-cdk/aws-docdb/test/instance.test.ts new file mode 100644 index 0000000000000..b36d6af554ef1 --- /dev/null +++ b/packages/@aws-cdk/aws-docdb/test/instance.test.ts @@ -0,0 +1,167 @@ +import { expect as expectCDK, haveOutput, haveResource, ResourcePart } from '@aws-cdk/assert'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as cdk from '@aws-cdk/core'; + +import { DatabaseCluster, DatabaseInstance } from '../lib'; + +const CLUSTER_INSTANCE_TYPE = ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.LARGE); +const SINGLE_INSTANCE_TYPE = ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.XLARGE); +const EXPECTED_SYNTH_INSTANCE_TYPE = `db.${SINGLE_INSTANCE_TYPE}`; + +describe('DatabaseInstance', () => { + test('check that instantiation works', () => { + // GIVEN + const stack = testStack(); + + // WHEN + new DatabaseInstance(stack, 'Instance', { + cluster: stack.cluster, + instanceClass: SINGLE_INSTANCE_TYPE, + }); + + // THEN + expectCDK(stack).to(haveResource('AWS::DocDB::DBInstance', { + Properties: { + DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, + DBInstanceClass: EXPECTED_SYNTH_INSTANCE_TYPE, + }, + DeletionPolicy: 'Retain', + UpdateReplacePolicy: 'Retain', + }, ResourcePart.CompleteDefinition)); + }); + + test('check that the endpoint works', () => { + // GIVEN + const stack = testStack(); + const instance = new DatabaseInstance(stack, 'Instance', { + cluster: stack.cluster, + instanceClass: SINGLE_INSTANCE_TYPE, + }); + const exportName = 'DbInstanceEndpoint'; + + // WHEN + new cdk.CfnOutput(stack, exportName, { + exportName, + value: instance.instanceEndpoint.socketAddress, + }); + + // THEN + expectCDK(stack).to(haveOutput({ + exportName, + outputValue: { + 'Fn::Join': [ + '', + [ + { 'Fn::GetAtt': [ 'InstanceC1063A87', 'Endpoint' ] }, + ':', + { 'Fn::GetAtt': [ 'InstanceC1063A87', 'Port' ] }, + ], + ], + }, + })); + }); + + test('check that instanceArn property works', () => { + // GIVEN + const stack = testStack(); + const instance = new DatabaseInstance(stack, 'Instance', { + cluster: stack.cluster, + instanceClass: SINGLE_INSTANCE_TYPE, + }); + const exportName = 'DbInstanceArn'; + + // WHEN + new cdk.CfnOutput(stack, exportName, { + exportName, + value: instance.instanceArn, + }); + + // THEN + expectCDK(stack).to(haveOutput({ + exportName, + outputValue: { + 'Fn::Join': [ + '', + [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':docdb:us-test-1:12345:db:', + { Ref: 'InstanceC1063A87' }, + ], + ], + }, + })); + }); + + test('check importing works as expected', () => { + // GIVEN + const stack = testStack(); + const arnExportName = 'DbInstanceArn'; + const endpointExportName = 'DbInstanceEndpoint'; + const instanceEndpointAddress = '127.0.0.1'; + const instanceIdentifier = 'InstanceID'; + const port = 8888; + + // WHEN + const instance = DatabaseInstance.fromDatabaseInstanceAttributes(stack, 'Instance', { + instanceEndpointAddress, + instanceIdentifier, + port, + }); + new cdk.CfnOutput(stack, 'ArnOutput', { + exportName: arnExportName, + value: instance.instanceArn, + }); + new cdk.CfnOutput(stack, 'EndpointOutput', { + exportName: endpointExportName, + value: instance.instanceEndpoint.socketAddress, + }); + + // THEN + expectCDK(stack).to(haveOutput({ + exportName: arnExportName, + outputValue: { + 'Fn::Join': [ + '', + [ + 'arn:', + { Ref: 'AWS::Partition' }, + `:docdb:us-test-1:12345:db:${instanceIdentifier}`, + ], + ], + }, + })); + expectCDK(stack).to(haveOutput({ + exportName: endpointExportName, + outputValue: `${instanceEndpointAddress}:${port}`, + })); + }); +}); + +class TestStack extends cdk.Stack { + public readonly vpc: ec2.Vpc; + public readonly cluster: DatabaseCluster; + + constructor(scope?: cdk.Construct, id?: string, props: cdk.StackProps = {}) { + super(scope, id, props); + + this.node.setContext('availability-zones:12345:us-test-1', ['us-test-1a', 'us-test-1b']); + + this.vpc = new ec2.Vpc(this, 'VPC'); + this.cluster = new DatabaseCluster(this, 'Database', { + masterUser: { + username: 'admin', + password: cdk.SecretValue.plainText('tooshort'), + }, + instanceProps: { + instanceType: CLUSTER_INSTANCE_TYPE, + vpc: this.vpc, + }, + }); + } +} + +function testStack() { + const stack = new TestStack(undefined, undefined, { env: { account: '12345', region: 'us-test-1' } }); + return stack; +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-docdb/test/integ.cluster-rotation.lit.expected.json b/packages/@aws-cdk/aws-docdb/test/integ.cluster-rotation.lit.expected.json new file mode 100644 index 0000000000000..13a549e5063de --- /dev/null +++ b/packages/@aws-cdk/aws-docdb/test/integ.cluster-rotation.lit.expected.json @@ -0,0 +1,798 @@ +{ + "Transform": "AWS::Serverless-2016-10-31", + "Resources": { + "VPCB9E5F0B4": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-docdb-cluster-rotation/VPC" + } + ] + } + }, + "VPCPublicSubnet1SubnetB4246D30": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/19", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-docdb-cluster-rotation/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1RouteTableFEE4B781": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-docdb-cluster-rotation/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1RouteTableAssociation0B0896DC": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + } + } + }, + "VPCPublicSubnet1DefaultRoute91CEF279": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet1EIP6AD938E8": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-docdb-cluster-rotation/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1NATGatewayE0556630": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet1EIP6AD938E8", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-docdb-cluster-rotation/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet2Subnet74179F39": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.32.0/19", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-docdb-cluster-rotation/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2RouteTable6F1A15F1": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-docdb-cluster-rotation/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2RouteTableAssociation5A808732": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + } + }, + "VPCPublicSubnet2DefaultRouteB7481BBA": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet2EIP4947BC00": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-docdb-cluster-rotation/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2NATGateway3C070193": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet2EIP4947BC00", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-docdb-cluster-rotation/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet3Subnet631C5E25": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/19", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1c", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-docdb-cluster-rotation/VPC/PublicSubnet3" + } + ] + } + }, + "VPCPublicSubnet3RouteTable98AE0E14": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-docdb-cluster-rotation/VPC/PublicSubnet3" + } + ] + } + }, + "VPCPublicSubnet3RouteTableAssociation427FE0C6": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet3RouteTable98AE0E14" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + } + } + }, + "VPCPublicSubnet3DefaultRouteA0D29D46": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet3RouteTable98AE0E14" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet3EIPAD4BC883": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-docdb-cluster-rotation/VPC/PublicSubnet3" + } + ] + } + }, + "VPCPublicSubnet3NATGatewayD3048F5C": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet3EIPAD4BC883", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-docdb-cluster-rotation/VPC/PublicSubnet3" + } + ] + } + }, + "VPCPrivateSubnet1Subnet8BCA10E0": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.96.0/19", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-docdb-cluster-rotation/VPC/PrivateSubnet1" + } + ] + } + }, + "VPCPrivateSubnet1RouteTableBE8A6027": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-docdb-cluster-rotation/VPC/PrivateSubnet1" + } + ] + } + }, + "VPCPrivateSubnet1RouteTableAssociation347902D1": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + } + } + }, + "VPCPrivateSubnet1DefaultRouteAE1D6490": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet1NATGatewayE0556630" + } + } + }, + "VPCPrivateSubnet2SubnetCFCDAA7A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/19", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-docdb-cluster-rotation/VPC/PrivateSubnet2" + } + ] + } + }, + "VPCPrivateSubnet2RouteTable0A19E10E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-docdb-cluster-rotation/VPC/PrivateSubnet2" + } + ] + } + }, + "VPCPrivateSubnet2RouteTableAssociation0C73D413": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + } + }, + "VPCPrivateSubnet2DefaultRouteF4F5CFD2": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet2NATGateway3C070193" + } + } + }, + "VPCPrivateSubnet3Subnet3EDCD457": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.160.0/19", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1c", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-docdb-cluster-rotation/VPC/PrivateSubnet3" + } + ] + } + }, + "VPCPrivateSubnet3RouteTable192186F8": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-docdb-cluster-rotation/VPC/PrivateSubnet3" + } + ] + } + }, + "VPCPrivateSubnet3RouteTableAssociationC28D144E": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet3RouteTable192186F8" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet3Subnet3EDCD457" + } + } + }, + "VPCPrivateSubnet3DefaultRoute27F311AE": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet3RouteTable192186F8" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet3NATGatewayD3048F5C" + } + } + }, + "VPCIGWB7E252D3": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-docdb-cluster-rotation/VPC" + } + ] + } + }, + "VPCVPCGW99B986DC": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "InternetGatewayId": { + "Ref": "VPCIGWB7E252D3" + } + } + }, + "DatabaseSubnets56F17B9A": { + "Type": "AWS::DocDB::DBSubnetGroup", + "Properties": { + "DBSubnetGroupDescription": "Subnets for Database database", + "SubnetIds": [ + { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + }, + { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + }, + { + "Ref": "VPCPrivateSubnet3Subnet3EDCD457" + } + ] + } + }, + "DatabaseSecurityGroup5C91FDCB": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "DocumentDB security group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "DatabaseSecurityGroupfromawscdkdocdbclusterrotationDatabaseRotationSingleUserSecurityGroupBF39D224IndirectPortE14845D7": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "Description": "from awscdkdocdbclusterrotationDatabaseRotationSingleUserSecurityGroupBF39D224:{IndirectPort}", + "FromPort": { + "Fn::GetAtt": [ + "DatabaseB269D8BB", + "Port" + ] + }, + "GroupId": { + "Fn::GetAtt": [ + "DatabaseSecurityGroup5C91FDCB", + "GroupId" + ] + }, + "SourceSecurityGroupId": { + "Fn::GetAtt": [ + "DatabaseRotationSingleUserSecurityGroupAC6E0E73", + "GroupId" + ] + }, + "ToPort": { + "Fn::GetAtt": [ + "DatabaseB269D8BB", + "Port" + ] + } + } + }, + "DatabaseSecret3B817195": { + "Type": "AWS::SecretsManager::Secret", + "Properties": { + "Description": { + "Fn::Join": [ + "", + [ + "Generated by the CDK for stack: ", + { + "Ref": "AWS::StackName" + } + ] + ] + }, + "GenerateSecretString": { + "ExcludeCharacters": "\"@/", + "GenerateStringKey": "password", + "PasswordLength": 41, + "SecretStringTemplate": "{\"username\":\"docdb\"}" + } + } + }, + "DatabaseSecretAttachmentE5D1B020": { + "Type": "AWS::SecretsManager::SecretTargetAttachment", + "Properties": { + "SecretId": { + "Ref": "DatabaseSecret3B817195" + }, + "TargetId": { + "Ref": "DatabaseB269D8BB" + }, + "TargetType": "AWS::DocDB::DBCluster" + } + }, + "DatabaseSecretAttachmentRotationScheduleA4E9F034": { + "Type": "AWS::SecretsManager::RotationSchedule", + "Properties": { + "SecretId": { + "Ref": "DatabaseSecretAttachmentE5D1B020" + }, + "RotationLambdaARN": { + "Fn::GetAtt": [ + "DatabaseRotationSingleUser65F55654", + "Outputs.RotationLambdaARN" + ] + }, + "RotationRules": { + "AutomaticallyAfterDays": 30 + } + } + }, + "DatabaseSecretAttachmentPolicy5ACFE6CA": { + "Type": "AWS::SecretsManager::ResourcePolicy", + "Properties": { + "ResourcePolicy": { + "Statement": [ + { + "Action": "secretsmanager:DeleteSecret", + "Effect": "Deny", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "SecretId": { + "Ref": "DatabaseSecretAttachmentE5D1B020" + } + } + }, + "DatabaseB269D8BB": { + "Type": "AWS::DocDB::DBCluster", + "Properties": { + "MasterUsername": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "DatabaseSecret3B817195" + }, + ":SecretString:username::}}" + ] + ] + }, + "MasterUserPassword": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "DatabaseSecret3B817195" + }, + ":SecretString:password::}}" + ] + ] + }, + "DBSubnetGroupName": { + "Ref": "DatabaseSubnets56F17B9A" + }, + "StorageEncrypted": true, + "VpcSecurityGroupIds": [ + { + "Fn::GetAtt": [ + "DatabaseSecurityGroup5C91FDCB", + "GroupId" + ] + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "DatabaseInstance1844F58FD": { + "Type": "AWS::DocDB::DBInstance", + "Properties": { + "DBClusterIdentifier": { + "Ref": "DatabaseB269D8BB" + }, + "DBInstanceClass": "db.r5.large" + }, + "DependsOn": [ + "VPCPrivateSubnet1DefaultRouteAE1D6490", + "VPCPrivateSubnet2DefaultRouteF4F5CFD2", + "VPCPrivateSubnet3DefaultRoute27F311AE" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "DatabaseRotationSingleUserSecurityGroupAC6E0E73": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-cdk-docdb-cluster-rotation/Database/RotationSingleUser/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "DatabaseRotationSingleUser65F55654": { + "Type": "AWS::Serverless::Application", + "Properties": { + "Location": { + "ApplicationId": "arn:aws:serverlessrepo:us-east-1:297356227824:applications/SecretsManagerMongoDBRotationSingleUser", + "SemanticVersion": "1.1.3" + }, + "Parameters": { + "endpoint": { + "Fn::Join": [ + "", + [ + "https://secretsmanager.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + }, + "functionName": "awscdkdocdbclusterrotationDatabaseRotationSingleUser7DAE65BE", + "vpcSubnetIds": { + "Fn::Join": [ + "", + [ + { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + }, + ",", + { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + }, + ",", + { + "Ref": "VPCPrivateSubnet3Subnet3EDCD457" + } + ] + ] + }, + "vpcSecurityGroupIds": { + "Fn::GetAtt": [ + "DatabaseRotationSingleUserSecurityGroupAC6E0E73", + "GroupId" + ] + } + } + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-docdb/test/integ.cluster-rotation.lit.ts b/packages/@aws-cdk/aws-docdb/test/integ.cluster-rotation.lit.ts new file mode 100644 index 0000000000000..e8c6ed141e1f9 --- /dev/null +++ b/packages/@aws-cdk/aws-docdb/test/integ.cluster-rotation.lit.ts @@ -0,0 +1,33 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as cdk from '@aws-cdk/core'; +import * as docdb from '../lib'; + +/* + * Stack verification steps: + * * aws secretsmanager describe-secret --secret-id + * * aws lambda get-function --function-name + */ + +class TestStack extends cdk.Stack { + constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) { + super(scope, id, props); + + const vpc = new ec2.Vpc(this, 'VPC', { maxAzs: 2 }); + + const params = new ClusterParameterGroup(this, 'Params', { + family: 'docdb3.6', + description: 'A nice parameter group', + parameters: { + audit_logs: 'disabled', + tls: 'enabled', + ttl_monitor: 'enabled', + }, + }); + + const kmsKey = new kms.Key(this, 'DbSecurity', { + removalPolicy: cdk.RemovalPolicy.DESTROY, + }); + + const cluster = new DatabaseCluster(this, 'Database', { + masterUser: { + username: 'docdb', + password: cdk.SecretValue.plainText('7959866cacc02c2d243ecfe177464fe6'), + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.LARGE), + vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC }, + vpc, + }, + parameterGroup: params, + kmsKey, + removalPolicy: cdk.RemovalPolicy.DESTROY, + }); + + cluster.connections.allowDefaultPortFromAnyIpv4('Open to the world'); + } +} + +const app = new cdk.App(); + +new TestStack(app, 'aws-cdk-docdb-integ'); + +app.synth(); diff --git a/packages/@aws-cdk/aws-docdb/test/parameter-group.test.ts b/packages/@aws-cdk/aws-docdb/test/parameter-group.test.ts new file mode 100644 index 0000000000000..34f88c5b33f4d --- /dev/null +++ b/packages/@aws-cdk/aws-docdb/test/parameter-group.test.ts @@ -0,0 +1,53 @@ +import { expect, haveResource } from '@aws-cdk/assert'; +import { Stack } from '@aws-cdk/core'; +import { ClusterParameterGroup } from '../lib'; + +describe('ClusterParameterGroup', () => { + + test('check that instantiation works', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + new ClusterParameterGroup(stack, 'Params', { + family: 'hello', + description: 'desc', + parameters: { + key: 'value', + }, + }); + + // THEN + expect(stack).to(haveResource('AWS::DocDB::DBClusterParameterGroup', { + Description: 'desc', + Family: 'hello', + Parameters: { + key: 'value', + }, + })); + + }); + + test('check automatically generated descriptions', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + new ClusterParameterGroup(stack, 'Params', { + family: 'hello', + parameters: { + key: 'value', + }, + }); + + // THEN + expect(stack).to(haveResource('AWS::DocDB::DBClusterParameterGroup', { + Description: 'Cluster parameter group for hello', + Family: 'hello', + Parameters: { + key: 'value', + }, + })); + + }); +}); diff --git a/packages/@aws-cdk/aws-dynamodb-global/.eslintrc.js b/packages/@aws-cdk/aws-dynamodb-global/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/.eslintrc.js +++ b/packages/@aws-cdk/aws-dynamodb-global/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dynamodb-global/package.json b/packages/@aws-cdk/aws-dynamodb-global/package.json index 88ca6f9af4b14..c280e52d7ffc4 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/package.json +++ b/packages/@aws-cdk/aws-dynamodb-global/package.json @@ -54,7 +54,7 @@ }, "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -83,7 +83,7 @@ "compat": "cdk-compat" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "main": "lib/index.js", "types": "lib/index.d.ts", diff --git a/packages/@aws-cdk/aws-dynamodb/.eslintrc.js b/packages/@aws-cdk/aws-dynamodb/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-dynamodb/.eslintrc.js +++ b/packages/@aws-cdk/aws-dynamodb/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dynamodb/.gitignore b/packages/@aws-cdk/aws-dynamodb/.gitignore index 2d2f100c9395d..b6a49df09e933 100644 --- a/packages/@aws-cdk/aws-dynamodb/.gitignore +++ b/packages/@aws-cdk/aws-dynamodb/.gitignore @@ -15,3 +15,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-dynamodb/.npmignore b/packages/@aws-cdk/aws-dynamodb/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-dynamodb/.npmignore +++ b/packages/@aws-cdk/aws-dynamodb/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-dynamodb/README.md b/packages/@aws-cdk/aws-dynamodb/README.md index e034e94b32654..de76cdb238b81 100644 --- a/packages/@aws-cdk/aws-dynamodb/README.md +++ b/packages/@aws-cdk/aws-dynamodb/README.md @@ -88,3 +88,53 @@ const globalTable = new dynamodb.Table(this, 'Table', { When doing so, a CloudFormation Custom Resource will be added to the stack in order to create the replica tables in the selected regions. + +### Encryption + +All user data stored in Amazon DynamoDB is fully encrypted at rest. When creating a new table, you can choose to encrypt using the following customer master keys (CMK) to encrypt your table: +* AWS owned CMK - By default, all tables are encrypted under an AWS owned customer master key (CMK) in the DynamoDB service account (no additional charges apply). +* AWS managed CMK - AWS KMS keys (one per region) are created in your account, managed, and used on your behalf by AWS DynamoDB (AWS KMS chages apply). +* Customer managed CMK - You have full control over the KMS key used to encrypt the DynamoDB Table (AWS KMS charges apply). + +Creating a Table encrypted with a customer managed CMK: + +```ts +import dynamodb = require('@aws-cdk/aws-dynamodb'); + +const table = new dynamodb.Table(stack, 'MyTable', { + partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING }, + encryption: TableEncryption.CUSTOMER_MANAGED, +}); + +// You can access the CMK that was added to the stack on your behalf by the Table construct via: +const tableEncryptionKey = table.encryptionKey; +``` + +You can also supply your own key: + +```ts +import dynamodb = require('@aws-cdk/aws-dynamodb'); +import kms = require('@aws-cdk/aws-kms'); + +const encryptionKey = new kms.Key(stack, 'Key', { + enableKeyRotation: true +}); +const table = new dynamodb.Table(stack, 'MyTable', { + partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING }, + encryption: TableEncryption.CUSTOMER_MANAGED, + encryptionKey, // This will be exposed as table.encryptionKey +}); +``` + +In order to use the AWS managed CMK instead, change the code to: + +```ts +import dynamodb = require('@aws-cdk/aws-dynamodb'); + +const table = new dynamodb.Table(stack, 'MyTable', { + partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING }, + encryption: TableEncryption.AWS_MANAGED, +}); + +// In this case, the CMK _cannot_ be accessed through table.encryptionKey. +``` diff --git a/packages/@aws-cdk/aws-dynamodb/jest.config.js b/packages/@aws-cdk/aws-dynamodb/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-dynamodb/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dynamodb/lib/perms.ts b/packages/@aws-cdk/aws-dynamodb/lib/perms.ts new file mode 100644 index 0000000000000..56b20a2220912 --- /dev/null +++ b/packages/@aws-cdk/aws-dynamodb/lib/perms.ts @@ -0,0 +1,30 @@ +export const READ_DATA_ACTIONS = [ + 'dynamodb:BatchGetItem', + 'dynamodb:GetRecords', + 'dynamodb:GetShardIterator', + 'dynamodb:Query', + 'dynamodb:GetItem', + 'dynamodb:Scan', +]; +export const KEY_READ_ACTIONS = [ + 'kms:Decrypt', + 'kms:DescribeKey', +]; + +export const WRITE_DATA_ACTIONS = [ + 'dynamodb:BatchWriteItem', + 'dynamodb:PutItem', + 'dynamodb:UpdateItem', + 'dynamodb:DeleteItem', +]; +export const KEY_WRITE_ACTIONS = [ + 'kms:Encrypt', + 'kms:ReEncrypt*', + 'kms:GenerateDataKey*', +]; + +export const READ_STREAM_DATA_ACTIONS = [ + 'dynamodb:DescribeStream', + 'dynamodb:GetRecords', + 'dynamodb:GetShardIterator', +]; diff --git a/packages/@aws-cdk/aws-dynamodb/lib/replica-handler/index.ts b/packages/@aws-cdk/aws-dynamodb/lib/replica-handler/index.ts index 9764566a3c08d..044d1c0c359ac 100644 --- a/packages/@aws-cdk/aws-dynamodb/lib/replica-handler/index.ts +++ b/packages/@aws-cdk/aws-dynamodb/lib/replica-handler/index.ts @@ -1,5 +1,5 @@ /* tslint:disable no-console */ -import { IsCompleteRequest, IsCompleteResponse, OnEventRequest, OnEventResponse } from '@aws-cdk/custom-resources/lib/provider-framework/types'; +import type { IsCompleteRequest, IsCompleteResponse, OnEventRequest, OnEventResponse } from '@aws-cdk/custom-resources/lib/provider-framework/types'; import { DynamoDB } from 'aws-sdk'; // eslint-disable-line import/no-extraneous-dependencies export async function onEventHandler(event: OnEventRequest): Promise { diff --git a/packages/@aws-cdk/aws-dynamodb/lib/replica-provider.ts b/packages/@aws-cdk/aws-dynamodb/lib/replica-provider.ts index d3607acc05c18..d10f023631297 100644 --- a/packages/@aws-cdk/aws-dynamodb/lib/replica-provider.ts +++ b/packages/@aws-cdk/aws-dynamodb/lib/replica-provider.ts @@ -32,9 +32,11 @@ export class ReplicaProvider extends NestedStack { private constructor(scope: Construct, id: string) { super(scope, id); + const code = lambda.Code.fromAsset(path.join(__dirname, 'replica-handler')); + // Issues UpdateTable API calls this.onEventHandler = new lambda.Function(this, 'OnEventHandler', { - code: lambda.Code.fromAsset(path.join(__dirname, 'replica-handler')), + code, runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.onEventHandler', timeout: Duration.minutes(5), @@ -42,7 +44,7 @@ export class ReplicaProvider extends NestedStack { // Checks if table is back to `ACTIVE` state this.isCompleteHandler = new lambda.Function(this, 'IsCompleteHandler', { - code: lambda.Code.fromAsset(path.join(__dirname, 'replica-handler')), + code, runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.isCompleteHandler', timeout: Duration.seconds(30), diff --git a/packages/@aws-cdk/aws-dynamodb/lib/table.ts b/packages/@aws-cdk/aws-dynamodb/lib/table.ts index cc5d4a7479d3f..186db2266c2fa 100644 --- a/packages/@aws-cdk/aws-dynamodb/lib/table.ts +++ b/packages/@aws-cdk/aws-dynamodb/lib/table.ts @@ -1,8 +1,10 @@ import * as appscaling from '@aws-cdk/aws-applicationautoscaling'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as iam from '@aws-cdk/aws-iam'; +import * as kms from '@aws-cdk/aws-kms'; import { Aws, CfnCondition, CfnCustomResource, Construct, CustomResource, Fn, IResource, Lazy, RemovalPolicy, Resource, Stack, Token } from '@aws-cdk/core'; -import { CfnTable } from './dynamodb.generated'; +import { CfnTable, CfnTableProps } from './dynamodb.generated'; +import * as perms from './perms'; import { ReplicaProvider } from './replica-provider'; import { EnableScalingProps, IScalableTableAttribute } from './scalable-attribute-api'; import { ScalableTableAttribute } from './scalable-table-attribute'; @@ -13,28 +15,6 @@ const RANGE_KEY_TYPE = 'RANGE'; // https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Limits.html#limits-secondary-indexes const MAX_LOCAL_SECONDARY_INDEX_COUNT = 5; -const READ_DATA_ACTIONS = [ - 'dynamodb:BatchGetItem', - 'dynamodb:GetRecords', - 'dynamodb:GetShardIterator', - 'dynamodb:Query', - 'dynamodb:GetItem', - 'dynamodb:Scan', -]; - -const READ_STREAM_DATA_ACTIONS = [ - 'dynamodb:DescribeStream', - 'dynamodb:GetRecords', - 'dynamodb:GetShardIterator', -]; - -const WRITE_DATA_ACTIONS = [ - 'dynamodb:BatchWriteItem', - 'dynamodb:PutItem', - 'dynamodb:UpdateItem', - 'dynamodb:DeleteItem', -]; - /** * Represents an attribute for describing the key schema for the table * and indexes. @@ -51,6 +31,27 @@ export interface Attribute { readonly type: AttributeType; } +/** + * What kind of server-side encryption to apply to this table. + */ +export enum TableEncryption { + /** + * Server-side KMS encryption with a master key owned by AWS. + */ + DEFAULT = 'AWS_OWNED', + + /** + * Server-side KMS encryption with a customer master key managed by customer. + * If `encryptionKey` is specified, this key will be used, otherwise, one will be defined. + */ + CUSTOMER_MANAGED = 'CUSTOMER_MANAGED', + + /** + * Server-side KMS encryption with a master key managed by AWS. + */ + AWS_MANAGED = 'AWS_MANAGED', +} + /** * Properties of a DynamoDB Table * @@ -103,10 +104,35 @@ export interface TableOptions { /** * Whether server-side encryption with an AWS managed customer master key is enabled. + * + * This property cannot be set if `encryption` and/or `encryptionKey` is set. + * * @default - server-side encryption is enabled with an AWS owned customer master key + * + * @deprecated This property is deprecated. In order to obtain the same behavior as + * enabling this, set the `encryption` property to `TableEncryption.AWS_MANAGED` instead. */ readonly serverSideEncryption?: boolean; + /** + * Whether server-side encryption with an AWS managed customer master key is enabled. + * + * This property cannot be set if `serverSideEncryption` is set. + * + * @default - server-side encryption is enabled with an AWS owned customer master key + */ + readonly encryption?: TableEncryption; + + /** + * External KMS key to use for table encryption. + * + * This property can only be set if `encryption` is set to `TableEncryption.CUSTOMER_MANAGED`. + * + * @default - If `encryption` is set to `TableEncryption.CUSTOMER_MANAGED` and this + * property is undefined, a new KMS key will be created and associated with this table. + */ + readonly encryptionKey?: kms.IKey; + /** * The name of TTL attribute. * @default - TTL is disabled @@ -239,9 +265,19 @@ export interface ITable extends IResource { */ readonly tableStreamArn?: string; + /** + * + * Optional KMS encryption key associated with this table. + */ + readonly encryptionKey?: kms.IKey; + /** * Adds an IAM policy statement associated with this table to an IAM * principal's policy. + * + * If `encryptionKey` is present, appropriate grants to the key needs to be added + * separately using the `table.encryptionKey.grant*` methods. + * * @param grantee The principal (no-op if undefined) * @param actions The set of actions to allow (i.e. "dynamodb:PutItem", "dynamodb:GetItem", ...) */ @@ -250,6 +286,10 @@ export interface ITable extends IResource { /** * Adds an IAM policy statement associated with this table's stream to an * IAM principal's policy. + * + * If `encryptionKey` is present, appropriate grants to the key needs to be added + * separately using the `table.encryptionKey.grant*` methods. + * * @param grantee The principal (no-op if undefined) * @param actions The set of actions to allow (i.e. "dynamodb:DescribeStream", "dynamodb:GetRecords", ...) */ @@ -258,6 +298,10 @@ export interface ITable extends IResource { /** * Permits an IAM principal all data read operations from this table: * BatchGetItem, GetRecords, GetShardIterator, Query, GetItem, Scan. + * + * Appropriate grants will also be added to the customer-managed KMS key + * if one was configured. + * * @param grantee The principal to grant access to */ grantReadData(grantee: iam.IGrantable): iam.Grant; @@ -273,6 +317,10 @@ export interface ITable extends IResource { * Permits an IAM principal all stream data read operations for this * table's stream: * DescribeStream, GetRecords, GetShardIterator, ListStreams. + * + * Appropriate grants will also be added to the customer-managed KMS key + * if one was configured. + * * @param grantee The principal to grant access to */ grantStreamRead(grantee: iam.IGrantable): iam.Grant; @@ -280,6 +328,10 @@ export interface ITable extends IResource { /** * Permits an IAM principal all data write operations to this table: * BatchWriteItem, PutItem, UpdateItem, DeleteItem. + * + * Appropriate grants will also be added to the customer-managed KMS key + * if one was configured. + * * @param grantee The principal to grant access to */ grantWriteData(grantee: iam.IGrantable): iam.Grant; @@ -288,12 +340,20 @@ export interface ITable extends IResource { * Permits an IAM principal to all data read/write operations to this table. * BatchGetItem, GetRecords, GetShardIterator, Query, GetItem, Scan, * BatchWriteItem, PutItem, UpdateItem, DeleteItem + * + * Appropriate grants will also be added to the customer-managed KMS key + * if one was configured. + * * @param grantee The principal to grant access to */ grantReadWriteData(grantee: iam.IGrantable): iam.Grant; /** * Permits all DynamoDB operations ("dynamodb:*") to an IAM principal. + * + * Appropriate grants will also be added to the customer-managed KMS key + * if one was configured. + * * @param grantee The principal to grant access to */ grantFullAccess(grantee: iam.IGrantable): iam.Grant; @@ -372,6 +432,13 @@ export interface TableAttributes { * @default - no table stream */ readonly tableStreamArn?: string; + + /** + * KMS encryption key, if this table uses a customer-managed encryption key. + * + * @default - no key + */ + readonly encryptionKey?: kms.IKey; } abstract class TableBase extends Resource implements ITable { @@ -390,11 +457,20 @@ abstract class TableBase extends Resource implements ITable { */ public abstract readonly tableStreamArn?: string; + /** + * KMS encryption key, if this table uses a customer-managed encryption key. + */ + public abstract readonly encryptionKey?: kms.IKey; + protected readonly regionalArns = new Array(); /** * Adds an IAM policy statement associated with this table to an IAM * principal's policy. + * + * If `encryptionKey` is present, appropriate grants to the key needs to be added + * separately using the `table.encryptionKey.grant*` methods. + * * @param grantee The principal (no-op if undefined) * @param actions The set of actions to allow (i.e. "dynamodb:PutItem", "dynamodb:GetItem", ...) */ @@ -417,6 +493,10 @@ abstract class TableBase extends Resource implements ITable { /** * Adds an IAM policy statement associated with this table's stream to an * IAM principal's policy. + * + * If `encryptionKey` is present, appropriate grants to the key needs to be added + * separately using the `table.encryptionKey.grant*` methods. + * * @param grantee The principal (no-op if undefined) * @param actions The set of actions to allow (i.e. "dynamodb:DescribeStream", "dynamodb:GetRecords", ...) */ @@ -436,10 +516,14 @@ abstract class TableBase extends Resource implements ITable { /** * Permits an IAM principal all data read operations from this table: * BatchGetItem, GetRecords, GetShardIterator, Query, GetItem, Scan. + * + * Appropriate grants will also be added to the customer-managed KMS key + * if one was configured. + * * @param grantee The principal to grant access to */ public grantReadData(grantee: iam.IGrantable): iam.Grant { - return this.grant(grantee, ...READ_DATA_ACTIONS); + return this.combinedGrant(grantee, { keyActions: perms.KEY_READ_ACTIONS, tableActions: perms.READ_DATA_ACTIONS }); } /** @@ -466,38 +550,57 @@ abstract class TableBase extends Resource implements ITable { * Permits an IAM principal all stream data read operations for this * table's stream: * DescribeStream, GetRecords, GetShardIterator, ListStreams. + * + * Appropriate grants will also be added to the customer-managed KMS key + * if one was configured. + * * @param grantee The principal to grant access to */ public grantStreamRead(grantee: iam.IGrantable): iam.Grant { this.grantTableListStreams(grantee); - return this.grantStream(grantee, ...READ_STREAM_DATA_ACTIONS); + return this.combinedGrant(grantee, { keyActions: perms.KEY_READ_ACTIONS, streamActions: perms.READ_STREAM_DATA_ACTIONS }); } /** * Permits an IAM principal all data write operations to this table: * BatchWriteItem, PutItem, UpdateItem, DeleteItem. + * + * Appropriate grants will also be added to the customer-managed KMS key + * if one was configured. + * * @param grantee The principal to grant access to */ public grantWriteData(grantee: iam.IGrantable): iam.Grant { - return this.grant(grantee, ...WRITE_DATA_ACTIONS); + return this.combinedGrant(grantee, { keyActions: perms.KEY_WRITE_ACTIONS, tableActions: perms.WRITE_DATA_ACTIONS }); } /** * Permits an IAM principal to all data read/write operations to this table. * BatchGetItem, GetRecords, GetShardIterator, Query, GetItem, Scan, * BatchWriteItem, PutItem, UpdateItem, DeleteItem + * + * Appropriate grants will also be added to the customer-managed KMS key + * if one was configured. + * * @param grantee The principal to grant access to */ public grantReadWriteData(grantee: iam.IGrantable): iam.Grant { - return this.grant(grantee, ...READ_DATA_ACTIONS, ...WRITE_DATA_ACTIONS); + const tableActions = perms.READ_DATA_ACTIONS.concat(perms.WRITE_DATA_ACTIONS); + const keyActions = perms.KEY_READ_ACTIONS.concat(perms.KEY_WRITE_ACTIONS); + return this.combinedGrant(grantee, { keyActions, tableActions }); } /** * Permits all DynamoDB operations ("dynamodb:*") to an IAM principal. + * + * Appropriate grants will also be added to the customer-managed KMS key + * if one was configured. + * * @param grantee The principal to grant access to */ public grantFullAccess(grantee: iam.IGrantable) { - return this.grant(grantee, 'dynamodb:*'); + const keyActions = perms.KEY_READ_ACTIONS.concat(perms.KEY_WRITE_ACTIONS); + return this.combinedGrant(grantee, { keyActions, tableActions: ['dynamodb:*'] }); } /** @@ -569,6 +672,51 @@ abstract class TableBase extends Resource implements ITable { } protected abstract get hasIndex(): boolean; + + /** + * Adds an IAM policy statement associated with this table to an IAM + * principal's policy. + * @param grantee The principal (no-op if undefined) + * @param opts Options for keyActions, tableActions and streamActions + */ + private combinedGrant( + grantee: iam.IGrantable, + opts: {keyActions?: string[], tableActions?: string[], streamActions?: string[]}, + ) { + if (opts.tableActions) { + const resources = [this.tableArn, + Lazy.stringValue({ produce: () => this.hasIndex ? `${this.tableArn}/index/*` : Aws.NO_VALUE }), + ...this.regionalArns, + ...this.regionalArns.map(arn => Lazy.stringValue({ + produce: () => this.hasIndex ? `${arn}/index/*` : Aws.NO_VALUE, + })), + ]; + const ret = iam.Grant.addToPrincipal({ + grantee, + actions: opts.tableActions, + resourceArns: resources, + scope: this, + }); + if (this.encryptionKey && opts.keyActions) { + this.encryptionKey.grant(grantee, ...opts.keyActions); + } + return ret; + } + if (opts.streamActions) { + if (!this.tableStreamArn) { + throw new Error(`DynamoDB Streams must be enabled on the table ${this.node.path}`); + } + const resources = [ this.tableStreamArn]; + const ret = iam.Grant.addToPrincipal({ + grantee, + actions: opts.streamActions, + resourceArns: resources, + scope: this, + }); + return ret; + } + throw new Error(`Unexpected 'action', ${ opts.tableActions || opts.streamActions }`); + } } /** @@ -624,12 +772,14 @@ export class Table extends TableBase { public readonly tableName: string; public readonly tableArn: string; public readonly tableStreamArn?: string; + public readonly encryptionKey?: kms.IKey; constructor(_tableArn: string, tableName: string, tableStreamArn?: string) { super(scope, id); this.tableArn = _tableArn; this.tableName = tableName; this.tableStreamArn = tableStreamArn; + this.encryptionKey = attrs.encryptionKey; } protected get hasIndex(): boolean { @@ -660,6 +810,8 @@ export class Table extends TableBase { return new Import(arn, name, attrs.tableStreamArn); } + public readonly encryptionKey?: kms.IKey; + /** * @attribute */ @@ -698,6 +850,8 @@ export class Table extends TableBase { physicalName: props.tableName, }); + const { sseSpecification, encryptionKey } = this.parseEncryption(props); + this.billingMode = props.billingMode || BillingMode.PROVISIONED; this.validateProvisioning(props); @@ -728,12 +882,14 @@ export class Table extends TableBase { readCapacityUnits: props.readCapacity || 5, writeCapacityUnits: props.writeCapacity || 5, }, - sseSpecification: props.serverSideEncryption ? { sseEnabled: props.serverSideEncryption } : undefined, + sseSpecification, streamSpecification, timeToLiveSpecification: props.timeToLiveAttribute ? { attributeName: props.timeToLiveAttribute, enabled: true } : undefined, }); this.table.applyRemovalPolicy(props.removalPolicy); + this.encryptionKey = encryptionKey; + if (props.tableName) { this.node.addMetadata('aws:cdk:hasPhysicalName', props.tableName); } this.tableArn = this.getResourceArnAttribute(this.table.attrArn, { @@ -1128,6 +1284,62 @@ export class Table extends TableBase { protected get hasIndex(): boolean { return this.globalSecondaryIndexes.length + this.localSecondaryIndexes.length > 0; } + + /** + * Set up key properties and return the Table encryption property from the + * user's configuration. + */ + private parseEncryption(props: TableProps): { sseSpecification: CfnTableProps['sseSpecification'], encryptionKey?: kms.IKey } { + let encryptionType = props.encryption; + + if (encryptionType != null && props.serverSideEncryption != null) { + throw new Error('Only one of encryption and serverSideEncryption can be specified, but both were provided'); + } + + if (props.serverSideEncryption && props.encryptionKey) { + throw new Error('encryptionKey cannot be specified when serverSideEncryption is specified. Use encryption instead'); + } + + if (encryptionType === undefined) { + encryptionType = props.encryptionKey != null + // If there is a configured encyptionKey, the encryption is implicitly CUSTOMER_MANAGED + ? TableEncryption.CUSTOMER_MANAGED + // Otherwise, if severSideEncryption is enabled, it's AWS_MANAGED; else DEFAULT + : props.serverSideEncryption ? TableEncryption.AWS_MANAGED : TableEncryption.DEFAULT; + } + + if (encryptionType !== TableEncryption.CUSTOMER_MANAGED && props.encryptionKey) { + throw new Error('`encryptionKey cannot be specified unless encryption is set to TableEncryption.CUSTOMER_MANAGED (it was set to ${encryptionType})`'); + } + + if (encryptionType === TableEncryption.CUSTOMER_MANAGED && props.replicationRegions) { + throw new Error('TableEncryption.CUSTOMER_MANAGED is not supported by DynamoDB Global Tables (where replicationRegions was set)'); + } + + switch (encryptionType) { + case TableEncryption.CUSTOMER_MANAGED: + const encryptionKey = props.encryptionKey ?? new kms.Key(this, 'Key', { + description: `Customer-managed key auto-created for encrypting DynamoDB table at ${this.node.path}`, + enableKeyRotation: true, + }); + + return { + sseSpecification: { sseEnabled: true, kmsMasterKeyId: encryptionKey.keyArn, sseType: 'KMS' }, + encryptionKey, + }; + + case TableEncryption.AWS_MANAGED: + // Not specifying "sseType: 'KMS'" here because it would cause phony changes to existing stacks. + return { sseSpecification: { sseEnabled: true } }; + + case TableEncryption.DEFAULT: + // Not specifying "sseEnabled: false" here because it would cause phony changes to existing stacks. + return { sseSpecification: undefined }; + + default: + throw new Error(`Unexpected 'encryptionType': ${encryptionType}`); + } + } } /** diff --git a/packages/@aws-cdk/aws-dynamodb/package.json b/packages/@aws-cdk/aws-dynamodb/package.json index 1f5ab51d07702..be0ac34ef307f 100644 --- a/packages/@aws-cdk/aws-dynamodb/package.json +++ b/packages/@aws-cdk/aws-dynamodb/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::DynamoDB" + "cloudformation": "AWS::DynamoDB", + "jest": true }, "keywords": [ "aws", @@ -63,8 +64,8 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/jest": "^25.2.1", - "aws-sdk": "^2.672.0", + "@types/jest": "^25.2.2", + "aws-sdk": "^2.678.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", @@ -72,13 +73,14 @@ "jest": "^25.5.4", "pkglint": "0.0.0", "sinon": "^9.0.2", - "ts-jest": "^25.5.0" + "ts-jest": "^26.0.0" }, "dependencies": { "@aws-cdk/aws-applicationautoscaling": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", "constructs": "^3.0.2" @@ -89,17 +91,17 @@ "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "stable", "awscdkio": { "announce": false }, - "jest": {}, "maturity": "stable" } diff --git a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts index 6575affc93740..c422330e2c1ce 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts @@ -2,6 +2,7 @@ import { ResourcePart, SynthUtils } from '@aws-cdk/assert'; 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, CfnDeletionPolicy, ConstructNode, Duration, RemovalPolicy, Stack, Tag } from '@aws-cdk/core'; import { Attribute, @@ -12,6 +13,7 @@ import { ProjectionType, StreamViewType, Table, + TableEncryption, } from '../lib'; // tslint:disable:object-literal-key-quotes @@ -345,6 +347,482 @@ test('when specifying every property', () => { ); }); +test('when specifying sse with customer managed CMK', () => { + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { + tableName: TABLE_NAME, + encryption: TableEncryption.CUSTOMER_MANAGED, + partitionKey: TABLE_PARTITION_KEY, + }); + table.node.applyAspect(new Tag('Environment', 'Production')); + + expect(stack).toHaveResource('AWS::DynamoDB::Table', { + 'SSESpecification': { + 'KMSMasterKeyId': { + 'Fn::GetAtt': [ + 'MyTableKey8597C7A6', + 'Arn', + ], + }, + 'SSEEnabled': true, + 'SSEType': 'KMS', + }, + }); +}); + +test('when specifying only encryptionKey', () => { + const stack = new Stack(); + const encryptionKey = new kms.Key(stack, 'Key', { + enableKeyRotation: true, + }); + const table = new Table(stack, CONSTRUCT_NAME, { + tableName: TABLE_NAME, + encryptionKey, + partitionKey: TABLE_PARTITION_KEY, + }); + table.node.applyAspect(new Tag('Environment', 'Production')); + + expect(stack).toHaveResource('AWS::DynamoDB::Table', { + 'SSESpecification': { + 'KMSMasterKeyId': { + 'Fn::GetAtt': [ + 'Key961B73FD', + 'Arn', + ], + }, + 'SSEEnabled': true, + 'SSEType': 'KMS', + }, + }); +}); + +test('when specifying sse with customer managed CMK with encryptionKey provided by user', () => { + const stack = new Stack(); + const encryptionKey = new kms.Key(stack, 'Key', { + enableKeyRotation: true, + }); + const table = new Table(stack, CONSTRUCT_NAME, { + tableName: TABLE_NAME, + encryption: TableEncryption.CUSTOMER_MANAGED, + encryptionKey, + partitionKey: TABLE_PARTITION_KEY, + }); + table.node.applyAspect(new Tag('Environment', 'Production')); + + expect(stack).toHaveResource('AWS::DynamoDB::Table', { + 'SSESpecification': { + 'KMSMasterKeyId': { + 'Fn::GetAtt': [ + 'Key961B73FD', + 'Arn', + ], + }, + 'SSEEnabled': true, + 'SSEType': 'KMS', + }, + }); +}); + +test('fails if encryption key is used with AWS managed CMK', () => { + const stack = new Stack(); + const encryptionKey = new kms.Key(stack, 'Key', { + enableKeyRotation: true, + }); + expect(() => new Table(stack, 'Table A', { + tableName: TABLE_NAME, + partitionKey: TABLE_PARTITION_KEY, + encryption: TableEncryption.AWS_MANAGED, + encryptionKey, + })).toThrow('`encryptionKey cannot be specified unless encryption is set to TableEncryption.CUSTOMER_MANAGED (it was set to ${encryptionType})`'); +}); + +test('fails if encryption key is used with default encryption', () => { + const stack = new Stack(); + const encryptionKey = new kms.Key(stack, 'Key', { + enableKeyRotation: true, + }); + expect(() => new Table(stack, 'Table A', { + tableName: TABLE_NAME, + partitionKey: TABLE_PARTITION_KEY, + encryption: TableEncryption.DEFAULT, + encryptionKey, + })).toThrow('`encryptionKey cannot be specified unless encryption is set to TableEncryption.CUSTOMER_MANAGED (it was set to ${encryptionType})`'); +}); + +test('fails if encryption key is used with serverSideEncryption', () => { + const stack = new Stack(); + const encryptionKey = new kms.Key(stack, 'Key', { + enableKeyRotation: true, + }); + expect(() => new Table(stack, 'Table A', { + tableName: TABLE_NAME, + partitionKey: TABLE_PARTITION_KEY, + serverSideEncryption: true, + encryptionKey, + })).toThrow(/encryptionKey cannot be specified when serverSideEncryption is specified. Use encryption instead/); +}); + +test('fails if both encryption and serverSideEncryption is specified', () => { + const stack = new Stack(); + expect(() => new Table(stack, 'Table A', { + tableName: TABLE_NAME, + partitionKey: TABLE_PARTITION_KEY, + encryption: TableEncryption.DEFAULT, + serverSideEncryption: true, + })).toThrow(/Only one of encryption and serverSideEncryption can be specified, but both were provided/); +}); + +test('fails if both replication regions used with customer managed CMK', () => { + const stack = new Stack(); + expect(() => new Table(stack, 'Table A', { + tableName: TABLE_NAME, + partitionKey: TABLE_PARTITION_KEY, + replicationRegions: ['us-east-1', 'us-east-2', 'us-west-2'], + encryption: TableEncryption.CUSTOMER_MANAGED, + })).toThrow('TableEncryption.CUSTOMER_MANAGED is not supported by DynamoDB Global Tables (where replicationRegions was set)'); +}); + +test('if an encryption key is included, decrypt permissions are also added for grantStream', () => { + const stack = new Stack(); + const encryptionKey = new kms.Key(stack, 'Key', { + enableKeyRotation: true, + }); + const table = new Table(stack, 'Table A', { + tableName: TABLE_NAME, + partitionKey: TABLE_PARTITION_KEY, + encryptionKey, + stream: StreamViewType.NEW_IMAGE, + }); + const user = new iam.User(stack, 'MyUser'); + table.grantStreamRead(user); + expect(stack).toMatchTemplate({ + 'Resources': { + 'Key961B73FD': { + 'Type': 'AWS::KMS::Key', + 'Properties': { + 'KeyPolicy': { + 'Statement': [ + { + 'Action': [ + 'kms:Create*', + 'kms:Describe*', + 'kms:Enable*', + 'kms:List*', + 'kms:Put*', + 'kms:Update*', + 'kms:Revoke*', + 'kms:Disable*', + 'kms:Get*', + 'kms:Delete*', + 'kms:ScheduleKeyDeletion', + 'kms:CancelKeyDeletion', + 'kms:GenerateDataKey', + 'kms:TagResource', + 'kms:UntagResource', + ], + 'Effect': 'Allow', + 'Principal': { + 'AWS': { + 'Fn::Join': [ + '', + [ + 'arn:', + { + 'Ref': 'AWS::Partition', + }, + ':iam::', + { + 'Ref': 'AWS::AccountId', + }, + ':root', + ], + ], + }, + }, + 'Resource': '*', + }, + ], + 'Version': '2012-10-17', + }, + 'EnableKeyRotation': true, + }, + 'UpdateReplacePolicy': 'Retain', + 'DeletionPolicy': 'Retain', + }, + 'TableA3D7B5AFA': { + 'Type': 'AWS::DynamoDB::Table', + 'Properties': { + 'KeySchema': [ + { + 'AttributeName': 'hashKey', + 'KeyType': 'HASH', + }, + ], + 'AttributeDefinitions': [ + { + 'AttributeName': 'hashKey', + 'AttributeType': 'S', + }, + ], + 'ProvisionedThroughput': { + 'ReadCapacityUnits': 5, + 'WriteCapacityUnits': 5, + }, + 'SSESpecification': { + 'KMSMasterKeyId': { + 'Fn::GetAtt': [ + 'Key961B73FD', + 'Arn', + ], + }, + 'SSEEnabled': true, + 'SSEType': 'KMS', + }, + 'StreamSpecification': { + 'StreamViewType': 'NEW_IMAGE', + }, + 'TableName': 'MyTable', + }, + 'UpdateReplacePolicy': 'Retain', + 'DeletionPolicy': 'Retain', + }, + 'MyUserDC45028B': { + 'Type': 'AWS::IAM::User', + }, + 'MyUserDefaultPolicy7B897426': { + 'Type': 'AWS::IAM::Policy', + 'Properties': { + 'PolicyDocument': { + 'Statement': [ + { + 'Action': 'dynamodb:ListStreams', + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': [ + '', + [ + { + 'Fn::GetAtt': [ + 'TableA3D7B5AFA', + 'Arn', + ], + }, + '/stream/*', + ], + ], + }, + }, + { + 'Action': [ + 'dynamodb:DescribeStream', + 'dynamodb:GetRecords', + 'dynamodb:GetShardIterator', + ], + 'Effect': 'Allow', + 'Resource': { + 'Fn::GetAtt': [ + 'TableA3D7B5AFA', + 'StreamArn', + ], + }, + }, + ], + 'Version': '2012-10-17', + }, + 'PolicyName': 'MyUserDefaultPolicy7B897426', + 'Users': [ + { + 'Ref': 'MyUserDC45028B', + }, + ], + }, + }, + }, + }); +}); + +test('if an encryption key is included, encrypt/decrypt permissions are also added both ways', () => { + const stack = new Stack(); + const table = new Table(stack, 'Table A', { + tableName: TABLE_NAME, + partitionKey: TABLE_PARTITION_KEY, + encryption: TableEncryption.CUSTOMER_MANAGED, + }); + const user = new iam.User(stack, 'MyUser'); + table.grantReadWriteData(user); + expect(stack).toMatchTemplate({ + 'Resources': { + 'TableAKey07CC09EC': { + 'Type': 'AWS::KMS::Key', + 'Properties': { + 'KeyPolicy': { + 'Statement': [ + { + 'Action': [ + 'kms:Create*', + 'kms:Describe*', + 'kms:Enable*', + 'kms:List*', + 'kms:Put*', + 'kms:Update*', + 'kms:Revoke*', + 'kms:Disable*', + 'kms:Get*', + 'kms:Delete*', + 'kms:ScheduleKeyDeletion', + 'kms:CancelKeyDeletion', + 'kms:GenerateDataKey', + 'kms:TagResource', + 'kms:UntagResource', + ], + 'Effect': 'Allow', + 'Principal': { + 'AWS': { + 'Fn::Join': [ + '', + [ + 'arn:', + { + 'Ref': 'AWS::Partition', + }, + ':iam::', + { + 'Ref': 'AWS::AccountId', + }, + ':root', + ], + ], + }, + }, + 'Resource': '*', + }, + { + 'Action': [ + 'kms:Decrypt', + 'kms:DescribeKey', + 'kms:Encrypt', + 'kms:ReEncrypt*', + 'kms:GenerateDataKey*', + ], + 'Effect': 'Allow', + 'Principal': { + 'AWS': { + 'Fn::GetAtt': [ + 'MyUserDC45028B', + 'Arn', + ], + }, + }, + 'Resource': '*', + }, + ], + 'Version': '2012-10-17', + }, + 'Description': 'Customer-managed key auto-created for encrypting DynamoDB table at Table A', + 'EnableKeyRotation': true, + }, + 'UpdateReplacePolicy': 'Retain', + 'DeletionPolicy': 'Retain', + }, + 'TableA3D7B5AFA': { + 'Type': 'AWS::DynamoDB::Table', + 'Properties': { + 'KeySchema': [ + { + 'AttributeName': 'hashKey', + 'KeyType': 'HASH', + }, + ], + 'AttributeDefinitions': [ + { + 'AttributeName': 'hashKey', + 'AttributeType': 'S', + }, + ], + 'ProvisionedThroughput': { + 'ReadCapacityUnits': 5, + 'WriteCapacityUnits': 5, + }, + 'SSESpecification': { + 'KMSMasterKeyId': { + 'Fn::GetAtt': [ + 'TableAKey07CC09EC', + 'Arn', + ], + }, + 'SSEEnabled': true, + 'SSEType': 'KMS', + }, + 'TableName': 'MyTable', + }, + 'UpdateReplacePolicy': 'Retain', + 'DeletionPolicy': 'Retain', + }, + 'MyUserDC45028B': { + 'Type': 'AWS::IAM::User', + }, + 'MyUserDefaultPolicy7B897426': { + 'Type': 'AWS::IAM::Policy', + 'Properties': { + 'PolicyDocument': { + 'Statement': [ + { + 'Action': [ + 'dynamodb:BatchGetItem', + 'dynamodb:GetRecords', + 'dynamodb:GetShardIterator', + 'dynamodb:Query', + 'dynamodb:GetItem', + 'dynamodb:Scan', + 'dynamodb:BatchWriteItem', + 'dynamodb:PutItem', + 'dynamodb:UpdateItem', + 'dynamodb:DeleteItem', + ], + 'Effect': 'Allow', + 'Resource': [ + { + 'Fn::GetAtt': [ + 'TableA3D7B5AFA', + 'Arn', + ], + }, + { + 'Ref': 'AWS::NoValue', + }, + ], + }, + { + 'Action': [ + 'kms:Decrypt', + 'kms:DescribeKey', + 'kms:Encrypt', + 'kms:ReEncrypt*', + 'kms:GenerateDataKey*', + ], + 'Effect': 'Allow', + 'Resource': { + 'Fn::GetAtt': [ + 'TableAKey07CC09EC', + 'Arn', + ], + }, + }, + ], + 'Version': '2012-10-17', + }, + 'PolicyName': 'MyUserDefaultPolicy7B897426', + 'Users': [ + { + 'Ref': 'MyUserDC45028B', + }, + ], + }, + }, + }, + }); +}); + test('when specifying PAY_PER_REQUEST billing mode', () => { const stack = new Stack(); new Table(stack, CONSTRUCT_NAME, { @@ -1168,6 +1646,54 @@ describe('metrics', () => { describe('grants', () => { + test('"grant" allows adding arbitrary actions associated with this table resource', () => { + // GIVEN + const stack = new Stack(); + const table = new Table(stack, 'my-table', { + partitionKey: { + name: 'id', + type: AttributeType.STRING, + }, + }); + const user = new iam.User(stack, 'user'); + + // WHEN + table.grant(user, 'dynamodb:action1', 'dynamodb:action2'); + + // THEN + expect(stack).toHaveResource('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': [ + { + 'Action': [ + 'dynamodb:action1', + 'dynamodb:action2', + ], + 'Effect': 'Allow', + 'Resource': [ + { + 'Fn::GetAtt': [ + 'mytable0324D45C', + 'Arn', + ], + }, + { + 'Ref': 'AWS::NoValue', + }, + ], + }, + ], + 'Version': '2012-10-17', + }, + 'PolicyName': 'userDefaultPolicy083DF682', + 'Users': [ + { + 'Ref': 'user2C2B57AE', + }, + ], + }); + }); + test('"grant" allows adding arbitrary actions associated with this table resource', () => { testGrant( ['action1', 'action2'], (p, t) => t.grant(p, 'dynamodb:action1', 'dynamodb:action2')); @@ -1349,14 +1875,37 @@ describe('grants', () => { ], 'Effect': 'Allow', 'Resource': [ - { 'Fn::GetAtt': ['mytable0324D45C', 'Arn'] }, - { 'Fn::Join': ['', [{ 'Fn::GetAtt': ['mytable0324D45C', 'Arn'] }, '/index/*']] }, + { + 'Fn::GetAtt': [ + 'mytable0324D45C', + 'Arn', + ], + }, + { + 'Fn::Join': [ + '', + [ + { + 'Fn::GetAtt': [ + 'mytable0324D45C', + 'Arn', + ], + }, + '/index/*', + ], + ], + }, ], }, ], 'Version': '2012-10-17', }, - 'Users': [{ 'Ref': 'user2C2B57AE' }], + 'PolicyName': 'userDefaultPolicy083DF682', + 'Users': [ + { + 'Ref': 'user2C2B57AE', + }, + ], }); }); @@ -2184,13 +2733,25 @@ function testGrant(expectedActions: string[], invocation: (user: iam.IPrincipal, 'Action': action, 'Effect': 'Allow', 'Resource': [ - { 'Fn::GetAtt': [ 'mytable0324D45C', 'Arn' ] }, - { 'Ref' : 'AWS::NoValue' }, + { + 'Fn::GetAtt': [ + 'mytable0324D45C', + 'Arn', + ], + }, + { + 'Ref': 'AWS::NoValue', + }, ], }, ], 'Version': '2012-10-17', }, - 'Users': [ { 'Ref': 'user2C2B57AE' } ], + 'PolicyName': 'userDefaultPolicy083DF682', + 'Users': [ + { + 'Ref': 'user2C2B57AE', + }, + ], }); } diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.sse.expected.json b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.sse.expected.json new file mode 100644 index 0000000000000..3a3b5788fd907 --- /dev/null +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.sse.expected.json @@ -0,0 +1,617 @@ +{ + "Resources": { + "TableKey25666F95": { + "Type": "AWS::KMS::Key", + "Properties": { + "KeyPolicy": { + "Statement": [ + { + "Action": [ + "kms:Create*", + "kms:Describe*", + "kms:Enable*", + "kms:List*", + "kms:Put*", + "kms:Update*", + "kms:Revoke*", + "kms:Disable*", + "kms:Get*", + "kms:Delete*", + "kms:ScheduleKeyDeletion", + "kms:CancelKeyDeletion", + "kms:GenerateDataKey", + "kms:TagResource", + "kms:UntagResource" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + }, + { + "Action": [ + "kms:Decrypt", + "kms:DescribeKey" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "Role1ABCC5F0", + "Arn" + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "Description": "Customer-managed key auto-created for encrypting DynamoDB table at aws-cdk-dynamodb/Table", + "EnableKeyRotation": true + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "TableCD117FA1": { + "Type": "AWS::DynamoDB::Table", + "Properties": { + "KeySchema": [ + { + "AttributeName": "hashKey", + "KeyType": "HASH" + } + ], + "AttributeDefinitions": [ + { + "AttributeName": "hashKey", + "AttributeType": "S" + } + ], + "ProvisionedThroughput": { + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + }, + "SSESpecification": { + "KMSMasterKeyId": { + "Fn::GetAtt": [ + "TableKey25666F95", + "Arn" + ] + }, + "SSEEnabled": true, + "SSEType": "KMS" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "TableWithGlobalAndLocalSecondaryIndexBC540710": { + "Type": "AWS::DynamoDB::Table", + "Properties": { + "KeySchema": [ + { + "AttributeName": "hashKey", + "KeyType": "HASH" + }, + { + "AttributeName": "sortKey", + "KeyType": "RANGE" + } + ], + "AttributeDefinitions": [ + { + "AttributeName": "hashKey", + "AttributeType": "S" + }, + { + "AttributeName": "sortKey", + "AttributeType": "N" + }, + { + "AttributeName": "gsiHashKey", + "AttributeType": "S" + }, + { + "AttributeName": "gsiSortKey", + "AttributeType": "N" + }, + { + "AttributeName": "lsiSortKey", + "AttributeType": "N" + } + ], + "GlobalSecondaryIndexes": [ + { + "IndexName": "GSI-PartitionKeyOnly", + "KeySchema": [ + { + "AttributeName": "gsiHashKey", + "KeyType": "HASH" + } + ], + "Projection": { + "ProjectionType": "ALL" + }, + "ProvisionedThroughput": { + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + } + }, + { + "IndexName": "GSI-PartitionAndSortKeyWithReadAndWriteCapacity", + "KeySchema": [ + { + "AttributeName": "gsiHashKey", + "KeyType": "HASH" + }, + { + "AttributeName": "gsiSortKey", + "KeyType": "RANGE" + } + ], + "Projection": { + "ProjectionType": "ALL" + }, + "ProvisionedThroughput": { + "ReadCapacityUnits": 10, + "WriteCapacityUnits": 10 + } + }, + { + "IndexName": "GSI-ProjectionTypeKeysOnly", + "KeySchema": [ + { + "AttributeName": "gsiHashKey", + "KeyType": "HASH" + }, + { + "AttributeName": "gsiSortKey", + "KeyType": "RANGE" + } + ], + "Projection": { + "ProjectionType": "KEYS_ONLY" + }, + "ProvisionedThroughput": { + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + } + }, + { + "IndexName": "GSI-ProjectionTypeInclude", + "KeySchema": [ + { + "AttributeName": "gsiHashKey", + "KeyType": "HASH" + }, + { + "AttributeName": "gsiSortKey", + "KeyType": "RANGE" + } + ], + "Projection": { + "NonKeyAttributes": [ + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J" + ], + "ProjectionType": "INCLUDE" + }, + "ProvisionedThroughput": { + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + } + }, + { + "IndexName": "GSI-InverseTableKeySchema", + "KeySchema": [ + { + "AttributeName": "sortKey", + "KeyType": "HASH" + }, + { + "AttributeName": "hashKey", + "KeyType": "RANGE" + } + ], + "Projection": { + "ProjectionType": "ALL" + }, + "ProvisionedThroughput": { + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + } + } + ], + "LocalSecondaryIndexes": [ + { + "IndexName": "LSI-PartitionAndTableSortKey", + "KeySchema": [ + { + "AttributeName": "hashKey", + "KeyType": "HASH" + }, + { + "AttributeName": "lsiSortKey", + "KeyType": "RANGE" + } + ], + "Projection": { + "ProjectionType": "ALL" + } + }, + { + "IndexName": "LSI-PartitionAndSortKey", + "KeySchema": [ + { + "AttributeName": "hashKey", + "KeyType": "HASH" + }, + { + "AttributeName": "sortKey", + "KeyType": "RANGE" + } + ], + "Projection": { + "ProjectionType": "ALL" + } + }, + { + "IndexName": "LSI-ProjectionTypeKeysOnly", + "KeySchema": [ + { + "AttributeName": "hashKey", + "KeyType": "HASH" + }, + { + "AttributeName": "lsiSortKey", + "KeyType": "RANGE" + } + ], + "Projection": { + "ProjectionType": "KEYS_ONLY" + } + }, + { + "IndexName": "LSI-ProjectionTypeInclude", + "KeySchema": [ + { + "AttributeName": "hashKey", + "KeyType": "HASH" + }, + { + "AttributeName": "lsiSortKey", + "KeyType": "RANGE" + } + ], + "Projection": { + "NonKeyAttributes": [ + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T" + ], + "ProjectionType": "INCLUDE" + } + } + ], + "PointInTimeRecoverySpecification": { + "PointInTimeRecoveryEnabled": true + }, + "ProvisionedThroughput": { + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + }, + "SSESpecification": { + "SSEEnabled": true + }, + "StreamSpecification": { + "StreamViewType": "KEYS_ONLY" + }, + "Tags": [ + { + "Key": "Environment", + "Value": "Production" + } + ], + "TimeToLiveSpecification": { + "AttributeName": "timeToLive", + "Enabled": true + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "Key961B73FD": { + "Type": "AWS::KMS::Key", + "Properties": { + "KeyPolicy": { + "Statement": [ + { + "Action": [ + "kms:Create*", + "kms:Describe*", + "kms:Enable*", + "kms:List*", + "kms:Put*", + "kms:Update*", + "kms:Revoke*", + "kms:Disable*", + "kms:Get*", + "kms:Delete*", + "kms:ScheduleKeyDeletion", + "kms:CancelKeyDeletion", + "kms:GenerateDataKey", + "kms:TagResource", + "kms:UntagResource" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "EnableKeyRotation": true + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "TableWithGlobalSecondaryIndexCC8E841E": { + "Type": "AWS::DynamoDB::Table", + "Properties": { + "KeySchema": [ + { + "AttributeName": "hashKey", + "KeyType": "HASH" + } + ], + "AttributeDefinitions": [ + { + "AttributeName": "hashKey", + "AttributeType": "S" + }, + { + "AttributeName": "gsiHashKey", + "AttributeType": "S" + } + ], + "GlobalSecondaryIndexes": [ + { + "IndexName": "GSI-PartitionKeyOnly", + "KeySchema": [ + { + "AttributeName": "gsiHashKey", + "KeyType": "HASH" + } + ], + "Projection": { + "ProjectionType": "ALL" + }, + "ProvisionedThroughput": { + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + } + } + ], + "ProvisionedThroughput": { + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + }, + "SSESpecification": { + "KMSMasterKeyId": { + "Fn::GetAtt": [ + "Key961B73FD", + "Arn" + ] + }, + "SSEEnabled": true, + "SSEType": "KMS" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "TableWithLocalSecondaryIndex4DA3D08F": { + "Type": "AWS::DynamoDB::Table", + "Properties": { + "KeySchema": [ + { + "AttributeName": "hashKey", + "KeyType": "HASH" + }, + { + "AttributeName": "sortKey", + "KeyType": "RANGE" + } + ], + "AttributeDefinitions": [ + { + "AttributeName": "hashKey", + "AttributeType": "S" + }, + { + "AttributeName": "sortKey", + "AttributeType": "N" + }, + { + "AttributeName": "lsiSortKey", + "AttributeType": "N" + } + ], + "LocalSecondaryIndexes": [ + { + "IndexName": "LSI-PartitionAndSortKey", + "KeySchema": [ + { + "AttributeName": "hashKey", + "KeyType": "HASH" + }, + { + "AttributeName": "lsiSortKey", + "KeyType": "RANGE" + } + ], + "Projection": { + "ProjectionType": "ALL" + } + } + ], + "ProvisionedThroughput": { + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "Role1ABCC5F0": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "sqs.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "RoleDefaultPolicy5FFB7DAB": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "dynamodb:BatchGetItem", + "dynamodb:GetRecords", + "dynamodb:GetShardIterator", + "dynamodb:Query", + "dynamodb:GetItem", + "dynamodb:Scan" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "TableCD117FA1", + "Arn" + ] + }, + { + "Ref": "AWS::NoValue" + } + ] + }, + { + "Action": [ + "kms:Decrypt", + "kms:DescribeKey" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "TableKey25666F95", + "Arn" + ] + } + }, + { + "Action": [ + "dynamodb:BatchGetItem", + "dynamodb:GetRecords", + "dynamodb:GetShardIterator", + "dynamodb:Query", + "dynamodb:GetItem", + "dynamodb:Scan" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "TableWithGlobalAndLocalSecondaryIndexBC540710", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "TableWithGlobalAndLocalSecondaryIndexBC540710", + "Arn" + ] + }, + "/index/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "RoleDefaultPolicy5FFB7DAB", + "Roles": [ + { + "Ref": "Role1ABCC5F0" + } + ] + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.sse.ts b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.sse.ts new file mode 100644 index 0000000000000..b1f3dca8b75a3 --- /dev/null +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.sse.ts @@ -0,0 +1,144 @@ +import * as iam from '@aws-cdk/aws-iam'; +import * as kms from '@aws-cdk/aws-kms'; +import { App, RemovalPolicy, Stack, Tag } from '@aws-cdk/core'; +import { Attribute, AttributeType, ProjectionType, StreamViewType, Table, TableEncryption } from '../lib'; + +// CDK parameters +const STACK_NAME = 'aws-cdk-dynamodb'; + +// DynamoDB table parameters +const TABLE = 'Table'; +const TABLE_WITH_GLOBAL_AND_LOCAL_SECONDARY_INDEX = 'TableWithGlobalAndLocalSecondaryIndex'; +const TABLE_WITH_GLOBAL_SECONDARY_INDEX = 'TableWithGlobalSecondaryIndex'; +const TABLE_WITH_LOCAL_SECONDARY_INDEX = 'TableWithLocalSecondaryIndex'; +const TABLE_PARTITION_KEY: Attribute = { name: 'hashKey', type: AttributeType.STRING }; +const TABLE_SORT_KEY: Attribute = { name: 'sortKey', type: AttributeType.NUMBER }; + +// DynamoDB global secondary index parameters +const GSI_TEST_CASE_1 = 'GSI-PartitionKeyOnly'; +const GSI_TEST_CASE_2 = 'GSI-PartitionAndSortKeyWithReadAndWriteCapacity'; +const GSI_TEST_CASE_3 = 'GSI-ProjectionTypeKeysOnly'; +const GSI_TEST_CASE_4 = 'GSI-ProjectionTypeInclude'; +const GSI_TEST_CASE_5 = 'GSI-InverseTableKeySchema'; +const GSI_PARTITION_KEY: Attribute = { name: 'gsiHashKey', type: AttributeType.STRING }; +const GSI_SORT_KEY: Attribute = { name: 'gsiSortKey', type: AttributeType.NUMBER }; +const GSI_NON_KEY: string[] = []; +for (let i = 0; i < 10; i++) { // 'A' to 'J' + GSI_NON_KEY.push(String.fromCharCode(65 + i)); +} + +// DynamoDB local secondary index parameters +const LSI_TEST_CASE_1 = 'LSI-PartitionAndSortKey'; +const LSI_TEST_CASE_2 = 'LSI-PartitionAndTableSortKey'; +const LSI_TEST_CASE_3 = 'LSI-ProjectionTypeKeysOnly'; +const LSI_TEST_CASE_4 = 'LSI-ProjectionTypeInclude'; +const LSI_SORT_KEY: Attribute = { name: 'lsiSortKey', type: AttributeType.NUMBER }; +const LSI_NON_KEY: string[] = []; +for (let i = 0; i < 10; i++) { // 'K' to 'T' + LSI_NON_KEY.push(String.fromCharCode(75 + i)); +} + +const app = new App(); + +const stack = new Stack(app, STACK_NAME); + +const table = new Table(stack, TABLE, { + partitionKey: TABLE_PARTITION_KEY, + removalPolicy: RemovalPolicy.DESTROY, + encryption: TableEncryption.CUSTOMER_MANAGED, +}); + +const tableWithGlobalAndLocalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL_AND_LOCAL_SECONDARY_INDEX, { + pointInTimeRecovery: true, + encryption: TableEncryption.AWS_MANAGED, + stream: StreamViewType.KEYS_ONLY, + timeToLiveAttribute: 'timeToLive', + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY, + removalPolicy: RemovalPolicy.DESTROY, +}); + +tableWithGlobalAndLocalSecondaryIndex.node.applyAspect(new Tag('Environment', 'Production')); +tableWithGlobalAndLocalSecondaryIndex.addGlobalSecondaryIndex({ + indexName: GSI_TEST_CASE_1, + partitionKey: GSI_PARTITION_KEY, +}); +tableWithGlobalAndLocalSecondaryIndex.addGlobalSecondaryIndex({ + indexName: GSI_TEST_CASE_2, + partitionKey: GSI_PARTITION_KEY, + sortKey: GSI_SORT_KEY, + readCapacity: 10, + writeCapacity: 10, +}); +tableWithGlobalAndLocalSecondaryIndex.addGlobalSecondaryIndex({ + indexName: GSI_TEST_CASE_3, + partitionKey: GSI_PARTITION_KEY, + sortKey: GSI_SORT_KEY, + projectionType: ProjectionType.KEYS_ONLY, +}); +tableWithGlobalAndLocalSecondaryIndex.addGlobalSecondaryIndex({ + indexName: GSI_TEST_CASE_4, + partitionKey: GSI_PARTITION_KEY, + sortKey: GSI_SORT_KEY, + projectionType: ProjectionType.INCLUDE, + nonKeyAttributes: GSI_NON_KEY, +}); +tableWithGlobalAndLocalSecondaryIndex.addGlobalSecondaryIndex({ + indexName: GSI_TEST_CASE_5, + partitionKey: TABLE_SORT_KEY, + sortKey: TABLE_PARTITION_KEY, +}); + +tableWithGlobalAndLocalSecondaryIndex.addLocalSecondaryIndex({ + indexName: LSI_TEST_CASE_2, + sortKey: LSI_SORT_KEY, +}); +tableWithGlobalAndLocalSecondaryIndex.addLocalSecondaryIndex({ + indexName: LSI_TEST_CASE_1, + sortKey: TABLE_SORT_KEY, +}); +tableWithGlobalAndLocalSecondaryIndex.addLocalSecondaryIndex({ + indexName: LSI_TEST_CASE_3, + sortKey: LSI_SORT_KEY, + projectionType: ProjectionType.KEYS_ONLY, +}); +tableWithGlobalAndLocalSecondaryIndex.addLocalSecondaryIndex({ + indexName: LSI_TEST_CASE_4, + sortKey: LSI_SORT_KEY, + projectionType: ProjectionType.INCLUDE, + nonKeyAttributes: LSI_NON_KEY, +}); + +const encryptionKey = new kms.Key(stack, 'Key', { + enableKeyRotation: true, +}); + +const tableWithGlobalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL_SECONDARY_INDEX, { + partitionKey: TABLE_PARTITION_KEY, + removalPolicy: RemovalPolicy.DESTROY, + encryptionKey, +}); +tableWithGlobalSecondaryIndex.addGlobalSecondaryIndex({ + indexName: GSI_TEST_CASE_1, + partitionKey: GSI_PARTITION_KEY, +}); + +const tableWithLocalSecondaryIndex = new Table(stack, TABLE_WITH_LOCAL_SECONDARY_INDEX, { + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY, + removalPolicy: RemovalPolicy.DESTROY, + encryption: TableEncryption.DEFAULT, +}); + +tableWithLocalSecondaryIndex.addLocalSecondaryIndex({ + indexName: LSI_TEST_CASE_1, + sortKey: LSI_SORT_KEY, +}); + +const role = new iam.Role(stack, 'Role', { + assumedBy: new iam.ServicePrincipal('sqs.amazonaws.com'), +}); +table.grantReadData(role); +tableWithGlobalAndLocalSecondaryIndex.grantReadData(role); + +app.synth(); 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 8db65da9e0a4c..dc4b5ce676ce6 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json @@ -91,7 +91,7 @@ }, "/", { - "Ref": "AssetParametersff9385d45e080dd6d7d73d81931d4eb97c31883610969bc8e00008b67f40ab68S3BucketF1B0B267" + "Ref": "AssetParameters1e7110d85a2e13b58c2a0fb09f018c144489abfafc62bf10f8ab3561a9cb8510S3BucketCE06C497" }, "/", { @@ -101,7 +101,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersff9385d45e080dd6d7d73d81931d4eb97c31883610969bc8e00008b67f40ab68S3VersionKey39DCF57D" + "Ref": "AssetParameters1e7110d85a2e13b58c2a0fb09f018c144489abfafc62bf10f8ab3561a9cb8510S3VersionKey6B6B0A66" } ] } @@ -114,7 +114,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersff9385d45e080dd6d7d73d81931d4eb97c31883610969bc8e00008b67f40ab68S3VersionKey39DCF57D" + "Ref": "AssetParameters1e7110d85a2e13b58c2a0fb09f018c144489abfafc62bf10f8ab3561a9cb8510S3VersionKey6B6B0A66" } ] } @@ -133,11 +133,11 @@ "referencetocdkdynamodbglobal20191121TableB640876BRef": { "Ref": "TableCD117FA1" }, - "referencetocdkdynamodbglobal20191121AssetParameters23c030d344d23d11a9deeaeca621a2fed8d153a4906d94da81b3cf75beb34260S3Bucket9DB95B91Ref": { - "Ref": "AssetParameters23c030d344d23d11a9deeaeca621a2fed8d153a4906d94da81b3cf75beb34260S3Bucket578442F1" + "referencetocdkdynamodbglobal20191121AssetParameters012c6b101abc4ea1f510921af61a3e08e05f30f84d7b35c40ca4adb1ace60746S3BucketE0999323Ref": { + "Ref": "AssetParameters012c6b101abc4ea1f510921af61a3e08e05f30f84d7b35c40ca4adb1ace60746S3BucketBDDEC9DD" }, - "referencetocdkdynamodbglobal20191121AssetParameters23c030d344d23d11a9deeaeca621a2fed8d153a4906d94da81b3cf75beb34260S3VersionKeyC55DE477Ref": { - "Ref": "AssetParameters23c030d344d23d11a9deeaeca621a2fed8d153a4906d94da81b3cf75beb34260S3VersionKey1B6BA461" + "referencetocdkdynamodbglobal20191121AssetParameters012c6b101abc4ea1f510921af61a3e08e05f30f84d7b35c40ca4adb1ace60746S3VersionKey8D3D9B9ARef": { + "Ref": "AssetParameters012c6b101abc4ea1f510921af61a3e08e05f30f84d7b35c40ca4adb1ace60746S3VersionKey1C286880" }, "referencetocdkdynamodbglobal20191121AssetParameters5e49cf64d8027f48872790f80cdb76c5b836ecf9a70b71be1eb937a5c25a47c1S3Bucket6627F4A7Ref": { "Ref": "AssetParameters5e49cf64d8027f48872790f80cdb76c5b836ecf9a70b71be1eb937a5c25a47c1S3Bucket663A709C" @@ -150,17 +150,17 @@ } }, "Parameters": { - "AssetParameters23c030d344d23d11a9deeaeca621a2fed8d153a4906d94da81b3cf75beb34260S3Bucket578442F1": { + "AssetParameters012c6b101abc4ea1f510921af61a3e08e05f30f84d7b35c40ca4adb1ace60746S3BucketBDDEC9DD": { "Type": "String", - "Description": "S3 bucket for asset \"23c030d344d23d11a9deeaeca621a2fed8d153a4906d94da81b3cf75beb34260\"" + "Description": "S3 bucket for asset \"012c6b101abc4ea1f510921af61a3e08e05f30f84d7b35c40ca4adb1ace60746\"" }, - "AssetParameters23c030d344d23d11a9deeaeca621a2fed8d153a4906d94da81b3cf75beb34260S3VersionKey1B6BA461": { + "AssetParameters012c6b101abc4ea1f510921af61a3e08e05f30f84d7b35c40ca4adb1ace60746S3VersionKey1C286880": { "Type": "String", - "Description": "S3 key for asset version \"23c030d344d23d11a9deeaeca621a2fed8d153a4906d94da81b3cf75beb34260\"" + "Description": "S3 key for asset version \"012c6b101abc4ea1f510921af61a3e08e05f30f84d7b35c40ca4adb1ace60746\"" }, - "AssetParameters23c030d344d23d11a9deeaeca621a2fed8d153a4906d94da81b3cf75beb34260ArtifactHash57F1E9B3": { + "AssetParameters012c6b101abc4ea1f510921af61a3e08e05f30f84d7b35c40ca4adb1ace60746ArtifactHashBB09F15F": { "Type": "String", - "Description": "Artifact hash for asset \"23c030d344d23d11a9deeaeca621a2fed8d153a4906d94da81b3cf75beb34260\"" + "Description": "Artifact hash for asset \"012c6b101abc4ea1f510921af61a3e08e05f30f84d7b35c40ca4adb1ace60746\"" }, "AssetParameters5e49cf64d8027f48872790f80cdb76c5b836ecf9a70b71be1eb937a5c25a47c1S3Bucket663A709C": { "Type": "String", @@ -174,17 +174,17 @@ "Type": "String", "Description": "Artifact hash for asset \"5e49cf64d8027f48872790f80cdb76c5b836ecf9a70b71be1eb937a5c25a47c1\"" }, - "AssetParametersff9385d45e080dd6d7d73d81931d4eb97c31883610969bc8e00008b67f40ab68S3BucketF1B0B267": { + "AssetParameters1e7110d85a2e13b58c2a0fb09f018c144489abfafc62bf10f8ab3561a9cb8510S3BucketCE06C497": { "Type": "String", - "Description": "S3 bucket for asset \"ff9385d45e080dd6d7d73d81931d4eb97c31883610969bc8e00008b67f40ab68\"" + "Description": "S3 bucket for asset \"1e7110d85a2e13b58c2a0fb09f018c144489abfafc62bf10f8ab3561a9cb8510\"" }, - "AssetParametersff9385d45e080dd6d7d73d81931d4eb97c31883610969bc8e00008b67f40ab68S3VersionKey39DCF57D": { + "AssetParameters1e7110d85a2e13b58c2a0fb09f018c144489abfafc62bf10f8ab3561a9cb8510S3VersionKey6B6B0A66": { "Type": "String", - "Description": "S3 key for asset version \"ff9385d45e080dd6d7d73d81931d4eb97c31883610969bc8e00008b67f40ab68\"" + "Description": "S3 key for asset version \"1e7110d85a2e13b58c2a0fb09f018c144489abfafc62bf10f8ab3561a9cb8510\"" }, - "AssetParametersff9385d45e080dd6d7d73d81931d4eb97c31883610969bc8e00008b67f40ab68ArtifactHash1FBBCC08": { + "AssetParameters1e7110d85a2e13b58c2a0fb09f018c144489abfafc62bf10f8ab3561a9cb8510ArtifactHashAB28BC52": { "Type": "String", - "Description": "Artifact hash for asset \"ff9385d45e080dd6d7d73d81931d4eb97c31883610969bc8e00008b67f40ab68\"" + "Description": "Artifact hash for asset \"1e7110d85a2e13b58c2a0fb09f018c144489abfafc62bf10f8ab3561a9cb8510\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/.eslintrc.js b/packages/@aws-cdk/aws-ec2/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-ec2/.eslintrc.js +++ b/packages/@aws-cdk/aws-ec2/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ec2/README.md b/packages/@aws-cdk/aws-ec2/README.md index aa8b4aaaf3212..318ffb55a1274 100644 --- a/packages/@aws-cdk/aws-ec2/README.md +++ b/packages/@aws-cdk/aws-ec2/README.md @@ -496,10 +496,8 @@ Endpoints are virtual devices. They are horizontally scaled, redundant, and high [example of setting up VPC endpoints](test/integ.vpc-endpoint.lit.ts) -Not all VPC endpoint services are available in all availability zones. By default, -CDK will place a VPC endpoint in one subnet per AZ, because CDK doesn't know about -unavailable AZs. You can determine what the available AZs are from the AWS console. -The AZs CDK places the VPC endpoint in can be configured as follows: +By default, CDK will place a VPC endpoint in one subnet per AZ. If you wish to override the AZs CDK places the VPC endpoint in, +use the `subnets` parameter as follows: ```ts new InterfaceVpcEndpoint(stack, 'VPC Endpoint', { @@ -513,6 +511,21 @@ new InterfaceVpcEndpoint(stack, 'VPC Endpoint', { }); ``` +Per the [AWS documentation](https://aws.amazon.com/premiumsupport/knowledge-center/interface-endpoint-availability-zone/), not all +VPC endpoint services are available in all AZs. If you specify the parameter `lookupSupportedAzs`, CDK attempts to discover which +AZs an endpoint service is available in, and will ensure the VPC endpoint is not placed in a subnet that doesn't match those AZs. +These AZs will be stored in cdk.context.json. + +```ts +new InterfaceVpcEndpoint(stack, 'VPC Endpoint', { + vpc, + service: new InterfaceVpcEndpointService('com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', 443), + // Choose which availability zones to place the VPC endpoint in, based on + // available AZs + lookupSupportedAzs: true +}); +``` + ### Security groups for interface VPC endpoints By default, interface VPC endpoints create a new security group and traffic is **not** automatically allowed from the VPC CIDR. diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc-endpoint.ts b/packages/@aws-cdk/aws-ec2/lib/vpc-endpoint.ts index e98201e0a93af..450cd9fc52e8a 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc-endpoint.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc-endpoint.ts @@ -1,5 +1,6 @@ import * as iam from '@aws-cdk/aws-iam'; -import { Aws, Construct, IResource, Lazy, Resource } from '@aws-cdk/core'; +import * as cxschema from '@aws-cdk/cloud-assembly-schema'; +import { Aws, Construct, ContextProvider, IResource, Lazy, Resource, Token } from '@aws-cdk/core'; import { Connections, IConnectable } from './connections'; import { CfnVPCEndpoint } from './ec2.generated'; import { Peer } from './peer'; @@ -360,6 +361,16 @@ export interface InterfaceVpcEndpointOptions { * @default true */ readonly open?: boolean; + + /** + * Limit to only those availability zones where the endpoint service can be created + * + * Setting this to 'true' requires a lookup to be performed at synthesis time. Account + * and region must be set on the containing stack for this to work. + * + * @default false + */ + readonly lookupSupportedAzs?: boolean; } /** @@ -459,8 +470,24 @@ export class InterfaceVpcEndpoint extends VpcEndpoint implements IInterfaceVpcEn this.connections.allowDefaultPortFrom(Peer.ipv4(props.vpc.vpcCidrBlock)); } - const subnets = props.vpc.selectSubnets({ ...props.subnets, onePerAz: true }); - const subnetIds = subnets.subnetIds; + const lookupSupportedAzs = props.lookupSupportedAzs ?? false; + const subnetSelection = props.vpc.selectSubnets({ ...props.subnets, onePerAz: true }); + let subnets; + + // If we don't have an account/region, we will not be able to do filtering on AZs since + // they will be undefined + // Otherwise, we filter by AZ + const agnostic = (Token.isUnresolved(this.stack.account) || Token.isUnresolved(this.stack.region)); + + if (agnostic && lookupSupportedAzs) { + throw new Error('Cannot look up VPC endpoint availability zones if account/region are not specified'); + } else if (!agnostic && lookupSupportedAzs) { + const availableAZs = this.availableAvailabilityZones(props.service.name); + subnets = subnetSelection.subnets.filter(s => availableAZs.includes(s.availabilityZone)); + } else { + subnets = subnetSelection.subnets; + } + const subnetIds = subnets.map(s => s.subnetId); const endpoint = new CfnVPCEndpoint(this, 'Resource', { privateDnsEnabled: props.privateDnsEnabled ?? props.service.privateDnsDefault ?? true, @@ -477,6 +504,21 @@ export class InterfaceVpcEndpoint extends VpcEndpoint implements IInterfaceVpcEn this.vpcEndpointDnsEntries = endpoint.attrDnsEntries; this.vpcEndpointNetworkInterfaceIds = endpoint.attrNetworkInterfaceIds; } + + private availableAvailabilityZones(serviceName: string): string[] { + // Here we check what AZs the endpoint service is available in + // If for whatever reason we can't retrieve the AZs, and no context is set, + // we will fall back to all AZs + const availableAZs = ContextProvider.getValue(this, { + provider: cxschema.ContextProvider.ENDPOINT_SERVICE_AVAILABILITY_ZONE_PROVIDER, + dummyValue: this.stack.availabilityZones, + props: {serviceName}, + }).value; + if (!Array.isArray(availableAZs)) { + throw new Error(`Discovered AZs for endpoint service ${serviceName} must be an array`); + } + return availableAZs; + } } /** diff --git a/packages/@aws-cdk/aws-ec2/package.json b/packages/@aws-cdk/aws-ec2/package.json index 0603d37d6ac67..7bed5e57ba6f5 100644 --- a/packages/@aws-cdk/aws-ec2/package.json +++ b/packages/@aws-cdk/aws-ec2/package.json @@ -63,7 +63,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -97,7 +97,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-ec2/test/integ.bastion-host.expected.json b/packages/@aws-cdk/aws-ec2/test/integ.bastion-host.expected.json index 4f7df1b2e43b1..73b52ab630a76 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.bastion-host.expected.json +++ b/packages/@aws-cdk/aws-ec2/test/integ.bastion-host.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "TestStack/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "TestStack/VPC/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "TestStack/VPC/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "TestStack/VPC/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "TestStack/VPC/PublicSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "TestStack/VPC/PublicSubnet3" } ] } @@ -316,10 +316,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "TestStack/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -327,6 +323,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "TestStack/VPC/PrivateSubnet1" } ] } @@ -378,10 +378,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "TestStack/VPC/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -389,6 +385,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "TestStack/VPC/PrivateSubnet2" } ] } @@ -440,10 +440,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "TestStack/VPC/PrivateSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -451,6 +447,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "TestStack/VPC/PrivateSubnet3" } ] } diff --git a/packages/@aws-cdk/aws-ec2/test/integ.instance.expected.json b/packages/@aws-cdk/aws-ec2/test/integ.instance.expected.json index 1f176f2d7fcd8..957af9c0f453e 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.instance.expected.json +++ b/packages/@aws-cdk/aws-ec2/test/integ.instance.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "TestStack/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "TestStack/VPC/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "TestStack/VPC/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "TestStack/VPC/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "TestStack/VPC/PublicSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "TestStack/VPC/PublicSubnet3" } ] } @@ -316,10 +316,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "TestStack/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -327,6 +323,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "TestStack/VPC/PrivateSubnet1" } ] } @@ -378,10 +378,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "TestStack/VPC/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -389,6 +385,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "TestStack/VPC/PrivateSubnet2" } ] } @@ -440,10 +440,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "TestStack/VPC/PrivateSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -451,6 +447,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "TestStack/VPC/PrivateSubnet3" } ] } diff --git a/packages/@aws-cdk/aws-ec2/test/integ.nat-instances.lit.expected.json b/packages/@aws-cdk/aws-ec2/test/integ.nat-instances.lit.expected.json index e418cf956c2bc..5ac907df6e0ac 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.nat-instances.lit.expected.json +++ b/packages/@aws-cdk/aws-ec2/test/integ.nat-instances.lit.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-vpc-nat-instances/MyVpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-vpc-nat-instances/MyVpc/PublicSubnet1" } ] } @@ -135,10 +135,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-vpc-nat-instances/MyVpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -146,6 +142,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-vpc-nat-instances/MyVpc/PublicSubnet2" } ] } @@ -245,10 +245,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-vpc-nat-instances/MyVpc/PublicSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -256,6 +252,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-vpc-nat-instances/MyVpc/PublicSubnet3" } ] } @@ -310,10 +310,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-vpc-nat-instances/MyVpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -321,6 +317,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-vpc-nat-instances/MyVpc/PrivateSubnet1" } ] } @@ -372,10 +372,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-vpc-nat-instances/MyVpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -383,6 +379,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-vpc-nat-instances/MyVpc/PrivateSubnet2" } ] } @@ -434,10 +434,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-vpc-nat-instances/MyVpc/PrivateSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -445,6 +441,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-vpc-nat-instances/MyVpc/PrivateSubnet3" } ] } diff --git a/packages/@aws-cdk/aws-ec2/test/integ.share-vpcs.lit.expected.json b/packages/@aws-cdk/aws-ec2/test/integ.share-vpcs.lit.expected.json index 153353b36f323..915796b1204c4 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.share-vpcs.lit.expected.json +++ b/packages/@aws-cdk/aws-ec2/test/integ.share-vpcs.lit.expected.json @@ -26,10 +26,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "Stack1/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -37,6 +33,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "Stack1/VPC/PublicSubnet1" } ] } @@ -123,10 +123,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "Stack1/VPC/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -134,6 +130,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "Stack1/VPC/PublicSubnet2" } ] } @@ -220,10 +220,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "Stack1/VPC/PublicSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -231,6 +227,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "Stack1/VPC/PublicSubnet3" } ] } @@ -317,10 +317,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "Stack1/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -328,6 +324,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "Stack1/VPC/PrivateSubnet1" } ] } @@ -379,10 +379,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "Stack1/VPC/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -390,6 +386,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "Stack1/VPC/PrivateSubnet2" } ] } @@ -441,10 +441,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "Stack1/VPC/PrivateSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -452,6 +448,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "Stack1/VPC/PrivateSubnet3" } ] } diff --git a/packages/@aws-cdk/aws-ec2/test/integ.vpc-endpoint.lit.expected.json b/packages/@aws-cdk/aws-ec2/test/integ.vpc-endpoint.lit.expected.json index 2c042511217f8..4adbc5e48fc91 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.vpc-endpoint.lit.expected.json +++ b/packages/@aws-cdk/aws-ec2/test/integ.vpc-endpoint.lit.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-ec2-vpc-endpoint/MyVpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-ec2-vpc-endpoint/MyVpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-ec2-vpc-endpoint/MyVpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-ec2-vpc-endpoint/MyVpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-ec2-vpc-endpoint/MyVpc/PublicSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-ec2-vpc-endpoint/MyVpc/PublicSubnet3" } ] } @@ -316,10 +316,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-ec2-vpc-endpoint/MyVpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -327,6 +323,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-ec2-vpc-endpoint/MyVpc/PrivateSubnet1" } ] } @@ -378,10 +378,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-ec2-vpc-endpoint/MyVpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -389,6 +385,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-ec2-vpc-endpoint/MyVpc/PrivateSubnet2" } ] } @@ -440,10 +440,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-ec2-vpc-endpoint/MyVpc/PrivateSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -451,6 +447,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-ec2-vpc-endpoint/MyVpc/PrivateSubnet3" } ] } diff --git a/packages/@aws-cdk/aws-ec2/test/integ.vpc-flow-logs.expected.json b/packages/@aws-cdk/aws-ec2/test/integ.vpc-flow-logs.expected.json index ca4ea65eab04b..d0831e24d6ab8 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.vpc-flow-logs.expected.json +++ b/packages/@aws-cdk/aws-ec2/test/integ.vpc-flow-logs.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "TestStack/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "TestStack/VPC/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "TestStack/VPC/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "TestStack/VPC/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "TestStack/VPC/PublicSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "TestStack/VPC/PublicSubnet3" } ] } @@ -316,10 +316,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "TestStack/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -327,6 +323,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "TestStack/VPC/PrivateSubnet1" } ] } @@ -378,10 +378,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "TestStack/VPC/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -389,6 +385,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "TestStack/VPC/PrivateSubnet2" } ] } @@ -440,10 +440,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "TestStack/VPC/PrivateSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -451,6 +447,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "TestStack/VPC/PrivateSubnet3" } ] } diff --git a/packages/@aws-cdk/aws-ec2/test/integ.vpc-networkacl.expected.json b/packages/@aws-cdk/aws-ec2/test/integ.vpc-networkacl.expected.json index e5043a0ebf809..71106b9a76c25 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.vpc-networkacl.expected.json +++ b/packages/@aws-cdk/aws-ec2/test/integ.vpc-networkacl.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-ec2-vpc/MyVpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-ec2-vpc/MyVpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-ec2-vpc/MyVpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-ec2-vpc/MyVpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-ec2-vpc/MyVpc/PublicSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-ec2-vpc/MyVpc/PublicSubnet3" } ] } @@ -316,10 +316,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-ec2-vpc/MyVpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -327,6 +323,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-ec2-vpc/MyVpc/PrivateSubnet1" } ] } @@ -378,10 +378,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-ec2-vpc/MyVpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -389,6 +385,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-ec2-vpc/MyVpc/PrivateSubnet2" } ] } @@ -440,10 +440,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-ec2-vpc/MyVpc/PrivateSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -451,6 +447,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-ec2-vpc/MyVpc/PrivateSubnet3" } ] } diff --git a/packages/@aws-cdk/aws-ec2/test/integ.vpc.expected.json b/packages/@aws-cdk/aws-ec2/test/integ.vpc.expected.json index f27ebb9f65089..1586cc8bff5e7 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.vpc.expected.json +++ b/packages/@aws-cdk/aws-ec2/test/integ.vpc.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-ec2-vpc/MyVpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-ec2-vpc/MyVpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-ec2-vpc/MyVpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-ec2-vpc/MyVpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-ec2-vpc/MyVpc/PublicSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-ec2-vpc/MyVpc/PublicSubnet3" } ] } @@ -316,10 +316,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-ec2-vpc/MyVpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -327,6 +323,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-ec2-vpc/MyVpc/PrivateSubnet1" } ] } @@ -378,10 +378,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-ec2-vpc/MyVpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -389,6 +385,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-ec2-vpc/MyVpc/PrivateSubnet2" } ] } @@ -440,10 +440,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-ec2-vpc/MyVpc/PrivateSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -451,6 +447,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-ec2-vpc/MyVpc/PrivateSubnet3" } ] } diff --git a/packages/@aws-cdk/aws-ec2/test/integ.vpn.expected.json b/packages/@aws-cdk/aws-ec2/test/integ.vpn.expected.json index e677f1341c29b..409f9d4f48bf2 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.vpn.expected.json +++ b/packages/@aws-cdk/aws-ec2/test/integ.vpn.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-ec2-vpn/MyVpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-ec2-vpn/MyVpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-ec2-vpn/MyVpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-ec2-vpn/MyVpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-ec2-vpn/MyVpc/PublicSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-ec2-vpn/MyVpc/PublicSubnet3" } ] } @@ -316,10 +316,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-ec2-vpn/MyVpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -327,6 +323,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-ec2-vpn/MyVpc/PrivateSubnet1" } ] } @@ -378,10 +378,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-ec2-vpn/MyVpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -389,6 +385,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-ec2-vpn/MyVpc/PrivateSubnet2" } ] } @@ -440,10 +440,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-ec2-vpn/MyVpc/PrivateSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -451,6 +447,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-ec2-vpn/MyVpc/PrivateSubnet3" } ] } diff --git a/packages/@aws-cdk/aws-ec2/test/test.vpc-endpoint.ts b/packages/@aws-cdk/aws-ec2/test/test.vpc-endpoint.ts index fa10ad4de05dc..159447c322749 100644 --- a/packages/@aws-cdk/aws-ec2/test/test.vpc-endpoint.ts +++ b/packages/@aws-cdk/aws-ec2/test/test.vpc-endpoint.ts @@ -1,6 +1,7 @@ import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; import { AnyPrincipal, PolicyStatement } from '@aws-cdk/aws-iam'; -import { Stack } from '@aws-cdk/core'; +import * as cxschema from '@aws-cdk/cloud-assembly-schema'; +import { ContextProvider, Stack } from '@aws-cdk/core'; import { Test } from 'nodeunit'; // tslint:disable-next-line:max-line-length import { GatewayVpcEndpoint, GatewayVpcEndpointAwsService, InterfaceVpcEndpoint, InterfaceVpcEndpointAwsService, InterfaceVpcEndpointService, SecurityGroup, SubnetType, Vpc } from '../lib'; @@ -385,6 +386,90 @@ export = { PrivateDnsEnabled: true, })); + test.done(); + }, + 'test endpoint service context azs discovered'(test: Test) { + // GIVEN + const stack = new Stack(undefined, 'TestStack', { env: { account: '123456789012', region: 'us-east-1' } }); + + // Setup context for stack AZs + stack.node.setContext( + ContextProvider.getKey(stack, { + provider: cxschema.ContextProvider.AVAILABILITY_ZONE_PROVIDER, + }).key, + ['us-east-1a', 'us-east-1b', 'us-east-1c']); + // Setup context for endpoint service AZs + stack.node.setContext( + ContextProvider.getKey(stack, { + provider: cxschema.ContextProvider.ENDPOINT_SERVICE_AVAILABILITY_ZONE_PROVIDER, + props: { + serviceName: 'com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', + }, + }).key, + ['us-east-1a', 'us-east-1c']); + + const vpc = new Vpc(stack, 'VPC'); + + // WHEN + vpc.addInterfaceEndpoint('YourService', { + service: { + name: 'com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', + port: 443}, + lookupSupportedAzs: true, + }); + + // THEN + expect(stack).to(haveResource('AWS::EC2::VPCEndpoint', { + ServiceName: 'com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', + SubnetIds: [ + { + Ref: 'VPCPrivateSubnet1Subnet8BCA10E0', + }, + { + Ref: 'VPCPrivateSubnet3Subnet3EDCD457', + }, + ], + })); + + test.done(); + }, + 'endpoint service setup with stack AZ context but no endpoint context'(test: Test) { + // GIVEN + const stack = new Stack(undefined, 'TestStack', { env: { account: '123456789012', region: 'us-east-1' } }); + + // Setup context for stack AZs + stack.node.setContext( + ContextProvider.getKey(stack, { + provider: cxschema.ContextProvider.AVAILABILITY_ZONE_PROVIDER, + }).key, + ['us-east-1a', 'us-east-1b', 'us-east-1c']); + + const vpc = new Vpc(stack, 'VPC'); + + // WHEN + vpc.addInterfaceEndpoint('YourService', { + service: { + name: 'com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', + port: 443}, + lookupSupportedAzs: true, + }); + + // THEN + expect(stack).to(haveResource('AWS::EC2::VPCEndpoint', { + ServiceName: 'com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', + SubnetIds: [ + { + Ref: 'VPCPrivateSubnet1Subnet8BCA10E0', + }, + { + Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A', + }, + { + Ref: 'VPCPrivateSubnet3Subnet3EDCD457', + }, + ], + })); + test.done(); }, }, diff --git a/packages/@aws-cdk/aws-ecr-assets/.eslintrc.js b/packages/@aws-cdk/aws-ecr-assets/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-ecr-assets/.eslintrc.js +++ b/packages/@aws-cdk/aws-ecr-assets/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ecr-assets/lib/image-asset.ts b/packages/@aws-cdk/aws-ecr-assets/lib/image-asset.ts index 6e84d63dad8d6..09c4a033a8476 100644 --- a/packages/@aws-cdk/aws-ecr-assets/lib/image-asset.ts +++ b/packages/@aws-cdk/aws-ecr-assets/lib/image-asset.ts @@ -140,7 +140,7 @@ export class DockerImageAsset extends Construct implements assets.IAsset { this.sourceHash = staging.sourceHash; const stack = Stack.of(this); - const location = stack.addDockerImageAsset({ + const location = stack.synthesizer.addDockerImageAsset({ directoryName: staging.stagedPath, dockerBuildArgs: props.buildArgs, dockerBuildTarget: props.target, diff --git a/packages/@aws-cdk/aws-ecr-assets/package.json b/packages/@aws-cdk/aws-ecr-assets/package.json index 37e26f2e10720..b8bf88738da1d 100644 --- a/packages/@aws-cdk/aws-ecr-assets/package.json +++ b/packages/@aws-cdk/aws-ecr-assets/package.json @@ -60,7 +60,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "@types/proxyquire": "^1.3.28", "aws-cdk": "0.0.0", "cdk-build-tools": "0.0.0", @@ -96,7 +96,7 @@ "statements": 70 }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "bundledDependencies": [ "minimatch" diff --git a/packages/@aws-cdk/aws-ecr/.eslintrc.js b/packages/@aws-cdk/aws-ecr/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-ecr/.eslintrc.js +++ b/packages/@aws-cdk/aws-ecr/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ecr/lib/repository.ts b/packages/@aws-cdk/aws-ecr/lib/repository.ts index 5bd273393fbc4..6a6f5b617b832 100644 --- a/packages/@aws-cdk/aws-ecr/lib/repository.ts +++ b/packages/@aws-cdk/aws-ecr/lib/repository.ts @@ -42,7 +42,7 @@ export interface IRepository extends IResource { /** * Add a policy statement to the repository's resource policy */ - addToResourcePolicy(statement: iam.PolicyStatement): void; + addToResourcePolicy(statement: iam.PolicyStatement): iam.AddToResourcePolicyResult; /** * Grant the given principal identity permissions to perform the actions on this repository @@ -115,7 +115,7 @@ export abstract class RepositoryBase extends Resource implements IRepository { /** * Add a policy statement to the repository's resource policy */ - public abstract addToResourcePolicy(statement: iam.PolicyStatement): void; + public abstract addToResourcePolicy(statement: iam.PolicyStatement): iam.AddToResourcePolicyResult; /** * The URI of this repository (represents the latest image): @@ -343,8 +343,9 @@ export class Repository extends RepositoryBase { public readonly repositoryName = attrs.repositoryName; public readonly repositoryArn = attrs.repositoryArn; - public addToResourcePolicy(_statement: iam.PolicyStatement) { + public addToResourcePolicy(_statement: iam.PolicyStatement): iam.AddToResourcePolicyResult { // dropped + return { statementAdded: false }; } } @@ -366,8 +367,9 @@ export class Repository extends RepositoryBase { public repositoryName = repositoryName; public repositoryArn = repositoryArn; - public addToResourcePolicy(_statement: iam.PolicyStatement): void { + public addToResourcePolicy(_statement: iam.PolicyStatement): iam.AddToResourcePolicyResult { // dropped + return { statementAdded: false }; } } @@ -379,8 +381,9 @@ export class Repository extends RepositoryBase { public repositoryName = repositoryName; public repositoryArn = Repository.arnForLocalRepository(repositoryName, scope); - public addToResourcePolicy(_statement: iam.PolicyStatement): void { + public addToResourcePolicy(_statement: iam.PolicyStatement): iam.AddToResourcePolicyResult { // dropped + return { statementAdded: false }; } } @@ -462,11 +465,12 @@ export class Repository extends RepositoryBase { } } - public addToResourcePolicy(statement: iam.PolicyStatement) { + public addToResourcePolicy(statement: iam.PolicyStatement): iam.AddToResourcePolicyResult { if (this.policyDocument === undefined) { this.policyDocument = new iam.PolicyDocument(); } this.policyDocument.addStatements(statement); + return { statementAdded: false, policyDependable: this.policyDocument }; } /** diff --git a/packages/@aws-cdk/aws-ecr/package.json b/packages/@aws-cdk/aws-ecr/package.json index d75818d7f75e6..fafe098831c9b 100644 --- a/packages/@aws-cdk/aws-ecr/package.json +++ b/packages/@aws-cdk/aws-ecr/package.json @@ -67,7 +67,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -90,7 +90,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ @@ -112,4 +112,4 @@ "awscdkio": { "announce": false } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-ecs-patterns/.eslintrc.js b/packages/@aws-cdk/aws-ecs-patterns/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/.eslintrc.js +++ b/packages/@aws-cdk/aws-ecs-patterns/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ecs-patterns/package.json b/packages/@aws-cdk/aws-ecs-patterns/package.json index b8c2fc284f2ff..451153745909f 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/package.json +++ b/packages/@aws-cdk/aws-ecs-patterns/package.json @@ -61,7 +61,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -103,7 +103,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "stable", "awslint": { diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.multiple-application-load-balanced-ecs-service.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.multiple-application-load-balanced-ecs-service.expected.json index 4f42515b434d8..9af53dfb65b39 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.multiple-application-load-balanced-ecs-service.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.multiple-application-load-balanced-ecs-service.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.lit.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.lit.expected.json index 0d76d2e9cbdb1..7cddaef40ca08 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.lit.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.lit.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" } ] } diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.asset-image.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.asset-image.expected.json index 63e74d7cadb80..d3c525b1bf847 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.asset-image.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.asset-image.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.executionrole.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.executionrole.expected.json index 9434388ae3cec..a1fd951c34ef6 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.executionrole.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.executionrole.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-autocreate.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-autocreate.expected.json index 1ab54d731956a..63aa998b3e48c 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-autocreate.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-autocreate.expected.json @@ -330,10 +330,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/EcsDefaultClusterMnL3mNNYN/Vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -341,6 +337,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsDefaultClusterMnL3mNNYN/Vpc/PublicSubnet1" } ] } @@ -427,10 +427,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/EcsDefaultClusterMnL3mNNYN/Vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -438,6 +434,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsDefaultClusterMnL3mNNYN/Vpc/PublicSubnet2" } ] } @@ -524,10 +524,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/EcsDefaultClusterMnL3mNNYN/Vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -535,6 +531,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsDefaultClusterMnL3mNNYN/Vpc/PrivateSubnet1" } ] } @@ -586,10 +586,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/EcsDefaultClusterMnL3mNNYN/Vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -597,6 +593,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsDefaultClusterMnL3mNNYN/Vpc/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-vpconly.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-vpconly.expected.json index 12e8cbf4dfb8d..bbbeb5aad9604 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-vpconly.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-vpconly.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } ] } @@ -685,10 +685,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc2/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -696,6 +692,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc2/PublicSubnet1" } ] } @@ -782,10 +782,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc2/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -793,6 +789,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc2/PublicSubnet2" } ] } @@ -879,10 +879,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc2/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -890,6 +886,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc2/PrivateSubnet1" } ] } @@ -941,10 +941,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc2/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -952,6 +948,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc2/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3.expected.json index 2fda0fb07bc7a..bf7ccdc34691f 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.load-balanced-fargate-service.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.load-balanced-fargate-service.expected.json index 352b325ef01ff..3f560edd9c37a 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.load-balanced-fargate-service.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.load-balanced-fargate-service.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.multiple-network-load-balanced-fargate-service.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.multiple-network-load-balanced-fargate-service.expected.json index 38b6701cdbbc4..4beb67e3e41ed 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.multiple-network-load-balanced-fargate-service.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.multiple-network-load-balanced-fargate-service.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.scheduled-fargate-task.lit.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.scheduled-fargate-task.lit.expected.json index 8b53d3042133f..76e8117cf8e42 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.scheduled-fargate-task.lit.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.scheduled-fargate-task.lit.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-fargate-integ/Vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-fargate-integ/Vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-fargate-integ/Vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-fargate-integ/Vpc/PrivateSubnet1" } ] } diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.special-listener.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.special-listener.expected.json index 32171ee9881cb..1b44af80fdfba 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.special-listener.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.special-listener.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-ecs/.eslintrc.js b/packages/@aws-cdk/aws-ecs/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-ecs/.eslintrc.js +++ b/packages/@aws-cdk/aws-ecs/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ecs/package.json b/packages/@aws-cdk/aws-ecs/package.json index 3177fcc099d09..8668c5ff06380 100644 --- a/packages/@aws-cdk/aws-ecs/package.json +++ b/packages/@aws-cdk/aws-ecs/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "@types/proxyquire": "^1.3.28", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", @@ -125,7 +125,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.expected.json index 25e4b801abe37..c644c86649ef6 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.expected.json index b6fc20ed2acf8..edb849319d5b8 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.firelens-s3-config.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.firelens-s3-config.expected.json index c58b52b13730a..a379d7c8c3109 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.firelens-s3-config.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.firelens-s3-config.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-awsvpc-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-awsvpc-nw.expected.json index ca2dfe2fa3f94..e5e7464767c36 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-awsvpc-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-awsvpc-nw.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-bridge-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-bridge-nw.expected.json index 00cfbec6de810..74b289cadbde6 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-bridge-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-bridge-nw.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-awsvpc-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-awsvpc-nw.expected.json index da042e495205e..46f3b9a4e26cf 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-awsvpc-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-awsvpc-nw.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-bridge-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-bridge-nw.expected.json index 4e6b74fb6cb35..16d9538eb2127 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-bridge-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-bridge-nw.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.spot-drain.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.spot-drain.expected.json index c6070c2783db6..71a61e7a4a4a7 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.spot-drain.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.spot-drain.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-spot/Vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-spot/Vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-spot/Vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-spot/Vpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-spot/Vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-spot/Vpc/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-spot/Vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-spot/Vpc/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/integ.firelens-cloudwatch.expected.json b/packages/@aws-cdk/aws-ecs/test/fargate/integ.firelens-cloudwatch.expected.json index 7aa3dc77ecda5..f45347575127a 100644 --- a/packages/@aws-cdk/aws-ecs/test/fargate/integ.firelens-cloudwatch.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/fargate/integ.firelens-cloudwatch.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/integ.lb-awsvpc-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/fargate/integ.lb-awsvpc-nw.expected.json index 721d19449100c..3086a7626b3bf 100644 --- a/packages/@aws-cdk/aws-ecs/test/fargate/integ.lb-awsvpc-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/fargate/integ.lb-awsvpc-nw.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/integ.nlb-awsvpc-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/fargate/integ.nlb-awsvpc-nw.expected.json index 5ca7893a6a1a2..c31bde0d07af8 100644 --- a/packages/@aws-cdk/aws-ecs/test/fargate/integ.nlb-awsvpc-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/fargate/integ.nlb-awsvpc-nw.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-efs/.eslintrc.js b/packages/@aws-cdk/aws-efs/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-efs/.eslintrc.js +++ b/packages/@aws-cdk/aws-efs/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-efs/.gitignore b/packages/@aws-cdk/aws-efs/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-efs/.gitignore +++ b/packages/@aws-cdk/aws-efs/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-efs/.npmignore b/packages/@aws-cdk/aws-efs/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-efs/.npmignore +++ b/packages/@aws-cdk/aws-efs/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-efs/jest.config.js b/packages/@aws-cdk/aws-efs/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-efs/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-efs/package.json b/packages/@aws-cdk/aws-efs/package.json index f574148eff728..f17fa315f03a2 100644 --- a/packages/@aws-cdk/aws-efs/package.json +++ b/packages/@aws-cdk/aws-efs/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::EFS" + "cloudformation": "AWS::EFS", + "jest": true }, "keywords": [ "aws", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -102,7 +86,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "experimental", diff --git a/packages/@aws-cdk/aws-eks-legacy/.eslintrc.js b/packages/@aws-cdk/aws-eks-legacy/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-eks-legacy/.eslintrc.js +++ b/packages/@aws-cdk/aws-eks-legacy/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-eks-legacy/package.json b/packages/@aws-cdk/aws-eks-legacy/package.json index e46908c9be762..b00924740d28b 100644 --- a/packages/@aws-cdk/aws-eks-legacy/package.json +++ b/packages/@aws-cdk/aws-eks-legacy/package.json @@ -63,7 +63,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -92,7 +92,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.defaults.expected.json b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.defaults.expected.json index 7ff2bc1aa7024..f98225e84b35e 100644 --- a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.defaults.expected.json +++ b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.defaults.expected.json @@ -26,10 +26,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-defaults/Cluster/DefaultVpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -41,6 +37,10 @@ { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-defaults/Cluster/DefaultVpc/PublicSubnet1" } ] } @@ -52,13 +52,13 @@ "Ref": "ClusterDefaultVpcFA9F2722" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-defaults/Cluster/DefaultVpc/PublicSubnet1" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-defaults/Cluster/DefaultVpc/PublicSubnet1" } ] } @@ -94,13 +94,13 @@ "Properties": { "Domain": "vpc", "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-defaults/Cluster/DefaultVpc/PublicSubnet1" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-defaults/Cluster/DefaultVpc/PublicSubnet1" } ] } @@ -118,13 +118,13 @@ "Ref": "ClusterDefaultVpcPublicSubnet1Subnet3BFE1BDA" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-defaults/Cluster/DefaultVpc/PublicSubnet1" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-defaults/Cluster/DefaultVpc/PublicSubnet1" } ] } @@ -139,10 +139,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-defaults/Cluster/DefaultVpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -154,6 +150,10 @@ { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-defaults/Cluster/DefaultVpc/PublicSubnet2" } ] } @@ -165,13 +165,13 @@ "Ref": "ClusterDefaultVpcFA9F2722" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-defaults/Cluster/DefaultVpc/PublicSubnet2" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-defaults/Cluster/DefaultVpc/PublicSubnet2" } ] } @@ -207,13 +207,13 @@ "Properties": { "Domain": "vpc", "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-defaults/Cluster/DefaultVpc/PublicSubnet2" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-defaults/Cluster/DefaultVpc/PublicSubnet2" } ] } @@ -231,13 +231,13 @@ "Ref": "ClusterDefaultVpcPublicSubnet2SubnetC4E9A966" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-defaults/Cluster/DefaultVpc/PublicSubnet2" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-defaults/Cluster/DefaultVpc/PublicSubnet2" } ] } @@ -252,10 +252,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-defaults/Cluster/DefaultVpc/PublicSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -267,6 +263,10 @@ { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-defaults/Cluster/DefaultVpc/PublicSubnet3" } ] } @@ -278,13 +278,13 @@ "Ref": "ClusterDefaultVpcFA9F2722" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-defaults/Cluster/DefaultVpc/PublicSubnet3" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-defaults/Cluster/DefaultVpc/PublicSubnet3" } ] } @@ -320,13 +320,13 @@ "Properties": { "Domain": "vpc", "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-defaults/Cluster/DefaultVpc/PublicSubnet3" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-defaults/Cluster/DefaultVpc/PublicSubnet3" } ] } @@ -344,13 +344,13 @@ "Ref": "ClusterDefaultVpcPublicSubnet3Subnet1A46184A" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-defaults/Cluster/DefaultVpc/PublicSubnet3" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-defaults/Cluster/DefaultVpc/PublicSubnet3" } ] } @@ -365,10 +365,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-defaults/Cluster/DefaultVpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -380,6 +376,10 @@ { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-defaults/Cluster/DefaultVpc/PrivateSubnet1" } ] } @@ -391,13 +391,13 @@ "Ref": "ClusterDefaultVpcFA9F2722" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-defaults/Cluster/DefaultVpc/PrivateSubnet1" - }, { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-defaults/Cluster/DefaultVpc/PrivateSubnet1" } ] } @@ -435,10 +435,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-defaults/Cluster/DefaultVpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -450,6 +446,10 @@ { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-defaults/Cluster/DefaultVpc/PrivateSubnet2" } ] } @@ -461,13 +461,13 @@ "Ref": "ClusterDefaultVpcFA9F2722" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-defaults/Cluster/DefaultVpc/PrivateSubnet2" - }, { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-defaults/Cluster/DefaultVpc/PrivateSubnet2" } ] } @@ -505,10 +505,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-defaults/Cluster/DefaultVpc/PrivateSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -520,6 +516,10 @@ { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-defaults/Cluster/DefaultVpc/PrivateSubnet3" } ] } @@ -531,13 +531,13 @@ "Ref": "ClusterDefaultVpcFA9F2722" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-defaults/Cluster/DefaultVpc/PrivateSubnet3" - }, { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-defaults/Cluster/DefaultVpc/PrivateSubnet3" } ] } @@ -934,10 +934,6 @@ } ], "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-defaults/Cluster/DefaultCapacity" - }, { "Key": { "Fn::Join": [ @@ -951,6 +947,10 @@ ] }, "Value": "owned" + }, + { + "Key": "Name", + "Value": "eks-integ-defaults/Cluster/DefaultCapacity" } ], "VpcId": { @@ -1083,10 +1083,6 @@ } ], "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-defaults/Cluster/DefaultCapacity" - }, { "Key": { "Fn::Join": [ @@ -1100,6 +1096,10 @@ ] }, "Value": "owned" + }, + { + "Key": "Name", + "Value": "eks-integ-defaults/Cluster/DefaultCapacity" } ] } @@ -1161,11 +1161,6 @@ "Ref": "ClusterDefaultCapacityLaunchConfig72790CF7" }, "Tags": [ - { - "Key": "Name", - "PropagateAtLaunch": true, - "Value": "eks-integ-defaults/Cluster/DefaultCapacity" - }, { "Key": { "Fn::Join": [ @@ -1180,6 +1175,11 @@ }, "PropagateAtLaunch": true, "Value": "owned" + }, + { + "Key": "Name", + "PropagateAtLaunch": true, + "Value": "eks-integ-defaults/Cluster/DefaultCapacity" } ], "VPCZoneIdentifier": [ diff --git a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.kubectl-disabled.expected.json b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.kubectl-disabled.expected.json index 70a617d90daa3..66e63cb1a7497 100644 --- a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.kubectl-disabled.expected.json +++ b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.kubectl-disabled.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -40,6 +36,10 @@ { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet1" } ] } @@ -51,13 +51,13 @@ "Ref": "VPCB9E5F0B4" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet1" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet1" } ] } @@ -93,13 +93,13 @@ "Properties": { "Domain": "vpc", "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet1" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet1" } ] } @@ -117,13 +117,13 @@ "Ref": "VPCPublicSubnet1SubnetB4246D30" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet1" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet1" } ] } @@ -138,10 +138,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -153,6 +149,10 @@ { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet2" } ] } @@ -164,13 +164,13 @@ "Ref": "VPCB9E5F0B4" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet2" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet2" } ] } @@ -206,13 +206,13 @@ "Properties": { "Domain": "vpc", "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet2" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet2" } ] } @@ -230,13 +230,13 @@ "Ref": "VPCPublicSubnet2Subnet74179F39" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet2" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet2" } ] } @@ -251,10 +251,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -266,6 +262,10 @@ { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet3" } ] } @@ -277,13 +277,13 @@ "Ref": "VPCB9E5F0B4" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet3" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet3" } ] } @@ -319,13 +319,13 @@ "Properties": { "Domain": "vpc", "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet3" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet3" } ] } @@ -343,13 +343,13 @@ "Ref": "VPCPublicSubnet3Subnet631C5E25" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet3" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet3" } ] } @@ -364,10 +364,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -379,6 +375,10 @@ { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet1" } ] } @@ -390,13 +390,13 @@ "Ref": "VPCB9E5F0B4" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet1" - }, { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet1" } ] } @@ -434,10 +434,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -449,6 +445,10 @@ { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet2" } ] } @@ -460,13 +460,13 @@ "Ref": "VPCB9E5F0B4" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet2" - }, { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet2" } ] } @@ -504,10 +504,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -519,6 +515,10 @@ { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet3" } ] } @@ -530,13 +530,13 @@ "Ref": "VPCB9E5F0B4" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet3" - }, { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet3" } ] } @@ -719,10 +719,6 @@ } ], "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/EKSCluster/Nodes" - }, { "Key": { "Fn::Join": [ @@ -736,6 +732,10 @@ ] }, "Value": "owned" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/EKSCluster/Nodes" } ], "VpcId": { @@ -868,10 +868,6 @@ } ], "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/EKSCluster/Nodes" - }, { "Key": { "Fn::Join": [ @@ -885,6 +881,10 @@ ] }, "Value": "owned" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/EKSCluster/Nodes" } ] } @@ -946,11 +946,6 @@ "Ref": "EKSClusterNodesLaunchConfig921F1106" }, "Tags": [ - { - "Key": "Name", - "PropagateAtLaunch": true, - "Value": "eks-integ-kubectl-disabled/EKSCluster/Nodes" - }, { "Key": { "Fn::Join": [ @@ -965,6 +960,11 @@ }, "PropagateAtLaunch": true, "Value": "owned" + }, + { + "Key": "Name", + "PropagateAtLaunch": true, + "Value": "eks-integ-kubectl-disabled/EKSCluster/Nodes" } ], "VPCZoneIdentifier": [ diff --git a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.lit.expected.json b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.lit.expected.json index ad3e616b39bb6..254e46a33dfd5 100644 --- a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.lit.expected.json +++ b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.lit.expected.json @@ -26,10 +26,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-test-basic/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -41,6 +37,10 @@ { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-test-basic/VPC/PublicSubnet1" } ] } @@ -52,13 +52,13 @@ "Ref": "VPCB9E5F0B4" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-test-basic/VPC/PublicSubnet1" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-test-basic/VPC/PublicSubnet1" } ] } @@ -94,13 +94,13 @@ "Properties": { "Domain": "vpc", "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-test-basic/VPC/PublicSubnet1" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-test-basic/VPC/PublicSubnet1" } ] } @@ -118,13 +118,13 @@ "Ref": "VPCPublicSubnet1SubnetB4246D30" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-test-basic/VPC/PublicSubnet1" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-test-basic/VPC/PublicSubnet1" } ] } @@ -139,10 +139,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-test-basic/VPC/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -154,6 +150,10 @@ { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-test-basic/VPC/PublicSubnet2" } ] } @@ -165,13 +165,13 @@ "Ref": "VPCB9E5F0B4" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-test-basic/VPC/PublicSubnet2" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-test-basic/VPC/PublicSubnet2" } ] } @@ -207,13 +207,13 @@ "Properties": { "Domain": "vpc", "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-test-basic/VPC/PublicSubnet2" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-test-basic/VPC/PublicSubnet2" } ] } @@ -231,13 +231,13 @@ "Ref": "VPCPublicSubnet2Subnet74179F39" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-test-basic/VPC/PublicSubnet2" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-test-basic/VPC/PublicSubnet2" } ] } @@ -252,10 +252,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-test-basic/VPC/PublicSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -267,6 +263,10 @@ { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-test-basic/VPC/PublicSubnet3" } ] } @@ -278,13 +278,13 @@ "Ref": "VPCB9E5F0B4" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-test-basic/VPC/PublicSubnet3" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-test-basic/VPC/PublicSubnet3" } ] } @@ -320,13 +320,13 @@ "Properties": { "Domain": "vpc", "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-test-basic/VPC/PublicSubnet3" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-test-basic/VPC/PublicSubnet3" } ] } @@ -344,13 +344,13 @@ "Ref": "VPCPublicSubnet3Subnet631C5E25" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-test-basic/VPC/PublicSubnet3" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-test-basic/VPC/PublicSubnet3" } ] } @@ -365,10 +365,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-test-basic/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -380,6 +376,10 @@ { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-test-basic/VPC/PrivateSubnet1" } ] } @@ -391,13 +391,13 @@ "Ref": "VPCB9E5F0B4" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-test-basic/VPC/PrivateSubnet1" - }, { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-test-basic/VPC/PrivateSubnet1" } ] } @@ -435,10 +435,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-test-basic/VPC/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -450,6 +446,10 @@ { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-test-basic/VPC/PrivateSubnet2" } ] } @@ -461,13 +461,13 @@ "Ref": "VPCB9E5F0B4" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-test-basic/VPC/PrivateSubnet2" - }, { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-test-basic/VPC/PrivateSubnet2" } ] } @@ -505,10 +505,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-test-basic/VPC/PrivateSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -520,6 +516,10 @@ { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-test-basic/VPC/PrivateSubnet3" } ] } @@ -531,13 +531,13 @@ "Ref": "VPCB9E5F0B4" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-test-basic/VPC/PrivateSubnet3" - }, { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-test-basic/VPC/PrivateSubnet3" } ] } @@ -934,10 +934,6 @@ } ], "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-test-basic/EKSCluster/Nodes" - }, { "Key": { "Fn::Join": [ @@ -951,6 +947,10 @@ ] }, "Value": "owned" + }, + { + "Key": "Name", + "Value": "eks-integ-test-basic/EKSCluster/Nodes" } ], "VpcId": { @@ -1083,10 +1083,6 @@ } ], "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-test-basic/EKSCluster/Nodes" - }, { "Key": { "Fn::Join": [ @@ -1100,6 +1096,10 @@ ] }, "Value": "owned" + }, + { + "Key": "Name", + "Value": "eks-integ-test-basic/EKSCluster/Nodes" } ] } @@ -1161,11 +1161,6 @@ "Ref": "EKSClusterNodesLaunchConfig921F1106" }, "Tags": [ - { - "Key": "Name", - "PropagateAtLaunch": true, - "Value": "eks-integ-test-basic/EKSCluster/Nodes" - }, { "Key": { "Fn::Join": [ @@ -1180,6 +1175,11 @@ }, "PropagateAtLaunch": true, "Value": "owned" + }, + { + "Key": "Name", + "PropagateAtLaunch": true, + "Value": "eks-integ-test-basic/EKSCluster/Nodes" } ], "VPCZoneIdentifier": [ diff --git a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-helm.lit.expected.json b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-helm.lit.expected.json index 10172624f8f2e..ba37ddbe77d70 100644 --- a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-helm.lit.expected.json +++ b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-helm.lit.expected.json @@ -26,10 +26,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "k8s-vpc/vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -41,6 +37,10 @@ { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "k8s-vpc/vpc/PublicSubnet1" } ] } @@ -52,13 +52,13 @@ "Ref": "vpcA2121C38" }, "Tags": [ - { - "Key": "Name", - "Value": "k8s-vpc/vpc/PublicSubnet1" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "k8s-vpc/vpc/PublicSubnet1" } ] } @@ -94,13 +94,13 @@ "Properties": { "Domain": "vpc", "Tags": [ - { - "Key": "Name", - "Value": "k8s-vpc/vpc/PublicSubnet1" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "k8s-vpc/vpc/PublicSubnet1" } ] } @@ -118,13 +118,13 @@ "Ref": "vpcPublicSubnet1Subnet2E65531E" }, "Tags": [ - { - "Key": "Name", - "Value": "k8s-vpc/vpc/PublicSubnet1" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "k8s-vpc/vpc/PublicSubnet1" } ] } @@ -139,10 +139,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "k8s-vpc/vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -154,6 +150,10 @@ { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "k8s-vpc/vpc/PublicSubnet2" } ] } @@ -165,13 +165,13 @@ "Ref": "vpcA2121C38" }, "Tags": [ - { - "Key": "Name", - "Value": "k8s-vpc/vpc/PublicSubnet2" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "k8s-vpc/vpc/PublicSubnet2" } ] } @@ -207,13 +207,13 @@ "Properties": { "Domain": "vpc", "Tags": [ - { - "Key": "Name", - "Value": "k8s-vpc/vpc/PublicSubnet2" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "k8s-vpc/vpc/PublicSubnet2" } ] } @@ -231,13 +231,13 @@ "Ref": "vpcPublicSubnet2Subnet009B674F" }, "Tags": [ - { - "Key": "Name", - "Value": "k8s-vpc/vpc/PublicSubnet2" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "k8s-vpc/vpc/PublicSubnet2" } ] } @@ -252,10 +252,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "k8s-vpc/vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -267,6 +263,10 @@ { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "k8s-vpc/vpc/PrivateSubnet1" } ] } @@ -278,13 +278,13 @@ "Ref": "vpcA2121C38" }, "Tags": [ - { - "Key": "Name", - "Value": "k8s-vpc/vpc/PrivateSubnet1" - }, { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "k8s-vpc/vpc/PrivateSubnet1" } ] } @@ -322,10 +322,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "k8s-vpc/vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -337,6 +333,10 @@ { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "k8s-vpc/vpc/PrivateSubnet2" } ] } @@ -348,13 +348,13 @@ "Ref": "vpcA2121C38" }, "Tags": [ - { - "Key": "Name", - "Value": "k8s-vpc/vpc/PrivateSubnet2" - }, { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "k8s-vpc/vpc/PrivateSubnet2" } ] } @@ -827,10 +827,6 @@ } ], "Tags": [ - { - "Key": "Name", - "Value": "k8s-cluster/cluster22/Nodes" - }, { "Key": { "Fn::Join": [ @@ -844,6 +840,10 @@ ] }, "Value": "owned" + }, + { + "Key": "Name", + "Value": "k8s-cluster/cluster22/Nodes" } ], "VpcId": { @@ -976,10 +976,6 @@ } ], "Tags": [ - { - "Key": "Name", - "Value": "k8s-cluster/cluster22/Nodes" - }, { "Key": { "Fn::Join": [ @@ -993,6 +989,10 @@ ] }, "Value": "owned" + }, + { + "Key": "Name", + "Value": "k8s-cluster/cluster22/Nodes" } ] } @@ -1054,11 +1054,6 @@ "Ref": "cluster22NodesLaunchConfig184BF3BA" }, "Tags": [ - { - "Key": "Name", - "PropagateAtLaunch": true, - "Value": "k8s-cluster/cluster22/Nodes" - }, { "Key": { "Fn::Join": [ @@ -1073,6 +1068,11 @@ }, "PropagateAtLaunch": true, "Value": "owned" + }, + { + "Key": "Name", + "PropagateAtLaunch": true, + "Value": "k8s-cluster/cluster22/Nodes" } ], "VPCZoneIdentifier": [ diff --git a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-kubectl.lit.expected.json b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-kubectl.lit.expected.json index 643dcd7152b16..fd726b6e62f29 100644 --- a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-kubectl.lit.expected.json +++ b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-kubectl.lit.expected.json @@ -26,10 +26,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "k8s-vpc/vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -41,6 +37,10 @@ { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "k8s-vpc/vpc/PublicSubnet1" } ] } @@ -52,13 +52,13 @@ "Ref": "vpcA2121C38" }, "Tags": [ - { - "Key": "Name", - "Value": "k8s-vpc/vpc/PublicSubnet1" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "k8s-vpc/vpc/PublicSubnet1" } ] } @@ -94,13 +94,13 @@ "Properties": { "Domain": "vpc", "Tags": [ - { - "Key": "Name", - "Value": "k8s-vpc/vpc/PublicSubnet1" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "k8s-vpc/vpc/PublicSubnet1" } ] } @@ -118,13 +118,13 @@ "Ref": "vpcPublicSubnet1Subnet2E65531E" }, "Tags": [ - { - "Key": "Name", - "Value": "k8s-vpc/vpc/PublicSubnet1" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "k8s-vpc/vpc/PublicSubnet1" } ] } @@ -139,10 +139,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "k8s-vpc/vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -154,6 +150,10 @@ { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "k8s-vpc/vpc/PublicSubnet2" } ] } @@ -165,13 +165,13 @@ "Ref": "vpcA2121C38" }, "Tags": [ - { - "Key": "Name", - "Value": "k8s-vpc/vpc/PublicSubnet2" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "k8s-vpc/vpc/PublicSubnet2" } ] } @@ -207,13 +207,13 @@ "Properties": { "Domain": "vpc", "Tags": [ - { - "Key": "Name", - "Value": "k8s-vpc/vpc/PublicSubnet2" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "k8s-vpc/vpc/PublicSubnet2" } ] } @@ -231,13 +231,13 @@ "Ref": "vpcPublicSubnet2Subnet009B674F" }, "Tags": [ - { - "Key": "Name", - "Value": "k8s-vpc/vpc/PublicSubnet2" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "k8s-vpc/vpc/PublicSubnet2" } ] } @@ -252,10 +252,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "k8s-vpc/vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -267,6 +263,10 @@ { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "k8s-vpc/vpc/PrivateSubnet1" } ] } @@ -278,13 +278,13 @@ "Ref": "vpcA2121C38" }, "Tags": [ - { - "Key": "Name", - "Value": "k8s-vpc/vpc/PrivateSubnet1" - }, { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "k8s-vpc/vpc/PrivateSubnet1" } ] } @@ -322,10 +322,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "k8s-vpc/vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -337,6 +333,10 @@ { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "k8s-vpc/vpc/PrivateSubnet2" } ] } @@ -348,13 +348,13 @@ "Ref": "vpcA2121C38" }, "Tags": [ - { - "Key": "Name", - "Value": "k8s-vpc/vpc/PrivateSubnet2" - }, { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "k8s-vpc/vpc/PrivateSubnet2" } ] } @@ -827,10 +827,6 @@ } ], "Tags": [ - { - "Key": "Name", - "Value": "k8s-cluster/cluster22/Nodes" - }, { "Key": { "Fn::Join": [ @@ -844,6 +840,10 @@ ] }, "Value": "owned" + }, + { + "Key": "Name", + "Value": "k8s-cluster/cluster22/Nodes" } ], "VpcId": { @@ -976,10 +976,6 @@ } ], "Tags": [ - { - "Key": "Name", - "Value": "k8s-cluster/cluster22/Nodes" - }, { "Key": { "Fn::Join": [ @@ -993,6 +989,10 @@ ] }, "Value": "owned" + }, + { + "Key": "Name", + "Value": "k8s-cluster/cluster22/Nodes" } ] } @@ -1054,11 +1054,6 @@ "Ref": "cluster22NodesLaunchConfig184BF3BA" }, "Tags": [ - { - "Key": "Name", - "PropagateAtLaunch": true, - "Value": "k8s-cluster/cluster22/Nodes" - }, { "Key": { "Fn::Join": [ @@ -1073,6 +1068,11 @@ }, "PropagateAtLaunch": true, "Value": "owned" + }, + { + "Key": "Name", + "PropagateAtLaunch": true, + "Value": "k8s-cluster/cluster22/Nodes" } ], "VPCZoneIdentifier": [ diff --git a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-spot.expected.json b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-spot.expected.json index cc4e0b4d7c0e7..56f7f71864838 100644 --- a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-spot.expected.json +++ b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-spot.expected.json @@ -26,10 +26,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "integ-eks-spot/vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -41,6 +37,10 @@ { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "integ-eks-spot/vpc/PublicSubnet1" } ] } @@ -52,13 +52,13 @@ "Ref": "vpcA2121C38" }, "Tags": [ - { - "Key": "Name", - "Value": "integ-eks-spot/vpc/PublicSubnet1" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "integ-eks-spot/vpc/PublicSubnet1" } ] } @@ -94,13 +94,13 @@ "Properties": { "Domain": "vpc", "Tags": [ - { - "Key": "Name", - "Value": "integ-eks-spot/vpc/PublicSubnet1" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "integ-eks-spot/vpc/PublicSubnet1" } ] } @@ -118,13 +118,13 @@ "Ref": "vpcPublicSubnet1Subnet2E65531E" }, "Tags": [ - { - "Key": "Name", - "Value": "integ-eks-spot/vpc/PublicSubnet1" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "integ-eks-spot/vpc/PublicSubnet1" } ] } @@ -139,10 +139,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "integ-eks-spot/vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -154,6 +150,10 @@ { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "integ-eks-spot/vpc/PublicSubnet2" } ] } @@ -165,13 +165,13 @@ "Ref": "vpcA2121C38" }, "Tags": [ - { - "Key": "Name", - "Value": "integ-eks-spot/vpc/PublicSubnet2" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "integ-eks-spot/vpc/PublicSubnet2" } ] } @@ -207,13 +207,13 @@ "Properties": { "Domain": "vpc", "Tags": [ - { - "Key": "Name", - "Value": "integ-eks-spot/vpc/PublicSubnet2" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "integ-eks-spot/vpc/PublicSubnet2" } ] } @@ -231,13 +231,13 @@ "Ref": "vpcPublicSubnet2Subnet009B674F" }, "Tags": [ - { - "Key": "Name", - "Value": "integ-eks-spot/vpc/PublicSubnet2" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "integ-eks-spot/vpc/PublicSubnet2" } ] } @@ -252,10 +252,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "integ-eks-spot/vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -267,6 +263,10 @@ { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "integ-eks-spot/vpc/PrivateSubnet1" } ] } @@ -278,13 +278,13 @@ "Ref": "vpcA2121C38" }, "Tags": [ - { - "Key": "Name", - "Value": "integ-eks-spot/vpc/PrivateSubnet1" - }, { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "integ-eks-spot/vpc/PrivateSubnet1" } ] } @@ -322,10 +322,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "integ-eks-spot/vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -337,6 +333,10 @@ { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "integ-eks-spot/vpc/PrivateSubnet2" } ] } @@ -348,13 +348,13 @@ "Ref": "vpcA2121C38" }, "Tags": [ - { - "Key": "Name", - "Value": "integ-eks-spot/vpc/PrivateSubnet2" - }, { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "integ-eks-spot/vpc/PrivateSubnet2" } ] } @@ -766,10 +766,6 @@ } ], "Tags": [ - { - "Key": "Name", - "Value": "integ-eks-spot/myCluster/DefaultCapacity" - }, { "Key": { "Fn::Join": [ @@ -783,6 +779,10 @@ ] }, "Value": "owned" + }, + { + "Key": "Name", + "Value": "integ-eks-spot/myCluster/DefaultCapacity" } ], "VpcId": { @@ -915,10 +915,6 @@ } ], "Tags": [ - { - "Key": "Name", - "Value": "integ-eks-spot/myCluster/DefaultCapacity" - }, { "Key": { "Fn::Join": [ @@ -932,6 +928,10 @@ ] }, "Value": "owned" + }, + { + "Key": "Name", + "Value": "integ-eks-spot/myCluster/DefaultCapacity" } ] } @@ -993,11 +993,6 @@ "Ref": "myClusterDefaultCapacityLaunchConfigCF6D4B81" }, "Tags": [ - { - "Key": "Name", - "PropagateAtLaunch": true, - "Value": "integ-eks-spot/myCluster/DefaultCapacity" - }, { "Key": { "Fn::Join": [ @@ -1012,6 +1007,11 @@ }, "PropagateAtLaunch": true, "Value": "owned" + }, + { + "Key": "Name", + "PropagateAtLaunch": true, + "Value": "integ-eks-spot/myCluster/DefaultCapacity" } ], "VPCZoneIdentifier": [ @@ -1087,10 +1087,6 @@ } ], "Tags": [ - { - "Key": "Name", - "Value": "integ-eks-spot/myCluster/spot" - }, { "Key": { "Fn::Join": [ @@ -1104,6 +1100,10 @@ ] }, "Value": "owned" + }, + { + "Key": "Name", + "Value": "integ-eks-spot/myCluster/spot" } ], "VpcId": { @@ -1236,10 +1236,6 @@ } ], "Tags": [ - { - "Key": "Name", - "Value": "integ-eks-spot/myCluster/spot" - }, { "Key": { "Fn::Join": [ @@ -1253,6 +1249,10 @@ ] }, "Value": "owned" + }, + { + "Key": "Name", + "Value": "integ-eks-spot/myCluster/spot" } ] } @@ -1314,11 +1314,6 @@ "Ref": "myClusterspotLaunchConfig6681F311" }, "Tags": [ - { - "Key": "Name", - "PropagateAtLaunch": true, - "Value": "integ-eks-spot/myCluster/spot" - }, { "Key": { "Fn::Join": [ @@ -1333,6 +1328,11 @@ }, "PropagateAtLaunch": true, "Value": "owned" + }, + { + "Key": "Name", + "PropagateAtLaunch": true, + "Value": "integ-eks-spot/myCluster/spot" } ], "VPCZoneIdentifier": [ diff --git a/packages/@aws-cdk/aws-eks-legacy/test/test.cluster.ts b/packages/@aws-cdk/aws-eks-legacy/test/test.cluster.ts index ed3da1685ede0..3e536e0b92f6e 100644 --- a/packages/@aws-cdk/aws-eks-legacy/test/test.cluster.ts +++ b/packages/@aws-cdk/aws-eks-legacy/test/test.cluster.ts @@ -102,10 +102,10 @@ export = { // THEN expect(stack).to(haveResource('AWS::EC2::Subnet', { Tags: [ - { Key: 'Name', Value: 'Stack/VPC/PrivateSubnet1' }, { 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: 'Stack/VPC/PrivateSubnet1' }, ], })); @@ -123,10 +123,10 @@ export = { expect(stack).to(haveResource('AWS::EC2::Subnet', { MapPublicIpOnLaunch: true, Tags: [ - { Key: 'Name', Value: 'Stack/VPC/PublicSubnet1' }, { Key: 'aws-cdk:subnet-name', Value: 'Public' }, { Key: 'aws-cdk:subnet-type', Value: 'Public' }, { Key: 'kubernetes.io/role/elb', Value: '1' }, + { Key: 'Name', Value: 'Stack/VPC/PublicSubnet1' }, ], })); @@ -147,14 +147,14 @@ export = { expect(stack).to(haveResource('AWS::AutoScaling::AutoScalingGroup', { Tags: [ { - Key: 'Name', + Key: { 'Fn::Join': [ '', [ 'kubernetes.io/cluster/', { Ref: 'ClusterEB0386A7' } ] ] }, PropagateAtLaunch: true, - Value: 'Stack/Cluster/Default', + Value: 'owned', }, { - Key: { 'Fn::Join': [ '', [ 'kubernetes.io/cluster/', { Ref: 'ClusterEB0386A7' } ] ] }, + Key: 'Name', PropagateAtLaunch: true, - Value: 'owned', + Value: 'Stack/Cluster/Default', }, ], })); diff --git a/packages/@aws-cdk/aws-eks/.eslintrc.js b/packages/@aws-cdk/aws-eks/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-eks/.eslintrc.js +++ b/packages/@aws-cdk/aws-eks/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-eks/package.json b/packages/@aws-cdk/aws-eks/package.json index d856da674f46b..0524927557dc9 100644 --- a/packages/@aws-cdk/aws-eks/package.json +++ b/packages/@aws-cdk/aws-eks/package.json @@ -63,8 +63,8 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.672.0", + "@types/nodeunit": "^0.0.31", + "aws-sdk": "^2.678.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -94,7 +94,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ 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 eabb31a0c499f..67ad7d6a50a2c 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 @@ -53,10 +53,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -68,6 +64,10 @@ { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PublicSubnet1" } ] } @@ -79,13 +79,13 @@ "Ref": "ClusterDefaultVpcFA9F2722" }, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PublicSubnet1" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PublicSubnet1" } ] } @@ -121,13 +121,13 @@ "Properties": { "Domain": "vpc", "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PublicSubnet1" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PublicSubnet1" } ] } @@ -145,13 +145,13 @@ "Ref": "ClusterDefaultVpcPublicSubnet1Subnet3BFE1BDA" }, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PublicSubnet1" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PublicSubnet1" } ] } @@ -166,10 +166,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -181,6 +177,10 @@ { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PublicSubnet2" } ] } @@ -192,13 +192,13 @@ "Ref": "ClusterDefaultVpcFA9F2722" }, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PublicSubnet2" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PublicSubnet2" } ] } @@ -234,13 +234,13 @@ "Properties": { "Domain": "vpc", "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PublicSubnet2" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PublicSubnet2" } ] } @@ -258,13 +258,13 @@ "Ref": "ClusterDefaultVpcPublicSubnet2SubnetC4E9A966" }, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PublicSubnet2" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PublicSubnet2" } ] } @@ -279,10 +279,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PublicSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -294,6 +290,10 @@ { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PublicSubnet3" } ] } @@ -305,13 +305,13 @@ "Ref": "ClusterDefaultVpcFA9F2722" }, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PublicSubnet3" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PublicSubnet3" } ] } @@ -347,13 +347,13 @@ "Properties": { "Domain": "vpc", "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PublicSubnet3" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PublicSubnet3" } ] } @@ -371,13 +371,13 @@ "Ref": "ClusterDefaultVpcPublicSubnet3Subnet1A46184A" }, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PublicSubnet3" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PublicSubnet3" } ] } @@ -392,10 +392,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -407,6 +403,10 @@ { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PrivateSubnet1" } ] } @@ -418,13 +418,13 @@ "Ref": "ClusterDefaultVpcFA9F2722" }, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PrivateSubnet1" - }, { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PrivateSubnet1" } ] } @@ -462,10 +462,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -477,6 +473,10 @@ { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PrivateSubnet2" } ] } @@ -488,13 +488,13 @@ "Ref": "ClusterDefaultVpcFA9F2722" }, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PrivateSubnet2" - }, { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PrivateSubnet2" } ] } @@ -532,10 +532,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PrivateSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -547,6 +543,10 @@ { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PrivateSubnet3" } ] } @@ -558,13 +558,13 @@ "Ref": "ClusterDefaultVpcFA9F2722" }, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PrivateSubnet3" - }, { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-cluster-test/Cluster/DefaultVpc/PrivateSubnet3" } ] } @@ -1139,10 +1139,6 @@ } ], "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-eks-cluster-test/Cluster/Nodes" - }, { "Key": { "Fn::Join": [ @@ -1156,6 +1152,10 @@ ] }, "Value": "owned" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-cluster-test/Cluster/Nodes" } ], "VpcId": { @@ -1288,10 +1288,6 @@ } ], "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-eks-cluster-test/Cluster/Nodes" - }, { "Key": { "Fn::Join": [ @@ -1305,6 +1301,10 @@ ] }, "Value": "owned" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-cluster-test/Cluster/Nodes" } ] } @@ -1365,11 +1365,6 @@ "Ref": "ClusterNodesLaunchConfig7C420A27" }, "Tags": [ - { - "Key": "Name", - "PropagateAtLaunch": true, - "Value": "aws-cdk-eks-cluster-test/Cluster/Nodes" - }, { "Key": { "Fn::Join": [ @@ -1384,6 +1379,11 @@ }, "PropagateAtLaunch": true, "Value": "owned" + }, + { + "Key": "Name", + "PropagateAtLaunch": true, + "Value": "aws-cdk-eks-cluster-test/Cluster/Nodes" } ], "VPCZoneIdentifier": [ @@ -1427,10 +1427,6 @@ } ], "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-eks-cluster-test/Cluster/BottlerocketNodes" - }, { "Key": { "Fn::Join": [ @@ -1444,6 +1440,10 @@ ] }, "Value": "owned" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-cluster-test/Cluster/BottlerocketNodes" } ], "VpcId": { @@ -1576,10 +1576,6 @@ } ], "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-eks-cluster-test/Cluster/BottlerocketNodes" - }, { "Key": { "Fn::Join": [ @@ -1593,6 +1589,10 @@ ] }, "Value": "owned" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-cluster-test/Cluster/BottlerocketNodes" } ] } @@ -1667,11 +1667,6 @@ "Ref": "ClusterBottlerocketNodesLaunchConfig76D7BEBE" }, "Tags": [ - { - "Key": "Name", - "PropagateAtLaunch": true, - "Value": "aws-cdk-eks-cluster-test/Cluster/BottlerocketNodes" - }, { "Key": { "Fn::Join": [ @@ -1686,6 +1681,11 @@ }, "PropagateAtLaunch": true, "Value": "owned" + }, + { + "Key": "Name", + "PropagateAtLaunch": true, + "Value": "aws-cdk-eks-cluster-test/Cluster/BottlerocketNodes" } ], "VPCZoneIdentifier": [ @@ -1729,10 +1729,6 @@ } ], "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-eks-cluster-test/Cluster/spot" - }, { "Key": { "Fn::Join": [ @@ -1746,6 +1742,10 @@ ] }, "Value": "owned" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-cluster-test/Cluster/spot" } ], "VpcId": { @@ -1878,10 +1878,6 @@ } ], "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-eks-cluster-test/Cluster/spot" - }, { "Key": { "Fn::Join": [ @@ -1895,6 +1891,10 @@ ] }, "Value": "owned" + }, + { + "Key": "Name", + "Value": "aws-cdk-eks-cluster-test/Cluster/spot" } ] } @@ -1956,11 +1956,6 @@ "Ref": "ClusterspotLaunchConfigCC19F2E6" }, "Tags": [ - { - "Key": "Name", - "PropagateAtLaunch": true, - "Value": "aws-cdk-eks-cluster-test/Cluster/spot" - }, { "Key": { "Fn::Join": [ @@ -1975,6 +1970,11 @@ }, "PropagateAtLaunch": true, "Value": "owned" + }, + { + "Key": "Name", + "PropagateAtLaunch": true, + "Value": "aws-cdk-eks-cluster-test/Cluster/spot" } ], "VPCZoneIdentifier": [ diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.kubectl-disabled.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.kubectl-disabled.expected.json index 8213dbf78c1bd..b390fb3c551cd 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.kubectl-disabled.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.kubectl-disabled.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -40,6 +36,10 @@ { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet1" } ] } @@ -51,13 +51,13 @@ "Ref": "VPCB9E5F0B4" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet1" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet1" } ] } @@ -93,13 +93,13 @@ "Properties": { "Domain": "vpc", "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet1" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet1" } ] } @@ -117,13 +117,13 @@ "Ref": "VPCPublicSubnet1SubnetB4246D30" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet1" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet1" } ] } @@ -138,10 +138,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -153,6 +149,10 @@ { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet2" } ] } @@ -164,13 +164,13 @@ "Ref": "VPCB9E5F0B4" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet2" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet2" } ] } @@ -206,13 +206,13 @@ "Properties": { "Domain": "vpc", "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet2" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet2" } ] } @@ -230,13 +230,13 @@ "Ref": "VPCPublicSubnet2Subnet74179F39" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet2" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet2" } ] } @@ -251,10 +251,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -266,6 +262,10 @@ { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet3" } ] } @@ -277,13 +277,13 @@ "Ref": "VPCB9E5F0B4" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet3" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet3" } ] } @@ -319,13 +319,13 @@ "Properties": { "Domain": "vpc", "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet3" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet3" } ] } @@ -343,13 +343,13 @@ "Ref": "VPCPublicSubnet3Subnet631C5E25" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet3" - }, { "Key": "kubernetes.io/role/elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PublicSubnet3" } ] } @@ -364,10 +364,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -379,6 +375,10 @@ { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet1" } ] } @@ -390,13 +390,13 @@ "Ref": "VPCB9E5F0B4" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet1" - }, { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet1" } ] } @@ -434,10 +434,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -449,6 +445,10 @@ { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet2" } ] } @@ -460,13 +460,13 @@ "Ref": "VPCB9E5F0B4" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet2" - }, { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet2" } ] } @@ -504,10 +504,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -519,6 +515,10 @@ { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet3" } ] } @@ -530,13 +530,13 @@ "Ref": "VPCB9E5F0B4" }, "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet3" - }, { "Key": "kubernetes.io/role/internal-elb", "Value": "1" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/VPC/PrivateSubnet3" } ] } @@ -707,10 +707,6 @@ } ], "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/EKSCluster/Nodes" - }, { "Key": { "Fn::Join": [ @@ -724,6 +720,10 @@ ] }, "Value": "owned" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/EKSCluster/Nodes" } ], "VpcId": { @@ -856,10 +856,6 @@ } ], "Tags": [ - { - "Key": "Name", - "Value": "eks-integ-kubectl-disabled/EKSCluster/Nodes" - }, { "Key": { "Fn::Join": [ @@ -873,6 +869,10 @@ ] }, "Value": "owned" + }, + { + "Key": "Name", + "Value": "eks-integ-kubectl-disabled/EKSCluster/Nodes" } ] } @@ -933,11 +933,6 @@ "Ref": "EKSClusterNodesLaunchConfig921F1106" }, "Tags": [ - { - "Key": "Name", - "PropagateAtLaunch": true, - "Value": "eks-integ-kubectl-disabled/EKSCluster/Nodes" - }, { "Key": { "Fn::Join": [ @@ -952,6 +947,11 @@ }, "PropagateAtLaunch": true, "Value": "owned" + }, + { + "Key": "Name", + "PropagateAtLaunch": true, + "Value": "eks-integ-kubectl-disabled/EKSCluster/Nodes" } ], "VPCZoneIdentifier": [ diff --git a/packages/@aws-cdk/aws-eks/test/test.cluster.ts b/packages/@aws-cdk/aws-eks/test/test.cluster.ts index e74373cc17eae..7ea3985ed4224 100644 --- a/packages/@aws-cdk/aws-eks/test/test.cluster.ts +++ b/packages/@aws-cdk/aws-eks/test/test.cluster.ts @@ -159,10 +159,10 @@ export = { // THEN expect(stack).to(haveResource('AWS::EC2::Subnet', { Tags: [ - { Key: 'Name', Value: 'Stack/VPC/PrivateSubnet1' }, { 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: 'Stack/VPC/PrivateSubnet1' }, ], })); @@ -180,10 +180,10 @@ export = { expect(stack).to(haveResource('AWS::EC2::Subnet', { MapPublicIpOnLaunch: true, Tags: [ - { Key: 'Name', Value: 'Stack/VPC/PublicSubnet1' }, { Key: 'aws-cdk:subnet-name', Value: 'Public' }, { Key: 'aws-cdk:subnet-type', Value: 'Public' }, { Key: 'kubernetes.io/role/elb', Value: '1' }, + { Key: 'Name', Value: 'Stack/VPC/PublicSubnet1' }, ], })); @@ -204,14 +204,14 @@ export = { expect(stack).to(haveResource('AWS::AutoScaling::AutoScalingGroup', { Tags: [ { - Key: 'Name', + Key: { 'Fn::Join': [ '', [ 'kubernetes.io/cluster/', { Ref: 'ClusterEB0386A7' } ] ] }, PropagateAtLaunch: true, - Value: 'Stack/Cluster/Default', + Value: 'owned', }, { - Key: { 'Fn::Join': [ '', [ 'kubernetes.io/cluster/', { Ref: 'ClusterEB0386A7' } ] ] }, + Key: 'Name', PropagateAtLaunch: true, - Value: 'owned', + Value: 'Stack/Cluster/Default', }, ], })); @@ -265,14 +265,14 @@ export = { expect(stack).to(haveResource('AWS::AutoScaling::AutoScalingGroup', { Tags: [ { - Key: 'Name', + Key: { 'Fn::Join': ['', ['kubernetes.io/cluster/', { Ref: 'ClusterEB0386A7' }]] }, PropagateAtLaunch: true, - Value: 'Stack/Cluster/Bottlerocket', + Value: 'owned', }, { - Key: { 'Fn::Join': ['', ['kubernetes.io/cluster/', { Ref: 'ClusterEB0386A7' }]] }, + Key: 'Name', PropagateAtLaunch: true, - Value: 'owned', + Value: 'Stack/Cluster/Bottlerocket', }, ], })); diff --git a/packages/@aws-cdk/aws-elasticache/.eslintrc.js b/packages/@aws-cdk/aws-elasticache/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-elasticache/.eslintrc.js +++ b/packages/@aws-cdk/aws-elasticache/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticache/.gitignore b/packages/@aws-cdk/aws-elasticache/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-elasticache/.gitignore +++ b/packages/@aws-cdk/aws-elasticache/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-elasticache/.npmignore b/packages/@aws-cdk/aws-elasticache/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-elasticache/.npmignore +++ b/packages/@aws-cdk/aws-elasticache/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-elasticache/jest.config.js b/packages/@aws-cdk/aws-elasticache/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-elasticache/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticache/package.json b/packages/@aws-cdk/aws-elasticache/package.json index 8e946e35db3e9..5c6963be97cb9 100644 --- a/packages/@aws-cdk/aws-elasticache/package.json +++ b/packages/@aws-cdk/aws-elasticache/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::ElastiCache" + "cloudformation": "AWS::ElastiCache", + "jest": true }, "keywords": [ "aws", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-elasticbeanstalk/.eslintrc.js b/packages/@aws-cdk/aws-elasticbeanstalk/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-elasticbeanstalk/.eslintrc.js +++ b/packages/@aws-cdk/aws-elasticbeanstalk/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticbeanstalk/.gitignore b/packages/@aws-cdk/aws-elasticbeanstalk/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-elasticbeanstalk/.gitignore +++ b/packages/@aws-cdk/aws-elasticbeanstalk/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-elasticbeanstalk/.npmignore b/packages/@aws-cdk/aws-elasticbeanstalk/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-elasticbeanstalk/.npmignore +++ b/packages/@aws-cdk/aws-elasticbeanstalk/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-elasticbeanstalk/jest.config.js b/packages/@aws-cdk/aws-elasticbeanstalk/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-elasticbeanstalk/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticbeanstalk/package.json b/packages/@aws-cdk/aws-elasticbeanstalk/package.json index 10b393f3289d1..e7845ae99891f 100644 --- a/packages/@aws-cdk/aws-elasticbeanstalk/package.json +++ b/packages/@aws-cdk/aws-elasticbeanstalk/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::ElasticBeanstalk" + "cloudformation": "AWS::ElasticBeanstalk", + "jest": true }, "keywords": [ "aws", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/.eslintrc.js b/packages/@aws-cdk/aws-elasticloadbalancing/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/.eslintrc.js +++ b/packages/@aws-cdk/aws-elasticloadbalancing/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/package.json b/packages/@aws-cdk/aws-elasticloadbalancing/package.json index 7f0f1423d3f11..3d2cf1442fd42 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancing/package.json @@ -63,7 +63,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -82,7 +82,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "nyc": { "statements": 75 diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.elb.expected.json b/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.elb.expected.json index 3ad8d8c6f8158..673c4d55bf81f 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.elb.expected.json +++ b/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.elb.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elb-integ/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-elb-integ/VPC/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elb-integ/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-elb-integ/VPC/PrivateSubnet1" } ] } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/.eslintrc.js b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/.eslintrc.js +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/.gitignore b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/.gitignore index cf3ce17244583..1109bfe833d86 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/.gitignore +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/.gitignore @@ -15,3 +15,4 @@ nyc.config.js *.snk .cdk.staging !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/.npmignore b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/.npmignore index 6ff7c3d72a36a..34ff973619988 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/.npmignore +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/.npmignore @@ -18,3 +18,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/jest.config.js b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/lib/lambda-target.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/lib/lambda-target.ts index 871d8f2b3c4e0..be1f10d465b81 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/lib/lambda-target.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/lib/lambda-target.ts @@ -18,7 +18,8 @@ export class LambdaTarget implements elbv2.IApplicationLoadBalancerTarget { * load balancer. */ public attachToApplicationTargetGroup(targetGroup: elbv2.IApplicationTargetGroup): elbv2.LoadBalancerTargetProps { - this.fn.grantInvoke(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); + const grant = this.fn.grantInvoke(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); + grant.applyBefore(targetGroup); return this.attach(targetGroup); } @@ -29,7 +30,8 @@ export class LambdaTarget implements elbv2.IApplicationLoadBalancerTarget { * load balancer. */ public attachToNetworkTargetGroup(targetGroup: elbv2.INetworkTargetGroup): elbv2.LoadBalancerTargetProps { - this.fn.grantInvoke(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); + const grant = this.fn.grantInvoke(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); + grant.applyBefore(targetGroup); return this.attach(targetGroup); } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json index ff807a3b702cf..768f9e7eebc7f 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json @@ -46,23 +46,6 @@ "build+test": "npm run build && npm test", "compat": "cdk-compat" }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 65, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "keywords": [ "aws", "cdk", @@ -101,7 +84,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "experimental", @@ -113,5 +96,8 @@ }, "awscdkio": { "announce": false + }, + "cdk-build": { + "jest": true } } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/integ.lambda-target.expected.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/integ.lambda-target.expected.json index 5cd8a99e0cee3..69d339ea6324d 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/integ.lambda-target.expected.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/integ.lambda-target.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "TestStack/Stack/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "TestStack/Stack/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "TestStack/Stack/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "TestStack/Stack/PublicSubnet2" } ] } @@ -187,10 +187,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "TestStack/Stack/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -198,6 +194,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "TestStack/Stack/PrivateSubnet1" } ] } @@ -249,10 +249,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "TestStack/Stack/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -260,6 +256,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "TestStack/Stack/PrivateSubnet2" } ] } @@ -409,7 +409,10 @@ } ], "TargetType": "lambda" - } + }, + "DependsOn": [ + "FunInvokeServicePrincipalelasticloadbalancingamazonawscomD2CAC0C4" + ] }, "FunServiceRole3CC876D7": { "Type": "AWS::IAM::Role", diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/lambda-target.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/lambda-target.test.ts index a356179e461c9..ab00be1b14c00 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/lambda-target.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/lambda-target.test.ts @@ -1,23 +1,28 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource, ResourcePart } from '@aws-cdk/assert'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import * as lambda from '@aws-cdk/aws-lambda'; import { Stack } from '@aws-cdk/core'; import * as targets from '../lib'; -test('Can create target groups with lambda targets', () => { - // GIVEN - const stack = new Stack(); +let stack: Stack; +let listener: elbv2.ApplicationListener; +let fn: lambda.Function; + +beforeEach(() => { + stack = new Stack(); const vpc = new ec2.Vpc(stack, 'Stack'); const lb = new elbv2.ApplicationLoadBalancer(stack, 'LB', { vpc }); - const listener = lb.addListener('Listener', { port: 80 }); + listener = lb.addListener('Listener', { port: 80 }); - const fn = new lambda.Function(stack, 'Fun', { + fn = new lambda.Function(stack, 'Fun', { code: lambda.Code.inline('foo'), runtime: lambda.Runtime.PYTHON_3_6, handler: 'index.handler', }); +}); +test('Can create target groups with lambda targets', () => { // WHEN listener.addTargets('Targets', { targets: [new targets.LambdaTarget(fn)], @@ -31,3 +36,15 @@ test('Can create target groups with lambda targets', () => { ], })); }); + +test('Lambda targets create dependency on Invoke permission', () => { + // WHEN + listener.addTargets('Targets', { + targets: [new targets.LambdaTarget(fn)], + }); + + // THEN + expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::TargetGroup', (def: any) => { + return (def.DependsOn ?? []).includes('FunInvokeServicePrincipalelasticloadbalancingamazonawscomD2CAC0C4'); + }, ResourcePart.CompleteDefinition)); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/.eslintrc.js b/packages/@aws-cdk/aws-elasticloadbalancingv2/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/.eslintrc.js +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json index 4a93d839e3a1a..0ad90f1fd4c85 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json @@ -63,7 +63,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -92,7 +92,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.expected.json b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.expected.json index f19500ba7b88e..ea742e41feaa2 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.expected.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.nlb.expected.json b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.nlb.expected.json index 872f346fba8a4..deae233796ea8 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.nlb.expected.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.nlb.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-elasticsearch/.eslintrc.js b/packages/@aws-cdk/aws-elasticsearch/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-elasticsearch/.eslintrc.js +++ b/packages/@aws-cdk/aws-elasticsearch/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticsearch/.gitignore b/packages/@aws-cdk/aws-elasticsearch/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-elasticsearch/.gitignore +++ b/packages/@aws-cdk/aws-elasticsearch/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-elasticsearch/.npmignore b/packages/@aws-cdk/aws-elasticsearch/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-elasticsearch/.npmignore +++ b/packages/@aws-cdk/aws-elasticsearch/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-elasticsearch/jest.config.js b/packages/@aws-cdk/aws-elasticsearch/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-elasticsearch/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticsearch/package.json b/packages/@aws-cdk/aws-elasticsearch/package.json index 62ee2d7db95cc..3b4da6e728f14 100644 --- a/packages/@aws-cdk/aws-elasticsearch/package.json +++ b/packages/@aws-cdk/aws-elasticsearch/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::Elasticsearch" + "cloudformation": "AWS::Elasticsearch", + "jest": true }, "keywords": [ "aws", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-emr/.eslintrc.js b/packages/@aws-cdk/aws-emr/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-emr/.eslintrc.js +++ b/packages/@aws-cdk/aws-emr/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-emr/.gitignore b/packages/@aws-cdk/aws-emr/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-emr/.gitignore +++ b/packages/@aws-cdk/aws-emr/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-emr/.npmignore b/packages/@aws-cdk/aws-emr/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-emr/.npmignore +++ b/packages/@aws-cdk/aws-emr/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-emr/jest.config.js b/packages/@aws-cdk/aws-emr/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-emr/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-emr/package.json b/packages/@aws-cdk/aws-emr/package.json index 0ca8914462171..b40e51a1a0fdf 100644 --- a/packages/@aws-cdk/aws-emr/package.json +++ b/packages/@aws-cdk/aws-emr/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::EMR" + "cloudformation": "AWS::EMR", + "jest": true }, "keywords": [ "aws", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-events-targets/.eslintrc.js b/packages/@aws-cdk/aws-events-targets/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-events-targets/.eslintrc.js +++ b/packages/@aws-cdk/aws-events-targets/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-events-targets/.gitignore b/packages/@aws-cdk/aws-events-targets/.gitignore index da83753de9079..317d3b822f33e 100644 --- a/packages/@aws-cdk/aws-events-targets/.gitignore +++ b/packages/@aws-cdk/aws-events-targets/.gitignore @@ -17,3 +17,4 @@ nyc.config.js lib/sdk-api-metadata.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-events-targets/.npmignore b/packages/@aws-cdk/aws-events-targets/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-events-targets/.npmignore +++ b/packages/@aws-cdk/aws-events-targets/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-events-targets/jest.config.js b/packages/@aws-cdk/aws-events-targets/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-events-targets/lib/ecs-task.ts b/packages/@aws-cdk/aws-events-targets/lib/ecs-task.ts index 68ef60739cc09..57cf46b6d4aeb 100644 --- a/packages/@aws-cdk/aws-events-targets/lib/ecs-task.ts +++ b/packages/@aws-cdk/aws-events-targets/lib/ecs-task.ts @@ -49,28 +49,68 @@ export interface EcsTaskProps { * (Only applicable in case the TaskDefinition is configured for AwsVpc networking) * * @default A new security group is created + * @deprecated use securityGroups instead */ readonly securityGroup?: ec2.ISecurityGroup; + + /** + * Existing security groups to use for the task's ENIs + * + * (Only applicable in case the TaskDefinition is configured for AwsVpc networking) + * + * @default A new security group is created + */ + readonly securityGroups?: ec2.ISecurityGroup[]; } /** * Start a task on an ECS cluster */ export class EcsTask implements events.IRuleTarget { + // Security group fields are public because we can generate a new security group if none is provided. + + /** + * The security group associated with the task. Only applicable with awsvpc network mode. + * + * @default - A new security group is created. + * @deprecated use securityGroups instead. + */ public readonly securityGroup?: ec2.ISecurityGroup; + + /** + * The security groups associated with the task. Only applicable with awsvpc network mode. + * + * @default - A new security group is created. + */ + public readonly securityGroups?: ec2.ISecurityGroup[]; private readonly cluster: ecs.ICluster; private readonly taskDefinition: ecs.TaskDefinition; private readonly taskCount: number; constructor(private readonly props: EcsTaskProps) { + if (props.securityGroup !== undefined && props.securityGroups !== undefined) { + throw new Error('Only one of SecurityGroup or SecurityGroups can be populated.'); + } + this.cluster = props.cluster; this.taskDefinition = props.taskDefinition; this.taskCount = props.taskCount !== undefined ? props.taskCount : 1; - if (this.taskDefinition.networkMode === ecs.NetworkMode.AWS_VPC) { - const securityGroup = props.securityGroup || this.taskDefinition.node.tryFindChild('SecurityGroup') as ec2.ISecurityGroup; - this.securityGroup = securityGroup || new ec2.SecurityGroup(this.taskDefinition, 'SecurityGroup', { vpc: this.props.cluster.vpc }); + // Security groups are only configurable with the "awsvpc" network mode. + if (this.taskDefinition.networkMode !== ecs.NetworkMode.AWS_VPC) { + if (props.securityGroup !== undefined || props.securityGroups !== undefined) { + this.taskDefinition.node.addWarning('security groups are ignored when network mode is not awsvpc'); + } + return; + } + if (props.securityGroups) { + this.securityGroups = props.securityGroups; + return; } + let securityGroup = props.securityGroup || this.taskDefinition.node.tryFindChild('SecurityGroup') as ec2.ISecurityGroup; + securityGroup = securityGroup || new ec2.SecurityGroup(this.taskDefinition, 'SecurityGroup', { vpc: this.props.cluster.vpc }); + this.securityGroup = securityGroup; // Maintain backwards-compatibility for customers that read the generated security group. + this.securityGroups = [securityGroup]; } /** @@ -123,7 +163,7 @@ export class EcsTask implements events.IRuleTarget { awsVpcConfiguration: { subnets: this.props.cluster.vpc.selectSubnets(subnetSelection).subnetIds, assignPublicIp, - securityGroups: this.securityGroup && [this.securityGroup.securityGroupId], + securityGroups: this.securityGroups && this.securityGroups.map(sg => sg.securityGroupId), }, }, } diff --git a/packages/@aws-cdk/aws-events-targets/package.json b/packages/@aws-cdk/aws-events-targets/package.json index fa91e4b0e62b2..3090d038e8a72 100644 --- a/packages/@aws-cdk/aws-events-targets/package.json +++ b/packages/@aws-cdk/aws-events-targets/package.json @@ -49,24 +49,8 @@ "cdk-build": { "pre": [ "cp -f $(node -p 'require.resolve(\"aws-sdk/apis/metadata.json\")') lib/sdk-api-metadata.json && rm -f lib/sdk-api-metadata.d.ts" - ] - }, - "jest": { - "moduleFileExtensions": [ - "js" ], - "coverageThreshold": { - "global": { - "branches": 30, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] + "jest": true }, "keywords": [ "aws", @@ -84,7 +68,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", - "aws-sdk": "^2.672.0", + "aws-sdk": "^2.678.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", @@ -125,7 +109,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "stable", "awslint": { diff --git a/packages/@aws-cdk/aws-events-targets/test/ecs/event-rule-target.test.ts b/packages/@aws-cdk/aws-events-targets/test/ecs/event-rule-target.test.ts index 3b991c4725dd3..66d7b2aced7fb 100644 --- a/packages/@aws-cdk/aws-events-targets/test/ecs/event-rule-target.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/ecs/event-rule-target.test.ts @@ -73,7 +73,7 @@ test('Can use Fargate taskdef as EventRule target', () => { }); // WHEN - rule.addTarget(new targets.EcsTask({ + const target = new targets.EcsTask({ cluster, taskDefinition, taskCount: 1, @@ -81,9 +81,11 @@ test('Can use Fargate taskdef as EventRule target', () => { containerName: 'TheContainer', command: ['echo', events.EventField.fromPath('$.detail.event')], }], - })); + }); + rule.addTarget(target); // THEN + expect(target.securityGroup).toBeDefined(); // Generated security groups should be accessible. expect(stack).toHaveResourceLike('AWS::Events::Rule', { Targets: [ { @@ -258,3 +260,96 @@ test('Isolated subnet does not have AssignPublicIp=true', () => { ], }); }); + +test('throws an error if both securityGroup and securityGroups is specified', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'TaskDef'); + taskDefinition.addContainer('TheContainer', { + image: ecs.ContainerImage.fromRegistry('henk'), + }); + + const rule = new events.Rule(stack, 'Rule', { + schedule: events.Schedule.expression('rate(1 min)'), + }); + const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup', { vpc }); + + // THEN + expect(() => { + rule.addTarget(new targets.EcsTask({ + cluster, + taskDefinition, + taskCount: 1, + securityGroup, + securityGroups: [securityGroup], + containerOverrides: [{ + containerName: 'TheContainer', + command: ['echo', 'yay'], + }], + })); + }).toThrow(/Only one of SecurityGroup or SecurityGroups can be populated./); +}); + +test('uses multiple security groups', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'TaskDef'); + taskDefinition.addContainer('TheContainer', { + image: ecs.ContainerImage.fromRegistry('henk'), + }); + + const rule = new events.Rule(stack, 'Rule', { + schedule: events.Schedule.expression('rate(1 min)'), + }); + const securityGroups = [ + new ec2.SecurityGroup(stack, 'SecurityGroupA', { vpc }), + new ec2.SecurityGroup(stack, 'SecurityGroupB', { vpc }), + ]; + + // WHEN + rule.addTarget(new targets.EcsTask({ + cluster, + taskDefinition, + taskCount: 1, + securityGroups, + containerOverrides: [{ + containerName: 'TheContainer', + command: ['echo', 'yay'], + }], + })); + + // THEN + expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Targets: [ + { + Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, + EcsParameters: { + LaunchType: 'FARGATE', + NetworkConfiguration: { + AwsVpcConfiguration: { + AssignPublicIp: 'DISABLED', + SecurityGroups: [ + { 'Fn::GetAtt': ['SecurityGroupAED40ADC5', 'GroupId']}, + {'Fn::GetAtt': ['SecurityGroupB04591F90', 'GroupId']}, + ], + Subnets: [{ Ref: 'VpcPrivateSubnet1Subnet536B997A'}], + }, + }, + TaskCount: 1, + TaskDefinitionArn: { + Ref: 'TaskDef54694570', + }, + }, + Id: 'Target0', + Input: '{"containerOverrides":[{"name":"TheContainer","command":["echo","yay"]}]}', + RoleArn: { 'Fn::GetAtt': ['TaskDefEventsRoleFB3B67B8', 'Arn'] }, + }, + ], + }); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-events-targets/test/ecs/integ.event-ec2-task.lit.expected.json b/packages/@aws-cdk/aws-events-targets/test/ecs/integ.event-ec2-task.lit.expected.json index 00d6fb582078a..d6af0f21c794a 100644 --- a/packages/@aws-cdk/aws-events-targets/test/ecs/integ.event-ec2-task.lit.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/ecs/integ.event-ec2-task.lit.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" } ] } diff --git a/packages/@aws-cdk/aws-events-targets/test/ecs/integ.event-fargate-task.expected.json b/packages/@aws-cdk/aws-events-targets/test/ecs/integ.event-fargate-task.expected.json index 4039dbafddaf1..e3899f84125c2 100644 --- a/packages/@aws-cdk/aws-events-targets/test/ecs/integ.event-fargate-task.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/ecs/integ.event-fargate-task.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-fargate/Vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-fargate/Vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-ecs-integ-fargate/Vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-fargate/Vpc/PrivateSubnet1" } ] } diff --git a/packages/@aws-cdk/aws-events/.eslintrc.js b/packages/@aws-cdk/aws-events/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-events/.eslintrc.js +++ b/packages/@aws-cdk/aws-events/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-events/lib/schedule.ts b/packages/@aws-cdk/aws-events/lib/schedule.ts index dc948d3a2b17f..719862f9ab009 100644 --- a/packages/@aws-cdk/aws-events/lib/schedule.ts +++ b/packages/@aws-cdk/aws-events/lib/schedule.ts @@ -59,7 +59,7 @@ export abstract class Schedule { /** * Options to configure a cron expression * - * All fields are strings so you can use complex expresions. Absence of + * All fields are strings so you can use complex expressions. Absence of * a field implies '*' or '?', whichever one is appropriate. * * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/ScheduledEvents.html#CronExpressions diff --git a/packages/@aws-cdk/aws-events/package.json b/packages/@aws-cdk/aws-events/package.json index 1316ef04bbb92..b8160a0a2d398 100644 --- a/packages/@aws-cdk/aws-events/package.json +++ b/packages/@aws-cdk/aws-events/package.json @@ -64,7 +64,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "nodeunit": "^0.11.3", @@ -82,7 +82,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-eventschemas/.eslintrc.js b/packages/@aws-cdk/aws-eventschemas/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-eventschemas/.eslintrc.js +++ b/packages/@aws-cdk/aws-eventschemas/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-eventschemas/.gitignore b/packages/@aws-cdk/aws-eventschemas/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-eventschemas/.gitignore +++ b/packages/@aws-cdk/aws-eventschemas/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-eventschemas/.npmignore b/packages/@aws-cdk/aws-eventschemas/.npmignore index d4f7bff69bdab..8ac959aca8fa5 100644 --- a/packages/@aws-cdk/aws-eventschemas/.npmignore +++ b/packages/@aws-cdk/aws-eventschemas/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json !.jsii .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-eventschemas/jest.config.js b/packages/@aws-cdk/aws-eventschemas/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-eventschemas/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-eventschemas/package.json b/packages/@aws-cdk/aws-eventschemas/package.json index e13dac8695926..0df440c7cdffb 100644 --- a/packages/@aws-cdk/aws-eventschemas/package.json +++ b/packages/@aws-cdk/aws-eventschemas/package.json @@ -48,7 +48,8 @@ "build+test+package": "npm run build+test && npm run package" }, "cdk-build": { - "cloudformation": "AWS::EventSchemas" + "cloudformation": "AWS::EventSchemas", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -95,7 +79,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-fms/.eslintrc.js b/packages/@aws-cdk/aws-fms/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-fms/.eslintrc.js +++ b/packages/@aws-cdk/aws-fms/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-fms/.gitignore b/packages/@aws-cdk/aws-fms/.gitignore index 6031555a5720f..d57af28d42320 100644 --- a/packages/@aws-cdk/aws-fms/.gitignore +++ b/packages/@aws-cdk/aws-fms/.gitignore @@ -15,3 +15,4 @@ coverage *.snk nyc.config.js !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-fms/.npmignore b/packages/@aws-cdk/aws-fms/.npmignore index e421b91419b9a..fb37683c5a457 100644 --- a/packages/@aws-cdk/aws-fms/.npmignore +++ b/packages/@aws-cdk/aws-fms/.npmignore @@ -20,3 +20,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-fms/jest.config.js b/packages/@aws-cdk/aws-fms/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-fms/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-fms/package.json b/packages/@aws-cdk/aws-fms/package.json index 4bb1851b9e365..cf8fbf92b10e4 100644 --- a/packages/@aws-cdk/aws-fms/package.json +++ b/packages/@aws-cdk/aws-fms/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::FMS" + "cloudformation": "AWS::FMS", + "jest": true }, "keywords": [ "aws", @@ -62,7 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": {}, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -79,7 +79,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-fsx/.eslintrc.js b/packages/@aws-cdk/aws-fsx/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-fsx/.eslintrc.js +++ b/packages/@aws-cdk/aws-fsx/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-fsx/.gitignore b/packages/@aws-cdk/aws-fsx/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-fsx/.gitignore +++ b/packages/@aws-cdk/aws-fsx/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-fsx/.npmignore b/packages/@aws-cdk/aws-fsx/.npmignore index dd7e4908d99e4..c0fc6f9e7667f 100644 --- a/packages/@aws-cdk/aws-fsx/.npmignore +++ b/packages/@aws-cdk/aws-fsx/.npmignore @@ -22,3 +22,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-fsx/jest.config.js b/packages/@aws-cdk/aws-fsx/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-fsx/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-fsx/package.json b/packages/@aws-cdk/aws-fsx/package.json index 6d9a655389238..9c7be9e74b414 100644 --- a/packages/@aws-cdk/aws-fsx/package.json +++ b/packages/@aws-cdk/aws-fsx/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::FSx" + "cloudformation": "AWS::FSx", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -102,7 +86,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ 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 24e0e5b9397e2..0164e2f1f0067 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 @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "AwsCdkFsxLustre/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "AwsCdkFsxLustre/VPC/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "AwsCdkFsxLustre/VPC/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "AwsCdkFsxLustre/VPC/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "AwsCdkFsxLustre/VPC/PublicSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "AwsCdkFsxLustre/VPC/PublicSubnet3" } ] } @@ -316,10 +316,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "AwsCdkFsxLustre/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -327,6 +323,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "AwsCdkFsxLustre/VPC/PrivateSubnet1" } ] } @@ -378,10 +378,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "AwsCdkFsxLustre/VPC/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -389,6 +385,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "AwsCdkFsxLustre/VPC/PrivateSubnet2" } ] } @@ -440,10 +440,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "AwsCdkFsxLustre/VPC/PrivateSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -451,6 +447,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "AwsCdkFsxLustre/VPC/PrivateSubnet3" } ] } diff --git a/packages/@aws-cdk/aws-gamelift/.eslintrc.js b/packages/@aws-cdk/aws-gamelift/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-gamelift/.eslintrc.js +++ b/packages/@aws-cdk/aws-gamelift/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-gamelift/.gitignore b/packages/@aws-cdk/aws-gamelift/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-gamelift/.gitignore +++ b/packages/@aws-cdk/aws-gamelift/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-gamelift/.npmignore b/packages/@aws-cdk/aws-gamelift/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-gamelift/.npmignore +++ b/packages/@aws-cdk/aws-gamelift/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-gamelift/jest.config.js b/packages/@aws-cdk/aws-gamelift/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-gamelift/package.json b/packages/@aws-cdk/aws-gamelift/package.json index 5a61bdfa31408..8151b203c8a9c 100644 --- a/packages/@aws-cdk/aws-gamelift/package.json +++ b/packages/@aws-cdk/aws-gamelift/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::GameLift" + "cloudformation": "AWS::GameLift", + "jest": true }, "keywords": [ "aws", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-glue/.eslintrc.js b/packages/@aws-cdk/aws-glue/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-glue/.eslintrc.js +++ b/packages/@aws-cdk/aws-glue/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-glue/README.md b/packages/@aws-cdk/aws-glue/README.md index f54cfe9970f8a..3f61ce18700b7 100644 --- a/packages/@aws-cdk/aws-glue/README.md +++ b/packages/@aws-cdk/aws-glue/README.md @@ -35,10 +35,10 @@ new glue.Table(stack, 'MyTable', { tableName: 'my_table', columns: [{ name: 'col1', - type: glue.Schema.string, + type: glue.Schema.STRING, }, { name: 'col2', - type: glue.Schema.array(Schema.string), + type: glue.Schema.array(Schema.STRING), comment: 'col2 is an array of strings' // comment is optional }] dataFormat: glue.DataFormat.JSON @@ -65,14 +65,14 @@ new glue.Table(stack, 'MyTable', { tableName: 'my_table', columns: [{ name: 'col1', - type: glue.Schema.string + type: glue.Schema.STRING }], partitionKeys: [{ name: 'year', - type: glue.Schema.smallint + type: glue.Schema.SMALL_INT }, { name: 'month', - type: glue.Schema.smallint + type: glue.Schema.SMALL_INT }], dataFormat: glue.DataFormat.JSON }); @@ -85,7 +85,7 @@ You can enable encryption on a Table's data: * [S3Managed](https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingServerSideEncryption.html) - Server side encryption (`SSE-S3`) with an Amazon S3-managed key. ```ts new glue.Table(stack, 'MyTable', { - encryption: glue.TableEncryption.S3Managed + encryption: glue.TableEncryption.S3_MANAGED ... }); ``` @@ -94,13 +94,13 @@ new glue.Table(stack, 'MyTable', { ```ts // KMS key is created automatically new glue.Table(stack, 'MyTable', { - encryption: glue.TableEncryption.Kms + encryption: glue.TableEncryption.KMS ... }); // with an explicit KMS key new glue.Table(stack, 'MyTable', { - encryption: glue.TableEncryption.Kms, + encryption: glue.TableEncryption.KMS, encryptionKey: new kms.Key(stack, 'MyKey') ... }); @@ -108,7 +108,7 @@ new glue.Table(stack, 'MyTable', { * [KmsManaged](https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingKMSEncryption.html) - Server-side encryption (`SSE-KMS`), like `Kms`, except with an AWS KMS Key managed by the AWS Key Management Service. ```ts new glue.Table(stack, 'MyTable', { - encryption: glue.TableEncryption.KmsManaged + encryption: glue.TableEncryption.KMS_MANAGED ... }); ``` @@ -116,19 +116,19 @@ new glue.Table(stack, 'MyTable', { ```ts // KMS key is created automatically new glue.Table(stack, 'MyTable', { - encryption: glue.TableEncryption.ClientSideKms + encryption: glue.TableEncryption.CLIENT_SIDE_KMS ... }); // with an explicit KMS key new glue.Table(stack, 'MyTable', { - encryption: glue.TableEncryption.ClientSideKms, + encryption: glue.TableEncryption.CLIENT_SIDE_KMS, encryptionKey: new kms.Key(stack, 'MyKey') ... }); ``` -*Note: you cannot provide a `Bucket` when creating the `Table` if you wish to use server-side encryption (`Kms`, `KmsManaged` or `S3Managed`)*. +*Note: you cannot provide a `Bucket` when creating the `Table` if you wish to use server-side encryption (`KMS`, `KMS_MANAGED` or `S3_MANAGED`)*. ### Types @@ -138,22 +138,22 @@ A table's schema is a collection of columns, each of which have a `name` and a ` new glue.Table(stack, 'MyTable', { columns: [{ name: 'primitive_column', - type: glue.Schema.string + type: glue.Schema.STRING }, { name: 'array_column', - type: glue.Schema.array(glue.Schema.integer), + type: glue.Schema.array(glue.Schema.INTEGER), comment: 'array' }, { name: 'map_column', type: glue.Schema.map( - glue.Schema.string, - glue.Schema.timestamp), + glue.Schema.STRING, + glue.Schema.TIMESTAMP), comment: 'map' }, { name: 'struct_column', type: glue.Schema.struct([{ name: 'nested_column', - type: glue.Schema.date, + type: glue.Schema.DATE, comment: 'nested comment' }]), comment: "struct" @@ -161,32 +161,45 @@ new glue.Table(stack, 'MyTable', { ... ``` -#### Primitive +#### Primitives -Numeric: -* `bigint` -* `float` -* `integer` -* `smallint` -* `tinyint` +##### Numeric +| Name | Type | Comments | +|----------- |---------- |------------------------------------------------------------------------------------------------------------------ | +| FLOAT | Constant | A 32-bit single-precision floating point number | +| INTEGER | Constant | A 32-bit signed value in two's complement format, with a minimum value of -2^31 and a maximum value of 2^31-1 | +| DOUBLE | Constant | A 64-bit double-precision floating point number | +| BIG_INT | Constant | A 64-bit signed INTEGER in two’s complement format, with a minimum value of -2^63 and a maximum value of 2^63 -1 | +| SMALL_INT | Constant | A 16-bit signed INTEGER in two’s complement format, with a minimum value of -2^15 and a maximum value of 2^15-1 | +| TINY_INT | Constant | A 8-bit signed INTEGER in two’s complement format, with a minimum value of -2^7 and a maximum value of 2^7-1 | -Date and Time: -* `date` -* `timestamp` +##### Date and time -String Types: +| Name | Type | Comments | +|----------- |---------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| DATE | Constant | A date in UNIX format, such as YYYY-MM-DD. | +| TIMESTAMP | Constant | Date and time instant in the UNiX format, such as yyyy-mm-dd hh:mm:ss[.f...]. For example, TIMESTAMP '2008-09-15 03:04:05.324'. This format uses the session time zone. | -* `string` -* `decimal` -* `char` -* `varchar` +##### String -Misc: -* `boolean` -* `binary` +| Name | Type | Comments | +|-------------------------------------------- |---------- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| STRING | Constant | A string literal enclosed in single or double quotes | +| decimal(precision: number, scale?: number) | Function | `precision` is the total number of digits. `scale` (optional) is the number of digits in fractional part with a default of 0. For example, use these type definitions: decimal(11,5), decimal(15) | +| char(length: number) | Function | Fixed length character data, with a specified length between 1 and 255, such as char(10) | +| varchar(length: number) | Function | Variable length character data, with a specified length between 1 and 65535, such as varchar(10) | + +##### Miscellaneous + +| Name | Type | Comments | +|--------- |---------- |------------------------------- | +| BOOLEAN | Constant | Values are `true` and `false` | +| BINARY | Constant | Value is in binary | #### Complex -* `array` - array of some other type -* `map` - map of some primitive key type to any value type. -* `struct` - nested structure containing individually named and typed columns. +| Name | Type | Comments | +|------------------------------------- |---------- |------------------------------------------------------------------- | +| array(itemType: Type) | Function | An array of some other type | +| map(keyType: Type, valueType: Type) | Function | A map of some primitive key type to any value type | +| struct(collumns: Column[]) | Function | Nested structure containing individually named and typed collumns | diff --git a/packages/@aws-cdk/aws-glue/package.json b/packages/@aws-cdk/aws-glue/package.json index 09778a0f5f773..d60997aff5011 100644 --- a/packages/@aws-cdk/aws-glue/package.json +++ b/packages/@aws-cdk/aws-glue/package.json @@ -63,7 +63,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -86,7 +86,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "experimental", diff --git a/packages/@aws-cdk/aws-greengrass/.eslintrc.js b/packages/@aws-cdk/aws-greengrass/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-greengrass/.eslintrc.js +++ b/packages/@aws-cdk/aws-greengrass/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-greengrass/.gitignore b/packages/@aws-cdk/aws-greengrass/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-greengrass/.gitignore +++ b/packages/@aws-cdk/aws-greengrass/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-greengrass/.npmignore b/packages/@aws-cdk/aws-greengrass/.npmignore index dd7e4908d99e4..c0fc6f9e7667f 100644 --- a/packages/@aws-cdk/aws-greengrass/.npmignore +++ b/packages/@aws-cdk/aws-greengrass/.npmignore @@ -22,3 +22,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-greengrass/jest.config.js b/packages/@aws-cdk/aws-greengrass/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-greengrass/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-greengrass/package.json b/packages/@aws-cdk/aws-greengrass/package.json index 938c951df65a8..8c56995fb2838 100644 --- a/packages/@aws-cdk/aws-greengrass/package.json +++ b/packages/@aws-cdk/aws-greengrass/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::Greengrass" + "cloudformation": "AWS::Greengrass", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -95,7 +79,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-guardduty/.eslintrc.js b/packages/@aws-cdk/aws-guardduty/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-guardduty/.eslintrc.js +++ b/packages/@aws-cdk/aws-guardduty/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-guardduty/.gitignore b/packages/@aws-cdk/aws-guardduty/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-guardduty/.gitignore +++ b/packages/@aws-cdk/aws-guardduty/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-guardduty/.npmignore b/packages/@aws-cdk/aws-guardduty/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-guardduty/.npmignore +++ b/packages/@aws-cdk/aws-guardduty/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-guardduty/jest.config.js b/packages/@aws-cdk/aws-guardduty/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-guardduty/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-guardduty/package.json b/packages/@aws-cdk/aws-guardduty/package.json index 5cceeb2711f6e..ecbd147877c71 100644 --- a/packages/@aws-cdk/aws-guardduty/package.json +++ b/packages/@aws-cdk/aws-guardduty/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::GuardDuty" + "cloudformation": "AWS::GuardDuty", + "jest": true }, "keywords": [ "aws", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-iam/.eslintrc.js b/packages/@aws-cdk/aws-iam/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-iam/.eslintrc.js +++ b/packages/@aws-cdk/aws-iam/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iam/.gitignore b/packages/@aws-cdk/aws-iam/.gitignore index bc6bf0b0605be..988ed792f9310 100644 --- a/packages/@aws-cdk/aws-iam/.gitignore +++ b/packages/@aws-cdk/aws-iam/.gitignore @@ -13,3 +13,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-iam/.npmignore b/packages/@aws-cdk/aws-iam/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-iam/.npmignore +++ b/packages/@aws-cdk/aws-iam/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-iam/jest.config.js b/packages/@aws-cdk/aws-iam/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-iam/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iam/lib/grant.ts b/packages/@aws-cdk/aws-iam/lib/grant.ts index d78fb25c545ef..0f882c4a73d00 100644 --- a/packages/@aws-cdk/aws-iam/lib/grant.ts +++ b/packages/@aws-cdk/aws-iam/lib/grant.ts @@ -100,7 +100,7 @@ export interface GrantOnPrincipalAndResourceOptions extends CommonGrantOptions { * This class is not instantiable by consumers on purpose, so that they will be * required to call the Grant factory functions. */ -export class Grant { +export class Grant implements cdk.IDependable { /** * Grant the given permissions to the principal * @@ -129,9 +129,13 @@ export class Grant { principals: [options.grantee!.grantPrincipal], }); - options.resource.addToResourcePolicy(statement); + const resourceResult = options.resource.addToResourcePolicy(statement); - return new Grant({ resourceStatement: statement, options }); + return new Grant({ + resourceStatement: statement, + options, + policyDependable: resourceResult.statementAdded ? resourceResult.policyDependable ?? options.resource : undefined, + }); } /** @@ -146,9 +150,16 @@ export class Grant { resources: options.resourceArns, }); - const addedToPrincipal = options.grantee.grantPrincipal.addToPolicy(statement); + const addedToPrincipal = options.grantee.grantPrincipal.addToPrincipalPolicy(statement); + if (!addedToPrincipal.statementAdded) { + return new Grant({ principalStatement: undefined, options }); + } + + if (!addedToPrincipal.policyDependable) { + throw new Error('Contract violation: when Principal returns statementAdded=true, it should return a dependable'); + } - return new Grant({ principalStatement: addedToPrincipal ? statement : undefined, options }); + return new Grant({ principalStatement: statement, options, policyDependable: addedToPrincipal.policyDependable }); } /** @@ -172,9 +183,15 @@ export class Grant { principals: [options.resourcePolicyPrincipal || options.grantee!.grantPrincipal], }); - options.resource.addToResourcePolicy(statement); + const resourceResult = options.resource.addToResourcePolicy(statement); + const resourceDependable = resourceResult.statementAdded ? resourceResult.policyDependable ?? options.resource : undefined; - return new Grant({ principalStatement: statement, resourceStatement: result.resourceStatement, options }); + return new Grant({ + principalStatement: statement, + resourceStatement: result.resourceStatement, + options, + policyDependable: resourceDependable ? new CompositeDependable(result, resourceDependable) : result, + }); } /** @@ -218,6 +235,12 @@ export class Grant { this.options = props.options; this.principalStatement = props.principalStatement; this.resourceStatement = props.resourceStatement; + + cdk.DependableTrait.implement(this, { + get dependencyRoots() { + return props.policyDependable ? cdk.DependableTrait.get(props.policyDependable).dependencyRoots : []; + }, + }); } /** @@ -236,6 +259,17 @@ export class Grant { throw new Error(`${describeGrant(this.options)} could not be added on either identity or resource policy.`); } } + + /** + * Make sure this grant is applied before the given constructs are deployed + * + * The same as construct.node.addDependency(grant), but slightly nicer to read. + */ + public applyBefore(...constructs: cdk.IConstruct[]) { + for (const construct of constructs) { + construct.node.addDependency(this); + } + } } function describeGrant(options: CommonGrantOptions) { @@ -246,6 +280,13 @@ interface GrantProps { readonly options: CommonGrantOptions; readonly principalStatement?: PolicyStatement; readonly resourceStatement?: PolicyStatement; + + /** + * Constructs whose deployment applies the grant + * + * Used to add dependencies on grants + */ + readonly policyDependable?: cdk.IDependable; } /** @@ -255,5 +296,40 @@ export interface IResourceWithPolicy extends cdk.IConstruct { /** * Add a statement to the resource's resource policy */ - addToResourcePolicy(statement: PolicyStatement): void; + addToResourcePolicy(statement: PolicyStatement): AddToResourcePolicyResult; } + +/** + * Result of calling addToResourcePolicy + */ +export interface AddToResourcePolicyResult { + /** + * Whether the statement was added + */ + readonly statementAdded: boolean; + + /** + * Dependable which allows depending on the policy change being applied + * + * @default - If `statementAdded` is true, the resource object itself. + * Otherwise, no dependable. + */ + readonly policyDependable?: cdk.IDependable; +} + +/** + * Composite dependable + * + * Not as simple as eagerly getting the dependency roots from the + * inner dependables, as they may be mutable so we need to defer + * the query. + */ +export class CompositeDependable implements cdk.IDependable { + constructor(...dependables: cdk.IDependable[]) { + cdk.DependableTrait.implement(this, { + get dependencyRoots(): cdk.IConstruct[] { + return Array.prototype.concat.apply([], dependables.map(d => cdk.DependableTrait.get(d).dependencyRoots)); + }, + }); + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iam/lib/group.ts b/packages/@aws-cdk/aws-iam/lib/group.ts index bdffbc1745c3f..08ef30cba9203 100644 --- a/packages/@aws-cdk/aws-iam/lib/group.ts +++ b/packages/@aws-cdk/aws-iam/lib/group.ts @@ -4,7 +4,7 @@ import { IIdentity } from './identity-base'; import { IManagedPolicy } from './managed-policy'; import { Policy } from './policy'; import { PolicyStatement } from './policy-statement'; -import { ArnPrincipal, IPrincipal, PrincipalPolicyFragment } from './principals'; +import { AddToPrincipalPolicyResult, ArnPrincipal, IPrincipal, PrincipalPolicyFragment } from './principals'; import { IUser } from './user'; import { AttachedPolicies } from './util'; @@ -104,14 +104,18 @@ abstract class GroupBase extends Resource implements IGroup { /** * Adds an IAM statement to the default policy. */ - public addToPolicy(statement: PolicyStatement): boolean { + public addToPrincipalPolicy(statement: PolicyStatement): AddToPrincipalPolicyResult { if (!this.defaultPolicy) { this.defaultPolicy = new Policy(this, 'DefaultPolicy'); this.defaultPolicy.attachToGroup(this); } this.defaultPolicy.addStatements(statement); - return true; + return { statementAdded: true, policyDependable: this.defaultPolicy }; + } + + public addToPolicy(statement: PolicyStatement): boolean { + return this.addToPrincipalPolicy(statement).statementAdded; } } diff --git a/packages/@aws-cdk/aws-iam/lib/lazy-role.ts b/packages/@aws-cdk/aws-iam/lib/lazy-role.ts index 616b1b92c58ba..bfc83817ad0f8 100644 --- a/packages/@aws-cdk/aws-iam/lib/lazy-role.ts +++ b/packages/@aws-cdk/aws-iam/lib/lazy-role.ts @@ -3,7 +3,7 @@ import { Grant } from './grant'; import { IManagedPolicy } from './managed-policy'; import { Policy } from './policy'; import { PolicyStatement } from './policy-statement'; -import { IPrincipal, PrincipalPolicyFragment } from './principals'; +import { AddToPrincipalPolicyResult, IPrincipal, PrincipalPolicyFragment } from './principals'; import { IRole, Role, RoleProps } from './role'; /** @@ -43,15 +43,19 @@ export class LazyRole extends cdk.Resource implements IRole { * If there is no default policy attached to this role, it will be created. * @param statement The permission statement to add to the policy document */ - public addToPolicy(statement: PolicyStatement): boolean { + public addToPrincipalPolicy(statement: PolicyStatement): AddToPrincipalPolicyResult { if (this.role) { - return this.role.addToPolicy(statement); + return this.role.addToPrincipalPolicy(statement); } else { this.statements.push(statement); - return true; + return { statementAdded: true, policyDependable: this }; } } + public addToPolicy(statement: PolicyStatement): boolean { + return this.addToPrincipalPolicy(statement).statementAdded; + } + /** * Attaches a policy to this role. * @param policy The policy to attach diff --git a/packages/@aws-cdk/aws-iam/lib/principals.ts b/packages/@aws-cdk/aws-iam/lib/principals.ts index a762b4c89c718..fcf8db593bd35 100644 --- a/packages/@aws-cdk/aws-iam/lib/principals.ts +++ b/packages/@aws-cdk/aws-iam/lib/principals.ts @@ -46,8 +46,35 @@ export interface IPrincipal extends IGrantable { * * @returns true if the statement was added, false if the principal in * question does not have a policy document to add the statement to. + * + * @deprecated Use `addToPrincipalPolicy` instead. */ addToPolicy(statement: PolicyStatement): boolean; + + /** + * Add to the policy of this principal. + */ + addToPrincipalPolicy(statement: PolicyStatement): AddToPrincipalPolicyResult; +} + +/** + * Result of calling `addToPrincipalPolicy` + */ +export interface AddToPrincipalPolicyResult { + /** + * Whether the statement was added to the identity's policies. + * + * @experimental + */ + readonly statementAdded: boolean; + + /** + * Dependable which allows depending on the policy change being applied + * + * @default - Required if `statementAdded` is true. + * @experimental + */ + readonly policyDependable?: cdk.IDependable; } /** @@ -66,10 +93,14 @@ export abstract class PrincipalBase implements IPrincipal { */ public readonly assumeRoleAction: string = 'sts:AssumeRole'; - public addToPolicy(_statement: PolicyStatement): boolean { + public addToPolicy(statement: PolicyStatement): boolean { + return this.addToPrincipalPolicy(statement).statementAdded; + } + + public addToPrincipalPolicy(_statement: PolicyStatement): AddToPrincipalPolicyResult { // This base class is used for non-identity principals. None of them // have a PolicyDocument to add to. - return false; + return { statementAdded: false }; } public toString() { @@ -153,7 +184,11 @@ export class PrincipalWithConditions implements IPrincipal { } public addToPolicy(statement: PolicyStatement): boolean { - return this.principal.addToPolicy(statement); + return this.addToPrincipalPolicy(statement).statementAdded; + } + + public addToPrincipalPolicy(statement: PolicyStatement): AddToPrincipalPolicyResult { + return this.principal.addToPrincipalPolicy(statement); } public toString() { diff --git a/packages/@aws-cdk/aws-iam/lib/private/immutable-role.ts b/packages/@aws-cdk/aws-iam/lib/private/immutable-role.ts index d1909ae2611fd..92aed748514d5 100644 --- a/packages/@aws-cdk/aws-iam/lib/private/immutable-role.ts +++ b/packages/@aws-cdk/aws-iam/lib/private/immutable-role.ts @@ -1,9 +1,9 @@ -import { Construct, DependableTrait } from '@aws-cdk/core'; +import { ConcreteDependable, Construct, DependableTrait } from '@aws-cdk/core'; import { Grant } from '../grant'; import { IManagedPolicy } from '../managed-policy'; import { Policy } from '../policy'; import { PolicyStatement } from '../policy-statement'; -import { IPrincipal } from '../principals'; +import { AddToPrincipalPolicyResult, IPrincipal } from '../principals'; import { IRole } from '../role'; /** @@ -44,9 +44,13 @@ export class ImmutableRole extends Construct implements IRole { // do nothing } - public addToPolicy(_statement: PolicyStatement): boolean { + public addToPolicy(statement: PolicyStatement): boolean { + return this.addToPrincipalPolicy(statement).statementAdded; + } + + public addToPrincipalPolicy(_statement: PolicyStatement): AddToPrincipalPolicyResult { // Not really added, but for the purposes of consumer code pretend that it was. - return true; + return { statementAdded: true, policyDependable: new ConcreteDependable() }; } public grant(grantee: IPrincipal, ...actions: string[]): Grant { diff --git a/packages/@aws-cdk/aws-iam/lib/role.ts b/packages/@aws-cdk/aws-iam/lib/role.ts index 84ca5939eca41..e62dcd45af0be 100644 --- a/packages/@aws-cdk/aws-iam/lib/role.ts +++ b/packages/@aws-cdk/aws-iam/lib/role.ts @@ -6,7 +6,7 @@ import { IManagedPolicy } from './managed-policy'; import { Policy } from './policy'; import { PolicyDocument } from './policy-document'; import { PolicyStatement } from './policy-statement'; -import { ArnPrincipal, IPrincipal, PrincipalPolicyFragment } from './principals'; +import { AddToPrincipalPolicyResult, ArnPrincipal, IPrincipal, PrincipalPolicyFragment } from './principals'; import { ImmutableRole } from './private/immutable-role'; import { AttachedPolicies } from './util'; @@ -192,12 +192,16 @@ export class Role extends Resource implements IRole { private defaultPolicy?: Policy; public addToPolicy(statement: PolicyStatement): boolean { + return this.addToPrincipalPolicy(statement).statementAdded; + } + + public addToPrincipalPolicy(statement: PolicyStatement): AddToPrincipalPolicyResult { if (!this.defaultPolicy) { this.defaultPolicy = new Policy(this, 'Policy'); this.attachInlinePolicy(this.defaultPolicy); } this.defaultPolicy.addStatements(statement); - return true; + return { statementAdded: true, policyDependable: this.defaultPolicy }; } public attachInlinePolicy(policy: Policy): void { @@ -351,13 +355,17 @@ export class Role extends Resource implements IRole { * If there is no default policy attached to this role, it will be created. * @param statement The permission statement to add to the policy document */ - public addToPolicy(statement: PolicyStatement): boolean { + public addToPrincipalPolicy(statement: PolicyStatement): AddToPrincipalPolicyResult { if (!this.defaultPolicy) { this.defaultPolicy = new Policy(this, 'DefaultPolicy'); this.attachInlinePolicy(this.defaultPolicy); } this.defaultPolicy.addStatements(statement); - return true; + return { statementAdded: true, policyDependable: this.defaultPolicy }; + } + + public addToPolicy(statement: PolicyStatement): boolean { + return this.addToPrincipalPolicy(statement).statementAdded; } /** diff --git a/packages/@aws-cdk/aws-iam/lib/unknown-principal.ts b/packages/@aws-cdk/aws-iam/lib/unknown-principal.ts index 181d2780bc513..da30dbf08227e 100644 --- a/packages/@aws-cdk/aws-iam/lib/unknown-principal.ts +++ b/packages/@aws-cdk/aws-iam/lib/unknown-principal.ts @@ -1,6 +1,6 @@ -import { IConstruct, Stack } from '@aws-cdk/core'; +import { ConcreteDependable, IConstruct, Stack } from '@aws-cdk/core'; import { PolicyStatement } from './policy-statement'; -import { IPrincipal, PrincipalPolicyFragment } from './principals'; +import { AddToPrincipalPolicyResult, IPrincipal, PrincipalPolicyFragment } from './principals'; /** * Properties for an UnknownPrincipal @@ -37,10 +37,15 @@ export class UnknownPrincipal implements IPrincipal { throw new Error(`Cannot get policy fragment of ${this.resource.node.path}, resource imported without a role`); } - public addToPolicy(statement: PolicyStatement): boolean { + public addToPrincipalPolicy(statement: PolicyStatement): AddToPrincipalPolicyResult { const stack = Stack.of(this.resource); const repr = JSON.stringify(stack.resolve(statement)); this.resource.node.addWarning(`Add statement to this resource's role: ${repr}`); - return true; // Pretend we did the work. The human will do it for us, eventually. + // Pretend we did the work. The human will do it for us, eventually. + return { statementAdded: true, policyDependable: new ConcreteDependable() }; + } + + public addToPolicy(statement: PolicyStatement): boolean { + return this.addToPrincipalPolicy(statement).statementAdded; } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iam/lib/user.ts b/packages/@aws-cdk/aws-iam/lib/user.ts index 8dc847788db05..886937fcf3cb8 100644 --- a/packages/@aws-cdk/aws-iam/lib/user.ts +++ b/packages/@aws-cdk/aws-iam/lib/user.ts @@ -5,7 +5,7 @@ import { IIdentity } from './identity-base'; import { IManagedPolicy } from './managed-policy'; import { Policy } from './policy'; import { PolicyStatement } from './policy-statement'; -import { ArnPrincipal, IPrincipal, PrincipalPolicyFragment } from './principals'; +import { AddToPrincipalPolicyResult, ArnPrincipal, IPrincipal, PrincipalPolicyFragment } from './principals'; import { AttachedPolicies, undefinedIfEmpty } from './util'; /** @@ -146,12 +146,16 @@ export class User extends Resource implements IIdentity, IUser { private defaultPolicy?: Policy; public addToPolicy(statement: PolicyStatement): boolean { + return this.addToPrincipalPolicy(statement).statementAdded; + } + + public addToPrincipalPolicy(statement: PolicyStatement): AddToPrincipalPolicyResult { if (!this.defaultPolicy) { this.defaultPolicy = new Policy(this, 'Policy'); this.defaultPolicy.attachToUser(this); } this.defaultPolicy.addStatements(statement); - return true; + return { statementAdded: true, policyDependable: this.defaultPolicy }; } public addToGroup(_group: IGroup): void { @@ -258,14 +262,18 @@ export class User extends Resource implements IIdentity, IUser { * * @returns true */ - public addToPolicy(statement: PolicyStatement): boolean { + public addToPrincipalPolicy(statement: PolicyStatement): AddToPrincipalPolicyResult { if (!this.defaultPolicy) { this.defaultPolicy = new Policy(this, 'DefaultPolicy'); this.defaultPolicy.attachToUser(this); } this.defaultPolicy.addStatements(statement); - return true; + return { statementAdded: true, policyDependable: this.defaultPolicy }; + } + + public addToPolicy(statement: PolicyStatement): boolean { + return this.addToPrincipalPolicy(statement).statementAdded; } private parseLoginProfile(props: UserProps): CfnUser.LoginProfileProperty | undefined { diff --git a/packages/@aws-cdk/aws-iam/package.json b/packages/@aws-cdk/aws-iam/package.json index e81c7b6b22b0f..a0dcc893ca6da 100644 --- a/packages/@aws-cdk/aws-iam/package.json +++ b/packages/@aws-cdk/aws-iam/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::IAM" + "cloudformation": "AWS::IAM", + "jest": true }, "keywords": [ "aws", @@ -80,26 +81,9 @@ "@aws-cdk/region-info": "0.0.0", "constructs": "^3.0.2" }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 70, - "statements": 70 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "homepage": "https://github.com/aws/aws-cdk", "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-iam/test/grant.test.ts b/packages/@aws-cdk/aws-iam/test/grant.test.ts index 8e2d4d3c3f814..93143f07c8125 100644 --- a/packages/@aws-cdk/aws-iam/test/grant.test.ts +++ b/packages/@aws-cdk/aws-iam/test/grant.test.ts @@ -1,10 +1,19 @@ +import { ResourcePart } from '@aws-cdk/assert'; import '@aws-cdk/assert/jest'; -import { Stack } from '@aws-cdk/core'; +import { CfnResource, Construct, Stack } from '@aws-cdk/core'; import * as iam from '../lib'; +let stack: Stack; +let resource: CfnResource; +beforeEach(() => { + stack = new Stack(); + resource = new CfnResource(stack, 'SomeResource', { + type: 'CDK::Test::SomeResource', + }); +}); + describe('IAM grant', () => { test('Grant.drop() returns a no-op grant', () => { - const stack = new Stack(); const user = new iam.User(stack, 'poo'); const grant = iam.Grant.drop(user, 'dropping me'); @@ -13,3 +22,110 @@ describe('IAM grant', () => { expect(grant.resourceStatement).toBeUndefined(); }); }); + +describe('Grant dependencies', () => { + test('can depend on grant added to role', () => { + // GIVEN + const role = new iam.Role(stack, 'Role', { + assumedBy: new iam.ServicePrincipal('bla.amazonaws.com'), + }); + + // WHEN + applyGrantWithDependencyTo(role); + + // THEN + expectDependencyOn('RoleDefaultPolicy5FFB7DAB'); + }); + + test('can depend on grant added to role wrapped with conditions', () => { + // GIVEN + const role = new iam.Role(stack, 'Role', { + assumedBy: new iam.ServicePrincipal('bla.amazonaws.com'), + }); + + // WHEN + applyGrantWithDependencyTo(new iam.PrincipalWithConditions(role, { + StringEquals: { 'aws:something': 'happy' }, + })); + + // THEN + expectDependencyOn('RoleDefaultPolicy5FFB7DAB'); + }); + + test('can depend on grant added to lazy role', () => { + // GIVEN + const role = new iam.LazyRole(stack, 'Role', { + assumedBy: new iam.ServicePrincipal('bla.amazonaws.com'), + }); + + // WHEN + applyGrantWithDependencyTo(role); + Array.isArray(role.roleArn); // Force instantiation + + // THEN + expectDependencyOn('RoleDefaultPolicy5FFB7DAB'); + }); + + test('can depend on grant added to resource', () => { + // WHEN + iam.Grant.addToPrincipalOrResource({ + actions: ['service:DoAThing'], + grantee: new iam.ServicePrincipal('bla.amazonaws.com'), + resourceArns: ['*'], + resource: new FakeResourceWithPolicy(stack, 'Buckaroo'), + }).applyBefore(resource); + + // THEN + expectDependencyOn('BuckarooPolicy74174DA4'); + }); + + test('can depend on grant added to principal AND resource', () => { + // GIVEN + const role = new iam.Role(stack, 'Role', { + assumedBy: new iam.ServicePrincipal('bla.amazonaws.com'), + }); + + // WHEN + iam.Grant.addToPrincipalAndResource({ + actions: ['service:DoAThing'], + grantee: role, + resourceArns: ['*'], + resource: new FakeResourceWithPolicy(stack, 'Buckaroo'), + }).applyBefore(resource); + + // THEN + expectDependencyOn('RoleDefaultPolicy5FFB7DAB'); + expectDependencyOn('BuckarooPolicy74174DA4'); + }); +}); + +function applyGrantWithDependencyTo(principal: iam.IPrincipal) { + iam.Grant.addToPrincipal({ + actions: ['service:DoAThing'], + grantee: principal, + resourceArns: ['*'], + }).applyBefore(resource); +} + +function expectDependencyOn(id: string) { + expect(stack).toHaveResource('CDK::Test::SomeResource', (props: any) => { + return (props?.DependsOn ?? []).includes(id); + }, ResourcePart.CompleteDefinition); +} + +class FakeResourceWithPolicy extends CfnResource implements iam.IResourceWithPolicy { + private policy: CfnResource; + + constructor(scope: Construct, id: string) { + super(scope, id, { + type: 'CDK::Test::Buckaroo', + }); + this.policy = new CfnResource(this, 'Policy', { + type: 'CDK::Test::BuckarooPolicy', + }); + } + + public addToResourcePolicy(_statement: iam.PolicyStatement): iam.AddToResourcePolicyResult { + return { statementAdded: true, policyDependable: this.policy }; + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iam/test/policy-document.test.ts b/packages/@aws-cdk/aws-iam/test/policy-document.test.ts index 6698dc9e34b74..2ea6c9848be0b 100644 --- a/packages/@aws-cdk/aws-iam/test/policy-document.test.ts +++ b/packages/@aws-cdk/aws-iam/test/policy-document.test.ts @@ -342,6 +342,7 @@ describe('IAM policy document', () => { assumeRoleAction: 'sts:AssumeRole', policyFragment: new PrincipalPolicyFragment({ AWS: ['foo', 'bar'] }), addToPolicy() { return false; }, + addToPrincipalPolicy() { return { statementAdded: false }; }, }; const s = new PolicyStatement(); s.addAccountRootPrincipal(); diff --git a/packages/@aws-cdk/aws-inspector/.eslintrc.js b/packages/@aws-cdk/aws-inspector/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-inspector/.eslintrc.js +++ b/packages/@aws-cdk/aws-inspector/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-inspector/.gitignore b/packages/@aws-cdk/aws-inspector/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-inspector/.gitignore +++ b/packages/@aws-cdk/aws-inspector/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-inspector/.npmignore b/packages/@aws-cdk/aws-inspector/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-inspector/.npmignore +++ b/packages/@aws-cdk/aws-inspector/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-inspector/jest.config.js b/packages/@aws-cdk/aws-inspector/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-inspector/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-inspector/package.json b/packages/@aws-cdk/aws-inspector/package.json index 2510cf843ca04..8932c2609ee1a 100644 --- a/packages/@aws-cdk/aws-inspector/package.json +++ b/packages/@aws-cdk/aws-inspector/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::Inspector" + "cloudformation": "AWS::Inspector", + "jest": true }, "keywords": [ "aws", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-iot/.eslintrc.js b/packages/@aws-cdk/aws-iot/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-iot/.eslintrc.js +++ b/packages/@aws-cdk/aws-iot/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iot/.gitignore b/packages/@aws-cdk/aws-iot/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-iot/.gitignore +++ b/packages/@aws-cdk/aws-iot/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-iot/.npmignore b/packages/@aws-cdk/aws-iot/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-iot/.npmignore +++ b/packages/@aws-cdk/aws-iot/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-iot/jest.config.js b/packages/@aws-cdk/aws-iot/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-iot/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iot/package.json b/packages/@aws-cdk/aws-iot/package.json index 6fecdcc054496..129bc07cc9612 100644 --- a/packages/@aws-cdk/aws-iot/package.json +++ b/packages/@aws-cdk/aws-iot/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::IoT" + "cloudformation": "AWS::IoT", + "jest": true }, "keywords": [ "aws", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-iot1click/.eslintrc.js b/packages/@aws-cdk/aws-iot1click/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-iot1click/.eslintrc.js +++ b/packages/@aws-cdk/aws-iot1click/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iot1click/.gitignore b/packages/@aws-cdk/aws-iot1click/.gitignore index 6ffc26f126c4a..adcba106db8d1 100644 --- a/packages/@aws-cdk/aws-iot1click/.gitignore +++ b/packages/@aws-cdk/aws-iot1click/.gitignore @@ -13,3 +13,4 @@ tsconfig.json *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-iot1click/.npmignore b/packages/@aws-cdk/aws-iot1click/.npmignore index 764850e022c5a..8afbe60698fb4 100644 --- a/packages/@aws-cdk/aws-iot1click/.npmignore +++ b/packages/@aws-cdk/aws-iot1click/.npmignore @@ -23,3 +23,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-iot1click/jest.config.js b/packages/@aws-cdk/aws-iot1click/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-iot1click/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iot1click/package.json b/packages/@aws-cdk/aws-iot1click/package.json index 65048626a334b..9ffd414d1ce54 100644 --- a/packages/@aws-cdk/aws-iot1click/package.json +++ b/packages/@aws-cdk/aws-iot1click/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::IoT1Click" + "cloudformation": "AWS::IoT1Click", + "jest": true }, "keywords": [ "aws", @@ -61,23 +62,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-iotanalytics/.eslintrc.js b/packages/@aws-cdk/aws-iotanalytics/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-iotanalytics/.eslintrc.js +++ b/packages/@aws-cdk/aws-iotanalytics/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotanalytics/.gitignore b/packages/@aws-cdk/aws-iotanalytics/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-iotanalytics/.gitignore +++ b/packages/@aws-cdk/aws-iotanalytics/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-iotanalytics/.npmignore b/packages/@aws-cdk/aws-iotanalytics/.npmignore index dd7e4908d99e4..c0fc6f9e7667f 100644 --- a/packages/@aws-cdk/aws-iotanalytics/.npmignore +++ b/packages/@aws-cdk/aws-iotanalytics/.npmignore @@ -22,3 +22,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-iotanalytics/jest.config.js b/packages/@aws-cdk/aws-iotanalytics/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-iotanalytics/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotanalytics/package.json b/packages/@aws-cdk/aws-iotanalytics/package.json index 0608eec53accf..cb3f04b6d7327 100644 --- a/packages/@aws-cdk/aws-iotanalytics/package.json +++ b/packages/@aws-cdk/aws-iotanalytics/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::IoTAnalytics" + "cloudformation": "AWS::IoTAnalytics", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -95,7 +79,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-iotevents/.eslintrc.js b/packages/@aws-cdk/aws-iotevents/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-iotevents/.eslintrc.js +++ b/packages/@aws-cdk/aws-iotevents/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotevents/.gitignore b/packages/@aws-cdk/aws-iotevents/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-iotevents/.gitignore +++ b/packages/@aws-cdk/aws-iotevents/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-iotevents/.npmignore b/packages/@aws-cdk/aws-iotevents/.npmignore index 6b86843be50f7..d04d75fba5945 100644 --- a/packages/@aws-cdk/aws-iotevents/.npmignore +++ b/packages/@aws-cdk/aws-iotevents/.npmignore @@ -22,3 +22,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-iotevents/jest.config.js b/packages/@aws-cdk/aws-iotevents/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotevents/package.json b/packages/@aws-cdk/aws-iotevents/package.json index 4dc2fda427c23..3fcd793108886 100644 --- a/packages/@aws-cdk/aws-iotevents/package.json +++ b/packages/@aws-cdk/aws-iotevents/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::IoTEvents" + "cloudformation": "AWS::IoTEvents", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -95,7 +79,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-iotthingsgraph/.eslintrc.js b/packages/@aws-cdk/aws-iotthingsgraph/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-iotthingsgraph/.eslintrc.js +++ b/packages/@aws-cdk/aws-iotthingsgraph/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotthingsgraph/.gitignore b/packages/@aws-cdk/aws-iotthingsgraph/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-iotthingsgraph/.gitignore +++ b/packages/@aws-cdk/aws-iotthingsgraph/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-iotthingsgraph/.npmignore b/packages/@aws-cdk/aws-iotthingsgraph/.npmignore index 5f6bdce6a4315..2b093ce17a11b 100644 --- a/packages/@aws-cdk/aws-iotthingsgraph/.npmignore +++ b/packages/@aws-cdk/aws-iotthingsgraph/.npmignore @@ -23,3 +23,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-iotthingsgraph/jest.config.js b/packages/@aws-cdk/aws-iotthingsgraph/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-iotthingsgraph/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotthingsgraph/package.json b/packages/@aws-cdk/aws-iotthingsgraph/package.json index e1289ac64ac85..57342d591fd11 100644 --- a/packages/@aws-cdk/aws-iotthingsgraph/package.json +++ b/packages/@aws-cdk/aws-iotthingsgraph/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::IoTThingsGraph" + "cloudformation": "AWS::IoTThingsGraph", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -95,7 +79,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-kinesis/.eslintrc.js b/packages/@aws-cdk/aws-kinesis/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-kinesis/.eslintrc.js +++ b/packages/@aws-cdk/aws-kinesis/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kinesis/.gitignore b/packages/@aws-cdk/aws-kinesis/.gitignore index 7fce433df3f45..20017a2b4c57d 100644 --- a/packages/@aws-cdk/aws-kinesis/.gitignore +++ b/packages/@aws-cdk/aws-kinesis/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-kinesis/.npmignore b/packages/@aws-cdk/aws-kinesis/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-kinesis/.npmignore +++ b/packages/@aws-cdk/aws-kinesis/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-kinesis/jest.config.js b/packages/@aws-cdk/aws-kinesis/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-kinesis/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kinesis/package.json b/packages/@aws-cdk/aws-kinesis/package.json index cb6e92a0aaf90..2e8866d2170d5 100644 --- a/packages/@aws-cdk/aws-kinesis/package.json +++ b/packages/@aws-cdk/aws-kinesis/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::Kinesis" + "cloudformation": "AWS::Kinesis", + "jest": true }, "keywords": [ "aws", @@ -60,7 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": {}, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -85,7 +85,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "stable", "maturity": "stable", diff --git a/packages/@aws-cdk/aws-kinesisanalytics/.eslintrc.js b/packages/@aws-cdk/aws-kinesisanalytics/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics/.eslintrc.js +++ b/packages/@aws-cdk/aws-kinesisanalytics/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kinesisanalytics/.gitignore b/packages/@aws-cdk/aws-kinesisanalytics/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics/.gitignore +++ b/packages/@aws-cdk/aws-kinesisanalytics/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-kinesisanalytics/.npmignore b/packages/@aws-cdk/aws-kinesisanalytics/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics/.npmignore +++ b/packages/@aws-cdk/aws-kinesisanalytics/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-kinesisanalytics/jest.config.js b/packages/@aws-cdk/aws-kinesisanalytics/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-kinesisanalytics/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kinesisanalytics/package.json b/packages/@aws-cdk/aws-kinesisanalytics/package.json index f5a505220ed13..65237840ff87d 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics/package.json +++ b/packages/@aws-cdk/aws-kinesisanalytics/package.json @@ -50,7 +50,8 @@ "cloudformation": [ "AWS::KinesisAnalytics", "AWS::KinesisAnalyticsV2" - ] + ], + "jest": true }, "keywords": [ "aws", @@ -63,23 +64,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -97,7 +81,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-kinesisfirehose/.eslintrc.js b/packages/@aws-cdk/aws-kinesisfirehose/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose/.eslintrc.js +++ b/packages/@aws-cdk/aws-kinesisfirehose/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kinesisfirehose/.gitignore b/packages/@aws-cdk/aws-kinesisfirehose/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose/.gitignore +++ b/packages/@aws-cdk/aws-kinesisfirehose/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-kinesisfirehose/.npmignore b/packages/@aws-cdk/aws-kinesisfirehose/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose/.npmignore +++ b/packages/@aws-cdk/aws-kinesisfirehose/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-kinesisfirehose/jest.config.js b/packages/@aws-cdk/aws-kinesisfirehose/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-kinesisfirehose/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kinesisfirehose/package.json b/packages/@aws-cdk/aws-kinesisfirehose/package.json index 084d1f7736c97..e468ddac10d1d 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose/package.json +++ b/packages/@aws-cdk/aws-kinesisfirehose/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::KinesisFirehose" + "cloudformation": "AWS::KinesisFirehose", + "jest": true }, "keywords": [ "aws", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-kms/.eslintrc.js b/packages/@aws-cdk/aws-kms/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-kms/.eslintrc.js +++ b/packages/@aws-cdk/aws-kms/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kms/lib/alias.ts b/packages/@aws-cdk/aws-kms/lib/alias.ts index 158548856d0df..df210f40afcc1 100644 --- a/packages/@aws-cdk/aws-kms/lib/alias.ts +++ b/packages/@aws-cdk/aws-kms/lib/alias.ts @@ -73,8 +73,8 @@ abstract class AliasBase extends Resource implements IAlias { return this.aliasTargetKey.addAlias(alias); } - public addToResourcePolicy(statement: iam.PolicyStatement, allowNoOp?: boolean): void { - this.aliasTargetKey.addToResourcePolicy(statement, allowNoOp); + public addToResourcePolicy(statement: iam.PolicyStatement, allowNoOp?: boolean): iam.AddToResourcePolicyResult { + return this.aliasTargetKey.addToResourcePolicy(statement, allowNoOp); } public grant(grantee: iam.IGrantable, ...actions: string[]): iam.Grant { diff --git a/packages/@aws-cdk/aws-kms/lib/key.ts b/packages/@aws-cdk/aws-kms/lib/key.ts index 381e63e7abc5b..2edcbafa45e84 100644 --- a/packages/@aws-cdk/aws-kms/lib/key.ts +++ b/packages/@aws-cdk/aws-kms/lib/key.ts @@ -34,7 +34,7 @@ export interface IKey extends IResource { * defined (i.e. external key), the operation will fail. Otherwise, it will * no-op. */ - addToResourcePolicy(statement: iam.PolicyStatement, allowNoOp?: boolean): void; + addToResourcePolicy(statement: iam.PolicyStatement, allowNoOp?: boolean): iam.AddToResourcePolicyResult; /** * Grant the indicated permissions on this key to the given principal @@ -107,15 +107,16 @@ abstract class KeyBase extends Resource implements IKey { * defined (i.e. external key), the operation will fail. Otherwise, it will * no-op. */ - public addToResourcePolicy(statement: iam.PolicyStatement, allowNoOp = true) { + public addToResourcePolicy(statement: iam.PolicyStatement, allowNoOp = true): iam.AddToResourcePolicyResult { const stack = Stack.of(this); if (!this.policy) { - if (allowNoOp) { return; } + if (allowNoOp) { return { statementAdded: false }; } throw new Error(`Unable to add statement to IAM resource policy for KMS key: ${JSON.stringify(stack.resolve(this.keyArn))}`); } this.policy.addStatements(statement); + return { statementAdded: true, policyDependable: this.policy }; } /** diff --git a/packages/@aws-cdk/aws-kms/package.json b/packages/@aws-cdk/aws-kms/package.json index 45d876f1832fd..2251944ffcb68 100644 --- a/packages/@aws-cdk/aws-kms/package.json +++ b/packages/@aws-cdk/aws-kms/package.json @@ -63,7 +63,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -82,7 +82,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-lakeformation/.eslintrc.js b/packages/@aws-cdk/aws-lakeformation/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-lakeformation/.eslintrc.js +++ b/packages/@aws-cdk/aws-lakeformation/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lakeformation/.gitignore b/packages/@aws-cdk/aws-lakeformation/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-lakeformation/.gitignore +++ b/packages/@aws-cdk/aws-lakeformation/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-lakeformation/.npmignore b/packages/@aws-cdk/aws-lakeformation/.npmignore index 6b86843be50f7..d04d75fba5945 100644 --- a/packages/@aws-cdk/aws-lakeformation/.npmignore +++ b/packages/@aws-cdk/aws-lakeformation/.npmignore @@ -22,3 +22,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-lakeformation/jest.config.js b/packages/@aws-cdk/aws-lakeformation/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-lakeformation/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lakeformation/package.json b/packages/@aws-cdk/aws-lakeformation/package.json index 4d4444ecd9f83..e64123f8085c2 100644 --- a/packages/@aws-cdk/aws-lakeformation/package.json +++ b/packages/@aws-cdk/aws-lakeformation/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::LakeFormation" + "cloudformation": "AWS::LakeFormation", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -95,7 +79,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-lambda-destinations/.eslintrc.js b/packages/@aws-cdk/aws-lambda-destinations/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-lambda-destinations/.eslintrc.js +++ b/packages/@aws-cdk/aws-lambda-destinations/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda-destinations/.gitignore b/packages/@aws-cdk/aws-lambda-destinations/.gitignore index 32a10d785e8fb..23a79075f642c 100644 --- a/packages/@aws-cdk/aws-lambda-destinations/.gitignore +++ b/packages/@aws-cdk/aws-lambda-destinations/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-lambda-destinations/.npmignore b/packages/@aws-cdk/aws-lambda-destinations/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-lambda-destinations/.npmignore +++ b/packages/@aws-cdk/aws-lambda-destinations/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-lambda-destinations/jest.config.js b/packages/@aws-cdk/aws-lambda-destinations/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-destinations/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda-destinations/package.json b/packages/@aws-cdk/aws-lambda-destinations/package.json index 0adfdeb214de2..92805e6004bd9 100644 --- a/packages/@aws-cdk/aws-lambda-destinations/package.json +++ b/packages/@aws-cdk/aws-lambda-destinations/package.json @@ -57,23 +57,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -103,7 +86,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "stable", "awslint": { @@ -112,5 +95,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "cdk-build": { + "jest": true + } } diff --git a/packages/@aws-cdk/aws-lambda-event-sources/.eslintrc.js b/packages/@aws-cdk/aws-lambda-event-sources/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/.eslintrc.js +++ b/packages/@aws-cdk/aws-lambda-event-sources/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda-event-sources/package.json b/packages/@aws-cdk/aws-lambda-event-sources/package.json index 528fca8a3ad67..e381573d61ca6 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/package.json +++ b/packages/@aws-cdk/aws-lambda-event-sources/package.json @@ -59,7 +59,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "nodeunit": "^0.11.3", @@ -97,7 +97,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "stable", "awslint": { diff --git a/packages/@aws-cdk/aws-lambda-nodejs/.eslintrc.js b/packages/@aws-cdk/aws-lambda-nodejs/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/.eslintrc.js +++ b/packages/@aws-cdk/aws-lambda-nodejs/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda-nodejs/.gitignore b/packages/@aws-cdk/aws-lambda-nodejs/.gitignore index b7a027fda6be5..7be76e8fa94c1 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/.gitignore +++ b/packages/@aws-cdk/aws-lambda-nodejs/.gitignore @@ -21,3 +21,4 @@ nyc.config.js !test/integ-handlers/js-handler.js !test/function.test.handler2.js !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-lambda-nodejs/.npmignore b/packages/@aws-cdk/aws-lambda-nodejs/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/.npmignore +++ b/packages/@aws-cdk/aws-lambda-nodejs/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-lambda-nodejs/jest.config.js b/packages/@aws-cdk/aws-lambda-nodejs/jest.config.js new file mode 100644 index 0000000000000..6371e05b69738 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-nodejs/jest.config.js @@ -0,0 +1,10 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = { + ...baseConfig, + coverageThreshold: { + global: { + ...baseConfig.coverageThreshold.global, + branches: 60, + }, + }, +}; diff --git a/packages/@aws-cdk/aws-lambda-nodejs/package.json b/packages/@aws-cdk/aws-lambda-nodejs/package.json index 9d21067b2c8f0..b932a81975ee0 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/package.json +++ b/packages/@aws-cdk/aws-lambda-nodejs/package.json @@ -57,23 +57,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,11 +77,14 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "experimental", "awscdkio": { "announce": false + }, + "cdk-build": { + "jest": true } } diff --git a/packages/@aws-cdk/aws-lambda/.eslintrc.js b/packages/@aws-cdk/aws-lambda/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-lambda/.eslintrc.js +++ b/packages/@aws-cdk/aws-lambda/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda/lib/code.ts b/packages/@aws-cdk/aws-lambda/lib/code.ts index f9df534834195..263e67f415bd4 100644 --- a/packages/@aws-cdk/aws-lambda/lib/code.ts +++ b/packages/@aws-cdk/aws-lambda/lib/code.ts @@ -36,7 +36,8 @@ export abstract class Code { } /** - * Loads the function code from a local disk asset. + * Loads the function code from a local disk path. + * * @param path Either a directory with the Lambda code bundle or a .zip file */ public static fromAsset(path: string, options?: s3_assets.AssetOptions): AssetCode { diff --git a/packages/@aws-cdk/aws-lambda/lib/function-base.ts b/packages/@aws-cdk/aws-lambda/lib/function-base.ts index eea549fbb957e..65a6fe6c05c26 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function-base.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function-base.ts @@ -283,6 +283,8 @@ export abstract class FunctionBase extends Resource implements IFunction { principal: grantee.grantPrincipal!, action: 'lambda:InvokeFunction', }); + + return { statementAdded: true, policyDependable: this.node.findChild(identifier) } as iam.AddToResourcePolicyResult; }, node: this.node, }, diff --git a/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts b/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts index 0fd972827dc9b..d9bf1f97372a0 100644 --- a/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts +++ b/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts @@ -65,6 +65,22 @@ export class SingletonFunction extends FunctionBase { return this.lambdaFunction.addPermission(name, permission); } + /** + * Using node.addDependency() does not work on this method as the underlying lambda function is modeled + * as a singleton across the stack. Use this method instead to declare dependencies. + */ + public addDependency(...up: cdk.IDependable[]) { + this.lambdaFunction.node.addDependency(...up); + } + + /** + * The SingletonFunction construct cannot be added as a dependency of another construct using + * node.addDependency(). Use this method instead to declare this as a dependency of another construct. + */ + public dependOn(down: cdk.IConstruct) { + down.node.addDependency(this.lambdaFunction); + } + private ensureLambda(props: SingletonFunctionProps): IFunction { const constructName = (props.lambdaPurpose || 'SingletonLambda') + slugify(props.uuid); const existing = cdk.Stack.of(this).node.tryFindChild(constructName); diff --git a/packages/@aws-cdk/aws-lambda/package.json b/packages/@aws-cdk/aws-lambda/package.json index 16bd0c10c7cc4..1c3f44a954a7e 100644 --- a/packages/@aws-cdk/aws-lambda/package.json +++ b/packages/@aws-cdk/aws-lambda/package.json @@ -68,10 +68,10 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/aws-lambda": "^8.10.39", - "@types/lodash": "^4.14.150", - "@types/nodeunit": "^0.0.30", - "@types/sinon": "^9.0.0", - "aws-sdk": "^2.672.0", + "@types/lodash": "^4.14.151", + "@types/nodeunit": "^0.0.31", + "@types/sinon": "^9.0.1", + "aws-sdk": "^2.678.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", @@ -110,7 +110,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-lambda/test/integ.vpc-lambda.expected.json b/packages/@aws-cdk/aws-lambda/test/integ.vpc-lambda.expected.json index af00fee2dba02..5aab3b725a0e6 100644 --- a/packages/@aws-cdk/aws-lambda/test/integ.vpc-lambda.expected.json +++ b/packages/@aws-cdk/aws-lambda/test/integ.vpc-lambda.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-vpc-lambda/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-vpc-lambda/VPC/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-vpc-lambda/VPC/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-vpc-lambda/VPC/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-vpc-lambda/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-vpc-lambda/VPC/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-vpc-lambda/VPC/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-vpc-lambda/VPC/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-lambda/test/test.singleton-lambda.ts b/packages/@aws-cdk/aws-lambda/test/test.singleton-lambda.ts index 536f9cd79434e..5f815d8f5e237 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.singleton-lambda.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.singleton-lambda.ts @@ -1,11 +1,12 @@ -import { expect, matchTemplate } from '@aws-cdk/assert'; +import { expect, haveResource, matchTemplate, ResourcePart } from '@aws-cdk/assert'; +import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; import * as lambda from '../lib'; export = { 'can add same singleton Lambda multiple times, only instantiated once in template'(test: Test) { - // GIVEN + // GIVEN const stack = new cdk.Stack(); // WHEN @@ -60,4 +61,56 @@ export = { test.done(); }, + + 'dependencies are correctly added'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const singleton = new lambda.SingletonFunction(stack, 'Singleton', { + uuid: '84c0de93-353f-4217-9b0b-45b6c993251a', + code: new lambda.InlineCode('def hello(): pass'), + runtime: lambda.Runtime.PYTHON_2_7, + handler: 'index.hello', + timeout: cdk.Duration.minutes(5), + }); + const dependency = new iam.User(stack, 'dependencyUser'); + + // WHEN + singleton.addDependency(dependency); + + // THEN + expect(stack).to(haveResource('AWS::Lambda::Function', { + DependsOn: [ + 'dependencyUser1B9CB07E', + 'SingletonLambda84c0de93353f42179b0b45b6c993251aServiceRole26D59235', + ], + }, ResourcePart.CompleteDefinition)); + + test.done(); + }, + + 'dependsOn are correctly added'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const singleton = new lambda.SingletonFunction(stack, 'Singleton', { + uuid: '84c0de93-353f-4217-9b0b-45b6c993251a', + code: new lambda.InlineCode('def hello(): pass'), + runtime: lambda.Runtime.PYTHON_2_7, + handler: 'index.hello', + timeout: cdk.Duration.minutes(5), + }); + const user = new iam.User(stack, 'user'); + + // WHEN + singleton.dependOn(user); + + // THEN + expect(stack).to(haveResource('AWS::IAM::User', { + DependsOn: [ + 'SingletonLambda84c0de93353f42179b0b45b6c993251a840BCC38', + 'SingletonLambda84c0de93353f42179b0b45b6c993251aServiceRole26D59235', + ], + }, ResourcePart.CompleteDefinition)); + + test.done(); + }, }; diff --git a/packages/@aws-cdk/aws-logs-destinations/.eslintrc.js b/packages/@aws-cdk/aws-logs-destinations/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-logs-destinations/.eslintrc.js +++ b/packages/@aws-cdk/aws-logs-destinations/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-logs-destinations/.gitignore b/packages/@aws-cdk/aws-logs-destinations/.gitignore index 32a10d785e8fb..23a79075f642c 100644 --- a/packages/@aws-cdk/aws-logs-destinations/.gitignore +++ b/packages/@aws-cdk/aws-logs-destinations/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-logs-destinations/.npmignore b/packages/@aws-cdk/aws-logs-destinations/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-logs-destinations/.npmignore +++ b/packages/@aws-cdk/aws-logs-destinations/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-logs-destinations/jest.config.js b/packages/@aws-cdk/aws-logs-destinations/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-logs-destinations/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-logs-destinations/package.json b/packages/@aws-cdk/aws-logs-destinations/package.json index e4daef2b516bd..c7e151e165b6c 100644 --- a/packages/@aws-cdk/aws-logs-destinations/package.json +++ b/packages/@aws-cdk/aws-logs-destinations/package.json @@ -57,23 +57,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 50, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -101,11 +84,14 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "stable", "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "cdk-build": { + "jest": true + } } diff --git a/packages/@aws-cdk/aws-logs/.eslintrc.js b/packages/@aws-cdk/aws-logs/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-logs/.eslintrc.js +++ b/packages/@aws-cdk/aws-logs/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-logs/package.json b/packages/@aws-cdk/aws-logs/package.json index dad14f807631b..c7dc3e58d9753 100644 --- a/packages/@aws-cdk/aws-logs/package.json +++ b/packages/@aws-cdk/aws-logs/package.json @@ -63,7 +63,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -84,7 +84,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-managedblockchain/.eslintrc.js b/packages/@aws-cdk/aws-managedblockchain/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-managedblockchain/.eslintrc.js +++ b/packages/@aws-cdk/aws-managedblockchain/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-managedblockchain/.gitignore b/packages/@aws-cdk/aws-managedblockchain/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-managedblockchain/.gitignore +++ b/packages/@aws-cdk/aws-managedblockchain/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-managedblockchain/.npmignore b/packages/@aws-cdk/aws-managedblockchain/.npmignore index 6b86843be50f7..d04d75fba5945 100644 --- a/packages/@aws-cdk/aws-managedblockchain/.npmignore +++ b/packages/@aws-cdk/aws-managedblockchain/.npmignore @@ -22,3 +22,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-managedblockchain/jest.config.js b/packages/@aws-cdk/aws-managedblockchain/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-managedblockchain/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-managedblockchain/package.json b/packages/@aws-cdk/aws-managedblockchain/package.json index 02c133f94a96e..115fdeb107cdc 100644 --- a/packages/@aws-cdk/aws-managedblockchain/package.json +++ b/packages/@aws-cdk/aws-managedblockchain/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::ManagedBlockchain" + "cloudformation": "AWS::ManagedBlockchain", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -95,7 +79,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-mediaconvert/.eslintrc.js b/packages/@aws-cdk/aws-mediaconvert/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-mediaconvert/.eslintrc.js +++ b/packages/@aws-cdk/aws-mediaconvert/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-mediaconvert/.gitignore b/packages/@aws-cdk/aws-mediaconvert/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-mediaconvert/.gitignore +++ b/packages/@aws-cdk/aws-mediaconvert/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-mediaconvert/.npmignore b/packages/@aws-cdk/aws-mediaconvert/.npmignore index d4f7bff69bdab..8ac959aca8fa5 100644 --- a/packages/@aws-cdk/aws-mediaconvert/.npmignore +++ b/packages/@aws-cdk/aws-mediaconvert/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json !.jsii .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-mediaconvert/jest.config.js b/packages/@aws-cdk/aws-mediaconvert/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-mediaconvert/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-mediaconvert/package.json b/packages/@aws-cdk/aws-mediaconvert/package.json index 28bd3313f6306..a9715d82568fe 100644 --- a/packages/@aws-cdk/aws-mediaconvert/package.json +++ b/packages/@aws-cdk/aws-mediaconvert/package.json @@ -48,7 +48,8 @@ "build+test+package": "npm run build+test && npm run package" }, "cdk-build": { - "cloudformation": "AWS::MediaConvert" + "cloudformation": "AWS::MediaConvert", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -95,7 +79,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-medialive/.eslintrc.js b/packages/@aws-cdk/aws-medialive/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-medialive/.eslintrc.js +++ b/packages/@aws-cdk/aws-medialive/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-medialive/.gitignore b/packages/@aws-cdk/aws-medialive/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-medialive/.gitignore +++ b/packages/@aws-cdk/aws-medialive/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-medialive/.npmignore b/packages/@aws-cdk/aws-medialive/.npmignore index 6b86843be50f7..d04d75fba5945 100644 --- a/packages/@aws-cdk/aws-medialive/.npmignore +++ b/packages/@aws-cdk/aws-medialive/.npmignore @@ -22,3 +22,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-medialive/jest.config.js b/packages/@aws-cdk/aws-medialive/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-medialive/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-medialive/package.json b/packages/@aws-cdk/aws-medialive/package.json index 1122a9543db2e..6c3d6071601ee 100644 --- a/packages/@aws-cdk/aws-medialive/package.json +++ b/packages/@aws-cdk/aws-medialive/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::MediaLive" + "cloudformation": "AWS::MediaLive", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -95,7 +79,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-mediastore/.eslintrc.js b/packages/@aws-cdk/aws-mediastore/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-mediastore/.eslintrc.js +++ b/packages/@aws-cdk/aws-mediastore/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-mediastore/.gitignore b/packages/@aws-cdk/aws-mediastore/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-mediastore/.gitignore +++ b/packages/@aws-cdk/aws-mediastore/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-mediastore/.npmignore b/packages/@aws-cdk/aws-mediastore/.npmignore index 6b86843be50f7..d04d75fba5945 100644 --- a/packages/@aws-cdk/aws-mediastore/.npmignore +++ b/packages/@aws-cdk/aws-mediastore/.npmignore @@ -22,3 +22,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-mediastore/jest.config.js b/packages/@aws-cdk/aws-mediastore/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-mediastore/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-mediastore/package.json b/packages/@aws-cdk/aws-mediastore/package.json index 694d454dfebc0..9dddf5241e70d 100644 --- a/packages/@aws-cdk/aws-mediastore/package.json +++ b/packages/@aws-cdk/aws-mediastore/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::MediaStore" + "cloudformation": "AWS::MediaStore", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -95,7 +79,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-msk/.eslintrc.js b/packages/@aws-cdk/aws-msk/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-msk/.eslintrc.js +++ b/packages/@aws-cdk/aws-msk/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-msk/.gitignore b/packages/@aws-cdk/aws-msk/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-msk/.gitignore +++ b/packages/@aws-cdk/aws-msk/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-msk/.npmignore b/packages/@aws-cdk/aws-msk/.npmignore index 5f6bdce6a4315..2b093ce17a11b 100644 --- a/packages/@aws-cdk/aws-msk/.npmignore +++ b/packages/@aws-cdk/aws-msk/.npmignore @@ -23,3 +23,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-msk/jest.config.js b/packages/@aws-cdk/aws-msk/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-msk/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-msk/package.json b/packages/@aws-cdk/aws-msk/package.json index 16dcefbe8d0ff..c2b6273e03135 100644 --- a/packages/@aws-cdk/aws-msk/package.json +++ b/packages/@aws-cdk/aws-msk/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::MSK" + "cloudformation": "AWS::MSK", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -95,7 +79,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-neptune/.eslintrc.js b/packages/@aws-cdk/aws-neptune/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-neptune/.eslintrc.js +++ b/packages/@aws-cdk/aws-neptune/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-neptune/.gitignore b/packages/@aws-cdk/aws-neptune/.gitignore index 6ffc26f126c4a..adcba106db8d1 100644 --- a/packages/@aws-cdk/aws-neptune/.gitignore +++ b/packages/@aws-cdk/aws-neptune/.gitignore @@ -13,3 +13,4 @@ tsconfig.json *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-neptune/.npmignore b/packages/@aws-cdk/aws-neptune/.npmignore index 764850e022c5a..8afbe60698fb4 100644 --- a/packages/@aws-cdk/aws-neptune/.npmignore +++ b/packages/@aws-cdk/aws-neptune/.npmignore @@ -23,3 +23,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-neptune/jest.config.js b/packages/@aws-cdk/aws-neptune/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-neptune/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-neptune/package.json b/packages/@aws-cdk/aws-neptune/package.json index 9221dc41715a6..93a966b1e782c 100644 --- a/packages/@aws-cdk/aws-neptune/package.json +++ b/packages/@aws-cdk/aws-neptune/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::Neptune" + "cloudformation": "AWS::Neptune", + "jest": true }, "keywords": [ "aws", @@ -61,23 +62,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-networkmanager/.eslintrc.js b/packages/@aws-cdk/aws-networkmanager/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-networkmanager/.eslintrc.js +++ b/packages/@aws-cdk/aws-networkmanager/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-networkmanager/.gitignore b/packages/@aws-cdk/aws-networkmanager/.gitignore index 6031555a5720f..d57af28d42320 100644 --- a/packages/@aws-cdk/aws-networkmanager/.gitignore +++ b/packages/@aws-cdk/aws-networkmanager/.gitignore @@ -15,3 +15,4 @@ coverage *.snk nyc.config.js !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-networkmanager/.npmignore b/packages/@aws-cdk/aws-networkmanager/.npmignore index e421b91419b9a..fb37683c5a457 100644 --- a/packages/@aws-cdk/aws-networkmanager/.npmignore +++ b/packages/@aws-cdk/aws-networkmanager/.npmignore @@ -20,3 +20,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-networkmanager/jest.config.js b/packages/@aws-cdk/aws-networkmanager/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-networkmanager/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-networkmanager/package.json b/packages/@aws-cdk/aws-networkmanager/package.json index 2fd95512a1c2e..7b1f0cd75be8e 100644 --- a/packages/@aws-cdk/aws-networkmanager/package.json +++ b/packages/@aws-cdk/aws-networkmanager/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::NetworkManager" + "cloudformation": "AWS::NetworkManager", + "jest": true }, "keywords": [ "aws", @@ -62,7 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": {}, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -77,7 +77,7 @@ "@aws-cdk/core": "0.0.0" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-opsworks/.eslintrc.js b/packages/@aws-cdk/aws-opsworks/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-opsworks/.eslintrc.js +++ b/packages/@aws-cdk/aws-opsworks/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-opsworks/.gitignore b/packages/@aws-cdk/aws-opsworks/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-opsworks/.gitignore +++ b/packages/@aws-cdk/aws-opsworks/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-opsworks/.npmignore b/packages/@aws-cdk/aws-opsworks/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-opsworks/.npmignore +++ b/packages/@aws-cdk/aws-opsworks/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-opsworks/jest.config.js b/packages/@aws-cdk/aws-opsworks/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-opsworks/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-opsworks/package.json b/packages/@aws-cdk/aws-opsworks/package.json index 801f679b13f34..020fe11906219 100644 --- a/packages/@aws-cdk/aws-opsworks/package.json +++ b/packages/@aws-cdk/aws-opsworks/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::OpsWorks" + "cloudformation": "AWS::OpsWorks", + "jest": true }, "keywords": [ "aws", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-opsworkscm/.eslintrc.js b/packages/@aws-cdk/aws-opsworkscm/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-opsworkscm/.eslintrc.js +++ b/packages/@aws-cdk/aws-opsworkscm/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-opsworkscm/.gitignore b/packages/@aws-cdk/aws-opsworkscm/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-opsworkscm/.gitignore +++ b/packages/@aws-cdk/aws-opsworkscm/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-opsworkscm/.npmignore b/packages/@aws-cdk/aws-opsworkscm/.npmignore index dd7e4908d99e4..c0fc6f9e7667f 100644 --- a/packages/@aws-cdk/aws-opsworkscm/.npmignore +++ b/packages/@aws-cdk/aws-opsworkscm/.npmignore @@ -22,3 +22,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-opsworkscm/jest.config.js b/packages/@aws-cdk/aws-opsworkscm/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-opsworkscm/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-opsworkscm/package.json b/packages/@aws-cdk/aws-opsworkscm/package.json index 0944ca14d0a9f..659eb8a9745c2 100644 --- a/packages/@aws-cdk/aws-opsworkscm/package.json +++ b/packages/@aws-cdk/aws-opsworkscm/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::OpsWorksCM" + "cloudformation": "AWS::OpsWorksCM", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -95,7 +79,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-pinpoint/.eslintrc.js b/packages/@aws-cdk/aws-pinpoint/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-pinpoint/.eslintrc.js +++ b/packages/@aws-cdk/aws-pinpoint/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-pinpoint/.gitignore b/packages/@aws-cdk/aws-pinpoint/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-pinpoint/.gitignore +++ b/packages/@aws-cdk/aws-pinpoint/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-pinpoint/.npmignore b/packages/@aws-cdk/aws-pinpoint/.npmignore index 5f6bdce6a4315..2b093ce17a11b 100644 --- a/packages/@aws-cdk/aws-pinpoint/.npmignore +++ b/packages/@aws-cdk/aws-pinpoint/.npmignore @@ -23,3 +23,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-pinpoint/jest.config.js b/packages/@aws-cdk/aws-pinpoint/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-pinpoint/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-pinpoint/package.json b/packages/@aws-cdk/aws-pinpoint/package.json index efd4fb1e7cc51..1ada031b4b640 100644 --- a/packages/@aws-cdk/aws-pinpoint/package.json +++ b/packages/@aws-cdk/aws-pinpoint/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::Pinpoint" + "cloudformation": "AWS::Pinpoint", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -95,7 +79,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-pinpointemail/.eslintrc.js b/packages/@aws-cdk/aws-pinpointemail/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-pinpointemail/.eslintrc.js +++ b/packages/@aws-cdk/aws-pinpointemail/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-pinpointemail/.gitignore b/packages/@aws-cdk/aws-pinpointemail/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-pinpointemail/.gitignore +++ b/packages/@aws-cdk/aws-pinpointemail/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-pinpointemail/.npmignore b/packages/@aws-cdk/aws-pinpointemail/.npmignore index 6b86843be50f7..d04d75fba5945 100644 --- a/packages/@aws-cdk/aws-pinpointemail/.npmignore +++ b/packages/@aws-cdk/aws-pinpointemail/.npmignore @@ -22,3 +22,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-pinpointemail/jest.config.js b/packages/@aws-cdk/aws-pinpointemail/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-pinpointemail/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-pinpointemail/package.json b/packages/@aws-cdk/aws-pinpointemail/package.json index 3536332c0a6cd..fbe2e8417bee9 100644 --- a/packages/@aws-cdk/aws-pinpointemail/package.json +++ b/packages/@aws-cdk/aws-pinpointemail/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::PinpointEmail" + "cloudformation": "AWS::PinpointEmail", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -95,7 +79,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-qldb/.eslintrc.js b/packages/@aws-cdk/aws-qldb/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-qldb/.eslintrc.js +++ b/packages/@aws-cdk/aws-qldb/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-qldb/.gitignore b/packages/@aws-cdk/aws-qldb/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-qldb/.gitignore +++ b/packages/@aws-cdk/aws-qldb/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-qldb/.npmignore b/packages/@aws-cdk/aws-qldb/.npmignore index 6b86843be50f7..d04d75fba5945 100644 --- a/packages/@aws-cdk/aws-qldb/.npmignore +++ b/packages/@aws-cdk/aws-qldb/.npmignore @@ -22,3 +22,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-qldb/jest.config.js b/packages/@aws-cdk/aws-qldb/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-qldb/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-qldb/package.json b/packages/@aws-cdk/aws-qldb/package.json index 44a058f20143c..5db773c1a026a 100644 --- a/packages/@aws-cdk/aws-qldb/package.json +++ b/packages/@aws-cdk/aws-qldb/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::QLDB" + "cloudformation": "AWS::QLDB", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -95,7 +79,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-ram/.eslintrc.js b/packages/@aws-cdk/aws-ram/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-ram/.eslintrc.js +++ b/packages/@aws-cdk/aws-ram/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ram/.gitignore b/packages/@aws-cdk/aws-ram/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-ram/.gitignore +++ b/packages/@aws-cdk/aws-ram/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-ram/.npmignore b/packages/@aws-cdk/aws-ram/.npmignore index dd7e4908d99e4..c0fc6f9e7667f 100644 --- a/packages/@aws-cdk/aws-ram/.npmignore +++ b/packages/@aws-cdk/aws-ram/.npmignore @@ -22,3 +22,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-ram/jest.config.js b/packages/@aws-cdk/aws-ram/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-ram/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ram/package.json b/packages/@aws-cdk/aws-ram/package.json index 3f9c93724f785..2799e1917e02e 100644 --- a/packages/@aws-cdk/aws-ram/package.json +++ b/packages/@aws-cdk/aws-ram/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::RAM" + "cloudformation": "AWS::RAM", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -95,7 +79,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-rds/.eslintrc.js b/packages/@aws-cdk/aws-rds/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-rds/.eslintrc.js +++ b/packages/@aws-cdk/aws-rds/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-rds/package.json b/packages/@aws-cdk/aws-rds/package.json index 19f1f9fda6edb..1568b3346b09b 100644 --- a/packages/@aws-cdk/aws-rds/package.json +++ b/packages/@aws-cdk/aws-rds/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-events-targets": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -99,7 +99,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ 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 e2207204e66fc..79fa1f3e2dab7 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 @@ -26,10 +26,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-rds-cluster-rotation/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -37,6 +33,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-rds-cluster-rotation/VPC/PublicSubnet1" } ] } @@ -123,10 +123,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-rds-cluster-rotation/VPC/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -134,6 +130,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-rds-cluster-rotation/VPC/PublicSubnet2" } ] } @@ -220,10 +220,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-rds-cluster-rotation/VPC/PublicSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -231,6 +227,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-rds-cluster-rotation/VPC/PublicSubnet3" } ] } @@ -317,10 +317,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-rds-cluster-rotation/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -328,6 +324,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-rds-cluster-rotation/VPC/PrivateSubnet1" } ] } @@ -379,10 +379,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-rds-cluster-rotation/VPC/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -390,6 +386,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-rds-cluster-rotation/VPC/PrivateSubnet2" } ] } @@ -441,10 +441,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-rds-cluster-rotation/VPC/PrivateSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -452,6 +448,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-rds-cluster-rotation/VPC/PrivateSubnet3" } ] } 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 56c9031c5c032..b9dc043a54b40 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 @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-rds-s3-integ/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-rds-s3-integ/VPC/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-rds-s3-integ/VPC/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-rds-s3-integ/VPC/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-rds-s3-integ/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-rds-s3-integ/VPC/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-rds-s3-integ/VPC/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-rds-s3-integ/VPC/PrivateSubnet2" } ] } 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 957401921230c..13642f995eeb1 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.cluster.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.cluster.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-rds-integ/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-rds-integ/VPC/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-rds-integ/VPC/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-rds-integ/VPC/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-rds-integ/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-rds-integ/VPC/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-rds-integ/VPC/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-rds-integ/VPC/PrivateSubnet2" } ] } 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 6a0a31787ba06..ae832999de3b7 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 @@ -26,10 +26,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-rds-instance/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -37,6 +33,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-rds-instance/VPC/PublicSubnet1" } ] } @@ -123,10 +123,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-rds-instance/VPC/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -134,6 +130,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-rds-instance/VPC/PublicSubnet2" } ] } @@ -220,10 +220,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-rds-instance/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -231,6 +227,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-rds-instance/VPC/PrivateSubnet1" } ] } @@ -282,10 +282,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-rds-instance/VPC/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -293,6 +289,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-rds-instance/VPC/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-redshift/.eslintrc.js b/packages/@aws-cdk/aws-redshift/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-redshift/.eslintrc.js +++ b/packages/@aws-cdk/aws-redshift/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-redshift/.gitignore b/packages/@aws-cdk/aws-redshift/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-redshift/.gitignore +++ b/packages/@aws-cdk/aws-redshift/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-redshift/.npmignore b/packages/@aws-cdk/aws-redshift/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-redshift/.npmignore +++ b/packages/@aws-cdk/aws-redshift/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-redshift/jest.config.js b/packages/@aws-cdk/aws-redshift/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-redshift/package.json b/packages/@aws-cdk/aws-redshift/package.json index 3739407201062..07283d9304b9f 100644 --- a/packages/@aws-cdk/aws-redshift/package.json +++ b/packages/@aws-cdk/aws-redshift/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::Redshift" + "cloudformation": "AWS::Redshift", + "jest": true }, "keywords": [ "aws", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-resourcegroups/.eslintrc.js b/packages/@aws-cdk/aws-resourcegroups/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-resourcegroups/.eslintrc.js +++ b/packages/@aws-cdk/aws-resourcegroups/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-resourcegroups/.gitignore b/packages/@aws-cdk/aws-resourcegroups/.gitignore index 6031555a5720f..d57af28d42320 100644 --- a/packages/@aws-cdk/aws-resourcegroups/.gitignore +++ b/packages/@aws-cdk/aws-resourcegroups/.gitignore @@ -15,3 +15,4 @@ coverage *.snk nyc.config.js !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-resourcegroups/.npmignore b/packages/@aws-cdk/aws-resourcegroups/.npmignore index e421b91419b9a..fb37683c5a457 100644 --- a/packages/@aws-cdk/aws-resourcegroups/.npmignore +++ b/packages/@aws-cdk/aws-resourcegroups/.npmignore @@ -20,3 +20,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-resourcegroups/jest.config.js b/packages/@aws-cdk/aws-resourcegroups/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-resourcegroups/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-resourcegroups/package.json b/packages/@aws-cdk/aws-resourcegroups/package.json index 16dbef1634377..b8f66b73856c6 100644 --- a/packages/@aws-cdk/aws-resourcegroups/package.json +++ b/packages/@aws-cdk/aws-resourcegroups/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::ResourceGroups" + "cloudformation": "AWS::ResourceGroups", + "jest": true }, "keywords": [ "aws", @@ -62,7 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": {}, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -77,7 +77,7 @@ "@aws-cdk/core": "0.0.0" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-robomaker/.eslintrc.js b/packages/@aws-cdk/aws-robomaker/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-robomaker/.eslintrc.js +++ b/packages/@aws-cdk/aws-robomaker/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-robomaker/.gitignore b/packages/@aws-cdk/aws-robomaker/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-robomaker/.gitignore +++ b/packages/@aws-cdk/aws-robomaker/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-robomaker/.npmignore b/packages/@aws-cdk/aws-robomaker/.npmignore index dd7e4908d99e4..c0fc6f9e7667f 100644 --- a/packages/@aws-cdk/aws-robomaker/.npmignore +++ b/packages/@aws-cdk/aws-robomaker/.npmignore @@ -22,3 +22,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-robomaker/jest.config.js b/packages/@aws-cdk/aws-robomaker/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-robomaker/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-robomaker/package.json b/packages/@aws-cdk/aws-robomaker/package.json index 1852dc7285d39..e74ee3bf2ebdf 100644 --- a/packages/@aws-cdk/aws-robomaker/package.json +++ b/packages/@aws-cdk/aws-robomaker/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::RoboMaker" + "cloudformation": "AWS::RoboMaker", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -95,7 +79,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-route53-patterns/.eslintrc.js b/packages/@aws-cdk/aws-route53-patterns/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-route53-patterns/.eslintrc.js +++ b/packages/@aws-cdk/aws-route53-patterns/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53-patterns/.gitignore b/packages/@aws-cdk/aws-route53-patterns/.gitignore index 32a10d785e8fb..23a79075f642c 100644 --- a/packages/@aws-cdk/aws-route53-patterns/.gitignore +++ b/packages/@aws-cdk/aws-route53-patterns/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-route53-patterns/.npmignore b/packages/@aws-cdk/aws-route53-patterns/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-route53-patterns/.npmignore +++ b/packages/@aws-cdk/aws-route53-patterns/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-route53-patterns/jest.config.js b/packages/@aws-cdk/aws-route53-patterns/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-route53-patterns/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53-patterns/package.json b/packages/@aws-cdk/aws-route53-patterns/package.json index 3c0f15d856b8b..09de36a416910 100644 --- a/packages/@aws-cdk/aws-route53-patterns/package.json +++ b/packages/@aws-cdk/aws-route53-patterns/package.json @@ -57,23 +57,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 70, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -107,11 +90,14 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "developer-preview", "awscdkio": { "announce": false + }, + "cdk-build": { + "jest": true } } diff --git a/packages/@aws-cdk/aws-route53-targets/.eslintrc.js b/packages/@aws-cdk/aws-route53-targets/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-route53-targets/.eslintrc.js +++ b/packages/@aws-cdk/aws-route53-targets/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53-targets/.gitignore b/packages/@aws-cdk/aws-route53-targets/.gitignore index 32a10d785e8fb..23a79075f642c 100644 --- a/packages/@aws-cdk/aws-route53-targets/.gitignore +++ b/packages/@aws-cdk/aws-route53-targets/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-route53-targets/.npmignore b/packages/@aws-cdk/aws-route53-targets/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-route53-targets/.npmignore +++ b/packages/@aws-cdk/aws-route53-targets/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-route53-targets/jest.config.js b/packages/@aws-cdk/aws-route53-targets/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-route53-targets/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53-targets/package.json b/packages/@aws-cdk/aws-route53-targets/package.json index 7fcf6a5607ec4..80d2e61663189 100644 --- a/packages/@aws-cdk/aws-route53-targets/package.json +++ b/packages/@aws-cdk/aws-route53-targets/package.json @@ -57,23 +57,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 70, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -115,11 +98,14 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "stable", "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "cdk-build": { + "jest": true + } } diff --git a/packages/@aws-cdk/aws-route53-targets/test/integ.alb-alias-target.expected.json b/packages/@aws-cdk/aws-route53-targets/test/integ.alb-alias-target.expected.json index 9c6b1c7fd8e24..828c0d7f4b6a5 100644 --- a/packages/@aws-cdk/aws-route53-targets/test/integ.alb-alias-target.expected.json +++ b/packages/@aws-cdk/aws-route53-targets/test/integ.alb-alias-target.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-route53-targets/test/integ.interface-vpc-endpoint-target.expected.json b/packages/@aws-cdk/aws-route53-targets/test/integ.interface-vpc-endpoint-target.expected.json index a8577ace006ca..f227b614dbcb5 100644 --- a/packages/@aws-cdk/aws-route53-targets/test/integ.interface-vpc-endpoint-target.expected.json +++ b/packages/@aws-cdk/aws-route53-targets/test/integ.interface-vpc-endpoint-target.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-interface-vpc-endpoint/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-interface-vpc-endpoint/VPC/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-interface-vpc-endpoint/VPC/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-interface-vpc-endpoint/VPC/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-interface-vpc-endpoint/VPC/PublicSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-interface-vpc-endpoint/VPC/PublicSubnet3" } ] } @@ -316,10 +316,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-interface-vpc-endpoint/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -327,6 +323,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-interface-vpc-endpoint/VPC/PrivateSubnet1" } ] } @@ -378,10 +378,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-interface-vpc-endpoint/VPC/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -389,6 +385,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-interface-vpc-endpoint/VPC/PrivateSubnet2" } ] } @@ -440,10 +440,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-interface-vpc-endpoint/VPC/PrivateSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -451,6 +447,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-interface-vpc-endpoint/VPC/PrivateSubnet3" } ] } diff --git a/packages/@aws-cdk/aws-route53/.eslintrc.js b/packages/@aws-cdk/aws-route53/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-route53/.eslintrc.js +++ b/packages/@aws-cdk/aws-route53/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53/package.json b/packages/@aws-cdk/aws-route53/package.json index ec1b1de7f9d38..d26e7eb3366de 100644 --- a/packages/@aws-cdk/aws-route53/package.json +++ b/packages/@aws-cdk/aws-route53/package.json @@ -63,8 +63,8 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.672.0", + "@types/nodeunit": "^0.0.31", + "aws-sdk": "^2.678.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -87,7 +87,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-route53/test/integ.route53.expected.json b/packages/@aws-cdk/aws-route53/test/integ.route53.expected.json index 11bb480abf9ad..94a87180fa758 100644 --- a/packages/@aws-cdk/aws-route53/test/integ.route53.expected.json +++ b/packages/@aws-cdk/aws-route53/test/integ.route53.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-route53-integ/VPC/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-route53-integ/VPC/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-route53-integ/VPC/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-route53-integ/VPC/PrivateSubnet1" } ] } diff --git a/packages/@aws-cdk/aws-route53resolver/.eslintrc.js b/packages/@aws-cdk/aws-route53resolver/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-route53resolver/.eslintrc.js +++ b/packages/@aws-cdk/aws-route53resolver/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53resolver/.gitignore b/packages/@aws-cdk/aws-route53resolver/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-route53resolver/.gitignore +++ b/packages/@aws-cdk/aws-route53resolver/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-route53resolver/.npmignore b/packages/@aws-cdk/aws-route53resolver/.npmignore index dd7e4908d99e4..c0fc6f9e7667f 100644 --- a/packages/@aws-cdk/aws-route53resolver/.npmignore +++ b/packages/@aws-cdk/aws-route53resolver/.npmignore @@ -22,3 +22,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-route53resolver/jest.config.js b/packages/@aws-cdk/aws-route53resolver/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-route53resolver/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53resolver/package.json b/packages/@aws-cdk/aws-route53resolver/package.json index 44d10ba170a26..55a0373fa39bb 100644 --- a/packages/@aws-cdk/aws-route53resolver/package.json +++ b/packages/@aws-cdk/aws-route53resolver/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::Route53Resolver" + "cloudformation": "AWS::Route53Resolver", + "jest": true }, "keywords": [ "aws", @@ -61,23 +62,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "experimental", diff --git a/packages/@aws-cdk/aws-s3-assets/.eslintrc.js b/packages/@aws-cdk/aws-s3-assets/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-s3-assets/.eslintrc.js +++ b/packages/@aws-cdk/aws-s3-assets/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3-assets/lib/asset.ts b/packages/@aws-cdk/aws-s3-assets/lib/asset.ts index 68484fcc4d985..f6b08bee2d132 100644 --- a/packages/@aws-cdk/aws-s3-assets/lib/asset.ts +++ b/packages/@aws-cdk/aws-s3-assets/lib/asset.ts @@ -110,7 +110,7 @@ export class Asset extends cdk.Construct implements assets.IAsset { const stack = cdk.Stack.of(this); - const location = stack.addFileAsset({ + const location = stack.synthesizer.addFileAsset({ packaging, sourceHash: this.sourceHash, fileName: staging.stagedPath, diff --git a/packages/@aws-cdk/aws-s3-assets/package.json b/packages/@aws-cdk/aws-s3-assets/package.json index fb26371f8fddf..2fc656188b655 100644 --- a/packages/@aws-cdk/aws-s3-assets/package.json +++ b/packages/@aws-cdk/aws-s3-assets/package.json @@ -60,8 +60,8 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", - "@types/sinon": "^9.0.0", + "@types/nodeunit": "^0.0.31", + "@types/sinon": "^9.0.1", "aws-cdk": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", @@ -89,7 +89,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "experimental", diff --git a/packages/@aws-cdk/aws-s3-deployment/.eslintrc.js b/packages/@aws-cdk/aws-s3-deployment/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-s3-deployment/.eslintrc.js +++ b/packages/@aws-cdk/aws-s3-deployment/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3-deployment/package.json b/packages/@aws-cdk/aws-s3-deployment/package.json index 144e678110ee1..9291eb8292125 100644 --- a/packages/@aws-cdk/aws-s3-deployment/package.json +++ b/packages/@aws-cdk/aws-s3-deployment/package.json @@ -77,7 +77,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "nodeunit": "^0.11.3", @@ -103,7 +103,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "experimental", diff --git a/packages/@aws-cdk/aws-s3-notifications/.eslintrc.js b/packages/@aws-cdk/aws-s3-notifications/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-s3-notifications/.eslintrc.js +++ b/packages/@aws-cdk/aws-s3-notifications/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3-notifications/.gitignore b/packages/@aws-cdk/aws-s3-notifications/.gitignore index 32a10d785e8fb..23a79075f642c 100644 --- a/packages/@aws-cdk/aws-s3-notifications/.gitignore +++ b/packages/@aws-cdk/aws-s3-notifications/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-s3-notifications/.npmignore b/packages/@aws-cdk/aws-s3-notifications/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-s3-notifications/.npmignore +++ b/packages/@aws-cdk/aws-s3-notifications/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-s3-notifications/jest.config.js b/packages/@aws-cdk/aws-s3-notifications/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-s3-notifications/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3-notifications/package.json b/packages/@aws-cdk/aws-s3-notifications/package.json index d2c3d074a29a6..10fcc8be6b5cd 100644 --- a/packages/@aws-cdk/aws-s3-notifications/package.json +++ b/packages/@aws-cdk/aws-s3-notifications/package.json @@ -56,23 +56,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -101,11 +84,14 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "stable", "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "cdk-build": { + "jest": true + } } diff --git a/packages/@aws-cdk/aws-s3/.eslintrc.js b/packages/@aws-cdk/aws-s3/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-s3/.eslintrc.js +++ b/packages/@aws-cdk/aws-s3/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3/lib/bucket.ts b/packages/@aws-cdk/aws-s3/lib/bucket.ts index 75b2d9d885336..ddc2b8939913c 100644 --- a/packages/@aws-cdk/aws-s3/lib/bucket.ts +++ b/packages/@aws-cdk/aws-s3/lib/bucket.ts @@ -73,7 +73,7 @@ export interface IBucket extends IResource { * contents. Use `bucketArn` and `arnForObjects(keys)` to obtain ARNs for * this bucket or objects. */ - addToResourcePolicy(permission: iam.PolicyStatement): void; + addToResourcePolicy(permission: iam.PolicyStatement): iam.AddToResourcePolicyResult; /** * The https URL of an S3 object. For example: @@ -418,14 +418,17 @@ abstract class BucketBase extends Resource implements IBucket { * contents. Use `bucketArn` and `arnForObjects(keys)` to obtain ARNs for * this bucket or objects. */ - public addToResourcePolicy(permission: iam.PolicyStatement) { + public addToResourcePolicy(permission: iam.PolicyStatement): iam.AddToResourcePolicyResult { if (!this.policy && this.autoCreatePolicy) { this.policy = new BucketPolicy(this, 'Policy', { bucket: this }); } if (this.policy) { this.policy.document.addStatements(permission); + return { statementAdded: true, policyDependable: this.policy }; } + + return { statementAdded: false }; } /** diff --git a/packages/@aws-cdk/aws-s3/package.json b/packages/@aws-cdk/aws-s3/package.json index bce2374d16da6..a28a0631c9621 100644 --- a/packages/@aws-cdk/aws-s3/package.json +++ b/packages/@aws-cdk/aws-s3/package.json @@ -63,7 +63,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -86,7 +86,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-sagemaker/.eslintrc.js b/packages/@aws-cdk/aws-sagemaker/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-sagemaker/.eslintrc.js +++ b/packages/@aws-cdk/aws-sagemaker/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sagemaker/.gitignore b/packages/@aws-cdk/aws-sagemaker/.gitignore index 6ffc26f126c4a..adcba106db8d1 100644 --- a/packages/@aws-cdk/aws-sagemaker/.gitignore +++ b/packages/@aws-cdk/aws-sagemaker/.gitignore @@ -13,3 +13,4 @@ tsconfig.json *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-sagemaker/.npmignore b/packages/@aws-cdk/aws-sagemaker/.npmignore index 3a3059a206b70..b033e481c6000 100644 --- a/packages/@aws-cdk/aws-sagemaker/.npmignore +++ b/packages/@aws-cdk/aws-sagemaker/.npmignore @@ -23,3 +23,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-sagemaker/jest.config.js b/packages/@aws-cdk/aws-sagemaker/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-sagemaker/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sagemaker/package.json b/packages/@aws-cdk/aws-sagemaker/package.json index 5152bd2debac3..712de070d4176 100644 --- a/packages/@aws-cdk/aws-sagemaker/package.json +++ b/packages/@aws-cdk/aws-sagemaker/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::SageMaker" + "cloudformation": "AWS::SageMaker", + "jest": true }, "keywords": [ "aws", @@ -61,23 +62,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-sam/.eslintrc.js b/packages/@aws-cdk/aws-sam/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-sam/.eslintrc.js +++ b/packages/@aws-cdk/aws-sam/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sam/.gitignore b/packages/@aws-cdk/aws-sam/.gitignore index 6ffc26f126c4a..adcba106db8d1 100644 --- a/packages/@aws-cdk/aws-sam/.gitignore +++ b/packages/@aws-cdk/aws-sam/.gitignore @@ -13,3 +13,4 @@ tsconfig.json *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-sam/.npmignore b/packages/@aws-cdk/aws-sam/.npmignore index 764850e022c5a..8afbe60698fb4 100644 --- a/packages/@aws-cdk/aws-sam/.npmignore +++ b/packages/@aws-cdk/aws-sam/.npmignore @@ -23,3 +23,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-sam/jest.config.js b/packages/@aws-cdk/aws-sam/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-sam/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sam/package.json b/packages/@aws-cdk/aws-sam/package.json index 3190eb0afba88..00ad279159672 100644 --- a/packages/@aws-cdk/aws-sam/package.json +++ b/packages/@aws-cdk/aws-sam/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::Serverless" + "cloudformation": "AWS::Serverless", + "jest": true }, "keywords": [ "aws", @@ -64,12 +65,12 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/jest": "^25.2.1", + "@types/jest": "^25.2.2", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "jest": "^25.5.4", "pkglint": "0.0.0", - "ts-jest": "^25.5.0" + "ts-jest": "^26.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", @@ -79,9 +80,8 @@ "@aws-cdk/core": "0.0.0", "constructs": "^3.0.2" }, - "jest": {}, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-sdb/.eslintrc.js b/packages/@aws-cdk/aws-sdb/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-sdb/.eslintrc.js +++ b/packages/@aws-cdk/aws-sdb/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sdb/.gitignore b/packages/@aws-cdk/aws-sdb/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-sdb/.gitignore +++ b/packages/@aws-cdk/aws-sdb/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-sdb/.npmignore b/packages/@aws-cdk/aws-sdb/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-sdb/.npmignore +++ b/packages/@aws-cdk/aws-sdb/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-sdb/jest.config.js b/packages/@aws-cdk/aws-sdb/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-sdb/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sdb/package.json b/packages/@aws-cdk/aws-sdb/package.json index 679ce84797d1c..298a065145bf1 100644 --- a/packages/@aws-cdk/aws-sdb/package.json +++ b/packages/@aws-cdk/aws-sdb/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::SDB" + "cloudformation": "AWS::SDB", + "jest": true }, "keywords": [ "aws", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-secretsmanager/.eslintrc.js b/packages/@aws-cdk/aws-secretsmanager/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-secretsmanager/.eslintrc.js +++ b/packages/@aws-cdk/aws-secretsmanager/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts b/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts index f48235bfb0857..9cb8b7c109e3e 100644 --- a/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts +++ b/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts @@ -53,7 +53,7 @@ export interface ISecret extends IResource { * automatically created upon the first call to `addToResourcePolicy`. If * the secret is imported, then this is a no-op. */ - addToResourcePolicy(statement: iam.PolicyStatement): void; + addToResourcePolicy(statement: iam.PolicyStatement): iam.AddToResourcePolicyResult; /** * Denies the `DeleteSecret` action to all principals within the current @@ -163,14 +163,16 @@ abstract class SecretBase extends Resource implements ISecret { }); } - public addToResourcePolicy(statement: iam.PolicyStatement) { + public addToResourcePolicy(statement: iam.PolicyStatement): iam.AddToResourcePolicyResult { if (!this.policy && this.autoCreatePolicy) { this.policy = new ResourcePolicy(this, 'Policy', { secret: this }); } if (this.policy) { this.policy.document.addStatements(statement); + return { statementAdded: true, policyDependable: this.policy }; } + return { statementAdded: false }; } public denyAccountRootDelete() { diff --git a/packages/@aws-cdk/aws-secretsmanager/package.json b/packages/@aws-cdk/aws-secretsmanager/package.json index f21d70c44ef5b..ca00bf77825cb 100644 --- a/packages/@aws-cdk/aws-secretsmanager/package.json +++ b/packages/@aws-cdk/aws-secretsmanager/package.json @@ -64,7 +64,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -90,7 +90,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-securityhub/.eslintrc.js b/packages/@aws-cdk/aws-securityhub/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-securityhub/.eslintrc.js +++ b/packages/@aws-cdk/aws-securityhub/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-securityhub/.gitignore b/packages/@aws-cdk/aws-securityhub/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-securityhub/.gitignore +++ b/packages/@aws-cdk/aws-securityhub/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-securityhub/.npmignore b/packages/@aws-cdk/aws-securityhub/.npmignore index 6b86843be50f7..d04d75fba5945 100644 --- a/packages/@aws-cdk/aws-securityhub/.npmignore +++ b/packages/@aws-cdk/aws-securityhub/.npmignore @@ -22,3 +22,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-securityhub/jest.config.js b/packages/@aws-cdk/aws-securityhub/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-securityhub/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-securityhub/package.json b/packages/@aws-cdk/aws-securityhub/package.json index 70a0195578aa8..f9fc70cdd1aa2 100644 --- a/packages/@aws-cdk/aws-securityhub/package.json +++ b/packages/@aws-cdk/aws-securityhub/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::SecurityHub" + "cloudformation": "AWS::SecurityHub", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -95,7 +79,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-servicecatalog/.eslintrc.js b/packages/@aws-cdk/aws-servicecatalog/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-servicecatalog/.eslintrc.js +++ b/packages/@aws-cdk/aws-servicecatalog/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-servicecatalog/.gitignore b/packages/@aws-cdk/aws-servicecatalog/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-servicecatalog/.gitignore +++ b/packages/@aws-cdk/aws-servicecatalog/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-servicecatalog/.npmignore b/packages/@aws-cdk/aws-servicecatalog/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-servicecatalog/.npmignore +++ b/packages/@aws-cdk/aws-servicecatalog/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-servicecatalog/jest.config.js b/packages/@aws-cdk/aws-servicecatalog/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-servicecatalog/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-servicecatalog/package.json b/packages/@aws-cdk/aws-servicecatalog/package.json index 3f6ed57f8e22f..83618ad430988 100644 --- a/packages/@aws-cdk/aws-servicecatalog/package.json +++ b/packages/@aws-cdk/aws-servicecatalog/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::ServiceCatalog" + "cloudformation": "AWS::ServiceCatalog", + "jest": true }, "keywords": [ "aws", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-servicediscovery/.eslintrc.js b/packages/@aws-cdk/aws-servicediscovery/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-servicediscovery/.eslintrc.js +++ b/packages/@aws-cdk/aws-servicediscovery/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-servicediscovery/package.json b/packages/@aws-cdk/aws-servicediscovery/package.json index 317d74dc015dd..78c05ec3aeac1 100644 --- a/packages/@aws-cdk/aws-servicediscovery/package.json +++ b/packages/@aws-cdk/aws-servicediscovery/package.json @@ -66,7 +66,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -89,7 +89,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-servicediscovery/test/integ.service-with-private-dns-namespace.lit.expected.json b/packages/@aws-cdk/aws-servicediscovery/test/integ.service-with-private-dns-namespace.lit.expected.json index 6f53f681dad90..da039a05c09fd 100644 --- a/packages/@aws-cdk/aws-servicediscovery/test/integ.service-with-private-dns-namespace.lit.expected.json +++ b/packages/@aws-cdk/aws-servicediscovery/test/integ.service-with-private-dns-namespace.lit.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-servicediscovery-integ/Vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-servicediscovery-integ/Vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-servicediscovery-integ/Vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-servicediscovery-integ/Vpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-servicediscovery-integ/Vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-servicediscovery-integ/Vpc/PrivateSubnet1" } ] } @@ -281,10 +281,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-servicediscovery-integ/Vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -292,6 +288,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-servicediscovery-integ/Vpc/PrivateSubnet2" } ] } diff --git a/packages/@aws-cdk/aws-ses-actions/.eslintrc.js b/packages/@aws-cdk/aws-ses-actions/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-ses-actions/.eslintrc.js +++ b/packages/@aws-cdk/aws-ses-actions/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ses-actions/.gitignore b/packages/@aws-cdk/aws-ses-actions/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-ses-actions/.gitignore +++ b/packages/@aws-cdk/aws-ses-actions/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-ses-actions/.npmignore b/packages/@aws-cdk/aws-ses-actions/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-ses-actions/.npmignore +++ b/packages/@aws-cdk/aws-ses-actions/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-ses-actions/jest.config.js b/packages/@aws-cdk/aws-ses-actions/jest.config.js new file mode 100644 index 0000000000000..6371e05b69738 --- /dev/null +++ b/packages/@aws-cdk/aws-ses-actions/jest.config.js @@ -0,0 +1,10 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = { + ...baseConfig, + coverageThreshold: { + global: { + ...baseConfig.coverageThreshold.global, + branches: 60, + }, + }, +}; diff --git a/packages/@aws-cdk/aws-ses-actions/package.json b/packages/@aws-cdk/aws-ses-actions/package.json index 8d15813149bf8..92472cec0d6bf 100644 --- a/packages/@aws-cdk/aws-ses-actions/package.json +++ b/packages/@aws-cdk/aws-ses-actions/package.json @@ -58,23 +58,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -106,7 +89,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "experimental", @@ -124,5 +107,8 @@ }, "awscdkio": { "announce": false + }, + "cdk-build": { + "jest": true } } diff --git a/packages/@aws-cdk/aws-ses/.eslintrc.js b/packages/@aws-cdk/aws-ses/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-ses/.eslintrc.js +++ b/packages/@aws-cdk/aws-ses/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ses/package.json b/packages/@aws-cdk/aws-ses/package.json index 360cf7e994746..69a866c63e23f 100644 --- a/packages/@aws-cdk/aws-ses/package.json +++ b/packages/@aws-cdk/aws-ses/package.json @@ -63,7 +63,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -84,7 +84,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "experimental", diff --git a/packages/@aws-cdk/aws-sns-subscriptions/.eslintrc.js b/packages/@aws-cdk/aws-sns-subscriptions/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/.eslintrc.js +++ b/packages/@aws-cdk/aws-sns-subscriptions/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sns-subscriptions/.gitignore b/packages/@aws-cdk/aws-sns-subscriptions/.gitignore index 32a10d785e8fb..23a79075f642c 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/.gitignore +++ b/packages/@aws-cdk/aws-sns-subscriptions/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-sns-subscriptions/.npmignore b/packages/@aws-cdk/aws-sns-subscriptions/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/.npmignore +++ b/packages/@aws-cdk/aws-sns-subscriptions/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-sns-subscriptions/jest.config.js b/packages/@aws-cdk/aws-sns-subscriptions/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-sns-subscriptions/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sns-subscriptions/package.json b/packages/@aws-cdk/aws-sns-subscriptions/package.json index 85442918e2a4d..07ea20698e7ed 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/package.json +++ b/packages/@aws-cdk/aws-sns-subscriptions/package.json @@ -57,23 +57,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -101,11 +84,14 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "stable", "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "cdk-build": { + "jest": true + } } diff --git a/packages/@aws-cdk/aws-sns/.eslintrc.js b/packages/@aws-cdk/aws-sns/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-sns/.eslintrc.js +++ b/packages/@aws-cdk/aws-sns/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sns/lib/topic-base.ts b/packages/@aws-cdk/aws-sns/lib/topic-base.ts index 57257af851d8c..263f4cf80aefa 100644 --- a/packages/@aws-cdk/aws-sns/lib/topic-base.ts +++ b/packages/@aws-cdk/aws-sns/lib/topic-base.ts @@ -34,7 +34,7 @@ export interface ITopic extends IResource { * will be automatically created upon the first call to `addToPolicy`. If * the topic is improted (`Topic.import`), then this is a no-op. */ - addToResourcePolicy(statement: iam.PolicyStatement): void; + addToResourcePolicy(statement: iam.PolicyStatement): iam.AddToResourcePolicyResult; /** * Grant topic publishing permissions to the given identity @@ -90,14 +90,16 @@ export abstract class TopicBase extends Resource implements ITopic { * will be automatically created upon the first call to `addToPolicy`. If * the topic is improted (`Topic.import`), then this is a no-op. */ - public addToResourcePolicy(statement: iam.PolicyStatement) { + public addToResourcePolicy(statement: iam.PolicyStatement): iam.AddToResourcePolicyResult { if (!this.policy && this.autoCreatePolicy) { this.policy = new TopicPolicy(this, 'Policy', { topics: [ this ] }); } if (this.policy) { this.policy.document.addStatements(statement); + return { statementAdded: true, policyDependable: this.policy }; } + return { statementAdded: false }; } /** diff --git a/packages/@aws-cdk/aws-sns/package.json b/packages/@aws-cdk/aws-sns/package.json index fbc16d7d6ffea..c8b1fae0c2e98 100644 --- a/packages/@aws-cdk/aws-sns/package.json +++ b/packages/@aws-cdk/aws-sns/package.json @@ -67,7 +67,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -92,7 +92,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-sqs/.eslintrc.js b/packages/@aws-cdk/aws-sqs/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-sqs/.eslintrc.js +++ b/packages/@aws-cdk/aws-sqs/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sqs/lib/queue-base.ts b/packages/@aws-cdk/aws-sqs/lib/queue-base.ts index 7e39d1b09a4be..0a5fed37656fd 100644 --- a/packages/@aws-cdk/aws-sqs/lib/queue-base.ts +++ b/packages/@aws-cdk/aws-sqs/lib/queue-base.ts @@ -42,7 +42,7 @@ export interface IQueue extends IResource { * will be automatically created upon the first call to `addToPolicy`. If * the queue is improted (`Queue.import`), then this is a no-op. */ - addToResourcePolicy(statement: iam.PolicyStatement): void; + addToResourcePolicy(statement: iam.PolicyStatement): iam.AddToResourcePolicyResult; /** * Grant permissions to consume messages from a queue @@ -141,14 +141,17 @@ export abstract class QueueBase extends Resource implements IQueue { * will be automatically created upon the first call to `addToPolicy`. If * the queue is improted (`Queue.import`), then this is a no-op. */ - public addToResourcePolicy(statement: iam.PolicyStatement) { + public addToResourcePolicy(statement: iam.PolicyStatement): iam.AddToResourcePolicyResult { if (!this.policy && this.autoCreatePolicy) { this.policy = new QueuePolicy(this, 'Policy', { queues: [ this ] }); } if (this.policy) { this.policy.document.addStatements(statement); + return { statementAdded: true, policyDependable: this.policy }; } + + return { statementAdded: false }; } /** diff --git a/packages/@aws-cdk/aws-sqs/package.json b/packages/@aws-cdk/aws-sqs/package.json index 7efc1e85684bd..c510af43a5dad 100644 --- a/packages/@aws-cdk/aws-sqs/package.json +++ b/packages/@aws-cdk/aws-sqs/package.json @@ -64,8 +64,8 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", - "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.672.0", + "@types/nodeunit": "^0.0.31", + "aws-sdk": "^2.678.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -88,7 +88,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-ssm/.eslintrc.js b/packages/@aws-cdk/aws-ssm/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-ssm/.eslintrc.js +++ b/packages/@aws-cdk/aws-ssm/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ssm/package.json b/packages/@aws-cdk/aws-ssm/package.json index 357aad127a955..2758e7b15bd10 100644 --- a/packages/@aws-cdk/aws-ssm/package.json +++ b/packages/@aws-cdk/aws-ssm/package.json @@ -63,7 +63,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -86,7 +86,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "stable", "awscdkio": { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/.eslintrc.js b/packages/@aws-cdk/aws-stepfunctions-tasks/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/.eslintrc.js +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/.gitignore b/packages/@aws-cdk/aws-stepfunctions-tasks/.gitignore index cf3ce17244583..1109bfe833d86 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/.gitignore +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/.gitignore @@ -15,3 +15,4 @@ nyc.config.js *.snk .cdk.staging !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/.npmignore b/packages/@aws-cdk/aws-stepfunctions-tasks/.npmignore index 6ff7c3d72a36a..34ff973619988 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/.npmignore +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/.npmignore @@ -18,3 +18,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/jest.config.js b/packages/@aws-cdk/aws-stepfunctions-tasks/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/evaluate-expression.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/evaluate-expression.ts index d136914cc9065..b2a630681bb83 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/evaluate-expression.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/evaluate-expression.ts @@ -11,7 +11,7 @@ import * as path from 'path'; */ export interface EvaluateExpressionProps { /** - * The expression to evaluate. It must contain state paths. + * The expression to evaluate. The expression may contain state paths. * * @example '$.a + $.b' */ @@ -56,30 +56,30 @@ export class EvaluateExpression implements sfn.IStepFunctionsTask { public bind(task: sfn.Task): sfn.StepFunctionsTaskConfig { const matches = this.props.expression.match(/\$[.\[][.a-zA-Z[\]0-9]+/g); - if (!matches) { - throw new Error('No paths found in expression'); + let expressionAttributeValues = {}; + if (matches) { + expressionAttributeValues = matches.reduce( + (acc, m) => ({ + ...acc, + [m]: sfn.Data.stringAt(m), // It's okay to always use `stringAt` here + }), + {}, + ); } - const expressionAttributeValues = matches.reduce( - (acc, m) => ({ - ...acc, - [m]: sfn.Data.stringAt(m), // It's okay to always use `stringAt` here - }), - {}, - ); - const evalFn = createEvalFn(this.props.runtime || lambda.Runtime.NODEJS_10_X, task); + const parameters: Event = { + expression: this.props.expression, + expressionAttributeValues, + }; return { resourceArn: evalFn.functionArn, policyStatements: [new iam.PolicyStatement({ resources: [evalFn.functionArn], actions: ['lambda:InvokeFunction'], })], - parameters: { - expression: this.props.expression, - expressionAttributeValues, - } as Event, + parameters, }; } } diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/start-execution.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/start-execution.ts index 2ae15593dabab..049e558971206 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/start-execution.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/start-execution.ts @@ -95,7 +95,13 @@ export class StartExecution implements sfn.IStepFunctionsTask { if (this.integrationPattern === sfn.ServiceIntegrationPattern.SYNC) { policyStatements.push(new iam.PolicyStatement({ actions: ['states:DescribeExecution', 'states:StopExecution'], - resources: ['*'], + // https://docs.aws.amazon.com/step-functions/latest/dg/concept-create-iam-advanced.html#concept-create-iam-advanced-execution + resources: [stack.formatArn({ + service: 'states', + resource: 'execution', + sep: ':', + resourceName: `${stack.parseArn(this.stateMachine.stateMachineArn, ':').resourceName}*`, + })], })); policyStatements.push(new iam.PolicyStatement({ diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json index 7e029a1e91df8..e58d18c644f49 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json @@ -46,23 +46,6 @@ "build+test": "npm run build && npm test", "compat": "cdk-compat" }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 65, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "keywords": [ "aws", "cdk", @@ -124,7 +107,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "experimental", @@ -133,5 +116,8 @@ }, "awscdkio": { "announce": false + }, + "cdk-build": { + "jest": true } } diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/integ.run-batch-job.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/integ.run-batch-job.expected.json index 2959dd9d50551..7d6104ca73d1a 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/integ.run-batch-job.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/integ.run-batch-job.expected.json @@ -25,10 +25,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-stepfunctions-integ/vpc/PublicSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -36,6 +32,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-integ/vpc/PublicSubnet1" } ] } @@ -122,10 +122,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-stepfunctions-integ/vpc/PublicSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -133,6 +129,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-integ/vpc/PublicSubnet2" } ] } @@ -219,10 +219,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": true, "Tags": [ - { - "Key": "Name", - "Value": "aws-stepfunctions-integ/vpc/PublicSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Public" @@ -230,6 +226,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-integ/vpc/PublicSubnet3" } ] } @@ -316,10 +316,6 @@ "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-stepfunctions-integ/vpc/PrivateSubnet1" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -327,6 +323,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-integ/vpc/PrivateSubnet1" } ] } @@ -378,10 +378,6 @@ "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-stepfunctions-integ/vpc/PrivateSubnet2" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -389,6 +385,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-integ/vpc/PrivateSubnet2" } ] } @@ -440,10 +440,6 @@ "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": false, "Tags": [ - { - "Key": "Name", - "Value": "aws-stepfunctions-integ/vpc/PrivateSubnet3" - }, { "Key": "aws-cdk:subnet-name", "Value": "Private" @@ -451,6 +447,10 @@ { "Key": "aws-cdk:subnet-type", "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-integ/vpc/PrivateSubnet3" } ] } diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/evaluate-expression.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/evaluate-expression.test.ts index e7282101253c0..d1235d66a16aa 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/evaluate-expression.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/evaluate-expression.test.ts @@ -43,11 +43,32 @@ test('Eval with Node.js', () => { }); }); -test('Throws when expression does not contain paths', () => { +test('expression does not contain paths', () => { // WHEN - expect(() => new sfn.Task(stack, 'Task', { + const task = new sfn.Task(stack, 'Task', { task: new tasks.EvaluateExpression({ expression: '2 + 2', }), - })).toThrow(/No paths found in expression/); + }); + new sfn.StateMachine(stack, 'SM', { + definition: task, + }); + + expect(stack).toHaveResource('AWS::StepFunctions::StateMachine', { + DefinitionString: { + 'Fn::Join': [ + '', + [ + '{"StartAt":"Task","States":{"Task":{"End":true,"Parameters":{"expression":"2 + 2",\"expressionAttributeValues\":{}},"Type":"Task","Resource":"', + { + 'Fn::GetAtt': [ + 'Evala0d2ce44871b4e7487a1f5e63d7c3bdc4DAC06E1', + 'Arn', + ], + }, + '"}}}', + ], + ], + }, + }); }); diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.evaluate-expression.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.evaluate-expression.expected.json index fb167ce67da6e..14b88ea6e252c 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.evaluate-expression.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.evaluate-expression.expected.json @@ -160,7 +160,14 @@ "Arn" ] }, - "\",\"ResultPath\":\"$.waitSeconds\"},\"Wait\":{\"Type\":\"Wait\",\"SecondsPath\":\"$.waitSeconds\",\"End\":true}}}" + "\",\"ResultPath\":\"$.d\"},\"Wait\":{\"Type\":\"Wait\",\"SecondsPath\":\"$.d\",\"Next\":\"Now\"},\"Now\":{\"End\":true,\"Parameters\":{\"expression\":\"(new Date()).toUTCString()\",\"expressionAttributeValues\":{}},\"Type\":\"Task\",\"Resource\":\"", + { + "Fn::GetAtt": [ + "Evala0d2ce44871b4e7487a1f5e63d7c3bdc4DAC06E1", + "Arn" + ] + }, + "\",\"ResultPath\":\"$.now\"}}}" ] ] }, @@ -190,5 +197,12 @@ "Type": "String", "Description": "Artifact hash for asset \"26ff0ffbfcb72e0fa136547addc06082857c59c734b1dd8c4294b58f03f1d26c\"" } + }, + "Outputs": { + "StateMachineARN": { + "Value": { + "Ref": "StateMachine2E01A3A5" + } + } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.evaluate-expression.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.evaluate-expression.ts index 03f6f06a918ce..0dac6789aeb7c 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.evaluate-expression.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.evaluate-expression.ts @@ -2,6 +2,13 @@ import * as sfn from '@aws-cdk/aws-stepfunctions'; import * as cdk from '@aws-cdk/core'; import * as tasks from '../lib'; +/* + * Stack verification steps: + * * aws stepfunctions start-execution --input '{"a": 3, "b": 4}' --state-machine-arn + * * aws stepfunctions describe-execution --execution-arn + * * The output here should contain `status: "SUCCEEDED"` and `output: "{ a: 3, b: 4, c: 7, d: 14, now: }" + */ + const app = new cdk.App(); const stack = new cdk.Stack(app, 'aws-stepfunctions-integ'); @@ -16,15 +23,27 @@ const multiply = new sfn.Task(stack, 'Multiply', { task: new tasks.EvaluateExpression({ expression: '$.c * 2', }), - resultPath: '$.waitSeconds', + resultPath: '$.d', }); -new sfn.StateMachine(stack, 'StateMachine', { +const now = new sfn.Task(stack, 'Now', { + task: new tasks.EvaluateExpression({ + expression: '(new Date()).toUTCString()', + }), + resultPath: '$.now', +}); + +const statemachine = new sfn.StateMachine(stack, 'StateMachine', { definition: sum .next(multiply) .next(new sfn.Wait(stack, 'Wait', { - time: sfn.WaitTime.secondsPath('$.waitSeconds'), - })), + time: sfn.WaitTime.secondsPath('$.d'), + })) + .next(now), +}); + +new cdk.CfnOutput(stack, 'StateMachineARN', { + value: statemachine.stateMachineArn, }); app.synth(); diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.start-execution.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.start-execution.expected.json new file mode 100644 index 0000000000000..40010a8634abe --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.start-execution.expected.json @@ -0,0 +1,205 @@ +{ + "Resources": { + "ChildRole1E3E0EF5": { + "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" + } + } + }, + "ChildDAB30558": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "DefinitionString": "{\"StartAt\":\"Pass\",\"States\":{\"Pass\":{\"Type\":\"Pass\",\"End\":true}}}", + "RoleArn": { + "Fn::GetAtt": [ + "ChildRole1E3E0EF5", + "Arn" + ] + } + }, + "DependsOn": [ + "ChildRole1E3E0EF5" + ] + }, + "ParentRole5F0C366C": { + "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" + } + } + }, + "ParentRoleDefaultPolicy9BDC56DC": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Effect": "Allow", + "Resource": { + "Ref": "ChildDAB30558" + } + }, + { + "Action": [ + "states:DescribeExecution", + "states:StopExecution" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":states:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":execution:", + { + "Fn::Select": [ + 6, + { + "Fn::Split": [ + ":", + { + "Ref": "ChildDAB30558" + } + ] + } + ] + }, + "*" + ] + ] + } + }, + { + "Action": [ + "events:PutTargets", + "events:PutRule", + "events:DescribeRule" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":events:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":rule/StepFunctionsGetEventsForStepFunctionsExecutionRule" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "ParentRoleDefaultPolicy9BDC56DC", + "Roles": [ + { + "Ref": "ParentRole5F0C366C" + } + ] + } + }, + "Parent8B210403": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "DefinitionString": { + "Fn::Join": [ + "", + [ + "{\"StartAt\":\"Task\",\"States\":{\"Task\":{\"End\":true,\"Parameters\":{\"Input\":{\"hello.$\":\"$.hello\"},\"StateMachineArn\":\"", + { + "Ref": "ChildDAB30558" + }, + "\"},\"Type\":\"Task\",\"Resource\":\"arn:", + { + "Ref": "AWS::Partition" + }, + ":states:::states:startExecution.sync\"}}}" + ] + ] + }, + "RoleArn": { + "Fn::GetAtt": [ + "ParentRole5F0C366C", + "Arn" + ] + } + }, + "DependsOn": [ + "ParentRoleDefaultPolicy9BDC56DC", + "ParentRole5F0C366C" + ] + } + }, + "Outputs": { + "StateMachineARN": { + "Value": { + "Ref": "Parent8B210403" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.start-execution.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.start-execution.ts new file mode 100644 index 0000000000000..8624c601f8c83 --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.start-execution.ts @@ -0,0 +1,41 @@ +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import { App, CfnOutput, Construct, Stack } from '@aws-cdk/core'; +import * as tasks from '../lib'; + +/* + * Stack verification steps: + * * aws stepfunctions start-execution --input '{"hello": "world"}' --state-machine-arn + * * aws stepfunctions describe-execution --execution-arn + * * The output here should contain `status: "SUCCEEDED"` and `output:"{...\"Output\":\"{\\\"hello\\\":\\\"world\\\"}\"...}"` + */ + +class TestStack extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + const child = new sfn.StateMachine(this, 'Child', { + definition: new sfn.Pass(this, 'Pass'), + }); + + const parent = new sfn.StateMachine(this, 'Parent', { + definition: new sfn.Task(this, 'Task', { + task: new tasks.StartExecution(child, { + input: { + hello: sfn.Data.stringAt('$.hello'), + }, + integrationPattern: sfn.ServiceIntegrationPattern.SYNC, + }), + }), + }); + + new CfnOutput(this, 'StateMachineARN', { + value: parent.stateMachineArn, + }); + } +} + +const app = new App(); + +new TestStack(app, 'integ-sfn-start-execution'); + +app.synth(); diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/start-execution.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/start-execution.test.ts index 05d62f56e7836..5d1ef3171debc 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/start-execution.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/start-execution.test.ts @@ -85,6 +85,95 @@ test('Execute State Machine - Sync', () => { }, }, }); + + expect(stack).toHaveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: 'states:StartExecution', + Effect: 'Allow', + Resource: { + Ref: 'ChildStateMachine9133117F', + }, + }, + { + Action: [ + 'states:DescribeExecution', + 'states:StopExecution', + ], + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':execution:', + { + 'Fn::Select': [ + 6, + { + 'Fn::Split': [ + ':', + { + Ref: 'ChildStateMachine9133117F', + }, + ], + }, + ], + }, + '*', + ], + ], + }, + }, + { + Action: [ + 'events:PutTargets', + 'events:PutRule', + 'events:DescribeRule', + ], + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':events:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':rule/StepFunctionsGetEventsForStepFunctionsExecutionRule', + ], + ], + }, + }, + ], + Version: '2012-10-17', + }, + Roles: [ + { + Ref: 'ParentStateMachineRoleE902D002', + }, + ], + }); }); test('Execute State Machine - Wait For Task Token', () => { diff --git a/packages/@aws-cdk/aws-stepfunctions/.eslintrc.js b/packages/@aws-cdk/aws-stepfunctions/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-stepfunctions/.eslintrc.js +++ b/packages/@aws-cdk/aws-stepfunctions/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-stepfunctions/.gitignore b/packages/@aws-cdk/aws-stepfunctions/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-stepfunctions/.gitignore +++ b/packages/@aws-cdk/aws-stepfunctions/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-stepfunctions/.npmignore b/packages/@aws-cdk/aws-stepfunctions/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-stepfunctions/.npmignore +++ b/packages/@aws-cdk/aws-stepfunctions/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-stepfunctions/jest.config.js b/packages/@aws-cdk/aws-stepfunctions/jest.config.js new file mode 100644 index 0000000000000..d984ff822379b --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions/jest.config.js @@ -0,0 +1,10 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = { + ...baseConfig, + coverageThreshold: { + global: { + ...baseConfig.coverageThreshold.global, + branches: 75, + }, + }, +}; diff --git a/packages/@aws-cdk/aws-stepfunctions/package.json b/packages/@aws-cdk/aws-stepfunctions/package.json index 2f8123ac4aea9..bae715668bf4b 100644 --- a/packages/@aws-cdk/aws-stepfunctions/package.json +++ b/packages/@aws-cdk/aws-stepfunctions/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::StepFunctions" + "cloudformation": "AWS::StepFunctions", + "jest": true }, "keywords": [ "aws", @@ -85,16 +86,8 @@ "@aws-cdk/core": "0.0.0", "constructs": "^3.0.2" }, - "jest": { - "coverageThreshold": { - "global": { - "branches": 75, - "statements": 80 - } - } - }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-synthetics/.eslintrc.js b/packages/@aws-cdk/aws-synthetics/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-synthetics/.eslintrc.js +++ b/packages/@aws-cdk/aws-synthetics/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-synthetics/.gitignore b/packages/@aws-cdk/aws-synthetics/.gitignore index 1d72e2af4beb4..e9fee23607e76 100644 --- a/packages/@aws-cdk/aws-synthetics/.gitignore +++ b/packages/@aws-cdk/aws-synthetics/.gitignore @@ -16,3 +16,4 @@ coverage *.snk nyc.config.js !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-synthetics/.npmignore b/packages/@aws-cdk/aws-synthetics/.npmignore index 36d0f522c8ab1..90dc55901a24e 100644 --- a/packages/@aws-cdk/aws-synthetics/.npmignore +++ b/packages/@aws-cdk/aws-synthetics/.npmignore @@ -19,4 +19,5 @@ dist tsconfig.json -.eslintrc.js \ No newline at end of file +.eslintrc.js +jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-synthetics/jest.config.js b/packages/@aws-cdk/aws-synthetics/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-synthetics/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-synthetics/package.json b/packages/@aws-cdk/aws-synthetics/package.json index ed0e3a2bc3d8e..b553ad1e05325 100644 --- a/packages/@aws-cdk/aws-synthetics/package.json +++ b/packages/@aws-cdk/aws-synthetics/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::Synthetics" + "cloudformation": "AWS::Synthetics", + "jest": true }, "keywords": [ "aws", @@ -62,7 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": {}, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -77,7 +77,7 @@ "@aws-cdk/core": "0.0.0" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-transfer/.eslintrc.js b/packages/@aws-cdk/aws-transfer/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-transfer/.eslintrc.js +++ b/packages/@aws-cdk/aws-transfer/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-transfer/.gitignore b/packages/@aws-cdk/aws-transfer/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-transfer/.gitignore +++ b/packages/@aws-cdk/aws-transfer/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-transfer/.npmignore b/packages/@aws-cdk/aws-transfer/.npmignore index 6b86843be50f7..d04d75fba5945 100644 --- a/packages/@aws-cdk/aws-transfer/.npmignore +++ b/packages/@aws-cdk/aws-transfer/.npmignore @@ -22,3 +22,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-transfer/jest.config.js b/packages/@aws-cdk/aws-transfer/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-transfer/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-transfer/package.json b/packages/@aws-cdk/aws-transfer/package.json index 9804b1da90d57..e791a0ebd8e77 100644 --- a/packages/@aws-cdk/aws-transfer/package.json +++ b/packages/@aws-cdk/aws-transfer/package.json @@ -48,7 +48,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::Transfer" + "cloudformation": "AWS::Transfer", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -95,7 +79,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-waf/.eslintrc.js b/packages/@aws-cdk/aws-waf/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-waf/.eslintrc.js +++ b/packages/@aws-cdk/aws-waf/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-waf/.gitignore b/packages/@aws-cdk/aws-waf/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-waf/.gitignore +++ b/packages/@aws-cdk/aws-waf/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-waf/.npmignore b/packages/@aws-cdk/aws-waf/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-waf/.npmignore +++ b/packages/@aws-cdk/aws-waf/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-waf/jest.config.js b/packages/@aws-cdk/aws-waf/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-waf/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-waf/package.json b/packages/@aws-cdk/aws-waf/package.json index 87c7f684dde88..2489e5da4104b 100644 --- a/packages/@aws-cdk/aws-waf/package.json +++ b/packages/@aws-cdk/aws-waf/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::WAF" + "cloudformation": "AWS::WAF", + "jest": true }, "keywords": [ "aws", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-wafregional/.eslintrc.js b/packages/@aws-cdk/aws-wafregional/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-wafregional/.eslintrc.js +++ b/packages/@aws-cdk/aws-wafregional/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-wafregional/.gitignore b/packages/@aws-cdk/aws-wafregional/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-wafregional/.gitignore +++ b/packages/@aws-cdk/aws-wafregional/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-wafregional/.npmignore b/packages/@aws-cdk/aws-wafregional/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-wafregional/.npmignore +++ b/packages/@aws-cdk/aws-wafregional/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-wafregional/jest.config.js b/packages/@aws-cdk/aws-wafregional/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-wafregional/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-wafregional/package.json b/packages/@aws-cdk/aws-wafregional/package.json index 5d5cfc8cdee0b..0487d24933b0e 100644 --- a/packages/@aws-cdk/aws-wafregional/package.json +++ b/packages/@aws-cdk/aws-wafregional/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::WAFRegional" + "cloudformation": "AWS::WAFRegional", + "jest": true }, "keywords": [ "aws", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-wafv2/.eslintrc.js b/packages/@aws-cdk/aws-wafv2/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-wafv2/.eslintrc.js +++ b/packages/@aws-cdk/aws-wafv2/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-wafv2/.gitignore b/packages/@aws-cdk/aws-wafv2/.gitignore index d5c0c2743f469..94c80a5f08e4a 100644 --- a/packages/@aws-cdk/aws-wafv2/.gitignore +++ b/packages/@aws-cdk/aws-wafv2/.gitignore @@ -12,3 +12,4 @@ coverage dist tsconfig.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-wafv2/.npmignore b/packages/@aws-cdk/aws-wafv2/.npmignore index d4f7bff69bdab..8ac959aca8fa5 100644 --- a/packages/@aws-cdk/aws-wafv2/.npmignore +++ b/packages/@aws-cdk/aws-wafv2/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json !.jsii .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-wafv2/jest.config.js b/packages/@aws-cdk/aws-wafv2/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-wafv2/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-wafv2/package.json b/packages/@aws-cdk/aws-wafv2/package.json index 71ae4ceb62a0e..751545a948b45 100644 --- a/packages/@aws-cdk/aws-wafv2/package.json +++ b/packages/@aws-cdk/aws-wafv2/package.json @@ -48,7 +48,8 @@ "build+test+package": "npm run build+test && npm run package" }, "cdk-build": { - "cloudformation": "AWS::WAFv2" + "cloudformation": "AWS::WAFv2", + "jest": true }, "keywords": [ "aws", @@ -62,23 +63,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -95,7 +79,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/aws-workspaces/.eslintrc.js b/packages/@aws-cdk/aws-workspaces/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/aws-workspaces/.eslintrc.js +++ b/packages/@aws-cdk/aws-workspaces/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-workspaces/.gitignore b/packages/@aws-cdk/aws-workspaces/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/aws-workspaces/.gitignore +++ b/packages/@aws-cdk/aws-workspaces/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/aws-workspaces/.npmignore b/packages/@aws-cdk/aws-workspaces/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/aws-workspaces/.npmignore +++ b/packages/@aws-cdk/aws-workspaces/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/aws-workspaces/jest.config.js b/packages/@aws-cdk/aws-workspaces/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-workspaces/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-workspaces/package.json b/packages/@aws-cdk/aws-workspaces/package.json index 491586d4c3f78..c031eddc57e37 100644 --- a/packages/@aws-cdk/aws-workspaces/package.json +++ b/packages/@aws-cdk/aws-workspaces/package.json @@ -47,7 +47,8 @@ "compat": "cdk-compat" }, "cdk-build": { - "cloudformation": "AWS::WorkSpaces" + "cloudformation": "AWS::WorkSpaces", + "jest": true }, "keywords": [ "aws", @@ -60,23 +61,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 60, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", @@ -94,7 +78,7 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "cfn-only", diff --git a/packages/@aws-cdk/cdk-assets-schema/.eslintrc.js b/packages/@aws-cdk/cdk-assets-schema/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/cdk-assets-schema/.eslintrc.js +++ b/packages/@aws-cdk/cdk-assets-schema/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/cdk-assets-schema/.gitignore b/packages/@aws-cdk/cdk-assets-schema/.gitignore index fc15e37f1cfdb..9c86e7fa0fe0b 100644 --- a/packages/@aws-cdk/cdk-assets-schema/.gitignore +++ b/packages/@aws-cdk/cdk-assets-schema/.gitignore @@ -13,3 +13,4 @@ tsconfig.json coverage nyc.config.js !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/cdk-assets-schema/.npmignore b/packages/@aws-cdk/cdk-assets-schema/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/cdk-assets-schema/.npmignore +++ b/packages/@aws-cdk/cdk-assets-schema/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/cdk-assets-schema/jest.config.js b/packages/@aws-cdk/cdk-assets-schema/jest.config.js new file mode 100644 index 0000000000000..c68c147dd5514 --- /dev/null +++ b/packages/@aws-cdk/cdk-assets-schema/jest.config.js @@ -0,0 +1,10 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = { + ...baseConfig, + coverageThreshold: { + global: { + ...baseConfig.coverageThreshold.global, + branches: 70, + }, + }, +}; diff --git a/packages/@aws-cdk/cdk-assets-schema/lib/aws-destination.ts b/packages/@aws-cdk/cdk-assets-schema/lib/aws-destination.ts index e4b00ed4d308d..f419fde03c56d 100644 --- a/packages/@aws-cdk/cdk-assets-schema/lib/aws-destination.ts +++ b/packages/@aws-cdk/cdk-assets-schema/lib/aws-destination.ts @@ -22,24 +22,4 @@ export interface AwsDestination { * @default - No ExternalId will be supplied */ readonly assumeRoleExternalId?: string; -} - -/** - * Placeholders which can be used in the destinations - */ -export class Placeholders { - /** - * Insert this into the destination fields to be replaced with the current region - */ - public static readonly CURRENT_REGION = '${AWS::Region}'; - - /** - * Insert this into the destination fields to be replaced with the current account - */ - public static readonly CURRENT_ACCOUNT = '${AWS::AccountId}'; - - /** - * Insert this into the destination fields to be replaced with the current partition - */ - public static readonly CURRENT_PARTITION = '${AWS::Partition}'; } \ No newline at end of file diff --git a/packages/@aws-cdk/cdk-assets-schema/package.json b/packages/@aws-cdk/cdk-assets-schema/package.json index 3f76d1fe902da..e22d82cab94bc 100644 --- a/packages/@aws-cdk/cdk-assets-schema/package.json +++ b/packages/@aws-cdk/cdk-assets-schema/package.json @@ -47,26 +47,9 @@ "dependencies": { "semver": "^7.2.2" }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 70, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^25.2.1", + "@types/jest": "^25.2.2", "cdk-build-tools": "0.0.0", "jest": "^25.5.4", "pkglint": "0.0.0" @@ -85,11 +68,14 @@ "semver" ], "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "stable", "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "cdk-build": { + "jest": true + } } diff --git a/packages/@aws-cdk/cfnspec/.eslintrc.js b/packages/@aws-cdk/cfnspec/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/cfnspec/.eslintrc.js +++ b/packages/@aws-cdk/cfnspec/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts b/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts index 92700785c14b5..64ba6ae0e26d1 100644 --- a/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts +++ b/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts @@ -150,6 +150,7 @@ async function main() { }, 'cdk-build': { cloudformation: namespace, + jest: true, }, keywords: [ 'aws', @@ -163,7 +164,6 @@ async function main() { url: 'https://aws.amazon.com', organization: true, }, - jest: {}, license: 'Apache-2.0', devDependencies: { '@aws-cdk/assert': version, @@ -178,7 +178,7 @@ async function main() { '@aws-cdk/core': version, }, engines: { - node: '>= 10.13.0', + node: '>= 10.13.0 <13 || >=13.7.0', }, stability: 'experimental', maturity: 'cfn-only', @@ -206,6 +206,7 @@ async function main() { '*.snk', 'nyc.config.js', '!.eslintrc.js', + '!jest.config.js', ]); await write('.npmignore', [ @@ -231,6 +232,7 @@ async function main() { 'tsconfig.json', '', '.eslintrc.js', + 'jest.config.js', ]); await write('lib/index.ts', [ @@ -268,6 +270,12 @@ async function main() { await write('.eslintrc.js', [ "const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc');", + "baseConfig.parserOptions.project = __dirname + '/tsconfig.json';", + 'module.exports = baseConfig;', + ]); + + await write('jest.config.js', [ + "const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config');", 'module.exports = baseConfig;', ]); diff --git a/packages/@aws-cdk/cfnspec/package.json b/packages/@aws-cdk/cfnspec/package.json index 4eb4d75908877..c5eeee5a7b837 100644 --- a/packages/@aws-cdk/cfnspec/package.json +++ b/packages/@aws-cdk/cfnspec/package.json @@ -24,7 +24,7 @@ "devDependencies": { "@types/fs-extra": "^8.1.0", "@types/md5": "^2.2.0", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "fast-json-patch": "^2.2.1", "fs-extra": "^8.1.0", diff --git a/packages/@aws-cdk/cfnspec/spec-source/500_IoT1Click_patch_PlacementTemplate_DeviceTemplates.json b/packages/@aws-cdk/cfnspec/spec-source/500_IoT1Click_patch_PlacementTemplate_DeviceTemplates.json index 187c45d921bb6..d74af21e9eb52 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/500_IoT1Click_patch_PlacementTemplate_DeviceTemplates.json +++ b/packages/@aws-cdk/cfnspec/spec-source/500_IoT1Click_patch_PlacementTemplate_DeviceTemplates.json @@ -10,10 +10,15 @@ { "op": "add", "path": "/Properties/DeviceTemplates/Type", + "value": "Map" + }, + { + "op": "add", + "path": "/Properties/DeviceTemplates/ItemType", "value": "DeviceTemplate" } ], - "description": "Set type of AWS::IoT1Click::Project.PlacementTemplate.DeviceTemplates to AWS::IoT1Click::Project.DeviceTemplate" + "description": "Set type of AWS::IoT1Click::Project.PlacementTemplate.DeviceTemplates to Map" } } } diff --git a/packages/@aws-cdk/cloud-assembly-schema/.eslintrc.js b/packages/@aws-cdk/cloud-assembly-schema/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/.eslintrc.js +++ b/packages/@aws-cdk/cloud-assembly-schema/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/cloud-assembly-schema/.gitignore b/packages/@aws-cdk/cloud-assembly-schema/.gitignore index 9ee85430fbdf2..072151f41441c 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/.gitignore +++ b/packages/@aws-cdk/cloud-assembly-schema/.gitignore @@ -16,3 +16,4 @@ tslint.json coverage nyc.config.js !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/cloud-assembly-schema/.npmignore b/packages/@aws-cdk/cloud-assembly-schema/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/.npmignore +++ b/packages/@aws-cdk/cloud-assembly-schema/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/cloud-assembly-schema/jest.config.js b/packages/@aws-cdk/cloud-assembly-schema/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/cloud-assembly-schema/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/artifact-schema.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/artifact-schema.ts new file mode 100644 index 0000000000000..866a1a6553c38 --- /dev/null +++ b/packages/@aws-cdk/cloud-assembly-schema/lib/artifact-schema.ts @@ -0,0 +1,90 @@ + +/** + * Artifact properties for CloudFormation stacks. + */ +export interface AwsCloudFormationStackProperties { + /** + * A file relative to the assembly root which contains the CloudFormation template for this stack. + */ + readonly templateFile: string; + + /** + * Values for CloudFormation stack parameters that should be passed when the stack is deployed. + * + * @default - No parameters + */ + readonly parameters?: { [id: string]: string }; + + /** + * The name to use for the CloudFormation stack. + * @default - name derived from artifact ID + */ + readonly stackName?: string; + + /** + * Whether to enable termination protection for this stack. + * + * @default false + */ + readonly terminationProtection?: boolean; + + /** + * The role that needs to be assumed to deploy the stack + * + * @default - No role is assumed (current credentials are used) + */ + readonly assumeRoleArn?: string; + + /** + * The role that is passed to CloudFormation to execute the change set + * + * @default - No role is passed (currently assumed role/credentials are used) + */ + readonly cloudFormationExecutionRoleArn?: string; + + /** + * If the stack template has already been included in the asset manifest, its asset URL + * + * @default - Not uploaded yet, upload just before deploying + */ + readonly stackTemplateAssetObjectUrl?: string; + + /** + * Version of bootstrap stack required to deploy this stack + * + * @default - No bootstrap stack required + */ + readonly requiresBootstrapStackVersion?: number; +} + +/** + * Artifact properties for the Asset Manifest + */ +export interface AssetManifestProperties { + /** + * Filename of the asset manifest + */ + readonly file: string; + + /** + * Version of bootstrap stack required to deploy this stack + * + * @default - Version 1 (basic modern bootstrap stack) + */ + readonly requiresBootstrapStackVersion?: number; +} + +/** + * Artifact properties for the Construct Tree Artifact + */ +export interface TreeArtifactProperties { + /** + * Filename of the tree artifact + */ + readonly file: string; +} + +/** + * Properties for manifest artifacts + */ +export type ArtifactProperties = AwsCloudFormationStackProperties | AssetManifestProperties | TreeArtifactProperties; \ No newline at end of file diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/context-queries.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/context-queries.ts index 88932e117ffa3..f2d11b76eac39 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/lib/context-queries.ts +++ b/packages/@aws-cdk/cloud-assembly-schema/lib/context-queries.ts @@ -27,6 +27,12 @@ export enum ContextProvider { * VPC Provider */ VPC_PROVIDER = 'vpc-provider', + + /** + * VPC Endpoint Service AZ Provider + */ + ENDPOINT_SERVICE_AVAILABILITY_ZONE_PROVIDER = 'endpoint-service-availability-zones', + } /** @@ -170,8 +176,29 @@ export interface VpcContextQuery { readonly subnetGroupNameTag?: string; } +/** + * Query to endpoint service context provider + */ +export interface EndpointServiceAvailabilityZonesContextQuery { + /** + * Query account + */ + readonly account: string; + + /** + * Query region + */ + readonly region: string; + + /** + * Query service name + */ + readonly serviceName: string; +} + export type ContextQueryProperties = AmiContextQuery | AvailabilityZonesContextQuery | HostedZoneContextQuery | SSMParameterContextQuery -| VpcContextQuery; +| VpcContextQuery +| EndpointServiceAvailabilityZonesContextQuery; diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/index.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/index.ts index 746eaa2ffb2ce..e9e9aa6a5863d 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/lib/index.ts +++ b/packages/@aws-cdk/cloud-assembly-schema/lib/index.ts @@ -1,3 +1,5 @@ export * from './manifest'; export * from './schema'; +export * from './metadata-schema'; +export * from './artifact-schema'; export * from './context-queries'; diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/manifest.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/manifest.ts index caa08bff0d01d..17b53ca499a50 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/lib/manifest.ts +++ b/packages/@aws-cdk/cloud-assembly-schema/lib/manifest.ts @@ -1,6 +1,7 @@ import * as fs from 'fs'; import * as jsonschema from 'jsonschema'; import * as semver from 'semver'; +import { ArtifactMetadataEntryType } from './metadata-schema'; import * as assembly from './schema'; // this prefix is used by the CLI to identify this specific error. @@ -100,7 +101,7 @@ export class Manifest { if (artifact.type === assembly.ArtifactType.AWS_CLOUDFORMATION_STACK) { for (const metadataEntries of Object.values(artifact.metadata || [])) { for (const metadataEntry of metadataEntries) { - if (metadataEntry.type === assembly.ArtifactMetadataEntryType.STACK_TAGS && metadataEntry.data) { + if (metadataEntry.type === ArtifactMetadataEntryType.STACK_TAGS && metadataEntry.data) { const metadataAny = metadataEntry as any; diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/metadata-schema.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/metadata-schema.ts new file mode 100644 index 0000000000000..54cabf83554fc --- /dev/null +++ b/packages/@aws-cdk/cloud-assembly-schema/lib/metadata-schema.ts @@ -0,0 +1,215 @@ +/** + * Common properties for asset metadata. + */ +interface BaseAssetMetadataEntry { + /** + * Requested packaging style + */ + readonly packaging: string; + + /** + * Logical identifier for the asset + */ + readonly id: string; + + /** + * The hash of the asset source. + */ + readonly sourceHash: string; + + /** + * Path on disk to the asset + */ + readonly path: string; +} + +/** + * Metadata Entry spec for files. + */ +export interface FileAssetMetadataEntry extends BaseAssetMetadataEntry { + /** + * Requested packaging style + */ + readonly packaging: 'zip' | 'file'; + + /** + * Name of parameter where S3 bucket should be passed in + */ + readonly s3BucketParameter: string; + + /** + * Name of parameter where S3 key should be passed in + */ + readonly s3KeyParameter: string; + + /** + * The name of the parameter where the hash of the bundled asset should be passed in. + */ + readonly artifactHashParameter: string; +} + +/** + * Metadata Entry spec for stack tag. + */ +export interface Tag { + /** + * Tag key. + */ + readonly key: string + + /** + * Tag value. + */ + readonly value: string +} + +/** + * Metadata Entry spec for container images. + */ +export interface ContainerImageAssetMetadataEntry extends BaseAssetMetadataEntry { + /** + * Type of asset + */ + readonly packaging: 'container-image'; + + /** + * ECR Repository name and repo digest (separated by "@sha256:") where this + * image is stored. + * + * @default undefined If not specified, `repositoryName` and `imageTag` are + * required because otherwise how will the stack know where to find the asset, + * ha? + * @deprecated specify `repositoryName` and `imageTag` instead, and then you + * know where the image will go. + */ + readonly imageNameParameter?: string; + + /** + * ECR repository name, if omitted a default name based on the asset's ID is + * used instead. Specify this property if you need to statically address the + * image, e.g. from a Kubernetes Pod. Note, this is only the repository name, + * without the registry and the tag parts. + * + * @default - this parameter is REQUIRED after 1.21.0 + */ + readonly repositoryName?: string; + + /** + * The docker image tag to use for tagging pushed images. This field is + * required if `imageParameterName` is ommited (otherwise, the app won't be + * able to find the image). + * + * @default - this parameter is REQUIRED after 1.21.0 + */ + readonly imageTag?: string; + + /** + * Build args to pass to the `docker build` command + * + * @default no build args are passed + */ + readonly buildArgs?: { [key: string]: string }; + + /** + * Docker target to build to + * + * @default no build target + */ + readonly target?: string; + + /** + * Path to the Dockerfile (relative to the directory). + * + * @default - no file is passed + */ + readonly file?: string; +} + +/** + * @see ArtifactMetadataEntryType.ASSET + */ +export type AssetMetadataEntry = FileAssetMetadataEntry | ContainerImageAssetMetadataEntry; + +// Type aliases for metadata entries. +// Used simply to assign names to data types for more clarity. + +/** + * @see ArtifactMetadataEntryType.INFO + * @see ArtifactMetadataEntryType.WARN + * @see ArtifactMetadataEntryType.ERROR + */ +export type LogMessageMetadataEntry = string; + +/** + * @see ArtifactMetadataEntryType.LOGICAL_ID + */ +export type LogicalIdMetadataEntry = string; + +/** + * @see ArtifactMetadataEntryType.STACK_TAGS + */ +export type StackTagsMetadataEntry = Tag[]; + +/** + * Union type for all metadata entries that might exist in the manifest. + */ +export type MetadataEntryData = AssetMetadataEntry | LogMessageMetadataEntry | LogicalIdMetadataEntry | StackTagsMetadataEntry; + +/** + * Type of artifact metadata entry. + */ +export enum ArtifactMetadataEntryType { + /** + * Asset in metadata. + */ + ASSET = 'aws:cdk:asset', + + /** + * Metadata key used to print INFO-level messages by the toolkit when an app is syntheized. + */ + INFO = 'aws:cdk:info', + + /** + * Metadata key used to print WARNING-level messages by the toolkit when an app is syntheized. + */ + WARN = 'aws:cdk:warning', + + /** + * Metadata key used to print ERROR-level messages by the toolkit when an app is syntheized. + */ + ERROR = 'aws:cdk:error', + + /** + * Represents the CloudFormation logical ID of a resource at a certain path. + */ + LOGICAL_ID = 'aws:cdk:logicalId', + + /** + * Represents tags of a stack. + */ + STACK_TAGS = 'aws:cdk:stack-tags' +} + +/** + * A metadata entry in a cloud assembly artifact. + */ +export interface MetadataEntry { + /** + * The type of the metadata entry. + */ + readonly type: string; + + /** + * The data. + * + * @default - no data. + */ + readonly data?: MetadataEntryData; + + /** + * A stack trace for when the entry was created. + * + * @default - no trace. + */ + readonly trace?: string[]; +} diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/schema.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/schema.ts index 3369c16e93b4c..1c4efd0cded5d 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/lib/schema.ts +++ b/packages/@aws-cdk/cloud-assembly-schema/lib/schema.ts @@ -1,196 +1,6 @@ +import { ArtifactProperties } from './artifact-schema'; import { ContextProvider, ContextQueryProperties } from './context-queries'; - -/** - * Common properties for asset metadata. - */ -interface BaseAssetMetadataEntry { - /** - * Requested packaging style - */ - readonly packaging: string; - - /** - * Logical identifier for the asset - */ - readonly id: string; - - /** - * The hash of the asset source. - */ - readonly sourceHash: string; - - /** - * Path on disk to the asset - */ - readonly path: string; -} - -/** - * Metadata Entry spec for files. - */ -export interface FileAssetMetadataEntry extends BaseAssetMetadataEntry { - /** - * Requested packaging style - */ - readonly packaging: 'zip' | 'file'; - - /** - * Name of parameter where S3 bucket should be passed in - */ - readonly s3BucketParameter: string; - - /** - * Name of parameter where S3 key should be passed in - */ - readonly s3KeyParameter: string; - - /** - * The name of the parameter where the hash of the bundled asset should be passed in. - */ - readonly artifactHashParameter: string; -} - -/** - * Metadata Entry spec for container images. - */ -export interface ContainerImageAssetMetadataEntry extends BaseAssetMetadataEntry { - /** - * Type of asset - */ - readonly packaging: 'container-image'; - - /** - * ECR Repository name and repo digest (separated by "@sha256:") where this - * image is stored. - * - * @default undefined If not specified, `repositoryName` and `imageTag` are - * required because otherwise how will the stack know where to find the asset, - * ha? - * @deprecated specify `repositoryName` and `imageTag` instead, and then you - * know where the image will go. - */ - readonly imageNameParameter?: string; - - /** - * ECR repository name, if omitted a default name based on the asset's ID is - * used instead. Specify this property if you need to statically address the - * image, e.g. from a Kubernetes Pod. Note, this is only the repository name, - * without the registry and the tag parts. - * - * @default - this parameter is REQUIRED after 1.21.0 - */ - readonly repositoryName?: string; - - /** - * The docker image tag to use for tagging pushed images. This field is - * required if `imageParameterName` is ommited (otherwise, the app won't be - * able to find the image). - * - * @default - this parameter is REQUIRED after 1.21.0 - */ - readonly imageTag?: string; - - /** - * Build args to pass to the `docker build` command - * - * @default no build args are passed - */ - readonly buildArgs?: { [key: string]: string }; - - /** - * Docker target to build to - * - * @default no build target - */ - readonly target?: string; - - /** - * Path to the Dockerfile (relative to the directory). - * - * @default - no file is passed - */ - readonly file?: string; -} - -/** - * Metadata Entry spec for stack tag. - */ -export interface Tag { - /** - * Tag key. - */ - readonly key: string - - /** - * Tag value. - */ - readonly value: string -} - -/** - * @see ArtifactMetadataEntryType.ASSET - */ -export type AssetMetadataEntry = FileAssetMetadataEntry | ContainerImageAssetMetadataEntry; - -// Type aliases for metadata entries. -// Used simply to assign names to data types for more clearity. - -/** - * @see ArtifactMetadataEntryType.INFO - * @see ArtifactMetadataEntryType.WARN - * @see ArtifactMetadataEntryType.ERROR - */ -export type LogMessageMetadataEntry = string; - -/** - * @see ArtifactMetadataEntryType.LOGICAL_ID - */ -export type LogicalIdMetadataEntry = string; - -/** - * @see ArtifactMetadataEntryType.STACK_TAGS - */ -export type StackTagsMetadataEntry = Tag[]; - -/** - * Union type for all metadata entries that might exist in the manifest. - */ -export type MetadataEntryData = AssetMetadataEntry | LogMessageMetadataEntry | LogicalIdMetadataEntry | StackTagsMetadataEntry; - -/** - * Type of artifact metadata entry. - */ -export enum ArtifactMetadataEntryType { - /** - * Asset in metadata. - */ - ASSET = 'aws:cdk:asset', - - /** - * Metadata key used to print INFO-level messages by the toolkit when an app is syntheized. - */ - INFO = 'aws:cdk:info', - - /** - * Metadata key used to print WARNING-level messages by the toolkit when an app is syntheized. - */ - WARN = 'aws:cdk:warning', - - /** - * Metadata key used to print ERROR-level messages by the toolkit when an app is syntheized. - */ - ERROR = 'aws:cdk:error', - - /** - * Represents the CloudFormation logical ID of a resource at a certain path. - */ - LOGICAL_ID = 'aws:cdk:logicalId', - - /** - * Represents tags of a stack. - */ - STACK_TAGS = 'aws:cdk:stack-tags' -} +import { MetadataEntry } from './metadata-schema'; /** * Type of cloud artifact. @@ -210,30 +20,11 @@ export enum ArtifactType { * The artifact contains the CDK application's construct tree. */ CDK_TREE = 'cdk:tree', -} - -/** - * A metadata entry in a cloud assembly artifact. - */ -export interface MetadataEntry { - /** - * The type of the metadata entry. - */ - readonly type: string; /** - * The data. - * - * @default - no data. - */ - readonly data?: MetadataEntryData; - - /** - * A stack trace for when the entry was created. - * - * @default - no trace. + * Manifest for all assets in the Cloud Assembly */ - readonly trace?: string[]; + ASSET_MANIFEST = 'cdk:asset-manifest', } /** @@ -301,7 +92,7 @@ export interface ArtifactManifest { * * @default - no properties. */ - readonly properties?: { [name: string]: any }; + readonly properties?: ArtifactProperties; } /** diff --git a/packages/@aws-cdk/cloud-assembly-schema/package.json b/packages/@aws-cdk/cloud-assembly-schema/package.json index 41ba167cc1111..7565c1062f3cc 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/package.json +++ b/packages/@aws-cdk/cloud-assembly-schema/package.json @@ -45,10 +45,9 @@ "url": "https://aws.amazon.com", "organization": true }, - "jest": {}, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^25.2.1", + "@types/jest": "^25.2.2", "@types/mock-fs": "^4.10.0", "cdk-build-tools": "0.0.0", "jest": "^25.5.4", @@ -71,7 +70,7 @@ "semver" ], "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "stable", "awslint": { @@ -84,5 +83,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "cdk-build": { + "jest": true + } } diff --git a/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.schema.json b/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.schema.json index 885af9359b4d4..73319145f8196 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.schema.json +++ b/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.schema.json @@ -63,8 +63,17 @@ }, "properties": { "description": "The set of properties for this artifact (depends on type) (Default - no properties.)", - "type": "object", - "additionalProperties": {} + "anyOf": [ + { + "$ref": "#/definitions/AwsCloudFormationStackProperties" + }, + { + "$ref": "#/definitions/AssetManifestProperties" + }, + { + "$ref": "#/definitions/TreeArtifactProperties" + } + ] } }, "required": [ @@ -75,6 +84,7 @@ "description": "Type of cloud artifact.", "enum": [ "aws:cloudformation:stack", + "cdk:asset-manifest", "cdk:tree", "none" ], @@ -246,6 +256,81 @@ "value" ] }, + "AwsCloudFormationStackProperties": { + "description": "Artifact properties for CloudFormation stacks.", + "type": "object", + "properties": { + "templateFile": { + "description": "A file relative to the assembly root which contains the CloudFormation template for this stack.", + "type": "string" + }, + "parameters": { + "description": "Values for CloudFormation stack parameters that should be passed when the stack is deployed. (Default - No parameters)", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "stackName": { + "description": "The name to use for the CloudFormation stack. (Default - name derived from artifact ID)", + "type": "string" + }, + "terminationProtection": { + "description": "Whether to enable termination protection for this stack.", + "default": false, + "type": "boolean" + }, + "assumeRoleArn": { + "description": "The role that needs to be assumed to deploy the stack (Default - No role is assumed (current credentials are used))", + "type": "string" + }, + "cloudFormationExecutionRoleArn": { + "description": "The role that is passed to CloudFormation to execute the change set (Default - No role is passed (currently assumed role/credentials are used))", + "type": "string" + }, + "stackTemplateAssetObjectUrl": { + "description": "If the stack template has already been included in the asset manifest, its asset URL (Default - Not uploaded yet, upload just before deploying)", + "type": "string" + }, + "requiresBootstrapStackVersion": { + "description": "Version of bootstrap stack required to deploy this stack (Default - No bootstrap stack required)", + "type": "number" + } + }, + "required": [ + "templateFile" + ] + }, + "AssetManifestProperties": { + "description": "Artifact properties for the Asset Manifest", + "type": "object", + "properties": { + "file": { + "description": "Filename of the asset manifest", + "type": "string" + }, + "requiresBootstrapStackVersion": { + "description": "Version of bootstrap stack required to deploy this stack (Default - Version 1 (basic modern bootstrap stack))", + "type": "number" + } + }, + "required": [ + "file" + ] + }, + "TreeArtifactProperties": { + "description": "Artifact properties for the Construct Tree Artifact", + "type": "object", + "properties": { + "file": { + "description": "Filename of the tree artifact", + "type": "string" + } + }, + "required": [ + "file" + ] + }, "MissingContext": { "description": "Represents a missing piece of context.", "type": "object", @@ -275,6 +360,9 @@ }, { "$ref": "#/definitions/VpcContextQuery" + }, + { + "$ref": "#/definitions/EndpointServiceAvailabilityZonesContextQuery" } ] } @@ -290,6 +378,7 @@ "enum": [ "ami", "availability-zones", + "endpoint-service-availability-zones", "hosted-zone", "ssm", "vpc-provider" @@ -333,7 +422,7 @@ ] }, "AvailabilityZonesContextQuery": { - "description": "Query to hosted zone context provider", + "description": "Query to availability zone context provider", "type": "object", "properties": { "account": { @@ -383,7 +472,7 @@ ] }, "SSMParameterContextQuery": { - "description": "Query to hosted zone context provider", + "description": "Query to SSM Parameter Context Provider", "type": "object", "properties": { "account": { @@ -440,6 +529,29 @@ "region" ] }, + "EndpointServiceAvailabilityZonesContextQuery": { + "description": "Query to endpoint service context provider", + "type": "object", + "properties": { + "account": { + "description": "Query account", + "type": "string" + }, + "region": { + "description": "Query region", + "type": "string" + }, + "serviceName": { + "description": "Query service name", + "type": "string" + } + }, + "required": [ + "account", + "region", + "serviceName" + ] + }, "RuntimeInfo": { "description": "Information about the application's runtime components.", "type": "object", diff --git a/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.version.json b/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.version.json index b0616139cced7..a1ac22091a50e 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.version.json +++ b/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.version.json @@ -1 +1 @@ -{"version":"2.0.0"} +{"version":"3.0.0"} diff --git a/packages/@aws-cdk/cloud-assembly-schema/test/manifest.test.ts b/packages/@aws-cdk/cloud-assembly-schema/test/manifest.test.ts index bd697e19e3b94..a90c2e411a39c 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/test/manifest.test.ts +++ b/packages/@aws-cdk/cloud-assembly-schema/test/manifest.test.ts @@ -50,7 +50,7 @@ test('manifest save', () => { }); -test('cloud-assembly.json.schema is correct', () => { +test('if this test fails, run "yarn update-schema"', () => { // when we compare schemas we ignore changes the // description that is generated from the ts docstrings. diff --git a/packages/@aws-cdk/cloudformation-diff/.eslintrc.js b/packages/@aws-cdk/cloudformation-diff/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/cloudformation-diff/.eslintrc.js +++ b/packages/@aws-cdk/cloudformation-diff/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/cloudformation-diff/.gitignore b/packages/@aws-cdk/cloudformation-diff/.gitignore index 892f05c6f236f..9d5b9f1ce1539 100644 --- a/packages/@aws-cdk/cloudformation-diff/.gitignore +++ b/packages/@aws-cdk/cloudformation-diff/.gitignore @@ -11,3 +11,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/cloudformation-diff/.npmignore b/packages/@aws-cdk/cloudformation-diff/.npmignore index f90c2f91756cb..18ab2081759df 100644 --- a/packages/@aws-cdk/cloudformation-diff/.npmignore +++ b/packages/@aws-cdk/cloudformation-diff/.npmignore @@ -14,3 +14,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/cloudformation-diff/jest.config.js b/packages/@aws-cdk/cloudformation-diff/jest.config.js new file mode 100644 index 0000000000000..e4f227679d683 --- /dev/null +++ b/packages/@aws-cdk/cloudformation-diff/jest.config.js @@ -0,0 +1,10 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = { + ...baseConfig, + coverageThreshold: { + global: { + statements: 60, + branches: 55, + }, + }, +}; diff --git a/packages/@aws-cdk/cloudformation-diff/package.json b/packages/@aws-cdk/cloudformation-diff/package.json index 6b9c9cf2a39fe..2358debef3509 100644 --- a/packages/@aws-cdk/cloudformation-diff/package.json +++ b/packages/@aws-cdk/cloudformation-diff/package.json @@ -14,15 +14,6 @@ "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test" }, - "jest": { - "coverageThreshold": { - "global": { - "statements": 60, - "lines": 60, - "branches": 55 - } - } - }, "author": { "name": "Amazon Web Services", "url": "https://aws.amazon.com", @@ -38,14 +29,14 @@ "table": "^5.4.6" }, "devDependencies": { - "@types/jest": "^25.2.1", + "@types/jest": "^25.2.2", "@types/string-width": "^4.0.1", "@types/table": "^4.0.7", "cdk-build-tools": "0.0.0", "fast-check": "^1.24.2", "jest": "^25.5.4", "pkglint": "0.0.0", - "ts-jest": "^25.5.0" + "ts-jest": "^26.0.0" }, "repository": { "url": "https://github.com/aws/aws-cdk.git", @@ -58,8 +49,11 @@ ], "homepage": "https://github.com/aws/aws-cdk", "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", - "maturity": "experimental" + "maturity": "experimental", + "cdk-build": { + "jest": true + } } diff --git a/packages/@aws-cdk/cloudformation-include/.eslintrc.js b/packages/@aws-cdk/cloudformation-include/.eslintrc.js new file mode 100644 index 0000000000000..1b28bad193ceb --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/.eslintrc.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/cloudformation-include/.gitignore b/packages/@aws-cdk/cloudformation-include/.gitignore new file mode 100644 index 0000000000000..4bd1c7e74895a --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/.gitignore @@ -0,0 +1,22 @@ +*.js +tslint.json +*.js.map +*.d.ts +*.generated.ts +dist +lib/generated/resources.ts +*.tgz +.jsii +tsconfig.json + +.LAST_BUILD +.nyc_output +coverage +nyc.config.js +.LAST_PACKAGE +*.snk + +!.eslintrc.js +!build.js +cfn-types-2-classes.json +!jest.config.js diff --git a/packages/@aws-cdk/cloudformation-include/.npmignore b/packages/@aws-cdk/cloudformation-include/.npmignore new file mode 100644 index 0000000000000..72d17ee76a860 --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/.npmignore @@ -0,0 +1,22 @@ +# Don't include original .ts files when doing `npm pack` +*.ts +!*.d.ts +coverage +.nyc_output +*.tgz + +dist +.LAST_PACKAGE +.LAST_BUILD +!*.js +.eslintrc.js + +# Include .jsii +!.jsii + +*.snk + +*.tsbuildinfo + +tsconfig.json +jest.config.js diff --git a/packages/@aws-cdk/cloudformation-include/LICENSE b/packages/@aws-cdk/cloudformation-include/LICENSE new file mode 100644 index 0000000000000..b71ec1688783a --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/@aws-cdk/cloudformation-include/NOTICE b/packages/@aws-cdk/cloudformation-include/NOTICE new file mode 100644 index 0000000000000..bfccac9a7f69c --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/cloudformation-include/README.md b/packages/@aws-cdk/cloudformation-include/README.md new file mode 100644 index 0000000000000..d4f2795b7d6d6 --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/README.md @@ -0,0 +1,133 @@ +# Include CloudFormation templates in the CDK + + +--- + +![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge) + +> The APIs of higher level constructs in this module are experimental and under active development. They are subject to non-backward compatible changes or removal in any future version. These are not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be announced in the release notes. This means that while you may use them, you may need to update your source code when upgrading to a newer version of this package. + +--- + + +This module contains a set of classes whose goal is to facilitate working +with existing CloudFormation templates in the CDK. +It can be thought of as an extension of the capabilities of the +[`CfnInclude` class](../@aws-cdk/core/lib/cfn-include.ts). + +## Basic usage + +Assume we have a file `my-template.json`, that contains the following CloudFormation template: + +```json +{ + "Resources": { + "Bucket": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketName": "some-bucket-name" + } + } + } +} +``` + +It can be included in a CDK application with the following code: + +```typescript +import * as cfn_inc from '@aws-cdk/cloudformation-include'; + +const cfnTemplate = new cfn_inc.CfnInclude(this, 'Template', { + templateFile: 'my-template.json', +}); +``` + +This will add all resources from `my-template.json` into the CDK application, +preserving their original logical IDs from the template file. + +Any resource from the included template can be retrieved by referring to it by its logical ID from the template. +If you know the class of the CDK object that corresponds to that resource, +you can cast the returned object to the correct type: + +```typescript +import * as s3 from '@aws-cdk/aws-s3'; + +const cfnBucket = cfnTemplate.getResource('Bucket') as s3.CfnBucket; +// cfnBucket is of type s3.CfnBucket +``` + +Any modifications made to that resource will be reflected in the resulting CDK template; +for example, the name of the bucket can be changed: + +```typescript +cfnBucket.bucketName = 'my-bucket-name'; +``` + +You can also refer to the resource when defining other constructs, +including the higher-level ones +(those whose name does not start with `Cfn`), +for example: + +```typescript +import * as iam from '@aws-cdk/aws-iam'; + +const role = new iam.Role(this, 'Role', { + assumedBy: new iam.AnyPrincipal(), +}); +role.addToPolicy(new iam.PolicyStatement({ + actions: ['s3:*'], + resources: [cfnBucket.attrArn], +})); +``` + +If you need, you can also convert the CloudFormation resource to a higher-level +resource by importing it by its name: + +```typescript +const bucket = s3.Bucket.fromBucketName(this, 'L2Bucket', cfnBucket.ref); +// bucket is of type s3.IBucket +``` + +## Known limitations + +This module is still in its early, experimental stage, +and so does not implement all features of CloudFormation templates. +All items unchecked below are currently not supported. + +### Ability to retrieve CloudFormation objects from the template: + +- [x] Resources +- [ ] Parameters +- [ ] Conditions +- [ ] Outputs + +### [Resource attributes](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-product-attribute-reference.html): + +- [x] Properties +- [ ] Condition +- [ ] DependsOn +- [ ] CreationPolicy +- [ ] UpdatePolicy +- [x] UpdateReplacePolicy +- [x] DeletionPolicy +- [x] Metadata + +### [CloudFormation functions](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html): + +- [x] Ref +- [x] Fn::GetAtt +- [x] Fn::Join +- [x] Fn::If +- [ ] Fn::And +- [ ] Fn::Equals +- [ ] Fn::Not +- [ ] Fn::Or +- [ ] Fn::Base64 +- [ ] Fn::Cidr +- [ ] Fn::FindInMap +- [ ] Fn::GetAZs +- [ ] Fn::ImportValue +- [ ] Fn::Select +- [ ] Fn::Split +- [ ] Fn::Sub +- [ ] Fn::Transform diff --git a/packages/@aws-cdk/cloudformation-include/build.js b/packages/@aws-cdk/cloudformation-include/build.js new file mode 100644 index 0000000000000..ab36ffd345d7f --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/build.js @@ -0,0 +1,103 @@ +/** + * This build file has two purposes: + * 1. It adds a dependency on each @aws-cdk/aws-xyz package with L1s to this package, + * similarly to how deps.js does for decdk. + * 2. It generates the file cfn-types-2-classes.json that contains a mapping + * between the CloudFormation type and the fully-qualified name of the L1 class, + * used in the logic of the CfnInclude class. + */ + +const fs = require('fs'); +const path = require('path'); + +const jsii_reflect = require('jsii-reflect'); + +const packageJson = require('./package.json'); +const dependencies = packageJson.dependencies || {}; +const peerDependencies = packageJson.peerDependencies || {}; + +async function main() { + const constructLibrariesRoot = path.resolve('..'); + const constructLibrariesDirs = fs.readdirSync(constructLibrariesRoot); + let errors = false; + + const typeSystem = new jsii_reflect.TypeSystem(); + const cfnType2L1Class = {}; + // load the @aws-cdk/core assembly first, to find the CfnResource class + await typeSystem.load(path.resolve(constructLibrariesRoot, 'core'), { validate: false }); + const cfnResourceClass = typeSystem.findClass('@aws-cdk/core.CfnResource'); + + for (const constructLibraryDir of constructLibrariesDirs) { + const absConstructLibraryDir = path.resolve(constructLibrariesRoot, constructLibraryDir); + const libraryPackageJson = require(path.join(absConstructLibraryDir, 'package.json')); + + const libraryDependencyVersion = dependencies[libraryPackageJson.name]; + if (libraryPackageJson.maturity === 'deprecated') { + if (libraryDependencyVersion) { + console.error(`Incorrect dependency on deprecated package: ${libraryPackageJson.name}`); + errors = true; + delete dependencies[libraryPackageJson.name]; + delete peerDependencies[libraryPackageJson.name]; + } + // we don't want dependencies on deprecated modules, + // even if they do contain L1s (like eks-legacy) + continue; + } + + // we're not interested in modules that don't use cfn2ts + // (as they don't contain any L1s) + const cfn2ts = (libraryPackageJson['cdk-build'] || {}).cloudformation; + if (!cfn2ts) { + continue; + } + + const libraryVersion = libraryPackageJson.version; + if (!libraryDependencyVersion) { + console.error(`Missing dependency on package: ${libraryPackageJson.name}`); + errors = true; + } else if (libraryDependencyVersion !== libraryVersion) { + console.error(`Incorrect dependency version for package ${libraryPackageJson.name}: expecting '${libraryVersion}', got: '${libraryDependencyVersion}'`); + errors = true; + } + + dependencies[libraryPackageJson.name] = libraryVersion; + // dependencies need to be in both sections to satisfy pkglint + peerDependencies[libraryPackageJson.name] = libraryVersion; + + // load the assembly of this package, + // and find all subclasses of CfnResource to put them in cfnType2L1Class + const assembly = await typeSystem.load(absConstructLibraryDir, { validate: false }); + for (let i = 0; i < assembly.classes.length; i++) { + const classs = assembly.classes[i]; + if (classs.extends(cfnResourceClass)) { + const properties = classs.spec.properties; + const cfnResourceTypeNameProp = (properties || []).find(p => p.name === 'CFN_RESOURCE_TYPE_NAME'); + if (cfnResourceTypeNameProp) { + const [moduleName, ...className] = classs.fqn.split('.'); + const module = require(moduleName); + const jsClassFromModule = module[className.join('.')]; + cfnType2L1Class[jsClassFromModule.CFN_RESOURCE_TYPE_NAME] = classs.fqn; + } + } + } + } + + fs.writeFileSync(path.join(__dirname, 'package.json'), + JSON.stringify(packageJson, undefined, 2) + '\n'); + fs.writeFileSync(path.join(__dirname, 'cfn-types-2-classes.json'), + JSON.stringify(cfnType2L1Class, undefined, 2) + '\n'); + + if (errors) { + console.error('errors found. updated package.json'); + process.exit(1); + } +} + +(async () => { + try { + await main(); + } catch (e) { + console.error(e); + process.exit(1); + } +})(); diff --git a/packages/@aws-cdk/cloudformation-include/jest.config.js b/packages/@aws-cdk/cloudformation-include/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/cloudformation-include/lib/cfn-include.ts b/packages/@aws-cdk/cloudformation-include/lib/cfn-include.ts new file mode 100644 index 0000000000000..9807e652dbdaf --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/lib/cfn-include.ts @@ -0,0 +1,116 @@ +import * as core from '@aws-cdk/core'; +import * as cfn_type_to_l1_mapping from './cfn-type-to-l1-mapping'; +import * as futils from './file-utils'; + +/** + * Construction properties of {@link CfnInclude}. + */ +export interface CfnIncludeProps { + /** + * Path to the template file. + * + * Currently, only JSON templates are supported. + */ + readonly templateFile: string; +} + +/** + * Construct to import an existing CloudFormation template file into a CDK application. + * All resources defined in the template file can be retrieved by calling the {@link getResource} method. + * Any modifications made on the returned resource objects will be reflected in the resulting CDK template. + */ +export class CfnInclude extends core.CfnElement { + private readonly resources: { [logicalId: string]: core.CfnResource } = {}; + private readonly template: any; + private readonly preserveLogicalIds: boolean; + + constructor(scope: core.Construct, id: string, props: CfnIncludeProps) { + super(scope, id); + + // read the template into a JS object + this.template = futils.readJsonSync(props.templateFile); + + // ToDo implement preserveLogicalIds=false + this.preserveLogicalIds = true; + + // instantiate all resources as CDK L1 objects + for (const logicalId of Object.keys(this.template.Resources || {})) { + this.getOrCreateResource(logicalId); + } + } + + /** + * Returns the low-level CfnResource from the template with the given logical ID. + * Any modifications performed on that resource will be reflected in the resulting CDK template. + * + * The returned object will be of the proper underlying class; + * you can always cast it to the correct type in your code: + * + * // assume the template contains an AWS::S3::Bucket with logical ID 'Bucket' + * const cfnBucket = cfnTemplate.getResource('Bucket') as s3.CfnBucket; + * // cfnBucket is of type s3.CfnBucket + * + * If the template does not contain a resource with the given logical ID, + * an exception will be thrown. + * + * @param logicalId the logical ID of the resource in the CloudFormation template file + */ + public getResource(logicalId: string): core.CfnResource { + const ret = this.resources[logicalId]; + if (!ret) { + throw new Error(`Resource with logical ID '${logicalId}' was not found in the template`); + } + return ret; + } + + /** @internal */ + public _toCloudFormation(): object { + const ret: { [section: string]: any } = {}; + + for (const section of Object.keys(this.template)) { + // render all sections of the template unchanged, + // except Resources, which will be taken care of by the created L1s + if (section !== 'Resources') { + ret[section] = this.template[section]; + } + } + + return ret; + } + + private getOrCreateResource(logicalId: string): core.CfnResource { + const ret = this.resources[logicalId]; + if (ret) { + return ret; + } + + const resourceAttributes: any = this.template.Resources[logicalId]; + const l1ClassFqn = cfn_type_to_l1_mapping.lookup(resourceAttributes.Type); + if (!l1ClassFqn) { + // currently, we only handle types we know the L1 for - + // in the future, we might construct an instance of CfnResource instead + throw new Error(`Unrecognized CloudFormation resource type: '${resourceAttributes.Type}'`); + } + // fail early for resource attributes we don't support yet + const knownAttributes = ['Type', 'Properties', 'DeletionPolicy', 'UpdateReplacePolicy', 'Metadata']; + for (const attribute of Object.keys(resourceAttributes)) { + if (!knownAttributes.includes(attribute)) { + throw new Error(`The ${attribute} resource attribute is not supported by cloudformation-include yet. ` + + 'Either remove it from the template, or use the CdkInclude class from the core package instead.'); + } + } + + const [moduleName, ...className] = l1ClassFqn.split('.'); + const module = require(moduleName); // eslint-disable-line @typescript-eslint/no-require-imports + const jsClassFromModule = module[className.join('.')]; + const l1Instance = jsClassFromModule.fromCloudFormation(this, logicalId, resourceAttributes); + + if (this.preserveLogicalIds) { + // override the logical ID to match the original template + l1Instance.overrideLogicalId(logicalId); + } + + this.resources[logicalId] = l1Instance; + return l1Instance; + } +} diff --git a/packages/@aws-cdk/cloudformation-include/lib/cfn-type-to-l1-mapping.ts b/packages/@aws-cdk/cloudformation-include/lib/cfn-type-to-l1-mapping.ts new file mode 100644 index 0000000000000..07bb5e61d63c0 --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/lib/cfn-type-to-l1-mapping.ts @@ -0,0 +1,25 @@ +import * as path from 'path'; +import * as futils from './file-utils'; + +let cfnTypeToL1Mapping: { [type: string]: string }; + +/** + * Returns the fully-qualified name + * (that is, including the NPM package name) + * of a class that corresponds to this CloudFormation type, + * or undefined if the given type was not found. + * + * For example, lookup("AWS::S3::Bucket") + * returns "@aws-cdk/aws-s3.CfnBucket". + */ +export function lookup(cfnType: string): string | undefined { + if (!cfnTypeToL1Mapping) { + cfnTypeToL1Mapping = loadCfnTypeToL1Mapping(); + } + + return cfnTypeToL1Mapping[cfnType]; +} + +function loadCfnTypeToL1Mapping(): any { + return futils.readJsonSync(path.join(__dirname, '..', 'cfn-types-2-classes.json')); +} diff --git a/packages/@aws-cdk/cloudformation-include/lib/file-utils.ts b/packages/@aws-cdk/cloudformation-include/lib/file-utils.ts new file mode 100644 index 0000000000000..aff2d3255f842 --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/lib/file-utils.ts @@ -0,0 +1,6 @@ +import * as fs from 'fs'; + +export function readJsonSync(filePath: string): any { + const fileContents = fs.readFileSync(filePath); + return JSON.parse(fileContents.toString()); +} diff --git a/packages/@aws-cdk/cloudformation-include/lib/index.ts b/packages/@aws-cdk/cloudformation-include/lib/index.ts new file mode 100644 index 0000000000000..4a16f02a2f228 --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/lib/index.ts @@ -0,0 +1 @@ +export * from './cfn-include'; diff --git a/packages/@aws-cdk/cloudformation-include/package.json b/packages/@aws-cdk/cloudformation-include/package.json new file mode 100644 index 0000000000000..8e2e1e34e0d1b --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/package.json @@ -0,0 +1,329 @@ +{ + "name": "@aws-cdk/cloudformation-include", + "version": "0.0.0", + "description": "A package that facilitates working with existing CloudFormation templates in the CDK", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "targets": { + "java": { + "package": "software.amazon.awscdk.cloudformation.include", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "cdk-cloudformation-include" + } + }, + "dotnet": { + "namespace": "Amazon.CDK.CloudFormation.Include", + "packageId": "Amazon.CDK.CloudFormation.Include", + "signAssembly": true, + "assemblyOriginatorKeyFile": "../../key.snk", + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png" + }, + "python": { + "distName": "aws-cdk.cloudformation-include", + "module": "aws_cdk.cloudformation_include" + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/cloudformation-include" + }, + "scripts": { + "build": "cdk-build", + "watch": "cdk-watch", + "lint": "cdk-lint", + "test": "cdk-test", + "pkglint": "pkglint -f", + "package": "cdk-package", + "awslint": "cdk-awslint", + "build+test": "npm run build && npm test", + "build+test+package": "npm run build+test && npm run package", + "compat": "cdk-compat" + }, + "cdk-build": { + "pre": [ + "node ./build.js" + ], + "jest": true + }, + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "dependencies": { + "@aws-cdk/alexa-ask": "0.0.0", + "@aws-cdk/aws-accessanalyzer": "0.0.0", + "@aws-cdk/aws-acmpca": "0.0.0", + "@aws-cdk/aws-amazonmq": "0.0.0", + "@aws-cdk/aws-amplify": "0.0.0", + "@aws-cdk/aws-apigateway": "0.0.0", + "@aws-cdk/aws-apigatewayv2": "0.0.0", + "@aws-cdk/aws-appconfig": "0.0.0", + "@aws-cdk/aws-applicationautoscaling": "0.0.0", + "@aws-cdk/aws-appmesh": "0.0.0", + "@aws-cdk/aws-appstream": "0.0.0", + "@aws-cdk/aws-appsync": "0.0.0", + "@aws-cdk/aws-athena": "0.0.0", + "@aws-cdk/aws-autoscaling": "0.0.0", + "@aws-cdk/aws-autoscalingplans": "0.0.0", + "@aws-cdk/aws-backup": "0.0.0", + "@aws-cdk/aws-batch": "0.0.0", + "@aws-cdk/aws-budgets": "0.0.0", + "@aws-cdk/aws-cassandra": "0.0.0", + "@aws-cdk/aws-ce": "0.0.0", + "@aws-cdk/aws-certificatemanager": "0.0.0", + "@aws-cdk/aws-chatbot": "0.0.0", + "@aws-cdk/aws-cloud9": "0.0.0", + "@aws-cdk/aws-cloudfront": "0.0.0", + "@aws-cdk/aws-cloudtrail": "0.0.0", + "@aws-cdk/aws-cloudwatch": "0.0.0", + "@aws-cdk/aws-codebuild": "0.0.0", + "@aws-cdk/aws-codecommit": "0.0.0", + "@aws-cdk/aws-codedeploy": "0.0.0", + "@aws-cdk/aws-codeguruprofiler": "0.0.0", + "@aws-cdk/aws-codepipeline": "0.0.0", + "@aws-cdk/aws-codestar": "0.0.0", + "@aws-cdk/aws-codestarconnections": "0.0.0", + "@aws-cdk/aws-codestarnotifications": "0.0.0", + "@aws-cdk/aws-cognito": "0.0.0", + "@aws-cdk/aws-config": "0.0.0", + "@aws-cdk/aws-datapipeline": "0.0.0", + "@aws-cdk/aws-dax": "0.0.0", + "@aws-cdk/aws-detective": "0.0.0", + "@aws-cdk/aws-directoryservice": "0.0.0", + "@aws-cdk/aws-dlm": "0.0.0", + "@aws-cdk/aws-dms": "0.0.0", + "@aws-cdk/aws-docdb": "0.0.0", + "@aws-cdk/aws-dynamodb": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-ecr": "0.0.0", + "@aws-cdk/aws-ecs": "0.0.0", + "@aws-cdk/aws-efs": "0.0.0", + "@aws-cdk/aws-eks": "0.0.0", + "@aws-cdk/aws-elasticache": "0.0.0", + "@aws-cdk/aws-elasticbeanstalk": "0.0.0", + "@aws-cdk/aws-elasticloadbalancing": "0.0.0", + "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", + "@aws-cdk/aws-elasticsearch": "0.0.0", + "@aws-cdk/aws-emr": "0.0.0", + "@aws-cdk/aws-events": "0.0.0", + "@aws-cdk/aws-eventschemas": "0.0.0", + "@aws-cdk/aws-fms": "0.0.0", + "@aws-cdk/aws-fsx": "0.0.0", + "@aws-cdk/aws-gamelift": "0.0.0", + "@aws-cdk/aws-glue": "0.0.0", + "@aws-cdk/aws-greengrass": "0.0.0", + "@aws-cdk/aws-guardduty": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-inspector": "0.0.0", + "@aws-cdk/aws-iot": "0.0.0", + "@aws-cdk/aws-iot1click": "0.0.0", + "@aws-cdk/aws-iotanalytics": "0.0.0", + "@aws-cdk/aws-iotevents": "0.0.0", + "@aws-cdk/aws-iotthingsgraph": "0.0.0", + "@aws-cdk/aws-kinesis": "0.0.0", + "@aws-cdk/aws-kinesisanalytics": "0.0.0", + "@aws-cdk/aws-kinesisfirehose": "0.0.0", + "@aws-cdk/aws-kms": "0.0.0", + "@aws-cdk/aws-lakeformation": "0.0.0", + "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/aws-logs": "0.0.0", + "@aws-cdk/aws-managedblockchain": "0.0.0", + "@aws-cdk/aws-mediaconvert": "0.0.0", + "@aws-cdk/aws-medialive": "0.0.0", + "@aws-cdk/aws-mediastore": "0.0.0", + "@aws-cdk/aws-msk": "0.0.0", + "@aws-cdk/aws-neptune": "0.0.0", + "@aws-cdk/aws-networkmanager": "0.0.0", + "@aws-cdk/aws-opsworks": "0.0.0", + "@aws-cdk/aws-opsworkscm": "0.0.0", + "@aws-cdk/aws-pinpoint": "0.0.0", + "@aws-cdk/aws-pinpointemail": "0.0.0", + "@aws-cdk/aws-qldb": "0.0.0", + "@aws-cdk/aws-ram": "0.0.0", + "@aws-cdk/aws-rds": "0.0.0", + "@aws-cdk/aws-redshift": "0.0.0", + "@aws-cdk/aws-resourcegroups": "0.0.0", + "@aws-cdk/aws-robomaker": "0.0.0", + "@aws-cdk/aws-route53": "0.0.0", + "@aws-cdk/aws-route53resolver": "0.0.0", + "@aws-cdk/aws-s3": "0.0.0", + "@aws-cdk/aws-sagemaker": "0.0.0", + "@aws-cdk/aws-sam": "0.0.0", + "@aws-cdk/aws-sdb": "0.0.0", + "@aws-cdk/aws-secretsmanager": "0.0.0", + "@aws-cdk/aws-securityhub": "0.0.0", + "@aws-cdk/aws-servicecatalog": "0.0.0", + "@aws-cdk/aws-servicediscovery": "0.0.0", + "@aws-cdk/aws-ses": "0.0.0", + "@aws-cdk/aws-sns": "0.0.0", + "@aws-cdk/aws-sqs": "0.0.0", + "@aws-cdk/aws-ssm": "0.0.0", + "@aws-cdk/aws-stepfunctions": "0.0.0", + "@aws-cdk/aws-synthetics": "0.0.0", + "@aws-cdk/aws-transfer": "0.0.0", + "@aws-cdk/aws-waf": "0.0.0", + "@aws-cdk/aws-wafregional": "0.0.0", + "@aws-cdk/aws-wafv2": "0.0.0", + "@aws-cdk/aws-workspaces": "0.0.0", + "@aws-cdk/core": "0.0.0", + "yaml": "1.10.0" + }, + "peerDependencies": { + "@aws-cdk/alexa-ask": "0.0.0", + "@aws-cdk/aws-accessanalyzer": "0.0.0", + "@aws-cdk/aws-acmpca": "0.0.0", + "@aws-cdk/aws-amazonmq": "0.0.0", + "@aws-cdk/aws-amplify": "0.0.0", + "@aws-cdk/aws-apigateway": "0.0.0", + "@aws-cdk/aws-apigatewayv2": "0.0.0", + "@aws-cdk/aws-appconfig": "0.0.0", + "@aws-cdk/aws-applicationautoscaling": "0.0.0", + "@aws-cdk/aws-appmesh": "0.0.0", + "@aws-cdk/aws-appstream": "0.0.0", + "@aws-cdk/aws-appsync": "0.0.0", + "@aws-cdk/aws-athena": "0.0.0", + "@aws-cdk/aws-autoscaling": "0.0.0", + "@aws-cdk/aws-autoscalingplans": "0.0.0", + "@aws-cdk/aws-backup": "0.0.0", + "@aws-cdk/aws-batch": "0.0.0", + "@aws-cdk/aws-budgets": "0.0.0", + "@aws-cdk/aws-cassandra": "0.0.0", + "@aws-cdk/aws-ce": "0.0.0", + "@aws-cdk/aws-certificatemanager": "0.0.0", + "@aws-cdk/aws-chatbot": "0.0.0", + "@aws-cdk/aws-cloud9": "0.0.0", + "@aws-cdk/aws-cloudfront": "0.0.0", + "@aws-cdk/aws-cloudtrail": "0.0.0", + "@aws-cdk/aws-cloudwatch": "0.0.0", + "@aws-cdk/aws-codebuild": "0.0.0", + "@aws-cdk/aws-codecommit": "0.0.0", + "@aws-cdk/aws-codedeploy": "0.0.0", + "@aws-cdk/aws-codeguruprofiler": "0.0.0", + "@aws-cdk/aws-codepipeline": "0.0.0", + "@aws-cdk/aws-codestar": "0.0.0", + "@aws-cdk/aws-codestarconnections": "0.0.0", + "@aws-cdk/aws-codestarnotifications": "0.0.0", + "@aws-cdk/aws-cognito": "0.0.0", + "@aws-cdk/aws-config": "0.0.0", + "@aws-cdk/aws-datapipeline": "0.0.0", + "@aws-cdk/aws-dax": "0.0.0", + "@aws-cdk/aws-detective": "0.0.0", + "@aws-cdk/aws-directoryservice": "0.0.0", + "@aws-cdk/aws-dlm": "0.0.0", + "@aws-cdk/aws-dms": "0.0.0", + "@aws-cdk/aws-docdb": "0.0.0", + "@aws-cdk/aws-dynamodb": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-ecr": "0.0.0", + "@aws-cdk/aws-ecs": "0.0.0", + "@aws-cdk/aws-efs": "0.0.0", + "@aws-cdk/aws-eks": "0.0.0", + "@aws-cdk/aws-elasticache": "0.0.0", + "@aws-cdk/aws-elasticbeanstalk": "0.0.0", + "@aws-cdk/aws-elasticloadbalancing": "0.0.0", + "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", + "@aws-cdk/aws-elasticsearch": "0.0.0", + "@aws-cdk/aws-emr": "0.0.0", + "@aws-cdk/aws-events": "0.0.0", + "@aws-cdk/aws-eventschemas": "0.0.0", + "@aws-cdk/aws-fms": "0.0.0", + "@aws-cdk/aws-fsx": "0.0.0", + "@aws-cdk/aws-gamelift": "0.0.0", + "@aws-cdk/aws-glue": "0.0.0", + "@aws-cdk/aws-greengrass": "0.0.0", + "@aws-cdk/aws-guardduty": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-inspector": "0.0.0", + "@aws-cdk/aws-iot": "0.0.0", + "@aws-cdk/aws-iot1click": "0.0.0", + "@aws-cdk/aws-iotanalytics": "0.0.0", + "@aws-cdk/aws-iotevents": "0.0.0", + "@aws-cdk/aws-iotthingsgraph": "0.0.0", + "@aws-cdk/aws-kinesis": "0.0.0", + "@aws-cdk/aws-kinesisanalytics": "0.0.0", + "@aws-cdk/aws-kinesisfirehose": "0.0.0", + "@aws-cdk/aws-kms": "0.0.0", + "@aws-cdk/aws-lakeformation": "0.0.0", + "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/aws-logs": "0.0.0", + "@aws-cdk/aws-managedblockchain": "0.0.0", + "@aws-cdk/aws-mediaconvert": "0.0.0", + "@aws-cdk/aws-medialive": "0.0.0", + "@aws-cdk/aws-mediastore": "0.0.0", + "@aws-cdk/aws-msk": "0.0.0", + "@aws-cdk/aws-neptune": "0.0.0", + "@aws-cdk/aws-networkmanager": "0.0.0", + "@aws-cdk/aws-opsworks": "0.0.0", + "@aws-cdk/aws-opsworkscm": "0.0.0", + "@aws-cdk/aws-pinpoint": "0.0.0", + "@aws-cdk/aws-pinpointemail": "0.0.0", + "@aws-cdk/aws-qldb": "0.0.0", + "@aws-cdk/aws-ram": "0.0.0", + "@aws-cdk/aws-rds": "0.0.0", + "@aws-cdk/aws-redshift": "0.0.0", + "@aws-cdk/aws-resourcegroups": "0.0.0", + "@aws-cdk/aws-robomaker": "0.0.0", + "@aws-cdk/aws-route53": "0.0.0", + "@aws-cdk/aws-route53resolver": "0.0.0", + "@aws-cdk/aws-s3": "0.0.0", + "@aws-cdk/aws-sagemaker": "0.0.0", + "@aws-cdk/aws-sam": "0.0.0", + "@aws-cdk/aws-sdb": "0.0.0", + "@aws-cdk/aws-secretsmanager": "0.0.0", + "@aws-cdk/aws-securityhub": "0.0.0", + "@aws-cdk/aws-servicecatalog": "0.0.0", + "@aws-cdk/aws-servicediscovery": "0.0.0", + "@aws-cdk/aws-ses": "0.0.0", + "@aws-cdk/aws-sns": "0.0.0", + "@aws-cdk/aws-sqs": "0.0.0", + "@aws-cdk/aws-ssm": "0.0.0", + "@aws-cdk/aws-stepfunctions": "0.0.0", + "@aws-cdk/aws-synthetics": "0.0.0", + "@aws-cdk/aws-transfer": "0.0.0", + "@aws-cdk/aws-waf": "0.0.0", + "@aws-cdk/aws-wafregional": "0.0.0", + "@aws-cdk/aws-wafv2": "0.0.0", + "@aws-cdk/aws-workspaces": "0.0.0", + "@aws-cdk/core": "0.0.0", + "constructs": "^3.0.2" + }, + "devDependencies": { + "@aws-cdk/assert": "0.0.0", + "@types/jest": "^25.2.2", + "@types/yaml": "1.2.0", + "cdk-build-tools": "0.0.0", + "jest": "^25.4.0", + "pkglint": "0.0.0", + "ts-jest": "^26.0.0" + }, + "bundledDependencies": [ + "yaml" + ], + "keywords": [ + "aws", + "cdk", + "cloudformation", + "template", + "include", + "including", + "migration", + "migrating", + "migrate" + ], + "homepage": "https://github.com/aws/aws-cdk", + "engines": { + "node": ">= 10.13.0 <13 || >=13.7.0" + }, + "stability": "experimental", + "maturity": "experimental", + "awscdkio": { + "announce": false + } +} diff --git a/packages/@aws-cdk/cloudformation-include/test/invalid-templates.test.ts b/packages/@aws-cdk/cloudformation-include/test/invalid-templates.test.ts new file mode 100644 index 0000000000000..955d6ff312d87 --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/test/invalid-templates.test.ts @@ -0,0 +1,53 @@ +import { SynthUtils } from '@aws-cdk/assert'; +import '@aws-cdk/assert/jest'; +import * as core from '@aws-cdk/core'; +import * as path from 'path'; +import * as inc from '../lib'; + +describe('CDK Include', () => { + let stack: core.Stack; + + beforeEach(() => { + stack = new core.Stack(); + }); + + test('throws a validation exception for a template with a missing required top-level resource property', () => { + expect(() => { + includeTestTemplate(stack, 'bucket-policy-without-bucket.json'); + }).toThrow(/missing required property: bucket/); + }); + + test('throws a validation exception for a template with a resource property expecting an array assigned the wrong type', () => { + includeTestTemplate(stack, 'bucket-with-cors-rules-not-an-array.json'); + + expect(() => { + SynthUtils.synthesize(stack); + }).toThrow(/corsRules: "CorsRules!" should be a list/); + }); + + test('throws a validation exception for a template with a null array element of a complex type with required fields', () => { + includeTestTemplate(stack, 'bucket-with-cors-rules-null-element.json'); + + expect(() => { + SynthUtils.synthesize(stack); + }).toThrow(/allowedMethods: required but missing/); + }); + + test('throws a validation exception for a template with a missing nested resource property', () => { + includeTestTemplate(stack, 'bucket-with-invalid-cors-rule.json'); + + expect(() => { + SynthUtils.synthesize(stack); + }).toThrow(/allowedOrigins: required but missing/); + }); +}); + +function includeTestTemplate(scope: core.Construct, testTemplate: string): inc.CfnInclude { + return new inc.CfnInclude(scope, 'MyScope', { + templateFile: _testTemplateFilePath(testTemplate), + }); +} + +function _testTemplateFilePath(testTemplate: string) { + return path.join(__dirname, 'test-templates', 'invalid', testTemplate); +} diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/bucket-with-encryption-key.json b/packages/@aws-cdk/cloudformation-include/test/test-templates/bucket-with-encryption-key.json new file mode 100644 index 0000000000000..75bb7d0c72b54 --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/bucket-with-encryption-key.json @@ -0,0 +1,75 @@ +{ + "Resources": { + "Key": { + "Type": "AWS::KMS::Key", + "Properties": { + "KeyPolicy": { + "Statement": [ + { + "Action": [ + "kms:*" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + } + }, + "DeletionPolicy": "Delete", + "UpdateReplacePolicy": "Delete" + }, + "Bucket": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "KMSMasterKeyID": { + "Fn::GetAtt": [ + "Key", + "Arn" + ] + }, + "SSEAlgorithm": "aws:kms" + } + } + ] + } + }, + "Metadata" : { + "Object1" : "Location1", + "KeyRef": { + "Ref": "Key" + }, + "KeyArn": { + "Fn::GetAtt": [ + "Key", + "Arn" + ] + } + }, + "DeletionPolicy": "Retain", + "UpdateReplacePolicy": "Retain" + } + } +} diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/if-complex-property.json b/packages/@aws-cdk/cloudformation-include/test/test-templates/if-complex-property.json new file mode 100644 index 0000000000000..8a6e83480f782 --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/if-complex-property.json @@ -0,0 +1,46 @@ +{ + "Conditions": { + "AlwaysFalseCond": { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "completely-made-up-region" + ] + } + }, + "Resources": { + "Bucket": { + "Type": "AWS::S3::Bucket", + "Properties": { + "CorsConfiguration": { + "CorsRules": [ + { + "Fn::If": [ + "AlwaysFalseCond", + { + "AllowedMethods": [ + "GET" + ], + "AllowedOrigins": [ + "*" + ], + "MaxAge": 10 + }, + { + "AllowedMethods": [ + "POST" + ], + "AllowedOrigins": [ + "/path/*" + ], + "MaxAge": 20 + } + ] + } + ] + } + } + } + } +} diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/if-simple-property.json b/packages/@aws-cdk/cloudformation-include/test/test-templates/if-simple-property.json new file mode 100644 index 0000000000000..0d833ec8031d1 --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/if-simple-property.json @@ -0,0 +1,26 @@ +{ + "Conditions": { + "AlwaysFalseCond": { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "completely-made-up-region" + ] + } + }, + "Resources": { + "Bucket": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketName": { + "Fn::If": [ + "AlwaysFalseCond", + "Name1", + "Name2" + ] + } + } + } + } +} diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/invalid/bucket-policy-without-bucket.json b/packages/@aws-cdk/cloudformation-include/test/test-templates/invalid/bucket-policy-without-bucket.json new file mode 100644 index 0000000000000..c665e5f2641b7 --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/invalid/bucket-policy-without-bucket.json @@ -0,0 +1,33 @@ +{ + "Resources": { + "BucketPolicy": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:GetObject", + "Effect": "Allow", + "Principal": "*", + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Bucket2", + "Arn" + ] + }, + "/*" + ] + ] + } + } + ], + "Version": "2012-10-17" + } + } + } + } +} diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/invalid/bucket-with-cors-rules-not-an-array.json b/packages/@aws-cdk/cloudformation-include/test/test-templates/invalid/bucket-with-cors-rules-not-an-array.json new file mode 100644 index 0000000000000..52bbe7131c709 --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/invalid/bucket-with-cors-rules-not-an-array.json @@ -0,0 +1,12 @@ +{ + "Resources": { + "Bucket": { + "Type": "AWS::S3::Bucket", + "Properties": { + "CorsConfiguration": { + "CorsRules": "CorsRules!" + } + } + } + } +} diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/invalid/bucket-with-cors-rules-null-element.json b/packages/@aws-cdk/cloudformation-include/test/test-templates/invalid/bucket-with-cors-rules-null-element.json new file mode 100644 index 0000000000000..e7d41a13d4360 --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/invalid/bucket-with-cors-rules-null-element.json @@ -0,0 +1,14 @@ +{ + "Resources": { + "Bucket": { + "Type": "AWS::S3::Bucket", + "Properties": { + "CorsConfiguration": { + "CorsRules": [ + null + ] + } + } + } + } +} diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/invalid/bucket-with-invalid-cors-rule.json b/packages/@aws-cdk/cloudformation-include/test/test-templates/invalid/bucket-with-invalid-cors-rule.json new file mode 100644 index 0000000000000..a58f9e7867c9c --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/invalid/bucket-with-invalid-cors-rule.json @@ -0,0 +1,16 @@ +{ + "Resources": { + "Bucket": { + "Type": "AWS::S3::Bucket", + "Properties": { + "CorsConfiguration": { + "CorsRules": [ + { + "AllowedMethods": [] + } + ] + } + } + } + } +} diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/non-existent-resource-type.json b/packages/@aws-cdk/cloudformation-include/test/test-templates/non-existent-resource-type.json new file mode 100644 index 0000000000000..9307ef8976f2d --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/non-existent-resource-type.json @@ -0,0 +1,7 @@ +{ + "Resources": { + "Bucket": { + "Type": "AWS::FakeService::DoesNotExist" + } + } +} diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/only-bucket-complex-props.json b/packages/@aws-cdk/cloudformation-include/test/test-templates/only-bucket-complex-props.json new file mode 100644 index 0000000000000..afaa16a4ab17a --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/only-bucket-complex-props.json @@ -0,0 +1,22 @@ +{ + "Resources": { + "Bucket": { + "Type": "AWS::S3::Bucket", + "Properties": { + "CorsConfiguration": { + "CorsRules": [ + { + "AllowedMethods": [ + "GET" + ], + "AllowedOrigins": [ + "*" + ], + "MaxAge": 10 + } + ] + } + } + } + } +} diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/only-codecommit-repo-using-cfn-functions.json b/packages/@aws-cdk/cloudformation-include/test/test-templates/only-codecommit-repo-using-cfn-functions.json new file mode 100644 index 0000000000000..a1037dbf2402a --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/only-codecommit-repo-using-cfn-functions.json @@ -0,0 +1,13 @@ +{ + "Resources": { + "Bucket": { + "Type": "AWS::CodeCommit::Repository", + "Properties": { + "RepositoryName": "my-repository", + "RepositoryDescription": { + "Fn::Base64": "my description, in base-64!" + } + } + } + } +} diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/only-empty-bucket-with-parameters.json b/packages/@aws-cdk/cloudformation-include/test/test-templates/only-empty-bucket-with-parameters.json new file mode 100644 index 0000000000000..66c92f4e4de41 --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/only-empty-bucket-with-parameters.json @@ -0,0 +1,41 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "My template description", + "Parameters": { + "Param": { + "Description": "The description of the parameter", + "Type": "String", + "Default": "" + } + }, + "Conditions": { + "Cond1": { + "Fn::Equals": ["a", "b"] + } + }, + "Outputs": { + "Output1": { + "Value": { + "Fn::Base64": "Output1Value" + } + } + }, + "Metadata": { + "Instances" : { + "Description" : "Information about the instances" + } + }, + "Mappings" : { + "Mapping01" : { + "Key01" : { + "Name" : "Value01" + } + } + }, + "Transform": "AWS::Serverless-2016-10-31", + "Resources": { + "Bucket": { + "Type": "AWS::S3::Bucket" + } + } +} diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/only-empty-bucket.json b/packages/@aws-cdk/cloudformation-include/test/test-templates/only-empty-bucket.json new file mode 100644 index 0000000000000..ead9c6c0e35a6 --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/only-empty-bucket.json @@ -0,0 +1,7 @@ +{ + "Resources": { + "Bucket": { + "Type": "AWS::S3::Bucket" + } + } +} diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/ref-array-property.json b/packages/@aws-cdk/cloudformation-include/test/test-templates/ref-array-property.json new file mode 100644 index 0000000000000..4c0c277c382ae --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/ref-array-property.json @@ -0,0 +1,29 @@ +{ + "Parameters": { + "Methods": { + "Description": "The description of the parameter", + "Type": "CommaDelimitedList", + "Default": "GET,PUT" + } + }, + "Resources": { + "Bucket": { + "Type": "AWS::S3::Bucket", + "Properties": { + "CorsConfiguration": { + "CorsRules": [ + { + "AllowedMethods": { + "Ref": "Methods" + }, + "AllowedOrigins": [ + "/path/*" + ], + "MaxAge": 20 + } + ] + } + } + } + } +} diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/resource-attribute-condition.json b/packages/@aws-cdk/cloudformation-include/test/test-templates/resource-attribute-condition.json new file mode 100644 index 0000000000000..77caf02cb0357 --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/resource-attribute-condition.json @@ -0,0 +1,18 @@ +{ + "Conditions": { + "AlwaysFalseCond": { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "completely-made-up-region" + ] + } + }, + "Resources": { + "Bucket": { + "Type": "AWS::S3::Bucket", + "Condition": "AlwaysFalseCond" + } + } +} diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/resource-attribute-creation-policy.json b/packages/@aws-cdk/cloudformation-include/test/test-templates/resource-attribute-creation-policy.json new file mode 100644 index 0000000000000..c342227788535 --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/resource-attribute-creation-policy.json @@ -0,0 +1,12 @@ +{ + "Resources": { + "Bucket": { + "Type": "AWS::S3::Bucket", + "CreationPolicy": { + "AutoScalingCreationPolicy": { + "MinSuccessfulInstancesPercent": 50 + } + } + } + } +} diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/resource-attribute-depends-on.json b/packages/@aws-cdk/cloudformation-include/test/test-templates/resource-attribute-depends-on.json new file mode 100644 index 0000000000000..82bd4fa42b847 --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/resource-attribute-depends-on.json @@ -0,0 +1,11 @@ +{ + "Resources": { + "Bucket1": { + "Type": "AWS::S3::Bucket" + }, + "Bucket2": { + "Type": "AWS::S3::Bucket", + "DependsOn": "Bucket1" + } + } +} diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/resource-attribute-update-policy.json b/packages/@aws-cdk/cloudformation-include/test/test-templates/resource-attribute-update-policy.json new file mode 100644 index 0000000000000..7032979006266 --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/resource-attribute-update-policy.json @@ -0,0 +1,12 @@ +{ + "Resources": { + "Bucket": { + "Type": "AWS::S3::Bucket", + "UpdatePolicy": { + "AutoScalingScheduledAction": { + "IgnoreUnmodifiedGroupSizeProperties": true + } + } + } + } +} diff --git a/packages/@aws-cdk/cloudformation-include/test/valid-templates.test.ts b/packages/@aws-cdk/cloudformation-include/test/valid-templates.test.ts new file mode 100644 index 0000000000000..6bdd001bddb27 --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/test/valid-templates.test.ts @@ -0,0 +1,257 @@ +import '@aws-cdk/assert/jest'; +import * as iam from '@aws-cdk/aws-iam'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as core from '@aws-cdk/core'; +import * as path from 'path'; +import * as inc from '../lib'; +import * as futils from '../lib/file-utils'; + +// tslint:disable:object-literal-key-quotes +/* eslint-disable quotes */ + +describe('CDK Include', () => { + let stack: core.Stack; + + beforeEach(() => { + stack = new core.Stack(); + }); + + test('can ingest a template with only an empty S3 Bucket, and output it unchanged', () => { + includeTestTemplate(stack, 'only-empty-bucket.json'); + + expect(stack).toMatchTemplate( + loadTestFileToJsObject('only-empty-bucket.json'), + ); + }); + + test('throws an exception if asked for resource with a logical ID not present in the template', () => { + const cfnTemplate = includeTestTemplate(stack, 'only-empty-bucket.json'); + + expect(() => { + cfnTemplate.getResource('LogicalIdThatDoesNotExist'); + }).toThrow(/Resource with logical ID 'LogicalIdThatDoesNotExist' was not found in the template/); + }); + + test('can ingest a template with only an empty S3 Bucket, and change its property', () => { + const cfnTemplate = includeTestTemplate(stack, 'only-empty-bucket.json'); + + const cfnBucket = cfnTemplate.getResource('Bucket') as s3.CfnBucket; + cfnBucket.bucketName = 'my-bucket-name'; + + expect(stack).toMatchTemplate({ + "Resources": { + "Bucket": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketName": "my-bucket-name", + }, + }, + }, + }); + }); + + test('can ingest a template with only an S3 Bucket with complex properties, and output it unchanged', () => { + const cfnTemplate = includeTestTemplate(stack, 'only-bucket-complex-props.json'); + const cfnBucket = cfnTemplate.getResource('Bucket') as s3.CfnBucket; + + expect((cfnBucket.corsConfiguration as any).corsRules).toHaveLength(1); + expect(stack).toMatchTemplate( + loadTestFileToJsObject('only-bucket-complex-props.json'), + ); + }); + + test('allows referring to a bucket defined in the template in your CDK code', () => { + const cfnTemplate = includeTestTemplate(stack, 'only-empty-bucket.json'); + const cfnBucket = cfnTemplate.getResource('Bucket') as s3.CfnBucket; + + const role = new iam.Role(stack, 'Role', { + assumedBy: new iam.AnyPrincipal(), + }); + role.addToPolicy(new iam.PolicyStatement({ + actions: ['s3:*'], + resources: [cfnBucket.attrArn], + })); + + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Resource": { + "Fn::GetAtt": [ + "Bucket", + "Arn", + ], + }, + }, + ], + }, + }); + }); + + test('can ingest a template with a Bucket Ref-erencing a KMS Key, and output it unchanged', () => { + includeTestTemplate(stack, 'bucket-with-encryption-key.json'); + + expect(stack).toMatchTemplate( + loadTestFileToJsObject('bucket-with-encryption-key.json'), + ); + }); + + xtest('correctly changes the logical IDs, including references, if imported with preserveLogicalIds=false', () => { + const cfnTemplate = includeTestTemplate(stack, 'bucket-with-encryption-key.json', { + preserveLogicalIds: false, + }); + + // even though the logical IDs in the resulting template are different than in the input template, + // the L1s can still be retrieved using their original logical IDs from the template file, + // and any modifications to them will be reflected in the resulting template + const cfnBucket = cfnTemplate.getResource('Bucket') as s3.CfnBucket; + cfnBucket.bucketName = 'my-bucket-name'; + + expect(stack).toMatchTemplate({ + "Resources": { + "MyScopeKey7673692F": { + "Type": "AWS::KMS::Key", + "Properties": { + "KeyPolicy": { + "Statement": [ + { + "Action": [ + "kms:*", + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": ["", [ + "arn:", + { "Ref": "AWS::Partition" }, + ":iam::", + { "Ref": "AWS::AccountId" }, + ":root", + ]], + }, + }, + "Resource": "*", + }, + ], + "Version": "2012-10-17", + }, + }, + "DeletionPolicy": "Delete", + "UpdateReplacePolicy": "Delete", + }, + "MyScopeBucket02C1313B": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketName": "my-bucket-name", + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "KMSMasterKeyID": { + "Fn::GetAtt": [ + "MyScopeKey7673692F", + "Arn", + ], + }, + "SSEAlgorithm": "aws:kms", + }, + }, + ], + }, + }, + "DeletionPolicy": "Retain", + "UpdateReplacePolicy": "Retain", + }, + }, + }); + }); + + test('can ingest a template with an Fn::If expression for simple values, and output it unchanged', () => { + includeTestTemplate(stack, 'if-simple-property.json'); + + expect(stack).toMatchTemplate( + loadTestFileToJsObject('if-simple-property.json'), + ); + }); + + test('can ingest a template with an Fn::If expression for complex values, and output it unchanged', () => { + includeTestTemplate(stack, 'if-complex-property.json'); + + expect(stack).toMatchTemplate( + loadTestFileToJsObject('if-complex-property.json'), + ); + }); + + test('can ingest a template with a Ref expression for an array value, and output it unchanged', () => { + includeTestTemplate(stack, 'ref-array-property.json'); + + expect(stack).toMatchTemplate( + loadTestFileToJsObject('ref-array-property.json'), + ); + }); + + test('renders non-Resources sections unchanged', () => { + includeTestTemplate(stack, 'only-empty-bucket-with-parameters.json'); + + expect(stack).toMatchTemplate( + loadTestFileToJsObject('only-empty-bucket-with-parameters.json'), + ); + }); + + test("throws an exception when encountering a Resource type it doesn't recognize", () => { + expect(() => { + includeTestTemplate(stack, 'non-existent-resource-type.json'); + }).toThrow(/Unrecognized CloudFormation resource type: 'AWS::FakeService::DoesNotExist'/); + }); + + test("throws an exception when encountering a CFN function it doesn't support", () => { + expect(() => { + includeTestTemplate(stack, 'only-codecommit-repo-using-cfn-functions.json'); + }).toThrow(/Unsupported CloudFormation function 'Fn::Base64'/); + }); + + test('throws an exception when encountering the Condition attribute in a resource', () => { + expect(() => { + includeTestTemplate(stack, 'resource-attribute-condition.json'); + }).toThrow(/The Condition resource attribute is not supported by cloudformation-include yet/); + }); + + test('throws an exception when encountering the DependsOn attribute in a resource', () => { + expect(() => { + includeTestTemplate(stack, 'resource-attribute-depends-on.json'); + }).toThrow(/The DependsOn resource attribute is not supported by cloudformation-include yet/); + }); + + test('throws an exception when encountering the CreationPolicy attribute in a resource', () => { + expect(() => { + includeTestTemplate(stack, 'resource-attribute-creation-policy.json'); + }).toThrow(/The CreationPolicy resource attribute is not supported by cloudformation-include yet/); + }); + + test('throws an exception when encountering the UpdatePolicy attribute in a resource', () => { + expect(() => { + includeTestTemplate(stack, 'resource-attribute-update-policy.json'); + }).toThrow(/The UpdatePolicy resource attribute is not supported by cloudformation-include yet/); + }); +}); + +interface IncludeTestTemplateProps { + /** @default true */ + readonly preserveLogicalIds?: boolean; +} + +function includeTestTemplate(scope: core.Construct, testTemplate: string, _props: IncludeTestTemplateProps = {}): inc.CfnInclude { + return new inc.CfnInclude(scope, 'MyScope', { + templateFile: _testTemplateFilePath(testTemplate), + // preserveLogicalIds: props.preserveLogicalIds, + }); +} + +function loadTestFileToJsObject(testTemplate: string): any { + return futils.readJsonSync(_testTemplateFilePath(testTemplate)); +} + +function _testTemplateFilePath(testTemplate: string) { + return path.join(__dirname, 'test-templates', testTemplate); +} diff --git a/packages/@aws-cdk/core/.eslintrc.js b/packages/@aws-cdk/core/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/core/.eslintrc.js +++ b/packages/@aws-cdk/core/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/core/README.md b/packages/@aws-cdk/core/README.md index db0bc2dd54a5d..4808b94857a04 100644 --- a/packages/@aws-cdk/core/README.md +++ b/packages/@aws-cdk/core/README.md @@ -426,14 +426,14 @@ export class Sum extends Construct { super(scope, id); const resourceType = 'Custom::Sum'; - const provider = CustomResourceProvider.getOrCreate(this, resourceType, { + const serviceToken = CustomResourceProvider.getOrCreate(this, resourceType, { codeDirectory: `${__dirname}/sum-handler`, runtime: CustomResourceProviderRuntime.NODEJS_12, }); const resource = new CustomResource(this, 'Resource', { resourceType: resourceType, - serviceToken: provider.serviceToken, + serviceToken: serviceToken, properties: { lhs: props.lhs, rhs: props.rhs diff --git a/packages/@aws-cdk/core/lib/cfn-fn.ts b/packages/@aws-cdk/core/lib/cfn-fn.ts index 889eef8fcc40d..30fb6cf435bec 100644 --- a/packages/@aws-cdk/core/lib/cfn-fn.ts +++ b/packages/@aws-cdk/core/lib/cfn-fn.ts @@ -22,6 +22,11 @@ export class Fn { return new FnRef(logicalName).toString(); } + /** @internal */ + public static _ref(logicalId: string): IResolvable { + return new FnRef(logicalId); + } + /** * The ``Fn::GetAtt`` intrinsic function returns the value of an attribute * from a resource in the template. diff --git a/packages/@aws-cdk/core/lib/cfn-parse.ts b/packages/@aws-cdk/core/lib/cfn-parse.ts new file mode 100644 index 0000000000000..a72f59240776c --- /dev/null +++ b/packages/@aws-cdk/core/lib/cfn-parse.ts @@ -0,0 +1,215 @@ +import { Fn } from './cfn-fn'; +import { Aws } from './cfn-pseudo'; +import { CfnDeletionPolicy } from './cfn-resource-policy'; +import { CfnTag } from './cfn-tag'; +import { IResolvable } from './resolvable'; +import { isResolvableObject, Token } from './token'; + +/** + * This class contains functions for translating from a pure CFN value + * (like a JS object { "Ref": "Bucket" }) + * to a form CDK understands + * (like Fn.ref('Bucket')). + * + * While this file not exported from the module + * (to not make it part of the public API), + * it is directly referenced in the generated L1 code, + * so any renames of it need to be reflected in cfn2ts/codegen.ts as well. + * + * @experimental + */ +export class FromCloudFormation { + public static parseValue(cfnValue: any): any { + return parseCfnValueToCdkValue(cfnValue); + } + + // nothing to for any but return it + public static getAny(value: any) { return value; } + + // nothing to do - if 'value' is not a boolean or a Token, + // a validator should report that at runtime + public static getBoolean(value: any): boolean | IResolvable { return value; } + + public static getDate(value: any): Date | IResolvable { + // if the date is a deploy-time value, just return it + if (isResolvableObject(value)) { + return value; + } + + // if the date has been given as a string, convert it + if (typeof value === 'string') { + return new Date(value); + } + + // all other cases - just return the value, + // if it's not a Date, a validator should catch it + return value; + } + + public static getString(value: any): string { + // if the string is a deploy-time value, serialize it to a Token + if (isResolvableObject(value)) { + return value.toString(); + } + + // in all other cases, just return the input, + // and let a validator handle it if it's not a string + return value; + } + + public static getNumber(value: any): number { + // if the string is a deploy-time value, serialize it to a Token + if (isResolvableObject(value)) { + return Token.asNumber(value); + } + + // in all other cases, just return the input, + // and let a validator handle it if it's not a number + return value; + } + + public static getStringArray(value: any): string[] { + // if the array is a deploy-time value, serialize it to a Token + if (isResolvableObject(value)) { + return Token.asList(value); + } + + // in all other cases, delegate to the standard mapping logic + return this.getArray(value, this.getString); + } + + public static getArray(value: any, mapper: (arg: any) => T): T[] { + if (!Array.isArray(value)) { + // break the type system, and just return the given value, + // which hopefully will be reported as invalid by the validator + // of the property we're transforming + // (unless it's a deploy-time value, + // which we can't map over at build time anyway) + return value; + } + + return value.map(mapper); + } + + public static getMap(value: any, mapper: (arg: any) => T): { [key: string]: T } { + if (typeof value !== 'object') { + // if the input is not a map (= object in JS land), + // just return it, and let the validator of this property handle it + // (unless it's a deploy-time value, + // which we can't map over at build time anyway) + return value; + } + + const ret: { [key: string]: T } = {}; + for (const [key, val] of Object.entries(value)) { + ret[key] = mapper(val); + } + return ret; + } + + public static parseDeletionPolicy(policy: any): CfnDeletionPolicy | undefined { + switch (policy) { + case null: return undefined; + case undefined: return undefined; + case 'Delete': return CfnDeletionPolicy.DELETE; + case 'Retain': return CfnDeletionPolicy.RETAIN; + case 'Snapshot': return CfnDeletionPolicy.SNAPSHOT; + default: throw new Error(`Unrecognized DeletionPolicy '${policy}'`); + } + } + + public static getCfnTag(tag: any): CfnTag { + return tag == null + ? { } as any // break the type system - this should be detected at runtime by a tag validator + : { + key: tag.Key, + value: tag.Value, + }; + } +} + +function parseCfnValueToCdkValue(cfnValue: any): any { + // == null captures undefined as well + if (cfnValue == null) { + return undefined; + } + // if we have any late-bound values, + // just return them + if (isResolvableObject(cfnValue)) { + return cfnValue; + } + if (Array.isArray(cfnValue)) { + return cfnValue.map(el => parseCfnValueToCdkValue(el)); + } + if (typeof cfnValue === 'object') { + // an object can be either a CFN intrinsic, or an actual object + const cfnIntrinsic = parseIfCfnIntrinsic(cfnValue); + if (cfnIntrinsic) { + return cfnIntrinsic; + } + const ret: any = {}; + for (const [key, val] of Object.entries(cfnValue)) { + ret[key] = parseCfnValueToCdkValue(val); + } + return ret; + } + // in all other cases, just return the input + return cfnValue; +} + +function parseIfCfnIntrinsic(object: any): any { + const key = looksLikeCfnIntrinsic(object); + switch (key) { + case undefined: + return undefined; + case 'Ref': { + // ToDo handle translating logical IDs + return specialCaseRefs(object[key]) ?? Fn._ref(object[key]); + } + case 'Fn::GetAtt': { + // Fn::GetAtt takes a 2-element list as its argument + const value = object[key]; + // ToDo same comment here as in Ref above + return Fn.getAtt((value[0]), value[1]); + } + case 'Fn::Join': { + // Fn::Join takes a 2-element list as its argument, + // where the first element is the delimiter, + // and the second is the list of elements to join + const value = parseCfnValueToCdkValue(object[key]); + return Fn.join(value[0], value[1]); + } + case 'Fn::If': { + // Fn::If takes a 3-element list as its argument + const value = parseCfnValueToCdkValue(object[key]); + return Fn.conditionIf(value[0], value[1], value[2]); + } + default: + throw new Error(`Unsupported CloudFormation function '${key}'`); + } +} + +function looksLikeCfnIntrinsic(object: object): string | undefined { + const objectKeys = Object.keys(object); + // a CFN intrinsic is always an object with a single key + if (objectKeys.length !== 1) { + return undefined; + } + + const key = objectKeys[0]; + return key === 'Ref' || key.startsWith('Fn::') ? key : undefined; +} + +function specialCaseRefs(value: any): any { + switch (value) { + case 'AWS::AccountId': return Aws.ACCOUNT_ID; + case 'AWS::Region': return Aws.REGION; + case 'AWS::Partition': return Aws.PARTITION; + case 'AWS::URLSuffix': return Aws.URL_SUFFIX; + case 'AWS::NotificationARNs': return Aws.NOTIFICATION_ARNS; + case 'AWS::StackId': return Aws.STACK_ID; + case 'AWS::StackName': return Aws.STACK_NAME; + case 'AWS::NoValue': return Aws.NO_VALUE; + default: return undefined; + } +} diff --git a/packages/@aws-cdk/core/lib/index.ts b/packages/@aws-cdk/core/lib/index.ts index 201de0947af84..a4690f41dc898 100644 --- a/packages/@aws-cdk/core/lib/index.ts +++ b/packages/@aws-cdk/core/lib/index.ts @@ -8,6 +8,7 @@ export * from './lazy'; export * from './tag-manager'; export * from './dependency'; export * from './string-fragments'; +export * from './stack-synthesizers'; export * from './reference'; export * from './cfn-condition'; diff --git a/packages/@aws-cdk/core/lib/nested-stack.ts b/packages/@aws-cdk/core/lib/nested-stack.ts index 647b5fc014720..4d87c148958f0 100644 --- a/packages/@aws-cdk/core/lib/nested-stack.ts +++ b/packages/@aws-cdk/core/lib/nested-stack.ts @@ -9,6 +9,7 @@ import { Duration } from './duration'; import { Lazy } from './lazy'; import { IResolveContext } from './resolvable'; import { Stack } from './stack'; +import { NestedStackSynthesizer } from './stack-synthesizers'; import { Token } from './token'; const NESTED_STACK_SYMBOL = Symbol.for('@aws-cdk/core.NestedStack'); @@ -96,7 +97,10 @@ export class NestedStack extends Stack { constructor(scope: Construct, id: string, props: NestedStackProps = { }) { const parentStack = findParentStack(scope); - super(scope, id, { env: { account: parentStack.account, region: parentStack.region } }); + super(scope, id, { + env: { account: parentStack.account, region: parentStack.region }, + synthesizer: new NestedStackSynthesizer(parentStack.synthesizer), + }); this._parentStack = parentStack; diff --git a/packages/@aws-cdk/core/lib/private/runtime-info.ts b/packages/@aws-cdk/core/lib/private/runtime-info.ts index 06d6815ff46d6..e18fabc5ecaa1 100644 --- a/packages/@aws-cdk/core/lib/private/runtime-info.ts +++ b/packages/@aws-cdk/core/lib/private/runtime-info.ts @@ -1,4 +1,5 @@ import * as cxschema from '@aws-cdk/cloud-assembly-schema'; +import { basename, dirname } from 'path'; import { major as nodeMajorVersion } from './node-version'; // list of NPM scopes included in version reporting e.g. @aws-cdk and @aws-solutions-konstruk @@ -72,7 +73,8 @@ function findNpmPackage(fileName: string): { name: string, version: string, priv return undefined; } - const paths = mod.paths.map(stripNodeModules); + // For any path in ``mod.paths`` that is a node_modules folder, use its parent directory instead. + const paths = mod.paths.map((path: string) => basename(path) === 'node_modules' ? dirname(path) : path); try { const packagePath = require.resolve( @@ -85,19 +87,6 @@ function findNpmPackage(fileName: string): { name: string, version: string, priv } catch (e) { return undefined; } - - /** - * @param s a path. - * @returns ``s`` with any terminating ``/node_modules`` - * (or ``\\node_modules``) stripped off.) - */ - function stripNodeModules(s: string): string { - if (s.endsWith('/node_modules') || s.endsWith('\\node_modules')) { - // /node_modules is 13 characters - return s.substr(0, s.length - 13); - } - return s; - } } function getJsiiAgentVersion() { diff --git a/packages/@aws-cdk/core/lib/runtime.ts b/packages/@aws-cdk/core/lib/runtime.ts index ad8077cc4631d..b475679338129 100644 --- a/packages/@aws-cdk/core/lib/runtime.ts +++ b/packages/@aws-cdk/core/lib/runtime.ts @@ -333,10 +333,10 @@ export function requiredValidator(x: any) { * @throws if the property ``name`` is not present in ``props``. */ export function requireProperty(props: { [name: string]: any }, name: string, context: Construct): any { - if (!(name in props)) { + const value = props[name]; + if (value == null) { throw new Error(`${context.toString()} is missing required property: ${name}`); } - const value = props[name]; // Possibly add type-checking here... return value; } diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/_shared.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/_shared.ts new file mode 100644 index 0000000000000..280a3f72d1079 --- /dev/null +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/_shared.ts @@ -0,0 +1,119 @@ +import * as cxschema from '@aws-cdk/cloud-assembly-schema'; +import * as crypto from 'crypto'; +import { ConstructNode, IConstruct, ISynthesisSession } from '../construct-compat'; +import { Stack } from '../stack'; + +/** + * Shared logic of writing stack artifact to the Cloud Assembly + * + * This logic is shared between StackSyntheses. + * + * It could have been a protected method on a base class, but it + * uses `Partial` in the + * parameters (which is convenient so I can remain typesafe without + * copy/pasting), and jsii will choke on this type. + */ +export function addStackArtifactToAssembly( + session: ISynthesisSession, + stack: Stack, + stackProps: Partial, + additionalStackDependencies: string[]) { + + // nested stack tags are applied at the AWS::CloudFormation::Stack resource + // level and are not needed in the cloud assembly. + // TODO: move these to the cloud assembly artifact properties instead of metadata + if (stack.tags.hasTags()) { + stack.node.addMetadata(cxschema.ArtifactMetadataEntryType.STACK_TAGS, stack.tags.renderTags()); + } + + const deps = [ + ...stack.dependencies.map(s => s.artifactId), + ...additionalStackDependencies, + ]; + const meta = collectStackMetadata(stack); + + // backwards compatibility since originally artifact ID was always equal to + // stack name the stackName attribute is optional and if it is not specified + // the CLI will use the artifact ID as the stack name. we *could have* + // always put the stack name here but wanted to minimize the risk around + // changes to the assembly manifest. so this means that as long as stack + // name and artifact ID are the same, the cloud assembly manifest will not + // change. + const stackNameProperty = stack.stackName === stack.artifactId + ? { } + : { stackName: stack.stackName }; + + const properties: cxschema.AwsCloudFormationStackProperties = { + templateFile: stack.templateFile, + terminationProtection: stack.terminationProtection, + ...stackProps, + ...stackNameProperty, + }; + + // add an artifact that represents this stack + session.assembly.addArtifact(stack.artifactId, { + type: cxschema.ArtifactType.AWS_CLOUDFORMATION_STACK, + environment: stack.environment, + properties, + dependencies: deps.length > 0 ? deps : undefined, + metadata: Object.keys(meta).length > 0 ? meta : undefined, + }); +} + +/** + * Collect the metadata from a stack + */ +function collectStackMetadata(stack: Stack) { + const output: { [id: string]: cxschema.MetadataEntry[] } = { }; + + visit(stack); + + return output; + + function visit(node: IConstruct) { + // break off if we reached a node that is not a child of this stack + const parent = findParentStack(node); + if (parent !== stack) { + return; + } + + if (node.node.metadata.length > 0) { + // Make the path absolute + output[ConstructNode.PATH_SEP + node.node.path] = node.node.metadata.map(md => stack.resolve(md) as cxschema.MetadataEntry); + } + + for (const child of node.node.children) { + visit(child); + } + } + + function findParentStack(node: IConstruct): Stack | undefined { + if (node instanceof Stack && node.nestedStackParent === undefined) { + return node; + } + + if (!node.node.scope) { + return undefined; + } + + return findParentStack(node.node.scope); + } +} + +/** + * Hash a string + */ +export function contentHash(content: string) { + return crypto.createHash('sha256').update(content).digest('hex'); +} + +/** + * Throw an error message about binding() if we don't have a value for x. + * + * This replaces the ! assertions we would need everywhere otherwise. + */ +export function assertBound(x: A | undefined): asserts x is NonNullable { + if (x === null && x === undefined) { + throw new Error('You must call bindStack() first'); + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts new file mode 100644 index 0000000000000..ca2f9b0b7e3fe --- /dev/null +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts @@ -0,0 +1,341 @@ +import * as asset_schema from '@aws-cdk/cdk-assets-schema'; +import * as cxschema from '@aws-cdk/cloud-assembly-schema'; +import * as cxapi from '@aws-cdk/cx-api'; +import * as fs from 'fs'; +import * as path from 'path'; +import { DockerImageAssetLocation, DockerImageAssetSource, FileAssetLocation, FileAssetPackaging, FileAssetSource } from '../assets'; +import { Fn } from '../cfn-fn'; +import { ISynthesisSession } from '../construct-compat'; +import { Stack } from '../stack'; +import { Token } from '../token'; +import { addStackArtifactToAssembly, assertBound, contentHash } from './_shared'; +import { IStackSynthesizer } from './types'; + +/** + * Configuration properties for DefaultStackSynthesizer + */ +export interface DefaultStackSynthesizerProps { + /** + * Name of the S3 bucket to hold file assets + * + * You must supply this if you have given a non-standard name to the staging bucket. + * + * The placeholders `${Qualifier}`, `${AWS::AccountId}` and `${AWS::Region}` will + * be replaced with the values of qualifier and the stack's account and region, + * respectively. + * + * @default DefaultStackSynthesizer.DEFAULT_FILE_ASSETS_BUCKET_NAME + */ + readonly fileAssetsBucketName?: string; + + /** + * Name of the ECR repository to hold Docker Image assets + * + * You must supply this if you have given a non-standard name to the ECR repository. + * + * The placeholders `${Qualifier}`, `${AWS::AccountId}` and `${AWS::Region}` will + * be replaced with the values of qualifier and the stack's account and region, + * respectively. + * + * @default DefaultStackSynthesizer.DEFAULT_IMAGE_ASSETS_REPOSITORY_NAME + */ + readonly imageAssetsRepositoryName?: string; + + /** + * The role to use to publish assets to this environment + * + * You must supply this if you have given a non-standard name to the publishing role. + * + * The placeholders `${Qualifier}`, `${AWS::AccountId}` and `${AWS::Region}` will + * be replaced with the values of qualifier and the stack's account and region, + * respectively. + * + * @default DefaultStackSynthesizer.DEFAULT_ASSET_PUBLISHING_ROLE_ARN + */ + readonly assetPublishingRoleArn?: string; + + /** + * External ID to use when assuming role for asset publishing + * + * @default - No external ID + */ + readonly assetPublishingExternalId?: string; + + /** + * The role to assume to initiate a deployment in this environment + * + * You must supply this if you have given a non-standard name to the publishing role. + * + * The placeholders `${Qualifier}`, `${AWS::AccountId}` and `${AWS::Region}` will + * be replaced with the values of qualifier and the stack's account and region, + * respectively. + * + * @default DefaultStackSynthesizer.DEFAULT_DEPLOY_ACTION_ROLE_ARN + */ + readonly deployActionRoleArn?: string; + + /** + * The role CloudFormation will assume when deploying the Stack + * + * You must supply this if you have given a non-standard name to the execution role. + * + * The placeholders `${Qualifier}`, `${AWS::AccountId}` and `${AWS::Region}` will + * be replaced with the values of qualifier and the stack's account and region, + * respectively. + * + * @default DefaultStackSynthesizer.DEFAULT_CLOUDFORMATION_ROLE_ARN + */ + readonly cloudFormationExecutionRole?: string; + + /** + * Qualifier to disambiguate multiple environments in the same account + * + * You can use this and leave the other naming properties empty if you have deployed + * the bootstrap environment with standard names but only differnet qualifiers. + * + * @default DefaultStackSynthesizer.DEFAULT_QUALIFIER + */ + readonly qualifier?: string; +} + +/** + * Uses conventionally named roles and reify asset storage locations + * + * This synthesizer is the only StackSynthesizer that generates + * an asset manifest, and is required to deploy CDK applications using the + * `@aws-cdk/app-delivery` CI/CD library. + * + * Requires the environment to have been bootstrapped with Bootstrap Stack V2. + */ +export class DefaultStackSynthesizer implements IStackSynthesizer { + /** + * Default ARN qualifier + */ + public static readonly DEFAULT_QUALIFIER = 'hnb659fds'; + + /** + * Default CloudFormation role ARN. + */ + public static readonly DEFAULT_CLOUDFORMATION_ROLE_ARN = 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-bootstrap-cfn-exec-role-${AWS::AccountId}-${AWS::Region}'; + + /** + * Default deploy action role ARN. + */ + public static readonly DEFAULT_DEPLOY_ACTION_ROLE_ARN = 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-bootstrap-deploy-action-role-${AWS::AccountId}-${AWS::Region}'; + + /** + * Default asset publishing role ARN. + */ + public static readonly DEFAULT_ASSET_PUBLISHING_ROLE_ARN = 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-bootstrap-publishing-role-${AWS::AccountId}-${AWS::Region}'; + + /** + * Default image assets repository name + */ + public static readonly DEFAULT_IMAGE_ASSETS_REPOSITORY_NAME = 'cdk-bootstrap-${Qualifier}-container-assets-${AWS::AccountId}-${AWS::Region}'; + + /** + * Default file assets bucket name + */ + public static readonly DEFAULT_FILE_ASSETS_BUCKET_NAME = 'cdk-bootstrap-${Qualifier}-assets-${AWS::AccountId}-${AWS::Region}'; + + private stack?: Stack; + private bucketName?: string; + private repositoryName?: string; + private deployActionRoleArn?: string; + private cloudFormationExecutionRoleArn?: string; + private assetPublishingRoleArn?: string; + + private readonly files: NonNullable = {}; + private readonly dockerImages: NonNullable = {}; + + constructor(private readonly props: DefaultStackSynthesizerProps = {}) { + } + + public bind(stack: Stack): void { + this.stack = stack; + + const qualifier = this.props.qualifier ?? DefaultStackSynthesizer.DEFAULT_QUALIFIER; + + // Function to replace placeholders in the input string as much as possible + // + // We replace: + // - ${Qualifier}: always + // - ${AWS::AccountId}, ${AWS::Region}: only if we have the actual values available + // - ${AWS::Partition}: never, since we never have the actual partition value. + const specialize = (s: string) => { + s = replaceAll(s, '${Qualifier}', qualifier); + return cxapi.EnvironmentPlaceholders.replace(s, { + region: resolvedOr(stack.region, cxapi.EnvironmentPlaceholders.CURRENT_REGION), + accountId: resolvedOr(stack.account, cxapi.EnvironmentPlaceholders.CURRENT_ACCOUNT), + partition: cxapi.EnvironmentPlaceholders.CURRENT_PARTITION, + }); + }; + + // tslint:disable:max-line-length + this.bucketName = specialize(this.props.fileAssetsBucketName ?? DefaultStackSynthesizer.DEFAULT_FILE_ASSETS_BUCKET_NAME); + this.repositoryName = specialize(this.props.imageAssetsRepositoryName ?? DefaultStackSynthesizer.DEFAULT_IMAGE_ASSETS_REPOSITORY_NAME); + this.deployActionRoleArn = specialize(this.props.deployActionRoleArn ?? DefaultStackSynthesizer.DEFAULT_DEPLOY_ACTION_ROLE_ARN); + this.cloudFormationExecutionRoleArn = specialize(this.props.cloudFormationExecutionRole ?? DefaultStackSynthesizer.DEFAULT_CLOUDFORMATION_ROLE_ARN); + this.assetPublishingRoleArn = specialize(this.props.assetPublishingRoleArn ?? DefaultStackSynthesizer.DEFAULT_ASSET_PUBLISHING_ROLE_ARN); + // tslint:enable:max-line-length + } + + public addFileAsset(asset: FileAssetSource): FileAssetLocation { + assertBound(this.stack); + assertBound(this.bucketName); + + const objectKey = asset.sourceHash + (asset.packaging === FileAssetPackaging.ZIP_DIRECTORY ? '.zip' : ''); + + // Add to manifest + this.files[asset.sourceHash] = { + source: { + path: asset.fileName, + packaging: asset.packaging, + }, + destinations: { + [this.manifestEnvName]: { + bucketName: this.bucketName, + objectKey, + region: resolvedOr(this.stack.region, undefined), + assumeRoleArn: this.assetPublishingRoleArn, + assumeRoleExternalId: this.props.assetPublishingExternalId, + }, + }, + }; + + // Return CFN expression + return { + bucketName: cfnify(this.bucketName), + objectKey, + s3Url: cfnify(`https://s3.${this.stack.region}.${this.stack.urlSuffix}/${this.bucketName}/${objectKey}`), + }; + } + + public addDockerImageAsset(asset: DockerImageAssetSource): DockerImageAssetLocation { + assertBound(this.stack); + assertBound(this.repositoryName); + + const imageTag = asset.sourceHash; + + // Add to manifest + this.dockerImages[asset.sourceHash] = { + source: { + directory: asset.directoryName, + dockerBuildArgs: asset.dockerBuildArgs, + dockerBuildTarget: asset.dockerBuildTarget, + dockerFile: asset.dockerFile, + }, + destinations: { + [this.manifestEnvName]: { + repositoryName: this.repositoryName, + imageTag, + region: resolvedOr(this.stack.region, undefined), + assumeRoleArn: this.assetPublishingRoleArn, + assumeRoleExternalId: this.props.assetPublishingExternalId, + }, + }, + }; + + // Return CFN expression + return { + repositoryName: cfnify(this.repositoryName), + imageUri: cfnify(`${this.stack.account}.dkr.ecr.${this.stack.region}.${this.stack.urlSuffix}/${this.repositoryName}:${imageTag}`), + }; + } + + public synthesizeStackArtifacts(session: ISynthesisSession): void { + assertBound(this.stack); + + // Add the stack's template to the artifact manifest + const templateAsset = this.addStackTemplateToAssetManifest(session); + + const artifactId = this.writeAssetManifest(session); + + addStackArtifactToAssembly(session, this.stack, { + assumeRoleArn: this.deployActionRoleArn, + cloudFormationExecutionRoleArn: this.cloudFormationExecutionRoleArn, + stackTemplateAssetObjectUrl: templateAsset.s3Url, + requiresBootstrapStackVersion: 1, + }, [artifactId]); + } + + /** + * Add the stack's template as one of the manifest assets + * + * This will make it get uploaded to S3 automatically by S3-assets. Return + * the URL. + */ + private addStackTemplateToAssetManifest(session: ISynthesisSession) { + assertBound(this.stack); + + const templatePath = path.join(session.assembly.outdir, this.stack.templateFile); + const template = fs.readFileSync(templatePath, { encoding: 'utf-8' }); + + return this.addFileAsset({ + fileName: this.stack.templateFile, + packaging: FileAssetPackaging.FILE, + sourceHash: contentHash(template), + }); + } + + /** + * Write an asset manifest to the Cloud Assembly, return the artifact IDs written + */ + private writeAssetManifest(session: ISynthesisSession): string { + assertBound(this.stack); + + const artifactId = `${this.stack.artifactId}.assets`; + const manifestFile = `${artifactId}.json`; + const outPath = path.join(session.assembly.outdir, manifestFile); + + const manifest: asset_schema.ManifestFile = { + version: asset_schema.AssetManifestSchema.currentVersion(), + files: this.files, + dockerImages: this.dockerImages, + }; + + fs.writeFileSync(outPath, JSON.stringify(manifest, undefined, 2)); + session.assembly.addArtifact(artifactId, { + type: cxschema.ArtifactType.ASSET_MANIFEST, + properties: { + file: manifestFile, + requiresBootstrapStackVersion: 1, + }, + }); + + return artifactId; + } + + private get manifestEnvName(): string { + assertBound(this.stack); + + return [ + resolvedOr(this.stack.account, 'current_account'), + resolvedOr(this.stack.region, 'current_region'), + ].join('-'); + } +} + +/** + * Return the given value if resolved or fall back to a default + */ +function resolvedOr(x: string, def: A): string | A { + return Token.isUnresolved(x) ? def : x; +} + +/** + * A "replace-all" function that doesn't require us escaping a literal string to a regex + */ +function replaceAll(s: string, search: string, replace: string) { + return s.split(search).join(replace); +} + +/** + * If the string still contains placeholders, wrap it in a Fn::Sub so they will be substituted at CFN deploymen time + * + * (This happens to work because the placeholders we picked map directly onto CFN + * placeholders. If they didn't we'd have to do a transformation here). + */ +function cfnify(s: string): string { + return s.indexOf('${') > -1 ? Fn.sub(s) : s; +} diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/index.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/index.ts new file mode 100644 index 0000000000000..5920f19bae2c9 --- /dev/null +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/index.ts @@ -0,0 +1,4 @@ +export * from './types'; +export * from './default-synthesizer'; +export * from './legacy'; +export * from './nested'; \ No newline at end of file diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/legacy.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/legacy.ts new file mode 100644 index 0000000000000..7d46d19544fba --- /dev/null +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/legacy.ts @@ -0,0 +1,177 @@ +import * as cxschema from '@aws-cdk/cloud-assembly-schema'; +import * as cxapi from '@aws-cdk/cx-api'; +import { DockerImageAssetLocation, DockerImageAssetSource, FileAssetLocation, FileAssetSource } from '../assets'; +import { Fn } from '../cfn-fn'; +import { Construct, ISynthesisSession } from '../construct-compat'; +import { FileAssetParameters } from '../private/asset-parameters'; +import { Stack } from '../stack'; +import { addStackArtifactToAssembly, assertBound } from './_shared'; +import { IStackSynthesizer } from './types'; + +/** + * The well-known name for the docker image asset ECR repository. All docker + * image assets will be pushed into this repository with an image tag based on + * the source hash. + */ +const ASSETS_ECR_REPOSITORY_NAME = 'aws-cdk/assets'; + +/** + * This allows users to work around the fact that the ECR repository is + * (currently) not configurable by setting this context key to their desired + * repository name. The CLI will auto-create this ECR repository if it's not + * already created. + */ +const ASSETS_ECR_REPOSITORY_NAME_OVERRIDE_CONTEXT_KEY = 'assets-ecr-repository-name'; + +/** + * Use the original deployment environment + * + * This deployment environment is restricted in cross-environment deployments, + * CI/CD deployments, and will use up CloudFormation parameters in your template. + * + * This is the only StackSynthesizer that supports customizing asset behavior + * by overriding `Stack.addFileAsset()` and `Stack.addDockerImageAsset()`. + */ +export class LegacyStackSynthesizer implements IStackSynthesizer { + private stack?: Stack; + private cycle = false; + + /** + * Includes all parameters synthesized for assets (lazy). + */ + private _assetParameters?: Construct; + + /** + * The image ID of all the docker image assets that were already added to this + * stack (to avoid duplication). + */ + private readonly addedImageAssets = new Set(); + + public bind(stack: Stack): void { + this.stack = stack; + } + + public addFileAsset(asset: FileAssetSource): FileAssetLocation { + assertBound(this.stack); + + // Backwards compatibility hack. We have a number of conflicting goals here: + // + // - We want put the actual logic in this class + // - We ALSO want to keep supporting people overriding Stack.addFileAsset (for backwards compatibility, + // because that mechanism is currently used to make CI/CD scenarios work) + // - We ALSO want to allow both entry points from user code (our own framework + // code will always call stack.deploymentMechanism.addFileAsset() but existing users + // may still be calling `stack.addFileAsset()` directly. + // + // Solution: delegate call to the stack, but if the stack delegates back to us again + // then do the actual logic. + if (this.cycle) { + return this.doAddFileAsset(asset); + } + this.cycle = true; + try { + return this.stack.addFileAsset(asset); + } finally { + this.cycle = false; + } + } + + public addDockerImageAsset(asset: DockerImageAssetSource): DockerImageAssetLocation { + assertBound(this.stack); + + // See `addFileAsset` for explanation. + if (this.cycle) { + return this.doAddDockerImageAsset(asset); + } + this.cycle = true; + try { + return this.stack.addDockerImageAsset(asset); + } finally { + this.cycle = false; + } + } + + public synthesizeStackArtifacts(session: ISynthesisSession): void { + assertBound(this.stack); + + // Just do the default stuff, nothing special + addStackArtifactToAssembly(session, this.stack, {}, []); + } + + private doAddDockerImageAsset(asset: DockerImageAssetSource): DockerImageAssetLocation { + assertBound(this.stack); + + // check if we have an override from context + const repositoryNameOverride = this.stack.node.tryGetContext(ASSETS_ECR_REPOSITORY_NAME_OVERRIDE_CONTEXT_KEY); + const repositoryName = asset.repositoryName ?? repositoryNameOverride ?? ASSETS_ECR_REPOSITORY_NAME; + const imageTag = asset.sourceHash; + const assetId = asset.sourceHash; + + // only add every image (identified by source hash) once for each stack that uses it. + if (!this.addedImageAssets.has(assetId)) { + const metadata: cxschema.ContainerImageAssetMetadataEntry = { + repositoryName, + imageTag, + id: assetId, + packaging: 'container-image', + path: asset.directoryName, + sourceHash: asset.sourceHash, + buildArgs: asset.dockerBuildArgs, + target: asset.dockerBuildTarget, + file: asset.dockerFile, + }; + + this.stack.node.addMetadata(cxschema.ArtifactMetadataEntryType.ASSET, metadata); + this.addedImageAssets.add(assetId); + } + + return { + imageUri: `${this.stack.account}.dkr.ecr.${this.stack.region}.${this.stack.urlSuffix}/${repositoryName}:${imageTag}`, + repositoryName, + }; + } + + private doAddFileAsset(asset: FileAssetSource): FileAssetLocation { + assertBound(this.stack); + + let params = this.assetParameters.node.tryFindChild(asset.sourceHash) as FileAssetParameters; + if (!params) { + params = new FileAssetParameters(this.assetParameters, asset.sourceHash); + + const metadata: cxschema.FileAssetMetadataEntry = { + path: asset.fileName, + id: asset.sourceHash, + packaging: asset.packaging, + sourceHash: asset.sourceHash, + + s3BucketParameter: params.bucketNameParameter.logicalId, + s3KeyParameter: params.objectKeyParameter.logicalId, + artifactHashParameter: params.artifactHashParameter.logicalId, + }; + + this.stack.node.addMetadata(cxschema.ArtifactMetadataEntryType.ASSET, metadata); + } + + const bucketName = params.bucketNameParameter.valueAsString; + + // key is prefix|postfix + const encodedKey = params.objectKeyParameter.valueAsString; + + const s3Prefix = Fn.select(0, Fn.split(cxapi.ASSET_PREFIX_SEPARATOR, encodedKey)); + const s3Filename = Fn.select(1, Fn.split(cxapi.ASSET_PREFIX_SEPARATOR, encodedKey)); + const objectKey = `${s3Prefix}${s3Filename}`; + + const s3Url = `https://s3.${this.stack.region}.${this.stack.urlSuffix}/${bucketName}/${objectKey}`; + + return { bucketName, objectKey, s3Url }; + } + + private get assetParameters() { + assertBound(this.stack); + + if (!this._assetParameters) { + this._assetParameters = new Construct(this.stack, 'AssetParameters'); + } + return this._assetParameters; + } +} diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/nested.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/nested.ts new file mode 100644 index 0000000000000..8841618823aa9 --- /dev/null +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/nested.ts @@ -0,0 +1,35 @@ +import { DockerImageAssetLocation, DockerImageAssetSource, FileAssetLocation, FileAssetSource } from '../assets'; +import { ISynthesisSession } from '../construct-compat'; +import { Stack } from '../stack'; +import { IStackSynthesizer } from './types'; + +/** + * Deployment environment for a nested stack + * + * Interoperates with the StackSynthesizer of the parent stack. + */ +export class NestedStackSynthesizer implements IStackSynthesizer { + constructor(private readonly parentDeployment: IStackSynthesizer) { + } + + public bind(_stack: Stack): void { + // Nothing to do + } + + public addFileAsset(asset: FileAssetSource): FileAssetLocation { + // Forward to parent deployment. By the magic of cross-stack references any parameter + // returned and used will magically be forwarded to the nested stack. + return this.parentDeployment.addFileAsset(asset); + } + + public addDockerImageAsset(asset: DockerImageAssetSource): DockerImageAssetLocation { + // Forward to parent deployment. By the magic of cross-stack references any parameter + // returned and used will magically be forwarded to the nested stack. + return this.parentDeployment.addDockerImageAsset(asset); + } + + public synthesizeStackArtifacts(_session: ISynthesisSession): void { + // Do not emit Nested Stack as a cloud assembly artifact. + // It will be registered as an S3 asset of its parent instead. + } +} diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/types.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/types.ts new file mode 100644 index 0000000000000..c7f5fce1a7cbf --- /dev/null +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/types.ts @@ -0,0 +1,36 @@ +import { DockerImageAssetLocation, DockerImageAssetSource, FileAssetLocation, FileAssetSource } from '../assets'; +import { ISynthesisSession } from '../construct-compat'; +import { Stack } from '../stack'; + +/** + * Encodes information how a certain Stack should be deployed + */ +export interface IStackSynthesizer { + /** + * Bind to the stack this environment is going to be used on + * + * Must be called before any of the other methods are called. + */ + bind(stack: Stack): void; + + /** + * Register a File Asset + * + * Returns the parameters that can be used to refer to the asset inside the template. + */ + addFileAsset(asset: FileAssetSource): FileAssetLocation; + + /** + * Register a Docker Image Asset + * + * Returns the parameters that can be used to refer to the asset inside the template. + */ + addDockerImageAsset(asset: DockerImageAssetSource): DockerImageAssetLocation; + + /** + * Synthesize all artifacts required for the stack into the session + * + * @experimental + */ + synthesizeStackArtifacts(session: ISynthesisSession): void; +} diff --git a/packages/@aws-cdk/core/lib/stack.ts b/packages/@aws-cdk/core/lib/stack.ts index cda56f53de5e8..7d5d41fe72feb 100644 --- a/packages/@aws-cdk/core/lib/stack.ts +++ b/packages/@aws-cdk/core/lib/stack.ts @@ -3,10 +3,9 @@ import * as cxapi from '@aws-cdk/cx-api'; import * as fs from 'fs'; import * as path from 'path'; import { DockerImageAssetLocation, DockerImageAssetSource, FileAssetLocation, FileAssetSource } from './assets'; -import { Construct, ConstructNode, IConstruct, ISynthesisSession } from './construct-compat'; +import { Construct, IConstruct, ISynthesisSession } from './construct-compat'; import { ContextProvider } from './context-provider'; import { Environment } from './environment'; -import { FileAssetParameters } from './private/asset-parameters'; import { CLOUDFORMATION_TOKEN_RESOLVER, CloudFormationLang } from './private/cloudformation-lang'; import { LogicalIDs } from './private/logical-id'; import { resolve } from './private/resolve'; @@ -17,21 +16,6 @@ const MY_STACK_CACHE = Symbol.for('@aws-cdk/core.Stack.myStack'); const VALID_STACK_NAME_REGEX = /^[A-Za-z][A-Za-z0-9-]*$/; -/** - * The well-known name for the docker image asset ECR repository. All docker - * image assets will be pushed into this repository with an image tag based on - * the source hash. - */ -const ASSETS_ECR_REPOSITORY_NAME = 'aws-cdk/assets'; - -/** - * This allows users to work around the fact that the ECR repository is - * (currently) not configurable by setting this context key to their desired - * repository name. The CLI will auto-create this ECR repository if it's not - * already created. - */ -const ASSETS_ECR_REPOSITORY_NAME_OVERRIDE_CONTEXT_KEY = 'assets-ecr-repository-name'; - export interface StackProps { /** * A description of the stack. @@ -62,6 +46,14 @@ export interface StackProps { */ readonly tags?: { [key: string]: string }; + /** + * Synthesis method to use while deploying this stack + * + * @default - `DefaultStackSynthesizer` if the `@aws-cdk/core:newStyleStackSynthesis` feature flag + * is set, `LegacyStackSynthesizer` otherwise. + */ + readonly synthesizer?: IStackSynthesizer; + /** * Whether to enable termination protection for this stack. * @@ -214,6 +206,13 @@ export class Stack extends Construct implements ITaggable { */ public readonly artifactId: string; + /** + * Synthesis method for this stack + * + * @experimental + */ + public readonly synthesizer: IStackSynthesizer; + /** * Logical ID generation strategy */ @@ -231,19 +230,8 @@ export class Stack extends Construct implements ITaggable { */ private readonly _missingContext = new Array(); - /** - * Includes all parameters synthesized for assets (lazy). - */ - private _assetParameters?: Construct; - private readonly _stackName: string; - /** - * The image ID of all the docker image assets that were already added to this - * stack (to avoid duplication). - */ - private readonly addedImageAssets = new Set(); - /** * Creates a new stack. * @@ -294,6 +282,11 @@ export class Stack extends Construct implements ITaggable { : this.stackName; this.templateFile = `${this.artifactId}.template.json`; + + this.synthesizer = props.synthesizer ?? (this.node.tryGetContext(cxapi.NEW_STYLE_STACK_SYNTHESIS_CONTEXT) + ? new DefaultStackSynthesizer() + : new LegacyStackSynthesizer()); + this.synthesizer.bind(this); } /** @@ -534,78 +527,24 @@ export class Stack extends Construct implements ITaggable { return value; } + /** + * Register a file asset on this Stack + * + * @deprecated Use `stack.synthesizer.addFileAsset()` if you are calling, + * and a different IDeploymentEnvironment class if you are implementing. + */ public addFileAsset(asset: FileAssetSource): FileAssetLocation { - - // assets are always added at the top-level stack - if (this.nestedStackParent) { - return this.nestedStackParent.addFileAsset(asset); - } - - let params = this.assetParameters.node.tryFindChild(asset.sourceHash) as FileAssetParameters; - if (!params) { - params = new FileAssetParameters(this.assetParameters, asset.sourceHash); - - const metadata: cxschema.FileAssetMetadataEntry = { - path: asset.fileName, - id: asset.sourceHash, - packaging: asset.packaging, - sourceHash: asset.sourceHash, - - s3BucketParameter: params.bucketNameParameter.logicalId, - s3KeyParameter: params.objectKeyParameter.logicalId, - artifactHashParameter: params.artifactHashParameter.logicalId, - }; - - this.node.addMetadata(cxschema.ArtifactMetadataEntryType.ASSET, metadata); - } - - const bucketName = params.bucketNameParameter.valueAsString; - - // key is prefix|postfix - const encodedKey = params.objectKeyParameter.valueAsString; - - const s3Prefix = Fn.select(0, Fn.split(cxapi.ASSET_PREFIX_SEPARATOR, encodedKey)); - const s3Filename = Fn.select(1, Fn.split(cxapi.ASSET_PREFIX_SEPARATOR, encodedKey)); - const objectKey = `${s3Prefix}${s3Filename}`; - - const s3Url = `https://s3.${this.region}.${this.urlSuffix}/${bucketName}/${objectKey}`; - - return { bucketName, objectKey, s3Url }; + return this.synthesizer.addFileAsset(asset); } + /** + * Register a docker image asset on this Stack + * + * @deprecated Use `stack.synthesizer.addDockerImageAsset()` if you are calling, + * and a different `IDeploymentEnvironment` class if you are implementing. + */ public addDockerImageAsset(asset: DockerImageAssetSource): DockerImageAssetLocation { - if (this.nestedStackParent) { - return this.nestedStackParent.addDockerImageAsset(asset); - } - - // check if we have an override from context - const repositoryNameOverride = this.node.tryGetContext(ASSETS_ECR_REPOSITORY_NAME_OVERRIDE_CONTEXT_KEY); - const repositoryName = asset.repositoryName ?? repositoryNameOverride ?? ASSETS_ECR_REPOSITORY_NAME; - const imageTag = asset.sourceHash; - const assetId = asset.sourceHash; - - // only add every image (identified by source hash) once for each stack that uses it. - if (!this.addedImageAssets.has(assetId)) { - const metadata: cxschema.ContainerImageAssetMetadataEntry = { - repositoryName, - imageTag, - id: assetId, - packaging: 'container-image', - path: asset.directoryName, - sourceHash: asset.sourceHash, - buildArgs: asset.dockerBuildArgs, - target: asset.dockerBuildTarget, - file: asset.dockerFile, - }; - - this.node.addMetadata(cxschema.ArtifactMetadataEntryType.ASSET, metadata); - this.addedImageAssets.add(assetId); - } - - return { - imageUri: `${this.account}.dkr.ecr.${this.region}.${this.urlSuffix}/${repositoryName}:${imageTag}`, - repositoryName, - }; + return this.synthesizer.addDockerImageAsset(asset); } /** @@ -758,6 +697,12 @@ export class Stack extends Construct implements ITaggable { } protected synthesize(session: ISynthesisSession): void { + // In principle, stack synthesis is delegated to the + // StackSynthesis object. + // + // However, some parts of synthesis currently use some private + // methods on Stack, and I don't really see the value in refactoring + // this right now, so some parts still happen here. const builder = session.assembly; // write the CloudFormation template as a JSON file @@ -769,46 +714,8 @@ export class Stack extends Construct implements ITaggable { builder.addMissing(ctx); } - // if this is a nested stack, do not emit it as a cloud assembly artifact (it will be registered as an s3 asset instead) - if (this.nested) { - return; - } - - // backwards compatibility since originally artifact ID was always equal to - // stack name the stackName attribute is optional and if it is not specified - // the CLI will use the artifact ID as the stack name. we *could have* - // always put the stack name here but wanted to minimize the risk around - // changes to the assembly manifest. so this means that as long as stack - // name and artifact ID are the same, the cloud assembly manifest will not - // change. - const stackNameProperty = this.stackName === this.artifactId - ? { } - : { stackName: this.stackName }; - - // nested stack tags are applied at the AWS::CloudFormation::Stack resource - // level and are not needed in the cloud assembly. - // TODO: move these to the cloud assembly artifact properties instead of metadata - if (this.tags.hasTags()) { - this.node.addMetadata(cxschema.ArtifactMetadataEntryType.STACK_TAGS, this.tags.renderTags()); - } - - const properties: cxapi.AwsCloudFormationStackProperties = { - templateFile: this.templateFile, - terminationProtection: this.terminationProtection, - ...stackNameProperty, - }; - - const deps = this.dependencies.map(s => s.artifactId); - const meta = this.collectMetadata(); - - // add an artifact that represents this stack - builder.addArtifact(this.artifactId, { - type: cxschema.ArtifactType.AWS_CLOUDFORMATION_STACK, - environment: this.environment, - properties, - dependencies: deps.length > 0 ? deps : undefined, - metadata: Object.keys(meta).length > 0 ? meta : undefined, - }); + // Delegate adding artifacts to the Synthesizer + this.synthesizer.synthesizeStackArtifacts(session); } /** @@ -910,44 +817,6 @@ export class Stack extends Construct implements ITaggable { return undefined; } - private collectMetadata() { - const output: { [id: string]: cxschema.MetadataEntry[] } = { }; - const stack = this; - - visit(this); - - return output; - - function visit(node: IConstruct) { - // break off if we reached a node that is not a child of this stack - const parent = findParentStack(node); - if (parent !== stack) { - return; - } - - if (node.node.metadata.length > 0) { - // Make the path absolute - output[ConstructNode.PATH_SEP + node.node.path] = node.node.metadata.map(md => stack.resolve(md) as cxschema.MetadataEntry); - } - - for (const child of node.node.children) { - visit(child); - } - } - - function findParentStack(node: IConstruct): Stack | undefined { - if (node instanceof Stack && node.nestedStackParent === undefined) { - return node; - } - - if (!node.node.scope) { - return undefined; - } - - return findParentStack(node.node.scope); - } - } - /** * Calculcate the stack name based on the construct path */ @@ -968,13 +837,6 @@ export class Stack extends Construct implements ITaggable { return makeUniqueId(ids); } - - private get assetParameters() { - if (!this._assetParameters) { - this._assetParameters = new Construct(this, 'AssetParameters'); - } - return this._assetParameters; - } } function merge(template: any, part: any) { @@ -1062,6 +924,7 @@ import { addDependency } from './deps'; import { prepareApp } from './private/prepare-app'; import { Reference } from './reference'; import { IResolvable } from './resolvable'; +import { DefaultStackSynthesizer, IStackSynthesizer, LegacyStackSynthesizer } from './stack-synthesizers'; import { ITaggable, TagManager } from './tag-manager'; import { Token } from './token'; diff --git a/packages/@aws-cdk/core/lib/tag-manager.ts b/packages/@aws-cdk/core/lib/tag-manager.ts index 690a4e34c98d7..b1db219ef4440 100644 --- a/packages/@aws-cdk/core/lib/tag-manager.ts +++ b/packages/@aws-cdk/core/lib/tag-manager.ts @@ -279,7 +279,8 @@ export class TagManager { * Renders tags into the proper format based on TagType */ public renderTags(): any { - return this.tagFormatter.formatTags(Array.from(this.tags.values())); + const sortedTags = Array.from(this.tags.values()).sort((a, b) => a.key.localeCompare(b.key)); + return this.tagFormatter.formatTags(sortedTags); } /** diff --git a/packages/@aws-cdk/core/package.json b/packages/@aws-cdk/core/package.json index 66a24307bad97..53971c1d69a25 100644 --- a/packages/@aws-cdk/core/package.json +++ b/packages/@aws-cdk/core/package.json @@ -108,7 +108,8 @@ "module-name:@aws-cdk/core", "construct-ctor:@aws-cdk/core.CustomResourceProvider", "construct-interface-extends-iconstruct:@aws-cdk/core.ICustomResourceProvider", - "props-physical-name:@aws-cdk/core.CustomResourceProps" + "props-physical-name:@aws-cdk/core.CustomResourceProps", + "integ-return-type:@aws-cdk/core.IStackSynthesizer.bind" ] }, "scripts": { @@ -149,9 +150,9 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/lodash": "^4.14.150", + "@types/lodash": "^4.14.151", "@types/node": "^10.17.21", - "@types/nodeunit": "^0.0.30", + "@types/nodeunit": "^0.0.31", "@types/minimatch": "^3.0.3", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -164,6 +165,7 @@ "dependencies": { "minimatch": "^3.0.4", "@aws-cdk/cx-api": "0.0.0", + "@aws-cdk/cdk-assets-schema": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", "constructs": "^3.0.2" }, @@ -172,12 +174,13 @@ ], "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { - "@aws-cdk/cx-api": "0.0.0", + "@aws-cdk/cdk-assets-schema": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", + "@aws-cdk/cx-api": "0.0.0", "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "stable", "awscdkio": { diff --git a/packages/@aws-cdk/core/test/evaluate-cfn.ts b/packages/@aws-cdk/core/test/evaluate-cfn.ts index 8e36aea9dc0e0..1c5a07dab7b5e 100644 --- a/packages/@aws-cdk/core/test/evaluate-cfn.ts +++ b/packages/@aws-cdk/core/test/evaluate-cfn.ts @@ -25,6 +25,16 @@ export function evaluateCFN(object: any, context: {[key: string]: string} = {}): } return context[key]; }, + + 'Fn::Sub'(argument: string | [string, Record]) { + const template: string = evaluate(Array.isArray(argument) ? argument[0] : argument); + const placeholders: Record = Array.isArray(argument) ? evaluate(argument[1]) : context; + + return template.replace(/\$\{([a-zA-Z0-9.:-]*)\}/g, (_: string, key: string) => { + if (key in placeholders) { return placeholders[key]; } + throw new Error(`Unknown placeholder in Fn::Sub: ${key}`); + }); + }, }; return evaluate(object); diff --git a/packages/@aws-cdk/core/test/stack-synthesis/test.new-style-synthesis.ts b/packages/@aws-cdk/core/test/stack-synthesis/test.new-style-synthesis.ts new file mode 100644 index 0000000000000..7b47858d9a6d7 --- /dev/null +++ b/packages/@aws-cdk/core/test/stack-synthesis/test.new-style-synthesis.ts @@ -0,0 +1,104 @@ +import * as asset_schema from '@aws-cdk/cdk-assets-schema'; +import * as cxapi from '@aws-cdk/cx-api'; +import * as fs from 'fs'; +import { Test } from 'nodeunit'; +import { App, FileAssetPackaging, Stack } from '../../lib'; +import { evaluateCFN } from '../evaluate-cfn'; + +const CFN_CONTEXT = { + 'AWS::Region': 'the_region', + 'AWS::AccountId': 'the_account', + 'AWS::URLSuffix': 'domain.aws', +}; + +let app: App; +let stack: Stack; +export = { + 'setUp'(cb: () => void) { + app = new App({ + context: { + [cxapi.NEW_STYLE_STACK_SYNTHESIS_CONTEXT]: 'true', + }, + }); + stack = new Stack(app, 'Stack'); + cb(); + }, + + 'add file asset'(test: Test) { + // WHEN + const location = stack.synthesizer.addFileAsset({ + fileName: __filename, + packaging: FileAssetPackaging.FILE, + sourceHash: 'abcdef', + }); + + // THEN - we have a fixed asset location with region placeholders + test.equals(evalCFN(location.bucketName), 'cdk-bootstrap-hnb659fds-assets-the_account-the_region'); + test.equals(evalCFN(location.s3Url), 'https://s3.the_region.domain.aws/cdk-bootstrap-hnb659fds-assets-the_account-the_region/abcdef'); + + // THEN - object key contains source hash somewhere + test.ok(location.objectKey.indexOf('abcdef') > -1); + + test.done(); + }, + + 'add docker image asset'(test: Test) { + // WHEN + const location = stack.synthesizer.addDockerImageAsset({ + directoryName: '.', + sourceHash: 'abcdef', + }); + + // THEN - we have a fixed asset location with region placeholders + test.equals(evalCFN(location.repositoryName), 'cdk-bootstrap-hnb659fds-container-assets-the_account-the_region'); + test.equals(evalCFN(location.imageUri), 'the_account.dkr.ecr.the_region.domain.aws/cdk-bootstrap-hnb659fds-container-assets-the_account-the_region:abcdef'); + + test.done(); + }, + + 'synthesis'(test: Test) { + // GIVEN + stack.synthesizer.addFileAsset({ + fileName: __filename, + packaging: FileAssetPackaging.FILE, + sourceHash: 'abcdef', + }); + stack.synthesizer.addDockerImageAsset({ + directoryName: '.', + sourceHash: 'abcdef', + }); + + // WHEN + const asm = app.synth(); + + // THEN - we have an asset manifest with both assets and the stack template in there + const manifestArtifact = asm.artifacts.filter(isAssetManifest)[0]; + test.ok(manifestArtifact); + const manifest: asset_schema.ManifestFile = JSON.parse(fs.readFileSync(manifestArtifact.file, { encoding: 'utf-8' })); + + test.equals(Object.keys(manifest.files || {}).length, 2); + test.equals(Object.keys(manifest.dockerImages || {}).length, 1); + + // THEN - every artifact has an assumeRoleArn + for (const file of Object.values({...manifest.files, ...manifest.dockerImages})) { + for (const destination of Object.values(file.destinations)) { + test.ok(destination.assumeRoleArn); + } + } + + test.done(); + }, +}; + +/** + * Evaluate a possibly string-containing value the same way CFN would do + * + * (Be invariant to the specific Fn::Sub or Fn::Join we would output) + */ +function evalCFN(value: any) { + return evaluateCFN(stack.resolve(value), CFN_CONTEXT); +} + +function isAssetManifest(x: cxapi.CloudArtifact): x is cxapi.AssetManifestArtifact { + return x instanceof cxapi.AssetManifestArtifact; +} \ No newline at end of file diff --git a/packages/@aws-cdk/core/test/test.app.ts b/packages/@aws-cdk/core/test/test.app.ts index 04ea5b47492c3..af7a301f5b95b 100644 --- a/packages/@aws-cdk/core/test/test.app.ts +++ b/packages/@aws-cdk/core/test/test.app.ts @@ -293,6 +293,7 @@ export = { test.deepEqual(libs, { '@aws-cdk/core': version, '@aws-cdk/cx-api': version, + '@aws-cdk/cdk-assets-schema': version, '@aws-cdk/cloud-assembly-schema': version, 'jsii-runtime': `node.js/${process.version}`, }); diff --git a/packages/@aws-cdk/core/test/test.logical-id.ts b/packages/@aws-cdk/core/test/test.logical-id.ts index 4310424d23796..332dad2f14eba 100644 --- a/packages/@aws-cdk/core/test/test.logical-id.ts +++ b/packages/@aws-cdk/core/test/test.logical-id.ts @@ -255,6 +255,21 @@ export = { }); test.done(); }, + + 'detects duplicate logical IDs in the same Stack caused by overrideLogicalId'(test: Test) { + const stack = new Stack(); + const resource1 = new CfnResource(stack, 'A', { type: 'Type::Of::A' }); + const resource2 = new CfnResource(stack, 'B', { type: 'Type::Of::B' }); + + resource1.overrideLogicalId('C'); + resource2.overrideLogicalId('C'); + + test.throws(() => { + toCloudFormation(stack); + }, /section 'Resources' already contains 'C'/); + + test.done(); + }, }; function generateString(chars: number) { @@ -277,4 +292,4 @@ function logicalForElementInPath(constructPath: string[]): string { } return stack.resolve((scope as CfnResource).logicalId); -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/core/test/test.runtime-info.ts b/packages/@aws-cdk/core/test/test.runtime-info.ts index fe0752f90b931..84abdf017124b 100644 --- a/packages/@aws-cdk/core/test/test.runtime-info.ts +++ b/packages/@aws-cdk/core/test/test.runtime-info.ts @@ -26,9 +26,36 @@ export = { '@aws-cdk/core': version, '@aws-cdk/cx-api': version, '@aws-cdk/cloud-assembly-schema': version, + '@aws-cdk/cdk-assets-schema': version, '@aws-solutions-konstruk/foo': mockVersion, 'jsii-runtime': `node.js/${process.version}`, }); test.done(); }, + + 'version reporting finds no version with no associated package.json'(test: Test) { + const pkgdir = fs.mkdtempSync(path.join(os.tmpdir(), 'runtime-info-find-npm-package-fixture')); + const mockVersion = '1.2.3'; + + fs.writeFileSync(path.join(pkgdir, 'index.js'), 'module.exports = \'this is bar\';'); + fs.mkdirSync(path.join(pkgdir, 'bar')); + fs.writeFileSync(path.join(pkgdir, 'bar', 'package.json'), JSON.stringify({ + name: '@aws-solutions-konstruk/bar', + version: mockVersion, + })); + + // eslint-disable-next-line @typescript-eslint/no-require-imports, import/no-extraneous-dependencies + require(pkgdir); + + const cwd = process.cwd(); + + // Switch to `bar` where the package.json is, then resolve version. Fails when module.resolve + // is passed an empty string in the paths array. + process.chdir(path.join(pkgdir, 'bar')); + const runtimeInfo = collectRuntimeInformation(); + process.chdir(cwd); + + test.equal(runtimeInfo.libraries['@aws-solutions-konstruk/bar'], undefined); + test.done(); + }, }; diff --git a/packages/@aws-cdk/core/test/test.stack.ts b/packages/@aws-cdk/core/test/test.stack.ts index 569ea65860d2c..7f8e625ee4428 100644 --- a/packages/@aws-cdk/core/test/test.stack.ts +++ b/packages/@aws-cdk/core/test/test.stack.ts @@ -853,6 +853,19 @@ export = { test.deepEqual(asm.getStackArtifact(stack2.artifactId).manifest.metadata, { '/stack1/stack2': expected }); test.done(); }, + + 'Termination Protection is reflected in Cloud Assembly artifact'(test: Test) { + // if the root is an app, invoke "synth" to avoid double synthesis + const app = new App(); + const stack = new Stack(app, 'Stack', { terminationProtection: true }); + + const assembly = app.synth(); + const artifact = assembly.getStackArtifact(stack.artifactId); + + test.equals(artifact.terminationProtection, true); + + test.done(); + }, }; class StackWithPostProcessor extends Stack { diff --git a/packages/@aws-cdk/core/test/test.tag-manager.ts b/packages/@aws-cdk/core/test/test.tag-manager.ts index 99b020d93b0a1..1ba8484fffb4f 100644 --- a/packages/@aws-cdk/core/test/test.tag-manager.ts +++ b/packages/@aws-cdk/core/test/test.tag-manager.ts @@ -72,16 +72,16 @@ export = { res.setTag('asg', 'only', 0, false); } test.deepEqual(standard.renderTags(), [ - {key: 'foo', value: 'bar'}, {key: 'asg', value: 'only'}, + {key: 'foo', value: 'bar'}, ]); test.deepEqual(asg.renderTags(), [ - {key: 'foo', value: 'bar', propagateAtLaunch: true}, {key: 'asg', value: 'only', propagateAtLaunch: false}, + {key: 'foo', value: 'bar', propagateAtLaunch: true}, ]); test.deepEqual(keyValue.renderTags(), [ - { Key: 'foo', Value : 'bar' }, { Key: 'asg', Value : 'only' }, + { Key: 'foo', Value : 'bar' }, ]); test.deepEqual(mapper.renderTags(), { foo: 'bar', @@ -111,6 +111,25 @@ export = { test.deepEqual(mgr.renderTags(), undefined); test.done(); }, + 'tags are always ordered by key name'(test: Test) { + const mgr = new TagManager(TagType.STANDARD, 'AWS::Resource::Type'); + mgr.setTag('key', 'foo'); + mgr.setTag('aardvark', 'zebra'); + mgr.setTag('name', 'test'); + test.deepEqual(mgr.renderTags(), [ + {key: 'aardvark', value: 'zebra'}, + {key: 'key', value: 'foo'}, + {key: 'name', value: 'test'}, + ]); + mgr.setTag('myKey', 'myVal'); + test.deepEqual(mgr.renderTags(), [ + {key: 'aardvark', value: 'zebra'}, + {key: 'key', value: 'foo'}, + {key: 'myKey', value: 'myVal'}, + {key: 'name', value: 'test'}, + ]); + test.done(); + }, 'excludeResourceTypes only tags resources that do not match'(test: Test) { const mgr = new TagManager(TagType.STANDARD, 'AWS::Fake::Resource'); diff --git a/packages/@aws-cdk/custom-resources/.eslintrc.js b/packages/@aws-cdk/custom-resources/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/custom-resources/.eslintrc.js +++ b/packages/@aws-cdk/custom-resources/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/custom-resources/.gitignore b/packages/@aws-cdk/custom-resources/.gitignore index 639df540dac26..669114bcaf206 100644 --- a/packages/@aws-cdk/custom-resources/.gitignore +++ b/packages/@aws-cdk/custom-resources/.gitignore @@ -17,3 +17,4 @@ nyc.config.js lib/aws-custom-resource/sdk-api-metadata.json !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/custom-resources/.npmignore b/packages/@aws-cdk/custom-resources/.npmignore index 273931f8b813c..d21f4808a6c14 100644 --- a/packages/@aws-cdk/custom-resources/.npmignore +++ b/packages/@aws-cdk/custom-resources/.npmignore @@ -20,3 +20,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/custom-resources/README.md b/packages/@aws-cdk/custom-resources/README.md index b724bbbaaeaa6..67d4e16a14263 100644 --- a/packages/@aws-cdk/custom-resources/README.md +++ b/packages/@aws-cdk/custom-resources/README.md @@ -9,7 +9,7 @@ ## Provider Framework -AWS CloudFormation [custom resources] are extension points to the provisioning +AWS CloudFormation [custom resources](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html) are extension points to the provisioning engine. When CloudFormation needs to create, update or delete a custom resource, it sends a lifecycle event notification to a **custom resource provider**. The provider handles the event (e.g. creates a resource) and sends back a response to CloudFormation. @@ -100,8 +100,6 @@ def is_complete(event, context): return { 'IsComplete': is_ready } ``` -[custom resources]: (https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html). - ### Handling Lifecycle Events: onEvent The user-defined `onEvent` AWS Lambda function is invoked whenever a resource diff --git a/packages/@aws-cdk/custom-resources/jest.config.js b/packages/@aws-cdk/custom-resources/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/custom-resources/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/custom-resources/package.json b/packages/@aws-cdk/custom-resources/package.json index 785cf8831bb91..d93639a313004 100644 --- a/packages/@aws-cdk/custom-resources/package.json +++ b/packages/@aws-cdk/custom-resources/package.json @@ -49,7 +49,8 @@ "cdk-build": { "pre": [ "cp -f $(node -p 'require.resolve(\"aws-sdk/apis/metadata.json\")') lib/aws-custom-resource/sdk-api-metadata.json && rm -rf test/aws-custom-resource/cdk.out" - ] + ], + "jest": true }, "keywords": [ "aws", @@ -72,8 +73,8 @@ "@aws-cdk/aws-ssm": "0.0.0", "@types/aws-lambda": "^8.10.39", "@types/fs-extra": "^8.1.0", - "@types/sinon": "^9.0.0", - "aws-sdk": "^2.672.0", + "@types/sinon": "^9.0.1", + "aws-sdk": "^2.678.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", @@ -102,25 +103,8 @@ "@aws-cdk/core": "0.0.0", "constructs": "^3.0.2" }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 70, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "stable", "awslint": { diff --git a/packages/@aws-cdk/cx-api/.eslintrc.js b/packages/@aws-cdk/cx-api/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/cx-api/.eslintrc.js +++ b/packages/@aws-cdk/cx-api/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/cx-api/.gitignore b/packages/@aws-cdk/cx-api/.gitignore index fc15e37f1cfdb..9c86e7fa0fe0b 100644 --- a/packages/@aws-cdk/cx-api/.gitignore +++ b/packages/@aws-cdk/cx-api/.gitignore @@ -13,3 +13,4 @@ tsconfig.json coverage nyc.config.js !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/cx-api/.npmignore b/packages/@aws-cdk/cx-api/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/cx-api/.npmignore +++ b/packages/@aws-cdk/cx-api/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/cx-api/jest.config.js b/packages/@aws-cdk/cx-api/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/cx-api/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/cx-api/lib/asset-manifest-artifact.ts b/packages/@aws-cdk/cx-api/lib/asset-manifest-artifact.ts new file mode 100644 index 0000000000000..8146a276d7e4f --- /dev/null +++ b/packages/@aws-cdk/cx-api/lib/asset-manifest-artifact.ts @@ -0,0 +1,30 @@ +import * as cxschema from '@aws-cdk/cloud-assembly-schema'; +import * as path from 'path'; +import { CloudArtifact } from './cloud-artifact'; +import { CloudAssembly } from './cloud-assembly'; + +/** + * Asset manifest is a description of a set of assets which need to be built and published + */ +export class AssetManifestArtifact extends CloudArtifact { + /** + * The file name of the asset manifest + */ + public readonly file: string; + + /** + * Version of bootstrap stack required to deploy this stack + */ + public readonly requiresBootstrapStackVersion: number; + + constructor(assembly: CloudAssembly, name: string, artifact: cxschema.ArtifactManifest) { + super(assembly, name, artifact); + + const properties = (this.manifest.properties || {}) as cxschema.AssetManifestProperties; + if (!properties.file) { + throw new Error('Invalid AssetManifestArtifact. Missing "file" property'); + } + this.file = path.resolve(this.assembly.directory, properties.file); + this.requiresBootstrapStackVersion = properties.requiresBootstrapStackVersion ?? 1; + } +} diff --git a/packages/@aws-cdk/cx-api/lib/cloud-artifact.ts b/packages/@aws-cdk/cx-api/lib/cloud-artifact.ts index d513743989a74..55cd7567e1612 100644 --- a/packages/@aws-cdk/cx-api/lib/cloud-artifact.ts +++ b/packages/@aws-cdk/cx-api/lib/cloud-artifact.ts @@ -1,9 +1,6 @@ import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import { CloudAssembly } from './cloud-assembly'; -import { - MetadataEntryResult, - SynthesisMessage, - SynthesisMessageLevel } from './metadata'; +import { MetadataEntryResult, SynthesisMessage, SynthesisMessageLevel } from './metadata'; /** * Artifact properties for CloudFormation stacks. @@ -50,6 +47,8 @@ export class CloudArtifact { return new CloudFormationStackArtifact(assembly, id, artifact); case cxschema.ArtifactType.CDK_TREE: return new TreeCloudArtifact(assembly, id, artifact); + case cxschema.ArtifactType.ASSET_MANIFEST: + return new AssetManifestArtifact(assembly, id, artifact); default: return undefined; } @@ -144,5 +143,6 @@ export class CloudArtifact { } // needs to be defined at the end to avoid a cyclic dependency +import { AssetManifestArtifact } from './asset-manifest-artifact'; import { CloudFormationStackArtifact } from './cloudformation-artifact'; -import { TreeCloudArtifact } from './tree-cloud-artifact'; +import { TreeCloudArtifact } from './tree-cloud-artifact'; \ No newline at end of file diff --git a/packages/@aws-cdk/cx-api/lib/cloudformation-artifact.ts b/packages/@aws-cdk/cx-api/lib/cloudformation-artifact.ts index b8b9c0ead664c..2373e45e0eabc 100644 --- a/packages/@aws-cdk/cx-api/lib/cloudformation-artifact.ts +++ b/packages/@aws-cdk/cx-api/lib/cloudformation-artifact.ts @@ -1,7 +1,7 @@ import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import * as fs from 'fs'; import * as path from 'path'; -import { AwsCloudFormationStackProperties, CloudArtifact } from './cloud-artifact'; +import { CloudArtifact } from './cloud-artifact'; import { CloudAssembly } from './cloud-assembly'; import { Environment, EnvironmentUtils } from './environment'; @@ -54,6 +54,34 @@ export class CloudFormationStackArtifact extends CloudArtifact { */ public readonly environment: Environment; + /** + * The role that needs to be assumed to deploy the stack + * + * @default - No role is assumed (current credentials are used) + */ + public readonly assumeRoleArn?: string; + + /** + * The role that is passed to CloudFormation to execute the change set + * + * @default - No role is passed (currently assumed role/credentials are used) + */ + public readonly cloudFormationExecutionRoleArn?: string; + + /** + * If the stack template has already been included in the asset manifest, its asset URL + * + * @default - Not uploaded yet, upload just before deploying + */ + public readonly stackTemplateAssetObjectUrl?: string; + + /** + * Version of bootstrap stack required to deploy this stack + * + * @default - No bootstrap stack required + */ + public readonly requiresBootstrapStackVersion?: number; + /** * Whether termination protection is enabled for this stack. */ @@ -62,16 +90,20 @@ export class CloudFormationStackArtifact extends CloudArtifact { constructor(assembly: CloudAssembly, artifactId: string, artifact: cxschema.ArtifactManifest) { super(assembly, artifactId, artifact); - if (!artifact.properties || !artifact.properties.templateFile) { + const properties = (this.manifest.properties || {}) as cxschema.AwsCloudFormationStackProperties; + if (!properties.templateFile) { throw new Error('Invalid CloudFormation stack artifact. Missing "templateFile" property in cloud assembly manifest'); } if (!artifact.environment) { throw new Error('Invalid CloudFormation stack artifact. Missing environment'); } this.environment = EnvironmentUtils.parse(artifact.environment); - const properties = (this.manifest.properties || {}) as AwsCloudFormationStackProperties; this.templateFile = properties.templateFile; this.parameters = properties.parameters || { }; + this.assumeRoleArn = properties.assumeRoleArn; + this.cloudFormationExecutionRoleArn = properties.cloudFormationExecutionRoleArn; + this.stackTemplateAssetObjectUrl = properties.stackTemplateAssetObjectUrl; + this.requiresBootstrapStackVersion = properties.requiresBootstrapStackVersion; this.terminationProtection = properties.terminationProtection; this.stackName = properties.stackName || artifactId; diff --git a/packages/@aws-cdk/cx-api/lib/context/endpoint-service-availability-zones.ts b/packages/@aws-cdk/cx-api/lib/context/endpoint-service-availability-zones.ts new file mode 100644 index 0000000000000..657a402cb2548 --- /dev/null +++ b/packages/@aws-cdk/cx-api/lib/context/endpoint-service-availability-zones.ts @@ -0,0 +1,26 @@ +export const ENDPOINT_SERVICE_AVAILABILITY_ZONE_PROVIDER = 'endpoint-service-availability-zones'; + +/** + * Query to hosted zone context provider + */ +export interface EndpointServiceAvailabilityZonesContextQuery { + /** + * Query account + */ + readonly account?: string; + + /** + * Query region + */ + readonly region?: string; + + /** + * Query service name + */ + readonly serviceName?: string; +} + +/** + * Response of the AZ provider looks like this + */ +export type EndpointServiceAvailabilityZonesContextResponse = string[]; diff --git a/packages/@aws-cdk/cx-api/lib/features.ts b/packages/@aws-cdk/cx-api/lib/features.ts index ca146e6d54522..cc3f94f91e23d 100644 --- a/packages/@aws-cdk/cx-api/lib/features.ts +++ b/packages/@aws-cdk/cx-api/lib/features.ts @@ -29,6 +29,11 @@ export const ENABLE_DIFF_NO_FAIL_CONTEXT = 'aws-cdk:enableDiffNoFail'; /** @deprecated use `ENABLE_DIFF_NO_FAIL_CONTEXT` */ export const ENABLE_DIFF_NO_FAIL = ENABLE_DIFF_NO_FAIL_CONTEXT; +/** + * Switch to new stack synthesis method which enable CI/CD + */ +export const NEW_STYLE_STACK_SYNTHESIS_CONTEXT = '@aws-cdk/core:newStyleStackSynthesis'; + /** * This map includes context keys and values for feature flags that enable * capabilities "from the future", which we could not introduce as the default @@ -45,4 +50,7 @@ export const ENABLE_DIFF_NO_FAIL = ENABLE_DIFF_NO_FAIL_CONTEXT; export const FUTURE_FLAGS = { [ENABLE_STACK_NAME_DUPLICATES_CONTEXT]: 'true', [ENABLE_DIFF_NO_FAIL_CONTEXT]: 'true', + + // We will advertise this flag when the feature is complete + // [NEW_STYLE_STACK_SYNTHESIS]: 'true', }; diff --git a/packages/@aws-cdk/cx-api/lib/index.ts b/packages/@aws-cdk/cx-api/lib/index.ts index cb4079a02d6a6..916ee80b068d4 100644 --- a/packages/@aws-cdk/cx-api/lib/index.ts +++ b/packages/@aws-cdk/cx-api/lib/index.ts @@ -2,7 +2,9 @@ export * from './cxapi'; export * from './context/vpc'; export * from './context/ami'; export * from './context/availability-zones'; +export * from './context/endpoint-service-availability-zones'; export * from './cloud-artifact'; +export * from './asset-manifest-artifact'; export * from './cloudformation-artifact'; export * from './tree-cloud-artifact'; export * from './cloud-assembly'; @@ -10,4 +12,5 @@ export * from './assets'; export * from './environment'; export * from './metadata'; export * from './features'; +export * from './placeholders'; export * from './app'; diff --git a/packages/@aws-cdk/cx-api/lib/placeholders.ts b/packages/@aws-cdk/cx-api/lib/placeholders.ts new file mode 100644 index 0000000000000..e32c02a891091 --- /dev/null +++ b/packages/@aws-cdk/cx-api/lib/placeholders.ts @@ -0,0 +1,123 @@ +/** + * Placeholders which can be used manifests + * + * These can occur both in the Asset Manifest as well as the general + * Cloud Assembly manifest. + */ +export class EnvironmentPlaceholders { + /** + * Insert this into the destination fields to be replaced with the current region + */ + public static readonly CURRENT_REGION = '${AWS::Region}'; + + /** + * Insert this into the destination fields to be replaced with the current account + */ + public static readonly CURRENT_ACCOUNT = '${AWS::AccountId}'; + + /** + * Insert this into the destination fields to be replaced with the current partition + */ + public static readonly CURRENT_PARTITION = '${AWS::Partition}'; + + /** + * Replace the environment placeholders in all strings found in a complex object. + * + * Duplicated between cdk-assets and aws-cdk CLI because we don't have a good single place to put it + * (they're nominally independent tools). + */ + public static replace(object: any, values: EnvironmentPlaceholderValues): any { + return this.recurse(object, value => { + value = replaceAll(value, EnvironmentPlaceholders.CURRENT_REGION, values.region); + value = replaceAll(value, EnvironmentPlaceholders.CURRENT_ACCOUNT, values.accountId); + value = replaceAll(value, EnvironmentPlaceholders.CURRENT_PARTITION, values.partition); + return value; + }); + } + + /** + * Like 'replace', but asynchronous + */ + public static async replaceAsync(object: any, provider: IEnvironmentPlaceholderProvider): Promise { + let needRegion = false; + let needAccountId = false; + let needPartition = false; + + this.recurse(object, value => { + if (value.indexOf(EnvironmentPlaceholders.CURRENT_REGION) > 1) { needRegion = true; } + if (value.indexOf(EnvironmentPlaceholders.CURRENT_ACCOUNT) > 1) { needAccountId = true; } + if (value.indexOf(EnvironmentPlaceholders.CURRENT_PARTITION) > 1) { needPartition = true; } + return value; + }); + + const region = needRegion ? await provider.region() : undefined; + const accountId = needAccountId ? await provider.accountId() : undefined; + const partition = needPartition ? await provider.partition() : undefined; + + return this.recurse(object, value => { + value = replaceAll(value, EnvironmentPlaceholders.CURRENT_REGION, region ?? 'WONTHAPPEN'); + value = replaceAll(value, EnvironmentPlaceholders.CURRENT_ACCOUNT, accountId ?? 'WONTHAPPEN'); + value = replaceAll(value, EnvironmentPlaceholders.CURRENT_PARTITION, partition ?? 'WONTHAPPEN'); + return value; + }); + } + + private static recurse(value: any, cb: (x: string) => string): any { + if (typeof value === 'string') { return cb(value); } + if (typeof value !== 'object' || value === null) { return value; } + if (Array.isArray(value)) { return value.map(x => this.recurse(x, cb)); } + + const ret: Record = {}; + for (const [key, inner] of Object.entries(value)) { + ret[key] = this.recurse(inner, cb); + } + return ret; + } +} + +/** + * Return the appropriate values for the environment placeholders + */ +export interface EnvironmentPlaceholderValues { + /** + * Return the region + */ + readonly region: string; + + /** + * Return the account + */ + readonly accountId: string; + + /** + * Return the partition + */ + readonly partition: string; +} + +/** + * Return the appropriate values for the environment placeholders + */ +export interface IEnvironmentPlaceholderProvider { + /** + * Return the region + */ + region(): Promise; + + /** + * Return the account + */ + accountId(): Promise; + + /** + * Return the partition + */ + partition(): Promise; +} + +/** + * A "replace-all" function that doesn't require us escaping a literal string to a regex + */ +function replaceAll(s: string, search: string, replace: string) { + return s.split(search).join(replace); +} diff --git a/packages/@aws-cdk/cx-api/lib/tree-cloud-artifact.ts b/packages/@aws-cdk/cx-api/lib/tree-cloud-artifact.ts index b31bc6d22fe1b..142671e882e23 100644 --- a/packages/@aws-cdk/cx-api/lib/tree-cloud-artifact.ts +++ b/packages/@aws-cdk/cx-api/lib/tree-cloud-artifact.ts @@ -8,7 +8,7 @@ export class TreeCloudArtifact extends CloudArtifact { constructor(assembly: CloudAssembly, name: string, artifact: cxschema.ArtifactManifest) { super(assembly, name, artifact); - const properties = (this.manifest.properties || {}); + const properties = (this.manifest.properties || {}) as cxschema.TreeArtifactProperties; if (!properties.file) { throw new Error('Invalid TreeCloudArtifact. Missing "file" property'); } diff --git a/packages/@aws-cdk/cx-api/package.json b/packages/@aws-cdk/cx-api/package.json index 7bb053a7b1371..6dd65b58083b8 100644 --- a/packages/@aws-cdk/cx-api/package.json +++ b/packages/@aws-cdk/cx-api/package.json @@ -51,28 +51,11 @@ "peerDependencies": { "@aws-cdk/cloud-assembly-schema": "0.0.0" }, - "jest": { - "moduleFileExtensions": [ - "js" - ], - "coverageThreshold": { - "global": { - "branches": 80, - "statements": 80 - } - }, - "collectCoverage": true, - "coverageReporters": [ - "lcov", - "html", - "text-summary" - ] - }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^25.2.1", + "@types/jest": "^25.2.2", "@types/mock-fs": "^4.10.0", - "@types/semver": "^7.1.0", + "@types/semver": "^7.2.0", "cdk-build-tools": "0.0.0", "jest": "^25.5.4", "mock-fs": "^4.12.0", @@ -92,7 +75,7 @@ "semver" ], "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "experimental", @@ -118,6 +101,9 @@ "props-default-doc:@aws-cdk/cx-api.AssemblyManifest.runtime", "props-default-doc:@aws-cdk/cx-api.AvailabilityZonesContextQuery.account", "props-default-doc:@aws-cdk/cx-api.AvailabilityZonesContextQuery.region", + "props-default-doc:@aws-cdk/cx-api.EndpointServiceAvailabilityZonesContextQuery.account", + "props-default-doc:@aws-cdk/cx-api.EndpointServiceAvailabilityZonesContextQuery.region", + "props-default-doc:@aws-cdk/cx-api.EndpointServiceAvailabilityZonesContextQuery.serviceName", "props-default-doc:@aws-cdk/cx-api.AwsCloudFormationStackProperties.parameters", "docs-public-apis:@aws-cdk/cx-api.ContainerImageAssetMetadataEntry", "docs-public-apis:@aws-cdk/cx-api.FileAssetMetadataEntry", @@ -156,5 +142,8 @@ }, "awscdkio": { "announce": false + }, + "cdk-build": { + "jest": true } } diff --git a/packages/@aws-cdk/cx-api/test/cloud-assembly.test.ts b/packages/@aws-cdk/cx-api/test/cloud-assembly.test.ts index d917217ecfd74..42d7dffd94233 100644 --- a/packages/@aws-cdk/cx-api/test/cloud-assembly.test.ts +++ b/packages/@aws-cdk/cx-api/test/cloud-assembly.test.ts @@ -44,7 +44,7 @@ test('assembly with invalid tree metadata', () => { }); test('assembly with tree metadata having no file property specified', () => { - expect(() => new CloudAssembly(path.join(FIXTURES, 'tree-no-file-property'))).toThrow(/Invalid TreeCloudArtifact/); + expect(() => new CloudAssembly(path.join(FIXTURES, 'tree-no-file-property'))).toThrow(/Invalid assembly manifest/); }); test('assembly with cloudformation artifact having no environment property specified', () => { @@ -144,3 +144,9 @@ test('displayName shows both artifact ID and stack name if needed', () => { expect(art1.id).toBe('MyStackName'); expect(art1.stackName).toBe('MyStackName'); }); + +test('can read assembly with asset manifest', () => { + const assembly = new CloudAssembly(path.join(FIXTURES, 'asset-manifest')); + expect(assembly.stacks).toHaveLength(1); + expect(assembly.artifacts).toHaveLength(2); +}); diff --git a/packages/@aws-cdk/cx-api/test/fixtures/asset-manifest/asset-dir/foo.txt b/packages/@aws-cdk/cx-api/test/fixtures/asset-manifest/asset-dir/foo.txt new file mode 100644 index 0000000000000..5783cb7e31483 --- /dev/null +++ b/packages/@aws-cdk/cx-api/test/fixtures/asset-manifest/asset-dir/foo.txt @@ -0,0 +1 @@ +hello, assets! diff --git a/packages/@aws-cdk/cx-api/test/fixtures/asset-manifest/assets.json b/packages/@aws-cdk/cx-api/test/fixtures/asset-manifest/assets.json new file mode 100644 index 0000000000000..eced01a4b1814 --- /dev/null +++ b/packages/@aws-cdk/cx-api/test/fixtures/asset-manifest/assets.json @@ -0,0 +1,3 @@ +{ + "$comment": "Empty on purpose for now" +} diff --git a/packages/@aws-cdk/cx-api/test/fixtures/asset-manifest/docker-asset/Dockerfile b/packages/@aws-cdk/cx-api/test/fixtures/asset-manifest/docker-asset/Dockerfile new file mode 100644 index 0000000000000..ceaf18ac05257 --- /dev/null +++ b/packages/@aws-cdk/cx-api/test/fixtures/asset-manifest/docker-asset/Dockerfile @@ -0,0 +1 @@ +FROM ubuntu diff --git a/packages/@aws-cdk/cx-api/test/fixtures/asset-manifest/manifest.json b/packages/@aws-cdk/cx-api/test/fixtures/asset-manifest/manifest.json new file mode 100644 index 0000000000000..fa63832eea44d --- /dev/null +++ b/packages/@aws-cdk/cx-api/test/fixtures/asset-manifest/manifest.json @@ -0,0 +1,21 @@ +{ + "version": "0.0.0", + "artifacts": { + "MyStackName": { + "type": "aws:cloudformation:stack", + "environment": "aws://37736633/us-region-1", + "properties": { + "templateFile": "template.json" + }, + "dependencies": ["AssetManifest"], + "metadata": { + } + }, + "AssetManifest": { + "type": "cdk:asset-manifest", + "properties": { + "file": "asset.json" + } + } + } +} diff --git a/packages/@aws-cdk/cx-api/test/fixtures/asset-manifest/template.json b/packages/@aws-cdk/cx-api/test/fixtures/asset-manifest/template.json new file mode 100644 index 0000000000000..284fd64cffc21 --- /dev/null +++ b/packages/@aws-cdk/cx-api/test/fixtures/asset-manifest/template.json @@ -0,0 +1,7 @@ +{ + "Resources": { + "MyBucket": { + "Type": "AWS::S3::Bucket" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/cx-api/test/placeholders.test.ts b/packages/@aws-cdk/cx-api/test/placeholders.test.ts new file mode 100644 index 0000000000000..9b39478abd611 --- /dev/null +++ b/packages/@aws-cdk/cx-api/test/placeholders.test.ts @@ -0,0 +1,27 @@ +import { EnvironmentPlaceholders, IEnvironmentPlaceholderProvider } from '../lib'; + +test('complex placeholder substitution', async () => { + const replacer: IEnvironmentPlaceholderProvider = { + accountId: () => Promise.resolve('current_account'), + region: () => Promise.resolve('current_region'), + partition: () => Promise.resolve('current_partition'), + }; + + expect(await EnvironmentPlaceholders.replaceAsync({ + destinations: { + theDestination: { + assumeRoleArn: 'arn:${AWS::Partition}:role-${AWS::AccountId}', + bucketName: 'some_bucket-${AWS::AccountId}-${AWS::Region}', + objectKey: 'some_key-${AWS::AccountId}-${AWS::Region}', + }, + }, + }, replacer)).toEqual({ + destinations: { + theDestination: { + assumeRoleArn: 'arn:current_partition:role-current_account', + bucketName: 'some_bucket-current_account-current_region', + objectKey: 'some_key-current_account-current_region', + }, + }, + }); +}); diff --git a/packages/@aws-cdk/example-construct-library/.eslintrc.js b/packages/@aws-cdk/example-construct-library/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/example-construct-library/.eslintrc.js +++ b/packages/@aws-cdk/example-construct-library/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/example-construct-library/.gitignore b/packages/@aws-cdk/example-construct-library/.gitignore index 0bd6133da4d09..c35d6e19fb425 100644 --- a/packages/@aws-cdk/example-construct-library/.gitignore +++ b/packages/@aws-cdk/example-construct-library/.gitignore @@ -14,3 +14,4 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/example-construct-library/.npmignore b/packages/@aws-cdk/example-construct-library/.npmignore index 174864d493a79..4e4f173de8358 100644 --- a/packages/@aws-cdk/example-construct-library/.npmignore +++ b/packages/@aws-cdk/example-construct-library/.npmignore @@ -19,3 +19,4 @@ dist tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/example-construct-library/jest.config.js b/packages/@aws-cdk/example-construct-library/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/example-construct-library/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/example-construct-library/package.json b/packages/@aws-cdk/example-construct-library/package.json index 31dd2522ddc41..49046856a2fbe 100644 --- a/packages/@aws-cdk/example-construct-library/package.json +++ b/packages/@aws-cdk/example-construct-library/package.json @@ -86,12 +86,14 @@ "constructs": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, - "jest": {}, "stability": "experimental", "maturity": "experimental", "awscdkio": { "announce": false + }, + "cdk-build": { + "jest": true } } diff --git a/packages/@aws-cdk/region-info/.eslintrc.js b/packages/@aws-cdk/region-info/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@aws-cdk/region-info/.eslintrc.js +++ b/packages/@aws-cdk/region-info/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/region-info/.gitignore b/packages/@aws-cdk/region-info/.gitignore index f58c6f86bb144..c592ef0622ef6 100644 --- a/packages/@aws-cdk/region-info/.gitignore +++ b/packages/@aws-cdk/region-info/.gitignore @@ -12,3 +12,4 @@ tsconfig.json coverage nyc.config.js !.eslintrc.js +!jest.config.js diff --git a/packages/@aws-cdk/region-info/.npmignore b/packages/@aws-cdk/region-info/.npmignore index 21b8a4ff8e0dc..3655c2f7c965a 100644 --- a/packages/@aws-cdk/region-info/.npmignore +++ b/packages/@aws-cdk/region-info/.npmignore @@ -17,3 +17,4 @@ coverage tsconfig.json .eslintrc.js +jest.config.js diff --git a/packages/@aws-cdk/region-info/jest.config.js b/packages/@aws-cdk/region-info/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/region-info/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/region-info/package.json b/packages/@aws-cdk/region-info/package.json index fee53a8c9856f..4bfca87660b45 100644 --- a/packages/@aws-cdk/region-info/package.json +++ b/packages/@aws-cdk/region-info/package.json @@ -30,7 +30,8 @@ "cdk-build": { "pre": [ "npm run gen" - ] + ], + "jest": true }, "scripts": { "gen": "bash build-tools/generate.sh", @@ -57,17 +58,6 @@ "fs-extra": "^8.1.0", "pkglint": "0.0.0" }, - "jest": { - "moduleFileExtensions": [ - "ts", - "js" - ], - "preset": "ts-jest", - "testMatch": [ - "**/__tests__/**/*.ts?(x)", - "**/?(*.)+(spec|test).ts?(x)" - ] - }, "repository": { "url": "https://github.com/aws/aws-cdk.git", "type": "git", @@ -79,7 +69,7 @@ ], "homepage": "https://github.com/aws/aws-cdk", "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "experimental", diff --git a/packages/@aws-cdk/region-info/test/__snapshots__/region-info.test.ts.snap b/packages/@aws-cdk/region-info/test/__snapshots__/region-info.test.js.snap similarity index 100% rename from packages/@aws-cdk/region-info/test/__snapshots__/region-info.test.ts.snap rename to packages/@aws-cdk/region-info/test/__snapshots__/region-info.test.js.snap diff --git a/packages/@monocdk-experiment/assert/.eslintrc.js b/packages/@monocdk-experiment/assert/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@monocdk-experiment/assert/.eslintrc.js +++ b/packages/@monocdk-experiment/assert/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@monocdk-experiment/assert/.gitignore b/packages/@monocdk-experiment/assert/.gitignore index 04fae96020518..17e3ae0ad2a83 100644 --- a/packages/@monocdk-experiment/assert/.gitignore +++ b/packages/@monocdk-experiment/assert/.gitignore @@ -18,3 +18,4 @@ dist coverage nyc.config.js !.eslintrc.js +!jest.config.js diff --git a/packages/@monocdk-experiment/assert/jest.config.js b/packages/@monocdk-experiment/assert/jest.config.js new file mode 100644 index 0000000000000..f81b80f39a2aa --- /dev/null +++ b/packages/@monocdk-experiment/assert/jest.config.js @@ -0,0 +1,10 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = { + ...baseConfig, + coverageThreshold: { + global: { + statements: 75, + branches: 65, + }, + }, +}; diff --git a/packages/@monocdk-experiment/assert/package.json b/packages/@monocdk-experiment/assert/package.json index 7b4ef8901ac8e..32b9c5ef9f79a 100644 --- a/packages/@monocdk-experiment/assert/package.json +++ b/packages/@monocdk-experiment/assert/package.json @@ -15,6 +15,7 @@ "build+test": "npm run build && npm test" }, "cdk-build": { + "jest": true, "pre": [ "./clone.sh" ], @@ -28,14 +29,6 @@ "disable": true } }, - "jest": { - "coverageThreshold": { - "global": { - "statements": 75, - "branches": 65 - } - } - }, "author": { "name": "Amazon Web Services", "url": "https://aws.amazon.com", @@ -43,11 +36,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^25.2.1", + "@types/jest": "^25.2.2", "cdk-build-tools": "0.0.0", "jest": "^25.5.4", "pkglint": "0.0.0", - "ts-jest": "^25.5.0", + "ts-jest": "^26.0.0", "@monocdk-experiment/rewrite-imports": "0.0.0", "monocdk-experiment": "0.0.0", "constructs": "^3.0.2" @@ -71,7 +64,7 @@ ], "homepage": "https://github.com/aws/aws-cdk", "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", "maturity": "developer-preview" diff --git a/packages/@monocdk-experiment/rewrite-imports/.eslintrc.js b/packages/@monocdk-experiment/rewrite-imports/.eslintrc.js index 1b28bad193ceb..a9d39af55b7e5 100644 --- a/packages/@monocdk-experiment/rewrite-imports/.eslintrc.js +++ b/packages/@monocdk-experiment/rewrite-imports/.eslintrc.js @@ -1,2 +1,3 @@ const baseConfig = require('../../../tools/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@monocdk-experiment/rewrite-imports/.gitignore b/packages/@monocdk-experiment/rewrite-imports/.gitignore index 78a8253d5c55a..864eca1bfa974 100644 --- a/packages/@monocdk-experiment/rewrite-imports/.gitignore +++ b/packages/@monocdk-experiment/rewrite-imports/.gitignore @@ -10,3 +10,4 @@ dist coverage nyc.config.js !.eslintrc.js +!jest.config.js diff --git a/packages/@monocdk-experiment/rewrite-imports/.npmignore b/packages/@monocdk-experiment/rewrite-imports/.npmignore index 831ab1c8d90b3..8e89ca26ab028 100644 --- a/packages/@monocdk-experiment/rewrite-imports/.npmignore +++ b/packages/@monocdk-experiment/rewrite-imports/.npmignore @@ -9,3 +9,4 @@ tsconfig.json *.ts !*.d.ts .eslintrc.js +jest.config.js diff --git a/packages/@monocdk-experiment/rewrite-imports/jest.config.js b/packages/@monocdk-experiment/rewrite-imports/jest.config.js new file mode 100644 index 0000000000000..f81b80f39a2aa --- /dev/null +++ b/packages/@monocdk-experiment/rewrite-imports/jest.config.js @@ -0,0 +1,10 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = { + ...baseConfig, + coverageThreshold: { + global: { + statements: 75, + branches: 65, + }, + }, +}; diff --git a/packages/@monocdk-experiment/rewrite-imports/package.json b/packages/@monocdk-experiment/rewrite-imports/package.json index f0cc64ebf87cc..1c46468003683 100644 --- a/packages/@monocdk-experiment/rewrite-imports/package.json +++ b/packages/@monocdk-experiment/rewrite-imports/package.json @@ -16,6 +16,9 @@ "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test" }, + "cdk-build": { + "jest": true + }, "keywords": [ "aws", "cdk", @@ -32,19 +35,11 @@ }, "devDependencies": { "@types/glob": "^7.1.1", - "@types/jest": "^25.2.1", + "@types/jest": "^25.2.2", "@types/node": "^10.17.21", "cdk-build-tools": "0.0.0", "pkglint": "0.0.0" }, - "jest": { - "coverageThreshold": { - "global": { - "statements": 75, - "branches": 65 - } - } - }, "repository": { "type": "git", "url": "https://github.com/aws/aws-cdk.git", @@ -54,6 +49,6 @@ "stability": "experimental", "maturity": "developer-preview", "engines": { - "node": ">= 10.13.0" + "node": ">= 10.13.0 <13 || >=13.7.0" } } diff --git a/packages/aws-cdk/.eslintrc.js b/packages/aws-cdk/.eslintrc.js index 75388dc12a0d5..f3c7e1564f9e9 100644 --- a/packages/aws-cdk/.eslintrc.js +++ b/packages/aws-cdk/.eslintrc.js @@ -1,3 +1,4 @@ const baseConfig = require('../../tools/cdk-build-tools/config/eslintrc'); baseConfig.ignorePatterns.push('lib/init-templates/*/typescript/**/*.ts'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/aws-cdk/.gitignore b/packages/aws-cdk/.gitignore index 39e42b7816d39..45b459bc9ec63 100644 --- a/packages/aws-cdk/.gitignore +++ b/packages/aws-cdk/.gitignore @@ -23,3 +23,12 @@ npm-shrinkwrap.json # But normally should be deleted after execution. test/integ/cli-backwards-tests-* !.eslintrc.js +!jest.config.js + +# Might be created when running integ tests +cdk.context.json + +# Exclude compiled integ tests specifically (but not any subdir +# as the subdirs contain .js files that should be committed) +test/integ/cli/*.js +test/integ/cli/*.d.ts diff --git a/packages/aws-cdk/.npmignore b/packages/aws-cdk/.npmignore index b82320272b24b..745c693953fd6 100644 --- a/packages/aws-cdk/.npmignore +++ b/packages/aws-cdk/.npmignore @@ -22,3 +22,5 @@ tsconfig.json # init templates include default tsconfig.json files which we need !lib/init-templates/**/tsconfig.json .eslintrc.js +jest.config.js +!lib/init-templates/**/jest.config.js diff --git a/packages/aws-cdk/jest.config.js b/packages/aws-cdk/jest.config.js new file mode 100644 index 0000000000000..797dd0665910a --- /dev/null +++ b/packages/aws-cdk/jest.config.js @@ -0,0 +1,10 @@ +const baseConfig = require('../../tools/cdk-build-tools/config/jest.config'); +module.exports = { + ...baseConfig, + coverageThreshold: { + global: { + statements: 60, + branches: 45, + }, + }, +}; diff --git a/packages/aws-cdk/lib/api/cloudformation-deployments.ts b/packages/aws-cdk/lib/api/cloudformation-deployments.ts index d41e128793f97..0ee09812629c9 100644 --- a/packages/aws-cdk/lib/api/cloudformation-deployments.ts +++ b/packages/aws-cdk/lib/api/cloudformation-deployments.ts @@ -1,6 +1,8 @@ -import { CloudFormationStackArtifact } from '@aws-cdk/cx-api'; +import * as cxapi from '@aws-cdk/cx-api'; +import { AssetManifest } from 'cdk-assets'; import { Tag } from '../cdk-toolkit'; import { debug } from '../logging'; +import { publishAssets } from '../util/asset-publishing'; import { Mode, SdkProvider } from './aws-auth'; import { deployStack, DeployStackResult, destroyStack } from './deploy-stack'; import { ToolkitInfo } from './toolkit-info'; @@ -10,7 +12,7 @@ export interface DeployStackOptions { /** * Stack to deploy */ - stack: CloudFormationStackArtifact; + stack: cxapi.CloudFormationStackArtifact; /** * Execution role for the deployment (pass through to CloudFormation) @@ -89,7 +91,7 @@ export interface DeployStackOptions { } export interface DestroyStackOptions { - stack: CloudFormationStackArtifact; + stack: cxapi.CloudFormationStackArtifact; deployName?: string; roleArn?: string; quiet?: boolean; @@ -97,7 +99,7 @@ export interface DestroyStackOptions { } export interface StackExistsOptions { - stack: CloudFormationStackArtifact; + stack: cxapi.CloudFormationStackArtifact; deployName?: string; } @@ -118,7 +120,7 @@ export class CloudFormationDeployments { this.sdkProvider = props.sdkProvider; } - public async readCurrentTemplate(stackArtifact: CloudFormationStackArtifact): Promise