diff --git a/.dependabot/config.yml b/.dependabot/config.yml deleted file mode 100644 index c54ea38a24f81..0000000000000 --- a/.dependabot/config.yml +++ /dev/null @@ -1,19 +0,0 @@ ---- -# See: https://dependabot.com/docs/config-file/ -version: 1 -update_configs: - # Dependabot will detect the lerna mono-repo and discover packages in there - - directory: / - package_manager: javascript - update_schedule: live - version_requirement_updates: increase_versions - ignored_updates: - - match: - dependency_name: "jsii*" - - match: - dependency_name: "@jsii/*" - - match: - dependency_name: "codemaker" - - match: - dependency_name: "@types/node" - version_requirement: ">=11.0.0-0" diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000000..1d4633809b73b --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +# Reference: https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates +# NOTE: dependabot only takes care of updating non-npm deps +# npm dependencies are updated through the "yarn-upgrade" github workflow. + +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + labels: + - "pr/auto-approve" + open-pull-requests-limit: 5 diff --git a/.github/workflows/auto-approve-dependabot.yml b/.github/workflows/auto-approve-dependabot.yml deleted file mode 100644 index 5eb14a05c1890..0000000000000 --- a/.github/workflows/auto-approve-dependabot.yml +++ /dev/null @@ -1,27 +0,0 @@ -# Automatically approve PRs made by Dependabot -# -# Written to look at the original author of the PR (instead of the current -# actor) in order to be able to backresolve existing PRs using this action (by -# mass labeling them). Leads to slightly unnecessary spammage of aprovals in a -# PR... -# -# Only does approvals! A different GitHub Action takes care of merging. -name: Auto-approve Dependabot -on: - pull_request: - types: - - labeled - - opened - - ready_for_review - - reopened - - synchronize - - unlabeled - - unlocked -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: hmarr/auto-approve-action@7782c7e2bdf62b4d79bdcded8332808fd2f179cd - if: github.event.pull_request.user.login == 'dependabot[bot]' || github.event.pull_request.user.login == 'dependabot-preview[bot]' - with: - github-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/auto-approve.yml b/.github/workflows/auto-approve.yml new file mode 100644 index 0000000000000..d36f6255bbc7d --- /dev/null +++ b/.github/workflows/auto-approve.yml @@ -0,0 +1,15 @@ +# Approve PRs with "pr/auto-approve". mergify takes care of the actual merge. + +name: auto-approve +on: pull_request + +jobs: + auto-approve: + if: > + contains(github.event.pull_request.labels.*.name, 'pr/auto-approve') && + contains(['aws-cdk-automation', 'dependabot[bot]', 'dependabot-preview[bot]'], github.event.pull_request.user.login) + runs-on: ubuntu-latest + steps: + - uses: hmarr/auto-approve-action@v2.0.0 + with: + github-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/issue-label-assign.yml b/.github/workflows/issue-label-assign.yml index 9e2f2ce7e3e34..22f20538795c7 100644 --- a/.github/workflows/issue-label-assign.yml +++ b/.github/workflows/issue-label-assign.yml @@ -11,7 +11,7 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: Naturalclar/issue-action@f229cda + - uses: Naturalclar/issue-action@v2.0.2 with: github-token: "${{ secrets.GITHUB_TOKEN }}" title-or-body: 'title' @@ -90,7 +90,7 @@ jobs: {"keywords":["(@aws-cdk/aws-elasticloadbalancingv2-targets)","(aws-elasticloadbalancingv2-targets)","(elasticloadbalancingv2-targets)","(elasticloadbalancingv2 targets)","(elbv2 targets)"],"labels":["@aws-cdk/aws-elasticloadbalancingv2-targets"],"assignees":["njlynch"]}, {"keywords":["(@aws-cdk/aws-elasticsearch)","(aws-elasticsearch)","(elasticsearch)","(elastic search)","(elastic-search)"],"labels":["@aws-cdk/aws-elasticsearch"],"assignees":["iliapolo"]}, {"keywords":["(@aws-cdk/aws-emr)","(aws-emr)","(emr)"],"labels":["@aws-cdk/aws-emr"],"assignees":["iliapolo"]}, - {"keywords":["(@aws-cdk/aws-events)","(aws-events)","(events)","(eventbridge)","event-bridge)"],"labels":["@aws-cdk/aws-events"],"assignees":["rix0rrr"]}, + {"keywords":["(@aws-cdk/aws-events)","(aws-events)","(events)","(eventbridge)","(event-bridge)"],"labels":["@aws-cdk/aws-events"],"assignees":["rix0rrr"]}, {"keywords":["(@aws-cdk/aws-events-targets)","(aws-events-targets)","(events-targets)","(events targets)"],"labels":["@aws-cdk/aws-events-targets"],"assignees":["rix0rrr"]}, {"keywords":["(@aws-cdk/aws-eventschemas)","(aws-eventschemas)","(eventschemas)","(event schemas)"],"labels":["@aws-cdk/aws-eventschemas"],"assignees":["skinny85"]}, {"keywords":["(@aws-cdk/aws-fms)","(aws-fms)","(fms)"],"labels":["@aws-cdk/aws-fms"],"assignees":["rix0rrr"]}, diff --git a/.github/workflows/v2-pull-request.yml b/.github/workflows/v2-pull-request.yml index c4118d3298a00..e820647947705 100644 --- a/.github/workflows/v2-pull-request.yml +++ b/.github/workflows/v2-pull-request.yml @@ -32,15 +32,3 @@ jobs: uses: stefanzweifel/git-auto-commit-action@v4 with: commit_message: 'automatic pkglint fixes' - - # Approve automated PRs - # Only approve! mergify takes care of the actual merge. - auto-approve: - if: > - github.event.pull_request.user.login == 'aws-cdk-automation' - && contains(github.event.pull_request.labels.*.name, 'pr/auto-approve') - runs-on: ubuntu-latest - steps: - - uses: hmarr/auto-approve-action@v2.0.0 - with: - github-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/yarn-upgrade.yml b/.github/workflows/yarn-upgrade.yml index 6734719a67184..17617a75537d3 100644 --- a/.github/workflows/yarn-upgrade.yml +++ b/.github/workflows/yarn-upgrade.yml @@ -25,7 +25,7 @@ jobs: run: echo "::set-output name=dir::$(yarn cache dir)" - name: Restore Yarn cache - uses: actions/cache@v2 + uses: actions/cache@v2.1.4 with: path: ${{ steps.yarn-cache.outputs.dir }} key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} @@ -74,7 +74,7 @@ jobs: title: 'chore: npm-check-updates && yarn upgrade' body: |- Ran npm-check-updates and yarn upgrade to keep the `yarn.lock` file up-to-date. - labels: contribution/core,dependencies + labels: contribution/core,dependencies,pr/auto-approve team-reviewers: aws-cdk-team # Privileged token so automated PR validation happens token: ${{ secrets.AUTOMATION_GITHUB_TOKEN }} diff --git a/CHANGELOG.md b/CHANGELOG.md index e62bd18aecd9d..ce9e72a3d6855 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,78 @@ 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.91.0](https://github.com/aws/aws-cdk/compare/v1.90.1...v1.91.0) (2021-02-23) + + +### ⚠ BREAKING CHANGES TO EXPERIMENTAL FEATURES + +* **aws-appsync:** RdsDataSource now takes a ServerlessCluster instead of a DatabaseCluster +* **aws-appsync:** graphqlapi.addRdsDataSource now takes databaseName as its fourth argument + +### Features + +* **aws-appsync:** add databaseName to rdsDataSource ([#12575](https://github.com/aws/aws-cdk/issues/12575)) ([f92b65e](https://github.com/aws/aws-cdk/commit/f92b65e2a158f918d8f05132ed12a4bb85228997)), closes [#12572](https://github.com/aws/aws-cdk/issues/12572) +* **cfnspec:** cloudformation spec v28.0.0 ([#13101](https://github.com/aws/aws-cdk/issues/13101)) ([13c9859](https://github.com/aws/aws-cdk/commit/13c9859cc62b3d472ba1be84b12d478f61f02ec9)) +* **ecs-patterns:** Add support for assignPublicIp for QueueProcessingFargateService ([#13122](https://github.com/aws/aws-cdk/issues/13122)) ([3fb4600](https://github.com/aws/aws-cdk/commit/3fb46001a7345cbefa6df70893999bcb304ed40d)), closes [#12815](https://github.com/aws/aws-cdk/issues/12815) +* **lambda:** Code.fromDockerBuildAsset ([#12258](https://github.com/aws/aws-cdk/issues/12258)) ([09afed5](https://github.com/aws/aws-cdk/commit/09afed5ca2b39919c1c84d200370d490110cd0d1)), closes [#11914](https://github.com/aws/aws-cdk/issues/11914) +* **stepfunctions-tasks:** add EKS call to SFN-tasks ([#12779](https://github.com/aws/aws-cdk/issues/12779)) ([296a10d](https://github.com/aws/aws-cdk/commit/296a10d76a9f6fc2a374d1a6461c460bcc3eeb79)) +* **synthetics:** Update CloudWatch Synthetics NodeJS runtimes ([#12907](https://github.com/aws/aws-cdk/issues/12907)) ([6aac3b6](https://github.com/aws/aws-cdk/commit/6aac3b6a9bb1586ee16e7a85ca657b544d0f8304)), closes [#12906](https://github.com/aws/aws-cdk/issues/12906) + + +### Bug Fixes + +* UserPool, Volume, ElasticSearch, FSx are now RETAIN by default ([#12920](https://github.com/aws/aws-cdk/issues/12920)) ([5a54741](https://github.com/aws/aws-cdk/commit/5a54741a414d3f8b7913163f4785759b984b41d8)), closes [#12563](https://github.com/aws/aws-cdk/issues/12563) +* **appsync:** revert to allow resolver creation from data source ([#12973](https://github.com/aws/aws-cdk/issues/12973)) ([d35f032](https://github.com/aws/aws-cdk/commit/d35f03226d6d7fb5be246b4d3584ee9205b0ef2d)), closes [#12635](https://github.com/aws/aws-cdk/issues/12635) [#11522](https://github.com/aws/aws-cdk/issues/11522) +* **aws-appsync:** use serverlessCluster on rdsDataSource ([#13206](https://github.com/aws/aws-cdk/issues/13206)) ([45cf387](https://github.com/aws/aws-cdk/commit/45cf3873fb48d4043e7a22284d36695ea6bde6ef)), closes [#12567](https://github.com/aws/aws-cdk/issues/12567) +* **cfn-diff:** handle Fn::If inside policies and statements ([#12975](https://github.com/aws/aws-cdk/issues/12975)) ([daf4e47](https://github.com/aws/aws-cdk/commit/daf4e47a790ab99639e471f6792f22e3e4f8ee73)), closes [#12887](https://github.com/aws/aws-cdk/issues/12887) +* **core:** ENOTDIR invalid cwd on "cdk deploy" ([#13145](https://github.com/aws/aws-cdk/issues/13145)) ([cd7a3ed](https://github.com/aws/aws-cdk/commit/cd7a3ed333570a3b26446e1e3a054ca886cd3906)), closes [#12258](https://github.com/aws/aws-cdk/issues/12258) [#13076](https://github.com/aws/aws-cdk/issues/13076) [#13131](https://github.com/aws/aws-cdk/issues/13131) +* **eks:** `KubectlProvider` creates un-necessary security group ([#13178](https://github.com/aws/aws-cdk/issues/13178)) ([c5e8b6d](https://github.com/aws/aws-cdk/commit/c5e8b6df1e5f0359d51d025edcc68508ab5daef1)) +* **eks:** Deployment fails for the first deployment in an account ([#13103](https://github.com/aws/aws-cdk/issues/13103)) ([e042879](https://github.com/aws/aws-cdk/commit/e042879851f8ddd558d20941019c9a6692a1c2bf)), closes [/github.com/aws/aws-cdk/issues/9027#issuecomment-780482124](https://github.com/aws//github.com/aws/aws-cdk/issues/9027/issues/issuecomment-780482124) +* **lambda-nodejs:** invalid sample in documentation ([#12404](https://github.com/aws/aws-cdk/issues/12404)) ([520c263](https://github.com/aws/aws-cdk/commit/520c263ca3c6b0ea7d9c09c23e509a3373ee2b8a)) + +## [1.90.1](https://github.com/aws/aws-cdk/compare/v1.90.0...v1.90.1) (2021-02-19) + +### Bug Fixes + +* **core:** ENOTDIR invalid cwd on "cdk deploy" ([#13145](https://github.com/aws/aws-cdk/issues/13145)) ([a735b52](https://github.com/aws/aws-cdk/commit/a735b52e4a33803b9ce1911bc0e2cc7b78ef581a)), closes [#12258](https://github.com/aws/aws-cdk/issues/12258) [#13076](https://github.com/aws/aws-cdk/issues/13076) [#13131](https://github.com/aws/aws-cdk/issues/13131) + +## [1.90.0](https://github.com/aws/aws-cdk/compare/v1.89.0...v1.90.0) (2021-02-17) + + +### Features + +* **apigatewayv2:** http api - jwt and cognito user pool authorizers ([#10972](https://github.com/aws/aws-cdk/issues/10972)) ([dd90e54](https://github.com/aws/aws-cdk/commit/dd90e5464b24e097a3e41a81556924018a422181)), closes [#10534](https://github.com/aws/aws-cdk/issues/10534) +* **aws-ecs-patterns:** allow ScheduledTaskBase be created in a DISABLED state ([#12837](https://github.com/aws/aws-cdk/issues/12837)) ([c625699](https://github.com/aws/aws-cdk/commit/c6256992902fc4237ceb9f965e970e2c2ef00777)), closes [#12836](https://github.com/aws/aws-cdk/issues/12836) +* **aws-kinesisanalyticsv2:** L2 construct for Flink applications ([#12464](https://github.com/aws/aws-cdk/issues/12464)) ([94279f3](https://github.com/aws/aws-cdk/commit/94279f35e4f5ef961e0ba8528e34a8fccb9ef3fe)), closes [#12407](https://github.com/aws/aws-cdk/issues/12407) +* **cfnspec:** cloudformation spec v27.0.0 ([#12960](https://github.com/aws/aws-cdk/issues/12960)) ([7730ac8](https://github.com/aws/aws-cdk/commit/7730ac8c6c7aedb233a24c665666b9651b2401a5)) +* **cli:** change set name is now a constant, and --no-execute will always produce one (even if empty) ([#12683](https://github.com/aws/aws-cdk/issues/12683)) ([00cdd2a](https://github.com/aws/aws-cdk/commit/00cdd2a2188d146af8b8df998e97da91c77dc270)), closes [#11075](https://github.com/aws/aws-cdk/issues/11075) +* **core:** customize bundling output packaging ([#13076](https://github.com/aws/aws-cdk/issues/13076)) ([367a055](https://github.com/aws/aws-cdk/commit/367a055688c97ca3b01aff19d6d91ed5b1b86e1e)), closes [#10776](https://github.com/aws/aws-cdk/issues/10776) +* **ecs:** support Fargate and Fargate spot capacity providers ([#12893](https://github.com/aws/aws-cdk/issues/12893)) ([843b480](https://github.com/aws/aws-cdk/commit/843b480e7a1bc51594d3580d2774d3b9a4eec2fb)), closes [#5850](https://github.com/aws/aws-cdk/issues/5850) +* **ecs-patterns:** Add support for taskSubnets and securityGroups on QueueProcessingFagateService ([#12604](https://github.com/aws/aws-cdk/issues/12604)) ([996e69d](https://github.com/aws/aws-cdk/commit/996e69dd6d33a3478f88a6e32afeebc4fd0e7ec5)), closes [#12603](https://github.com/aws/aws-cdk/issues/12603) +* **eks:** support Kubernetes 1.19 ([#13094](https://github.com/aws/aws-cdk/issues/13094)) ([72c22dc](https://github.com/aws/aws-cdk/commit/72c22dc39c1fa69905cfd0d3259b429e1c5b8447)), closes [#13093](https://github.com/aws/aws-cdk/issues/13093) +* **elasticsearch:** add custom endpoint options ([#12904](https://github.com/aws/aws-cdk/issues/12904)) ([f67ab86](https://github.com/aws/aws-cdk/commit/f67ab8689dc38803253067c4f9632b9bc5ea653f)), closes [#12261](https://github.com/aws/aws-cdk/issues/12261) +* **glue:** Connection construct ([#12444](https://github.com/aws/aws-cdk/issues/12444)) ([c64ec6b](https://github.com/aws/aws-cdk/commit/c64ec6bea6c4cee90530f292ea29f774c68c7667)), closes [#12442](https://github.com/aws/aws-cdk/issues/12442) +* **glue:** SecurityConfiguration construct ([#12450](https://github.com/aws/aws-cdk/issues/12450)) ([0a8e681](https://github.com/aws/aws-cdk/commit/0a8e68185d75327d37a00b967520ba98026d6fad)), closes [#12449](https://github.com/aws/aws-cdk/issues/12449) +* **redshift:** add missing current generation RA3 NodeTypes ([#12784](https://github.com/aws/aws-cdk/issues/12784)) ([f91a3f1](https://github.com/aws/aws-cdk/commit/f91a3f1302c395e8c7ffe9d6164e8f3b252f9a27)), closes [#12783](https://github.com/aws/aws-cdk/issues/12783) +* **stepfunctions:** Implement IGrantable ([#12830](https://github.com/aws/aws-cdk/issues/12830)) ([3b5ff05](https://github.com/aws/aws-cdk/commit/3b5ff0562090059f3a94140161acce53e484776c)), closes [#12829](https://github.com/aws/aws-cdk/issues/12829) + + +### Bug Fixes + +* **apigatewayv2:** HttpApi and Route in different stacks creates cycles ([#13010](https://github.com/aws/aws-cdk/issues/13010)) ([b5efb88](https://github.com/aws/aws-cdk/commit/b5efb88aebebb14673ea2a3736c710b09626f8e1)), closes [#13021](https://github.com/aws/aws-cdk/issues/13021) +* **aws-rds:** correct Policy resource for Proxy::grantConnect() ([#12416](https://github.com/aws/aws-cdk/issues/12416)) ([b3197db](https://github.com/aws/aws-cdk/commit/b3197db1c87067231b0642b7f9e1e37a48b12b6d)), closes [#12415](https://github.com/aws/aws-cdk/issues/12415) +* **cfn-diff:** correctly handle version strings like '0.0.0' ([#13022](https://github.com/aws/aws-cdk/issues/13022)) ([34a921b](https://github.com/aws/aws-cdk/commit/34a921b9667402b6d90731f1fd9e3de1ef27f8bf)), closes [#13016](https://github.com/aws/aws-cdk/issues/13016) +* **cfn2ts:** correctly choose between string and object without required properties in a union ([#12954](https://github.com/aws/aws-cdk/issues/12954)) ([b7137c5](https://github.com/aws/aws-cdk/commit/b7137c59d04f14a6ad890bff1faf0f36cae131b0)), closes [#12854](https://github.com/aws/aws-cdk/issues/12854) +* **cloudfront:** bucket policy for Origin Access Identities is overly permissive ([#13087](https://github.com/aws/aws-cdk/issues/13087)) ([cc28312](https://github.com/aws/aws-cdk/commit/cc2831238d965950dad74607ac0199b75b4bc459)), closes [#3486](https://github.com/aws/aws-cdk/issues/3486) [#13086](https://github.com/aws/aws-cdk/issues/13086) +* **cloudfront:** EdgeFunction us-east-1 stack created in different account ([#13055](https://github.com/aws/aws-cdk/issues/13055)) ([2f1fc95](https://github.com/aws/aws-cdk/commit/2f1fc959b1cbe406351cc0d3e057841497af1c19)), closes [#12789](https://github.com/aws/aws-cdk/issues/12789) +* **codecommit:** take the region and account of an imported Repository from its ARN ([#13066](https://github.com/aws/aws-cdk/issues/13066)) ([5f0ee88](https://github.com/aws/aws-cdk/commit/5f0ee88ff1e618a3f3c50dec7308c4da279e42ac)), closes [#13025](https://github.com/aws/aws-cdk/issues/13025) +* **codedeploy:** allow the install agent script's commands to exit with errors ([#12782](https://github.com/aws/aws-cdk/issues/12782)) ([23d52a5](https://github.com/aws/aws-cdk/commit/23d52a570b591f080eebfbd9dc679a9ef2daeebf)), closes [#12764](https://github.com/aws/aws-cdk/issues/12764) +* **codepipeline-actions:** use BatchGetBuildBatches permission for batch builds ([#13018](https://github.com/aws/aws-cdk/issues/13018)) ([09ba573](https://github.com/aws/aws-cdk/commit/09ba573a816cc4fa9898c1700136bb332801721c)) +* **core:** `exportValue()` does not work with resource names ([#13052](https://github.com/aws/aws-cdk/issues/13052)) ([46043e0](https://github.com/aws/aws-cdk/commit/46043e04a1603796c766dd1e280384f46c27e2de)), closes [#13002](https://github.com/aws/aws-cdk/issues/13002) [#12918](https://github.com/aws/aws-cdk/issues/12918) +* **ec2:** volume props validations are incorrect ([#12821](https://github.com/aws/aws-cdk/issues/12821)) ([12cddff](https://github.com/aws/aws-cdk/commit/12cddffcfa38cc0522e4c36327f193e6a605f441)), closes [#12816](https://github.com/aws/aws-cdk/issues/12816) [#12816](https://github.com/aws/aws-cdk/issues/12816) [#12074](https://github.com/aws/aws-cdk/issues/12074) +* **rds:** proxy cannot connect to cluster/instance ([#12953](https://github.com/aws/aws-cdk/issues/12953)) ([4b0abbc](https://github.com/aws/aws-cdk/commit/4b0abbcdc6efe2d37e2a9eee382848d2de82de5c)) +* **tools:** doc block links not clickable in VS Code ([#12336](https://github.com/aws/aws-cdk/issues/12336)) ([4f17f92](https://github.com/aws/aws-cdk/commit/4f17f923edc5e55b0977dcb250c9908027297d1b)) + ## [1.89.0](https://github.com/aws/aws-cdk/compare/v1.88.0...v1.89.0) (2021-02-09) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1d113183c9a67..2b1a950a551fe 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -129,12 +129,12 @@ and instead only depend on having a working Docker install. ### Step 1: Open Issue If there isn't one already, open an issue describing what you intend to contribute. It's useful to communicate in -advance, because sometimes, someone is already working in this space, so maybe it's worth collaborating with them -instead of duplicating the efforts. +advance because if someone is already working in this space, it may be worth collaborating with them +instead of duplicating the effort. ### Step 2: Design (optional) -In some cases, it is useful to seek for feedback by iterating on a design document. This is useful +In some cases, it is useful to seek feedback by iterating on a design document. This is useful when you plan a big change or feature, or you want advice on what would be the best path forward. Sometimes, the GitHub issue is sufficient for such discussions, and can be sufficient to get @@ -166,7 +166,7 @@ Work your magic. Here are some guidelines: * Every change requires a unit test * If you change APIs, make sure to update the module's README file * Try to maintain a single feature/bugfix per pull request. It's okay to introduce a little bit of housekeeping - changes along the way, but try to avoid conflating multiple features. Eventually all these are going to go into a + changes along the way, but try to avoid conflating multiple features. Eventually, all these are going to go into a single commit, so you can use that to frame your scope. * If your change introduces a new construct, take a look at the our [example Construct Library](packages/@aws-cdk/example-construct-library) for an explanation of the common patterns we use. @@ -249,7 +249,7 @@ BREAKING CHANGE: Description of what broke and how to achieve this behavior now ### Step 5: Pull Request -* Push to a GitHub fork or to a branch (naming convention: `/`) +* Push to a GitHub fork or to a branch (naming convention: `/`). * Submit a Pull Request on GitHub. A reviewer will later be assigned by the maintainers. * Please follow the PR checklist written below. We trust our contributors to self-check, and this helps that process! * Discuss review comments and iterate until you get at least one “Approve”. When iterating, push new commits to the @@ -262,15 +262,15 @@ BREAKING CHANGE: Description of what broke and how to achieve this behavior now ### Step 6: Merge -* Make sure your PR builds successfully (we have CodeBuild setup to automatically build all PRs) +* Make sure your PR builds successfully (we have CodeBuild setup to automatically build all PRs). * Once approved and tested, a maintainer will squash-merge to master and will use your PR title/description as the commit message. ## Tools -The CDK is a big project, and, at the moment, all of the CDK modules are mastered in a single monolithic repository +The CDK is a big project, and at the moment, all of the CDK modules are mastered in a single monolithic repository (uses [lerna](https://github.com/lerna/lerna)). There are pros and cons to this approach, and it's especially valuable -to maintain integrity in the early stage of the project where things constantly change across the stack. In the future +to maintain integrity in the early stage of the project where things constantly change across the stack. In the future, we believe many of these modules will be extracted to their own repositories. Another complexity is that the CDK is packaged using [jsii](https://github.com/aws/jsii) to multiple programming @@ -328,7 +328,7 @@ They can also be executed independently of the build script. From the root of a yarn lint ``` -The following linters are used - +The following linters are used: - [eslint](#eslint) - [pkglint](#pkglint) @@ -375,7 +375,7 @@ the [guidelines](./DESIGN_GUIDELINES.md). Here are a few useful commands: * `yarn awslint` in every module will run __awslint__ for that module. - * `yarn awslint list` prints all rules (details and rationale in the guidelines doc) + * `yarn awslint list` prints all rules (details and rationale in the guidelines doc). * `scripts/foreach.sh yarn awslint` will start linting the entire repo, progressively. Rerun `scripts/foreach.sh` after fixing to continue. * `lerna run awslint --no-bail --stream 2> awslint.txt` will run __awslint__ in all modules and collect all results into awslint.txt * `lerna run awslint -- -i ` will run awslint throughout the repo and @@ -391,7 +391,7 @@ examples are still accurate. Successfully building examples is also necessary to other supported languages (`C#`, `Java`, `Python`, ...). > Note that examples may use libraries that are not part of the `dependencies` or `devDependencies` of the documented -> package. For example `@aws-cdk/core` contains mainy examples that leverage libraries built *on top of it* (such as +> package. For example, `@aws-cdk/core` contains many examples that leverage libraries built *on top of it* (such as > `@aws-cdk/aws-sns`). Such libraries must be built (using `yarn build`) before **jsii-rosetta** can verify that > examples are correct. @@ -426,7 +426,7 @@ Each module also has an npm script called `cfn2ts`: ### scripts/foreach.sh This wonderful tool allows you to execute a command for all modules in this repo -in topological order, but has the incredible property of being stateful. this +in topological order, but has the incredible property of being stateful. This means that if a command fails, you can fix the issue and resume from where you left off. @@ -437,7 +437,7 @@ $ scripts/foreach.sh COMMAND ``` This will execute "COMMAND" for each module in the repo (cwd will be the directory of the module). -if a task fails, it will stop, and then to resume, simply run `foreach.sh` again (with or without the same command). +If a task fails, it will stop. To resume, simply run `foreach.sh` again (with or without the same command). To reset the session (either when all tasks finished or if you wish to run a different session), run: @@ -452,11 +452,11 @@ $ cd packages/my-module $ ../scripts/foreach.sh --up COMMAND ``` -This will execute `COMMAND` against `my-module` and all it's deps (in a topological order of course). +This will execute `COMMAND` against `my-module` and all its deps (in a topological order, of course). ### Jetbrains support (WebStorm/IntelliJ) -This project uses lerna and utilizes symlinks inside nested node_modules directories. You may encounter an issue during +This project uses lerna and utilizes symlinks inside nested `node_modules` directories. You may encounter an issue during indexing where the IDE attempts to index these directories and keeps following links until the process runs out of available memory and crashes. To fix this, you can run ```node ./scripts/jetbrains-remove-node-modules.js``` to exclude these directories. @@ -528,12 +528,12 @@ $ cd packages/@aws-cdk/aws-ec2 $ ../../../scripts/buildup ``` -Note that `buildup` uses `foreach.sh`, which means it's resumable. If your build fails and you wish to resume, just run +Note that `buildup` uses `foreach.sh`, which means it is resumable. If your build fails and you wish to resume, just run `buildup --resume`. If you wish to restart, run `buildup` again. ### Partial pack -Packing involves generating CDK code in the various target languages, and packaged up ready to be published to the +Packing involves generating CDK code in the various target languages and packaging them up to be published to their respective package managers. Once in a while, these will need to be generated either to test the experience of a new feature, or reproduce a packaging failure. @@ -569,14 +569,14 @@ Code... Now to test, you can either use `yarn test` or invoke nodeunit/jest directly: -Running nodeunit tests directly on a module +Running nodeunit tests directly on a module: ```console $ cd packages/@aws-cdk/aws-iam $ nodeunit test/test.*.js ``` -Running jest tests directly on a module +Running jest tests directly on a module: ```console $ cd packages/@aws-cdk/aws-iam $ jest test/*test.js @@ -599,7 +599,7 @@ One can use the `postinstall` script to symlink this repo: ``` This assumes this repo is a sibling of the target repo and will install the CDK as a linked dependency during -__yarn install__. +`yarn install`. ### Running integration tests in parallel @@ -713,7 +713,7 @@ can be used in these cases. #### Fixture Files Examples typed in fenced code blocks (looking like `'''ts`, but then with backticks -instead of regular quotes) will be automatically extrated, compiled and translated +instead of regular quotes) will be automatically extracted, compiled and translated to other languages when the bindings are generated. To successfully do that, they must be compilable. The easiest way to do that is using @@ -765,14 +765,14 @@ In order to offer a consistent documentation style throughout the AWS CDK codebase, example code should follow the following recommendations (there may be cases where some of those do not apply - good judgement is to be applied): -- Types from the documented module should be **un-qualified** +- Types from the documented module should be **un-qualified**: ```ts // An example in the @aws-cdk/core library, which defines Duration Duration.minutes(15); ``` -- Types from other modules should be **qualified** +- Types from other modules should be **qualified**: ```ts // An example in the @aws-cdk/core library, using something from @aws-cdk/aws-s3 @@ -849,6 +849,22 @@ CDK](https://github.com/aws/aws-cdk/issues/3398) we will either remove the legacy behavior or flip the logic for all these features and then reset the `FEATURE_FLAGS` map for the next cycle. +#### CDKv2 + +We have started working on the next version of the CDK, specifically CDKv2. This is currently being maintained +on a separate branch `v2-main` whereas `master` continues to track versions `1.x`. + +Feature flags introduced in the CDK 1.x and removed in 2.x, must be added to the `FUTURE_FLAGS_EXPIRED` list in +[cx-api/lib/features.ts](https://github.com/aws/aws-cdk/blob/master/packages/%40aws-cdk/cx-api/lib/features.ts) +on the `v2-main` branch. +This will make the default behaviour in CDKv2 as if the flag is enabled and also prevents users from disabling +the feature flag. + +A couple of [jest helper methods] are available for use with unit tests. These help run unit tests that test +behaviour when flags are enabled or disabled in the two major versions. + +[jest helper methods]: https://github.com/aws/aws-cdk/blob/master/tools/cdk-build-tools/lib/feature-flag.ts + ### Versioning and Release The `release.json` file at the root of the repo determines which release line @@ -864,7 +880,7 @@ this branch belongs to. To reduce merge conflicts in automatic merges between version branches, the current version number is stored under `version.vNN.json` (where `NN` is `majorVersion`) and changelogs are stored under `CHANGELOG.NN.md` (for -historical reasons, the changelog for 1.x is under `CHANGELOG.md`). When we +historical reasons, the changelog for 1.x is under `CHANGELOG.md`). When we fork to a new release branch (e.g. `v2-main`), we will update `release.json` in this branch to reflect the new version line, and this information will be used to determine how releases are cut. @@ -915,8 +931,7 @@ $ yarn build However, this will be time consuming. In this section we'll describe some common issues you may encounter and some more targeted commands you can run to resolve your issue. -* The compiler is throwing errors on files that I renamed/it's running old tests that I meant to remove/code coverage is - low and I didn't change anything. +#### The compiler is throwing errors on files that I renamed/it's running old tests that I meant to remove/code coverage is low and I didn't change anything. If you switch to a branch in which `.ts` files got renamed or deleted, the generated `.js` and `.d.ts` files from the previous compilation run are still around and may in some cases still be picked up by the compiler or test runners. @@ -927,7 +942,7 @@ Run the following to clear out stale build artifacts: $ scripts/clean-stale-files.sh ``` -* I added a dependency but it's not being picked up by the build +#### I added a dependency but it's not being picked up by the build You need to tell Lerna to update all dependencies: @@ -935,19 +950,18 @@ You need to tell Lerna to update all dependencies: $ node_modules/.bin/lerna bootstrap ``` -* I added a dependency but it's not being picked up by a `watch` background compilation run. +#### I added a dependency but it's not being picked up by a `watch` background compilation run. No it's not. After re-bootstrapping you need to restart the watch command. -* I added a dependency but it's not being picked up by Visual Studio Code (I still get red underlines). +#### I added a dependency but it's not being picked up by Visual Studio Code (I still get red underlines). The TypeScript compiler that's running has cached your dependency tree. After re-bootstrapping, restart the TypeScript compiler. Hit F1, type `> TypeScript: Restart TS Server`. -* I'm doing refactorings between packages and compile times are killing me/I need to switch between - differently-verionsed branches a lot and rebuilds because of version errors are taking too long. +#### I'm doing refactorings between packages and compile times are killing me/I need to switch between differently-verionsed branches a lot and rebuilds because of version errors are taking too long. Our build steps for each package do a couple of things, such as generating code and generating JSII assemblies. If you've done a full build at least once to generate all source files, you can do a quicker TypeScript-only rebuild of the @@ -980,7 +994,7 @@ $ CDK_TEST_BUILD=false lr test To debug your CDK application along with the CDK repository, 1. Clone the CDK repository locally and build the repository. See [Workflows](#workflows) section for the different build options. -2. Build the CDK application using the appropriate npm script (typically, `yarn build`) and then run the `link-all.sh` script as so - +2. Build the CDK application using the appropriate npm script (typically, `yarn build`) and then run the `link-all.sh` script as follows: ``` cd /path/to/cdk/app @@ -1020,7 +1034,7 @@ To debug your CDK application along with the CDK repository, } ``` - *Go [here](https://code.visualstudio.com/docs/editor/debugging#_launch-configurations) for more about launch configurations.* + *NOTE: Go [here](https://code.visualstudio.com/docs/editor/debugging#_launch-configurations) for more about launch configurations.* 6. The debug view, should now have a launch configuration called 'Debug hello-cdk' and launching that will start the debugger. 7. Any time you modify the CDK app or any of the CDK modules, they need to be re-built and depending on the change the `link-all.sh` script from step#2, may need to be re-run. Only then, would VS code recognize the change and potentially the breakpoint. diff --git a/DESIGN_GUIDELINES.md b/DESIGN_GUIDELINES.md index 6a3da024723c4..e6cebe9f434c6 100644 --- a/DESIGN_GUIDELINES.md +++ b/DESIGN_GUIDELINES.md @@ -199,7 +199,7 @@ the fact that the Bucket class needs the ARN or that it needs to request encryption permissions are not the user's concern, and the API of the Bucket class should not “leak” these implementation details. In the future, the Bucket class can decide to interact differently with the **key** and this won't require -expanding it's surface area. It also allows the **Key** class to change it's +expanding its surface area. It also allows the **Key** class to change its behavior (i.e. add an IAM action to enable encryption of certain types of keys) without affecting the API of the consumer. @@ -207,7 +207,7 @@ without affecting the API of the consumer. Using object references instead of attribute references provides a richer API, but also introduces an inherent challenge: how do we reference constructs that -are not defined inside the same app (“**owned**” by the app). These could be +are not defined inside the same app (“**owned**” by the app)? These could be resources that were created by some other AWS CDK app, via the AWS console, etc. We call these **“unowned” constructs.** @@ -272,7 +272,7 @@ as “props” (to distinguish them from JavaScript object properties). Props are the most important aspect of designing a construct. Props are the entry point of the construct. They should reflect the entire surface area of the service through semantics that are intuitive to how developers perceive the -service and it's capabilities. +service and its capabilities. When designing the props of an AWS resource, consult the AWS Console experience for creating this resource. Service teams spend a lot of energy thinking about @@ -300,7 +300,7 @@ API. In almost all cases, a richer object-oriented API can be exposed to encapsulate the low-level surface [_awslint:props-no-cfn-types_]. Do not use the **Token** type. It provides zero type safety, and is a functional -interface that may not translate cleanly in other JSII runtimes: ergo it should +interface that may not translate cleanly in other JSII runtimes. Therefore, it should be avoided wherever possible [_awslint:props-no-tokens_]. **deCDK** allows users to synthesize CDK stacks through a CloudFormation-like @@ -308,7 +308,7 @@ be avoided wherever possible [_awslint:props-no-tokens_]. like CloudFormation resources. Technically, this means that when a construct is defined, users supply an ID, type and a set of properties. In order to allow users to instantiate all AWS Construct Library constructs through the - deCDK syntax, we pose restrictions on prop types _[awslint:props-decdk]_: + deCDK syntax, we impose restrictions on prop types _[awslint:props-decdk]_: * Primitives (string, number, boolean, date) * Collections (list, map) @@ -390,7 +390,7 @@ item). It just means that you can remove redundant context from the property names. For example, there is no need to repeat the resource type, the property type or indicate that this is a "configuration". -For example prefer “readCapacity” versus “readCapacityUnits”. +For example, prefer “readCapacity” versus “readCapacityUnits”. #### Naming @@ -546,7 +546,7 @@ be treated as an opaque token, the JSDoc “@returns” annotation should begin When an app defines a construct or resource, it specifies its provisioning configuration upon initialization. For example, when an SQS queue is defined, -it's visibility timeout can be configured. +its visibility timeout can be configured. Naturally, when constructs are imported (unowned), the importing app does not have control over its configuration (e.g. you cannot change the visibility @@ -609,17 +609,17 @@ consistency and interoperability, we allow mutating methods to be exposed on the interface. For example, **grant** methods are exposed on the construct interface and not on the concrete class. In most cases, when you grant a permission on an AWS resource, the *principal's* policy needs to be updated, which mutates the -consumer . However, there are certain cases where a *resource policy* must be +consumer. However, there are certain cases where a *resource policy* must be updated. However, if the resource is unowned, it doesn't make sense (or even impossible) to update its policy (there is usually a 1:1 relationship between a -resource and a resource policy). In such a case, we decided that grant methods -will simply skip any changes to resource policies, but will issue attach a +resource and a resource policy). In such cases, we decided that grant methods +will simply skip any changes to resource policies, but will attach a **permission notice** to the app, which will be printed when the stack is synthesized by the toolkit. ### Factories -In most AWS services, there's a one or more resource which can be referred to as +In most AWS services, there are one or more resources which can be referred to as “primary resources” (normally one), while other resources exposed by the service can be considered “secondary resources”. @@ -687,7 +687,7 @@ their app. The signature of all “from” methods should adhere to the following rules _[awslint:from-signature]_: -* First argument must be **scope** of type **Construct** +* First argument must be **scope** of type **Construct**. * Second argument is a **string**. This string will be used to determine the ID of the new construct. If the import method uses some value that is promised to be unique within the stack scope (such as ARN, export name), @@ -697,8 +697,8 @@ _[awslint:from-signature]_: #### “from” Methods Resource constructs should export static “from” methods for importing unowned -resources given one more of it's physical attributes such as ARN, name, etc. All -constructs should have at least one fromXxx method _[awslint:from-method]_: +resources given one more of its physical attributes such as ARN, name, etc. All +constructs should have at least one "fromXxx" method _[awslint:from-method]_: ```ts static fromFooArn(scope: Construct, id: string, bucketArn: string): IFoo; @@ -713,7 +713,7 @@ static fromFooName(scope: Construct, id: string, bucketName: string): IFoo; doesn't have unresolved tokens (using **Token.unresolved**). Preferably, they can use **Stack.parseArn** to achieve this purpose. -If a resource has an ARN attribute it should implement at least a **fromFooArn** +If a resource has an ARN attribute, it should implement at least a **fromFooArn** import method [_awslint:from-arn_]. To implement **fromAttribute** methods, use the abstract base class construct as @@ -769,7 +769,7 @@ interface FooProps { } ``` -The construct interface should expose a **role**property, and extends +The construct interface should expose a **role** property, and extends **iam.IGrantable** _[awslint:role-property]_: ```ts @@ -793,7 +793,7 @@ interface IFoo { } ``` -If the construct is unowned this method should no-op and issue a **permissions +If the construct is unowned, this method should no-op and issue a **permissions notice** (TODO) to the user indicating that they should ensure that the role of this resource should have the specified permission. @@ -947,7 +947,7 @@ suffix and adhere to the following rules _[awslint:metrics-method-signature]:_ * Name should be “metricXxx” where “Xxx” is the official metric name * Accepts a single “options” argument of type **MetricOptions** -* Returns a **Metric** object. +* Returns a **Metric** object ```ts interface IFunction { @@ -1001,7 +1001,7 @@ extend **ec2.IConnectable** _[awslint:connectable-interface]_. ### Integrations -Many AWS services offer “integrations” to other services. For example, AWS +Many AWS services offer “integrations” with other services. For example, AWS CodePipeline has actions that can trigger AWS Lambda functions, ECS tasks, CodeBuild projects and more. AWS Lambda can be triggered by a variety of event sources, AWS CloudWatch event rules can trigger many types of targets, SNS can @@ -1017,7 +1017,7 @@ the central service and can be triggered by multiple event sources. Integrations are an abstract concept, not necessarily a specific mechanism. For example, each AWS Lambda event source is implemented in a different way (SNS, -Bucket notifications, CloudWatch events, etc), but conceptually, *some*users +Bucket notifications, CloudWatch events, etc), but conceptually, *some* users like to think about AWS Lambda as the “center”. It is also completely legitimate to have multiple ways to connect two services on AWS. To trigger an AWS Lambda function from an SNS topic, you could either use the integration or the SNS APIs @@ -1102,7 +1102,7 @@ export class Table { } ``` Persistent resources must have a **removalPolicy** prop, defaults to -**Orphan**_[awslint:state-removal-policy-prop]_: +**Orphan** _[awslint:state-removal-policy-prop]_: ```ts import { RemovalPolicy } from '@aws-cdk/cdk'; @@ -1179,14 +1179,14 @@ implementation of AWS constructs. not one that you made up and you force them to learn. * Multiple ways of achieving the same thing is legitimate. * Constantly maintain the invariants. -* Fewer “if statements” the better. +* The fewer “if statements” the better. ### Construct IDs Construct IDs (the second argument passed to all constructs when they are defined) are used to formulate resource logical IDs which must be **stable** across updates. The logical ID of a resource is calculated based on the **full -path** of it's construct in the construct scope hierarchy. This means that any +path** of its construct in the construct scope hierarchy. This means that any change to a logical ID in this path will invalidate all the logical IDs within this scope. This will result in **replacements of all underlying resources** within the next update, which is extremely undesirable. @@ -1196,7 +1196,7 @@ construct. Therefore, when implementing constructs, you should treat the construct hierarchy and all construct IDs as part of the **external contract** of the -construct. Any chance to either should be considered and called out as a +construct. Any change to either should be considered and called out as a breaking change. There is no need to concatenate logical IDs. If you find yourself needing to @@ -1226,10 +1226,10 @@ Error since all errors in the CDK are unrecoverable): * Include a descriptive message * Include the value provided * Include the expected/allowed values -* No need to include information that can be obtained from the stack trace. -* No need to add a period at the end of error messages. +* No need to include information that can be obtained from the stack trace +* No need to add a period at the end of error messages -#### Avoid Errors if Possible +#### Avoid Errors If Possible Always prefer to do the right thing for the user instead of raising an error. Only fail if the user has explicitly specified bad configuration. For diff --git a/allowed-breaking-changes.txt b/allowed-breaking-changes.txt index 2ca2ca5b6067f..964bb4d5c7712 100644 --- a/allowed-breaking-changes.txt +++ b/allowed-breaking-changes.txt @@ -56,3 +56,10 @@ incompatible-argument:@aws-cdk/aws-ecs.TaskDefinition.addVolume # We made properties optional and it's really fine but our differ doesn't think so. weakened:@aws-cdk/cloud-assembly-schema.DockerImageSource weakened:@aws-cdk/cloud-assembly-schema.FileSource + +# https://github.com/aws/aws-cdk/pull/13145 +removed:@aws-cdk/core.AssetStaging.isArchive +removed:@aws-cdk/core.AssetStaging.packaging +removed:@aws-cdk/core.BundlingOutput +removed:@aws-cdk/core.BundlingOptions.outputType + diff --git a/design/aws-ecs/aws-ecs-fargate-capacity-providers.md b/design/aws-ecs/aws-ecs-fargate-capacity-providers.md new file mode 100644 index 0000000000000..66451ece2843a --- /dev/null +++ b/design/aws-ecs/aws-ecs-fargate-capacity-providers.md @@ -0,0 +1,121 @@ +# Fargate Spot Capacity Provider support in the CDK + +## Objective + +Since Capacity Providers are now supported in CloudFormation, incorporating support for Fargate Spot capacity has been one of the [top asks](https://github.com/aws/aws-cdk/issues?q=is%3Aissue+is%3Aopen+label%3A%40aws-cdk%2Faws-ecs+sort%3Areactions-%2B1-desc) for the ECS CDK module, with over 60 customer reactions. While there are still some outstanding issues regarding capacity provider support in general, specifically regarding cyclic workflows with named clusters (See: [CFN issue](http://%20https//github.com/aws/containers-roadmap/issues/631#issuecomment-702580141)), we should be able to move ahead with supporting `FARGATE` and `FARGATE_SPOT` capacity providers with our existing FargateService construct. + +See: https://github.com/aws/aws-cdk/issues/5850 + +## CloudFormation Requirements + +### Cluster + +A list of capacity providers (specifically, `FARGATE` and `FARGATE_SPOT`) need to be specified on the cluster itself as part of the [CapacityProviders](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-cluster.html#cfn-ecs-cluster-capacityproviders) field. + +Additionally, there is a [DefaultCapacityProviderStrategy](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-cluster.html#cfn-ecs-cluster-defaultcapacityproviderstrategy) on the cluster. While it is considered best practice to specify one if using capacity providers, this may not be necessary when only using Fargate capacity providers. + +### Service + +The [CapacityProviderStrategy](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-service.html#cfn-ecs-service-capacityproviderstrategy) field will need to be added to the Service construct. This would be a list of capacity provider strategies (aka [CapacityProviderStrategyItem](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-capacityproviderstrategyitem.html) in CFN) used for the service. + +_Note_: It may be more readable to name the `CapacityProviderStrategy` field on the service to *CapacityProviderStrategies*, which would be a list of *CapacityProviderStrategy* objects that correspond to the CFN `CapacityProviderStrategyItem`. + + +## Proposed solution + +### User Experience + +The most straightforward solution would be to add the *capacityProviders* field on cluster, which the customer would have to set to the Fargate capacity providers (`FARGATE` and `FARGATE_SPOT`), and then specify the *capacityProviderStrategies* field on the FargateService with one or more strategies that use the Fargate capacity providers. + +Example: + +```ts +const stack = new cdk.Stack(); +const vpc = new ec2.Vpc(stack, 'MyVpc', {}); +const cluster = new ecs.Cluster(stack, 'EcsCluster', { + vpc, + *capacityProviders: ['FARGATE', 'FARGATE_SPOT'],* +}); + +const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); + +const container = taskDefinition.addContainer('web', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 512, +}); +container.addPortMappings({ containerPort: 8000 }); + +new ecs.FargateService(stack, 'FargateService', { + cluster, + taskDefinition, + *capacityProviderStrategies**: [ + { + capacityProvider: 'FARGATE_SPOT', + weight: 2, + }, + { + capacityProvider: 'FARGATE', + weight: 1, + } + ],* +}); +``` + +The type for the *capacityProviders* field on a *Cluster* would be a list of string literals. An alternative that ensures type safety is to have `FARGATE` and `FARGATE_SPOT` as enum values; however, this would make it potentially more difficult to support Autoscaling Group capacity providers in the future, since [capacity providers](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/cluster-capacity-providers.html) of that type would have be specified by their capacity provider name (as a string literal). + +The type for the *capacityProviderStrategies* field on a *Service* would be a list of [*CapacityProviderStrategy*](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-capacityproviderstrategyitem.html) objects, taking the form: + +{"[Base](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-capacityproviderstrategyitem.html#cfn-ecs-service-capacityproviderstrategyitem-base)" : Integer, "[CapacityProvider](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-capacityproviderstrategyitem.html#cfn-ecs-service-capacityproviderstrategyitem-capacityprovider)" : String, "[Weight](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-capacityproviderstrategyitem.html#cfn-ecs-service-capacityproviderstrategyitem-weight)" : Integer } + +*Base* and *Weight* fields will be *optional*; *CapacityProvider* is *required*. I.e.: + +```ts +/** + * A Capacity Provider strategy to use for the service. + */ +export interface CapacityProviderStrategy { + /** + * The name of the Capacity Provider. Currently only FARGATE and FARGATE_SPOT are supported. + */ + readonly capacityProvider: string; + + /** + * The base value designates how many tasks, at a minimum, to run on the specified capacity provider. Only one + * capacity provider in a capacity provider strategy can have a base defined. If no value is specified, the default + * value of 0 is used. + * + * @default - none + */ + readonly base?: number; + + /** + * The weight value designates the relative percentage of the total number of tasks launched that should use the + * specified +capacity provider. The weight value is taken into consideration after the base value, if defined, is satisfied. + * + * @default - 0 + */ + readonly weight?: number; +} + +``` +This new field would be added to the BaseService, not only for better extensibility when we add support for ASG capacity providers, but also to facilitate construction, since the FargateService extends the BaseService and would necessarily call super into the BaseService constructor. + +Implications Setting Launch Type + +Since it can be reasonably assumed that any CapacityProvideStrategies defined on the Service are what the customer intends to use on the Service, the LaunchType will *not* be set on the Service if CapacityProvideStrategies are specified. This is similar to how the LaunchType field is unset if the service uses an external DeploymentController (https://github.com/aws/aws-cdk/blob/master/packages/%40aws-cdk/aws-ecs/lib/base/base-service.ts#L374). + +On the other hand, this intent would not be as obvious with Default Capacity Provider Strategies defined a cluster. A *defaultCapacityProviderStrategy* specified on a cluster is used for any service that does not specify either a launchType or its own CapacityProviderStrategies. From the point of view of the ECS APIs, similar to how custom CapacityProvideStrategies defined on the Service are expected to supersede the defaultCapacityProviderStrategy on a cluster, the expected behavior for an ECS Service that specifies a launchType is for it to also ignore the Cluster’s defaultCapacityProviderStrategy. + +However, since the two Service constructs in the CDK (Ec2Service and FargateService) do not support having the launchType field passed in explicitly, it would not possible to infer whether the intent of the customer using one of these Service constructs is to use the implied launchType (currently set under the hood in the service’s constructor (https://github.com/aws/aws-cdk/blob/master/packages/%40aws-cdk/aws-ecs/lib/fargate/fargate-service.ts#L155)) or the defaultCapacityProviderStrategy. For this reason, we will not be adding the defaultCapacityProviderStrategy field on the Cluster construct for this iteration. + +_*Note*_: Future for support will be dependent on a re-design of the existing Service strategies. This will be treated in v2 of the ECS modules, likely with a single Service L2 construct and deprecation of the Ec2Service and FargateService constructs. + + +### Alternatives: +One alternative considered was to provide a more magical experience by populating the capacityProviders field under the hood (for example, by modifying the cluster if capacityProviderStrategies is set on a FargateService). However, there is the slight disadvantage of this being a less consistent behavior with how ASG capacity providers will be set in the future, and would break from the general pattern of setting resource fields at construction time. Furthermore, given that the cluster field on a service is of type ICluster, this may make it prohibitively difficult/impossible to provide the magical experience of modifying fields on the Cluster from the service. In the case where an ICluster is defined in a different stack, its properties cannot be modified from the stack where the Service is defined at all. For this reason, we will have to enforce the capacityProviders field being set explicitly on the Cluster construct. + +For future extensibility, we can however add an `addCapacityProvider` method on the Cluster resource, to allow modifying the cluster CapacityProviders field post-construction. + +Another option would be to create a new FargateCluster resource, that would have the two Fargate capacity providers set by default. The main advantage with this alternative would be that it would be consistent with the current Console experience, which sets the Fargate capacity providers for you if you choose the “Networking Only” cluster template via the cluster wizard. The downside is that it would be a more restrictive resource model that would go back on the decision to have a single generic ECS Cluster resource that could potentially contain both Fargate and EC2 services or tasks. Given that we are moving towards more generic versions of ECS resources, this is not a preferable solution. That being said, in the current iteration we can set the Fargate Capacity Providers on the cluster by default, but put them behind a feature flag, which we would be able to remove in the v2 version of the ECS module. Using the feature flag would ensure that there would not be a diff in the generated CFN template for existing customers defining ECS clusters in their stack who redeploy using an updated version of the CDK. + diff --git a/package.json b/package.json index 8dc6fcb73814b..a986d658240f5 100644 --- a/package.json +++ b/package.json @@ -16,14 +16,14 @@ "devDependencies": { "conventional-changelog-cli": "^2.1.1", "fs-extra": "^9.1.0", - "graceful-fs": "^4.2.5", + "graceful-fs": "^4.2.6", "jest-junit": "^12.0.0", - "jsii-diff": "^1.20.1", - "jsii-pacmak": "^1.20.1", - "jsii-rosetta": "^1.20.1", + "jsii-diff": "^1.21.0", + "jsii-pacmak": "^1.21.0", + "jsii-rosetta": "^1.21.0", "lerna": "^3.22.1", - "standard-version": "^9.1.0", - "typescript": "~3.9.7" + "standard-version": "^9.1.1", + "typescript": "~3.9.9" }, "resolutions-comment": "should be removed or reviewed when nodeunit dependency is dropped or adjusted", "resolutions": { diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/package.json b/packages/@aws-cdk-containers/ecs-service-extensions/package.json index f388877969ce0..05781b7cc3750 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/package.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/package.json @@ -100,5 +100,8 @@ "announce": false }, "maturity": "stable", - "stability": "stable" + "stability": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json index 6a9f04c284047..6b7a3f0e42086 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json @@ -400,7 +400,9 @@ "Type": "AWS::SQS::Queue", "Properties": { "MessageRetentionPeriod": 1209600 - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "nameserviceTaskRecordManagerEventsQueueF805A6C1": { "Type": "AWS::SQS::Queue", @@ -415,7 +417,9 @@ "maxReceiveCount": 500 }, "VisibilityTimeout": 30 - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "nameserviceTaskRecordManagerEventsQueuePolicy65CC6F9E": { "Type": "AWS::SQS::QueuePolicy", @@ -746,14 +750,12 @@ ] } }, - "Handler": "index.queue_handler", "Role": { "Fn::GetAtt": [ "nameserviceTaskRecordManagerEventHandlerServiceRoleE66EE52A", "Arn" ] }, - "Runtime": "python3.8", "Environment": { "Variables": { "HOSTED_ZONE_ID": { @@ -777,7 +779,9 @@ } } }, + "Handler": "index.queue_handler", "ReservedConcurrentExecutions": 1, + "Runtime": "python3.8", "Timeout": 30 }, "DependsOn": [ @@ -788,14 +792,14 @@ "nameserviceTaskRecordManagerEventHandlerSqsEventSourceawsecsintegnameserviceTaskRecordManagerEventsQueueC5EE9A869F1EB155": { "Type": "AWS::Lambda::EventSourceMapping", "Properties": { + "FunctionName": { + "Ref": "nameserviceTaskRecordManagerEventHandler4B8C6905" + }, "EventSourceArn": { "Fn::GetAtt": [ "nameserviceTaskRecordManagerEventsQueueF805A6C1", "Arn" ] - }, - "FunctionName": { - "Ref": "nameserviceTaskRecordManagerEventHandler4B8C6905" } } }, @@ -909,13 +913,13 @@ ] } }, - "Handler": "index.cleanup_resource_handler", "Role": { "Fn::GetAtt": [ "nameserviceTaskRecordManagerCleanupResourceProviderHandlerServiceRoleCCA462F0", "Arn" ] }, + "Handler": "index.cleanup_resource_handler", "Runtime": "python3.8", "Timeout": 300 }, @@ -1022,14 +1026,12 @@ ] } }, - "Handler": "framework.onEvent", "Role": { "Fn::GetAtt": [ "nameserviceTaskRecordManagerCleanupResourceProviderframeworkonEventServiceRoleF0570BD0", "Arn" ] }, - "Runtime": "nodejs10.x", "Description": "AWS CDK resource provider framework - onEvent (aws-ecs-integ/name-service/TaskRecordManager/CleanupResourceProvider)", "Environment": { "Variables": { @@ -1041,6 +1043,8 @@ } } }, + "Handler": "framework.onEvent", + "Runtime": "nodejs10.x", "Timeout": 900 }, "DependsOn": [ @@ -1242,13 +1246,13 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs12.x", "Timeout": 120 }, diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.imported-environment.expected.json b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.imported-environment.expected.json index 80156c0ed0d2d..dbc216370e40d 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.imported-environment.expected.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.imported-environment.expected.json @@ -49,7 +49,9 @@ ] ] } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "ServiceloadbalancerD5D60894": { "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", diff --git a/packages/@aws-cdk/alexa-ask/package.json b/packages/@aws-cdk/alexa-ask/package.json index 04cddb184db13..48b5fa2b1e003 100644 --- a/packages/@aws-cdk/alexa-ask/package.json +++ b/packages/@aws-cdk/alexa-ask/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/app-delivery/package.json b/packages/@aws-cdk/app-delivery/package.json index 82eea1a46a6bb..8ac9e9cae6a12 100644 --- a/packages/@aws-cdk/app-delivery/package.json +++ b/packages/@aws-cdk/app-delivery/package.json @@ -63,7 +63,7 @@ "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", - "fast-check": "^2.12.1", + "fast-check": "^2.13.0", "nodeunit": "^0.11.3", "pkglint": "0.0.0" }, @@ -114,5 +114,8 @@ }, "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/app-delivery/test/integ.cicd.expected.json b/packages/@aws-cdk/app-delivery/test/integ.cicd.expected.json index da4773e7fb72e..9b2ed51da9ff2 100644 --- a/packages/@aws-cdk/app-delivery/test/integ.cicd.expected.json +++ b/packages/@aws-cdk/app-delivery/test/integ.cicd.expected.json @@ -33,7 +33,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -467,4 +467,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/assert/package.json b/packages/@aws-cdk/assert/package.json index 4b324b6536a91..1416fd7f4673c 100644 --- a/packages/@aws-cdk/assert/package.json +++ b/packages/@aws-cdk/assert/package.json @@ -25,7 +25,7 @@ "cdk-build-tools": "0.0.0", "jest": "^26.6.3", "pkglint": "0.0.0", - "ts-jest": "^26.5.0" + "ts-jest": "^26.5.1" }, "dependencies": { "@aws-cdk/cloud-assembly-schema": "0.0.0", @@ -56,5 +56,8 @@ "maturity": "experimental", "cdk-build": { "jest": true + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/assets/package.json b/packages/@aws-cdk/assets/package.json index cd15c2c2d83a5..45735a4da140f 100644 --- a/packages/@aws-cdk/assets/package.json +++ b/packages/@aws-cdk/assets/package.json @@ -96,5 +96,8 @@ "maturity": "deprecated", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-accessanalyzer/package.json b/packages/@aws-cdk/aws-accessanalyzer/package.json index 6981503a54ad7..85c2a0d682662 100644 --- a/packages/@aws-cdk/aws-accessanalyzer/package.json +++ b/packages/@aws-cdk/aws-accessanalyzer/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-acmpca/package.json b/packages/@aws-cdk/aws-acmpca/package.json index c46c2f99c1757..e0956bffbf2c6 100644 --- a/packages/@aws-cdk/aws-acmpca/package.json +++ b/packages/@aws-cdk/aws-acmpca/package.json @@ -93,5 +93,8 @@ "maturity": "experimental", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-amazonmq/package.json b/packages/@aws-cdk/aws-amazonmq/package.json index 9c6ab30f28c1e..c9d6412f5effa 100644 --- a/packages/@aws-cdk/aws-amazonmq/package.json +++ b/packages/@aws-cdk/aws-amazonmq/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-amplify/package.json b/packages/@aws-cdk/aws-amplify/package.json index 865109cf27561..ea1abbde2ba37 100644 --- a/packages/@aws-cdk/aws-amplify/package.json +++ b/packages/@aws-cdk/aws-amplify/package.json @@ -109,5 +109,8 @@ }, "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-apigateway/lib/access-log.ts b/packages/@aws-cdk/aws-apigateway/lib/access-log.ts index 72550daa9e528..726a6928315ee 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/access-log.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/access-log.ts @@ -411,7 +411,7 @@ export class AccessLogField { * not from the backend Lambda function. */ public static contextIntegrationStatus() { - return '$context.integrationStatus.'; + return '$context.integrationStatus'; } /** diff --git a/packages/@aws-cdk/aws-apigateway/package.json b/packages/@aws-cdk/aws-apigateway/package.json index 3a0641e8b1162..7465b7d45a6bd 100644 --- a/packages/@aws-cdk/aws-apigateway/package.json +++ b/packages/@aws-cdk/aws-apigateway/package.json @@ -318,12 +318,17 @@ "attribute-tag:@aws-cdk/aws-apigateway.RestApi.restApiName", "attribute-tag:@aws-cdk/aws-apigateway.SpecRestApi.restApiName", "attribute-tag:@aws-cdk/aws-apigateway.LambdaRestApi.restApiName", - "from-method:@aws-cdk/aws-apigateway.Stage" + "from-method:@aws-cdk/aws-apigateway.Stage", + "resource-attribute:@aws-cdk/aws-apigateway.ApiKey.apiKeyId", + "resource-attribute:@aws-cdk/aws-apigateway.RateLimitedApiKey.apiKeyId" ] }, "stability": "stable", "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.cognito-authorizer.expected.json b/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.cognito-authorizer.expected.json index 990619cb495d4..ef5bfef19c2c3 100644 --- a/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.cognito-authorizer.expected.json +++ b/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.cognito-authorizer.expected.json @@ -27,7 +27,9 @@ "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } - } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" }, "myauthorizer23CB99DD": { "Type": "AWS::ApiGateway::Authorizer", diff --git a/packages/@aws-cdk/aws-apigateway/test/integ.restapi-import.lit.expected.json b/packages/@aws-cdk/aws-apigateway/test/integ.restapi-import.lit.expected.json index 349ae37ce27c8..54805c9f2e682 100644 --- a/packages/@aws-cdk/aws-apigateway/test/integ.restapi-import.lit.expected.json +++ b/packages/@aws-cdk/aws-apigateway/test/integ.restapi-import.lit.expected.json @@ -130,7 +130,9 @@ "Ref": "RestApi0C43BF4B" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "integrestapiimportBooksStackNestedStackintegrestapiimportBooksStackNestedStackResource395C2C9B": { "Type": "AWS::CloudFormation::Stack", @@ -192,7 +194,9 @@ "Ref": "RestApi0C43BF4B" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "integrestapiimportDeployStackNestedStackintegrestapiimportDeployStackNestedStackResource0D0EE737": { "Type": "AWS::CloudFormation::Stack", @@ -252,7 +256,9 @@ "DependsOn": [ "integrestapiimportBooksStackNestedStackintegrestapiimportBooksStackNestedStackResource395C2C9B", "integrestapiimportPetsStackNestedStackintegrestapiimportPetsStackNestedStackResource2B31898B" - ] + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json b/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json index de6dffe1edc61..f21b19c75f329 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json @@ -97,5 +97,8 @@ "maturity": "experimental", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.expected.json b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.expected.json index cdfdf727a21f3..17e2ae9976378 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.expected.json +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.expected.json @@ -72,14 +72,14 @@ [ "integrations/", { - "Ref": "MyHttpApiHttpIntegration6f095b8469365f72e33fa33d9711b140C45F3B26" + "Ref": "MyHttpApiGETHttpIntegration6f095b8469365f72e33fa33d9711b140516EBE31" } ] ] } } }, - "MyHttpApiHttpIntegration6f095b8469365f72e33fa33d9711b140C45F3B26": { + "MyHttpApiGETHttpIntegration6f095b8469365f72e33fa33d9711b140516EBE31": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { @@ -157,7 +157,9 @@ "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } - } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" }, "userpoolmyclientFAD947AB": { "Type": "AWS::Cognito::UserPoolClient", diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json b/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json index a6bbd74293860..c4a3e3039b9a3 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json @@ -103,5 +103,8 @@ "maturity": "experimental", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.alb.expected.json b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.alb.expected.json index 891c7ab616b10..e0ffbc32a3349 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.alb.expected.json +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.alb.expected.json @@ -622,7 +622,7 @@ [ "integrations/", { - "Ref": "HttpProxyPrivateApiHttpIntegration1a580b19954e4317026ffbce1f7d5ade82925DF0" + "Ref": "HttpProxyPrivateApiDefaultRouteHttpIntegration1a580b19954e4317026ffbce1f7d5ade7A32685B" } ] ] @@ -647,7 +647,7 @@ "SecurityGroupIds": [] } }, - "HttpProxyPrivateApiHttpIntegration1a580b19954e4317026ffbce1f7d5ade82925DF0": { + "HttpProxyPrivateApiDefaultRouteHttpIntegration1a580b19954e4317026ffbce1f7d5ade7A32685B": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.http-proxy.expected.json b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.http-proxy.expected.json index 71c6674df6b90..e5220fe2959b7 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.http-proxy.expected.json +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.http-proxy.expected.json @@ -108,14 +108,14 @@ [ "integrations/", { - "Ref": "LambdaProxyApiHttpIntegration70df0ec52c3e3b6bbc96e64ce3a05f24467606A4" + "Ref": "LambdaProxyApiDefaultRouteHttpIntegration70df0ec52c3e3b6bbc96e64ce3a05f24EE575CBA" } ] ] } } }, - "LambdaProxyApiHttpIntegration70df0ec52c3e3b6bbc96e64ce3a05f24467606A4": { + "LambdaProxyApiDefaultRouteHttpIntegration70df0ec52c3e3b6bbc96e64ce3a05f24EE575CBA": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { @@ -162,14 +162,14 @@ [ "integrations/", { - "Ref": "HttpProxyApiHttpIntegration8eeecf9ecdb91f31bebf6bd54fb711a4F32A389A" + "Ref": "HttpProxyApiDefaultRouteHttpIntegration8eeecf9ecdb91f31bebf6bd54fb711a41921AB82" } ] ] } } }, - "HttpProxyApiHttpIntegration8eeecf9ecdb91f31bebf6bd54fb711a4F32A389A": { + "HttpProxyApiDefaultRouteHttpIntegration8eeecf9ecdb91f31bebf6bd54fb711a41921AB82": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.lambda-proxy.expected.json b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.lambda-proxy.expected.json index 573cd3bcb8bb3..f5bc444d929c3 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.lambda-proxy.expected.json +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.lambda-proxy.expected.json @@ -108,14 +108,14 @@ [ "integrations/", { - "Ref": "LambdaProxyApiHttpIntegration70df0ec52c3e3b6bbc96e64ce3a05f24467606A4" + "Ref": "LambdaProxyApiDefaultRouteHttpIntegration70df0ec52c3e3b6bbc96e64ce3a05f24EE575CBA" } ] ] } } }, - "LambdaProxyApiHttpIntegration70df0ec52c3e3b6bbc96e64ce3a05f24467606A4": { + "LambdaProxyApiDefaultRouteHttpIntegration70df0ec52c3e3b6bbc96e64ce3a05f24EE575CBA": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.nlb.expected.json b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.nlb.expected.json index 6c9fa0633f138..0446031c61a19 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.nlb.expected.json +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.nlb.expected.json @@ -587,7 +587,7 @@ [ "integrations/", { - "Ref": "HttpProxyPrivateApiHttpIntegration1a580b19954e4317026ffbce1f7d5ade82925DF0" + "Ref": "HttpProxyPrivateApiDefaultRouteHttpIntegration1a580b19954e4317026ffbce1f7d5ade7A32685B" } ] ] @@ -612,7 +612,7 @@ "SecurityGroupIds": [] } }, - "HttpProxyPrivateApiHttpIntegration1a580b19954e4317026ffbce1f7d5ade82925DF0": { + "HttpProxyPrivateApiDefaultRouteHttpIntegration1a580b19954e4317026ffbce1f7d5ade7A32685B": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.service-discovery.expected.json b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.service-discovery.expected.json index ada88fe7be66f..28b636ef54808 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.service-discovery.expected.json +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.service-discovery.expected.json @@ -588,14 +588,14 @@ [ "integrations/", { - "Ref": "HttpProxyPrivateApiHttpIntegrationa5ec5390ca688d567e9449daf58afc6fB75CE02B" + "Ref": "HttpProxyPrivateApiDefaultRouteHttpIntegrationa5ec5390ca688d567e9449daf58afc6f6DEAA8A8" } ] ] } } }, - "HttpProxyPrivateApiHttpIntegrationa5ec5390ca688d567e9449daf58afc6fB75CE02B": { + "HttpProxyPrivateApiDefaultRouteHttpIntegrationa5ec5390ca688d567e9449daf58afc6f6DEAA8A8": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts index 2a481925c0a8b..52e5f1fccbe07 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts @@ -92,7 +92,7 @@ export interface IHttpApi extends IResource { * Add a http integration * @internal */ - _addIntegration(config: HttpRouteIntegrationConfig): HttpIntegration; + _addIntegration(scope: Construct, config: HttpRouteIntegrationConfig): HttpIntegration; } /** @@ -274,15 +274,15 @@ abstract class HttpApiBase extends Resource implements IHttpApi { // note that t /** * @internal */ - public _addIntegration(config: HttpRouteIntegrationConfig): HttpIntegration { - const stringifiedConfig = JSON.stringify(Stack.of(this).resolve(config)); + public _addIntegration(scope: Construct, config: HttpRouteIntegrationConfig): HttpIntegration { + const stringifiedConfig = JSON.stringify(Stack.of(scope).resolve(config)); const configHash = crypto.createHash('md5').update(stringifiedConfig).digest('hex'); if (configHash in this.httpIntegrations) { return this.httpIntegrations[configHash]; } - const integration = new HttpIntegration(this, `HttpIntegration-${configHash}`, { + const integration = new HttpIntegration(scope, `HttpIntegration-${configHash}`, { httpApi: this, integrationType: config.type, integrationUri: config.uri, diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/route.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/route.ts index dac962f7bfee4..4510d13ed6f2b 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/route.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/route.ts @@ -140,7 +140,7 @@ export class HttpRoute extends Resource implements IHttpRoute { scope: this, }); - const integration = props.httpApi._addIntegration(config); + const integration = props.httpApi._addIntegration(this, config); const authBindResult = props.authorizer ? props.authorizer.bind({ route: this, diff --git a/packages/@aws-cdk/aws-apigatewayv2/package.json b/packages/@aws-cdk/aws-apigatewayv2/package.json index 53cfaeefc2515..19abb0ca10b3f 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2/package.json @@ -77,7 +77,6 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@aws-cdk/aws-cognito": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -127,5 +126,8 @@ ], "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/http/route.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/http/route.test.ts index bfeb036a3fa72..a5ce1b7b64b64 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/http/route.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/http/route.test.ts @@ -1,5 +1,5 @@ import '@aws-cdk/assert/jest'; -import { Stack } from '@aws-cdk/core'; +import { Stack, App } from '@aws-cdk/core'; import { HttpApi, HttpAuthorizer, HttpAuthorizerType, HttpConnectionType, HttpIntegrationType, HttpMethod, HttpRoute, HttpRouteAuthorizerBindOptions, HttpRouteAuthorizerConfig, HttpRouteIntegrationConfig, HttpRouteKey, IHttpRouteAuthorizer, IHttpRouteIntegration, PayloadFormatVersion, @@ -25,7 +25,7 @@ describe('HttpRoute', () => { [ 'integrations/', { - Ref: 'HttpApiHttpIntegrationcff2618c192d3bd8581dd2a4093464f6CDB667B8', + Ref: 'HttpRouteHttpIntegrationcff2618c192d3bd8581dd2a4093464f6FB1097D0', }, ], ], @@ -115,6 +115,27 @@ describe('HttpRoute', () => { expect(stack2).toCountResources('AWS::ApiGatewayV2::Integration', 1); }); + test('route defined in a separate stack does not create cycles', () => { + // GIVEN + const integration = new DummyIntegration(); + + // WHEN + const app = new App(); + const stack1 = new Stack(app, 'ApiStack'); + const httpApi = new HttpApi(stack1, 'HttpApi'); + + const stack2 = new Stack(app, 'RouteStack'); + new HttpRoute(stack2, 'HttpRoute1', { + httpApi, + integration, + routeKey: HttpRouteKey.with('/books', HttpMethod.GET), + }); + + // THEN + expect(stack1).toCountResources('AWS::ApiGatewayV2::Integration', 0); + expect(stack2).toCountResources('AWS::ApiGatewayV2::Integration', 1); + }); + test('throws when path not start with /', () => { const stack = new Stack(); const httpApi = new HttpApi(stack, 'HttpApi'); @@ -253,4 +274,4 @@ class DummyAuthorizer implements IHttpRouteAuthorizer { authorizationType: HttpAuthorizerType.JWT, }; } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-appconfig/package.json b/packages/@aws-cdk/aws-appconfig/package.json index c009b9ea40639..0836a936f672c 100644 --- a/packages/@aws-cdk/aws-appconfig/package.json +++ b/packages/@aws-cdk/aws-appconfig/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-appflow/package.json b/packages/@aws-cdk/aws-appflow/package.json index f1cbc900a0d13..6d047b697b394 100644 --- a/packages/@aws-cdk/aws-appflow/package.json +++ b/packages/@aws-cdk/aws-appflow/package.json @@ -88,5 +88,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-applicationautoscaling/package.json b/packages/@aws-cdk/aws-applicationautoscaling/package.json index ae135c546f89c..71036cd220e5f 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/package.json +++ b/packages/@aws-cdk/aws-applicationautoscaling/package.json @@ -74,7 +74,7 @@ "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "fast-check": "^2.12.1", + "fast-check": "^2.13.0", "nodeunit": "^0.11.3", "pkglint": "0.0.0" }, @@ -131,5 +131,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-applicationinsights/package.json b/packages/@aws-cdk/aws-applicationinsights/package.json index 67037d3b3524c..edef6de6de7f0 100644 --- a/packages/@aws-cdk/aws-applicationinsights/package.json +++ b/packages/@aws-cdk/aws-applicationinsights/package.json @@ -91,5 +91,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-appmesh/package.json b/packages/@aws-cdk/aws-appmesh/package.json index cf21301f13e5c..32176758bd410 100644 --- a/packages/@aws-cdk/aws-appmesh/package.json +++ b/packages/@aws-cdk/aws-appmesh/package.json @@ -190,5 +190,8 @@ "maturity": "developer-preview", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-appstream/package.json b/packages/@aws-cdk/aws-appstream/package.json index 6d2011bf3bfe1..e9655519ab834 100644 --- a/packages/@aws-cdk/aws-appstream/package.json +++ b/packages/@aws-cdk/aws-appstream/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-appsync/README.md b/packages/@aws-cdk/aws-appsync/README.md index 61c4e797f5bb4..d15051d191a25 100644 --- a/packages/@aws-cdk/aws-appsync/README.md +++ b/packages/@aws-cdk/aws-appsync/README.md @@ -89,7 +89,7 @@ demoDS.createResolver({ fieldName: 'addDemo', requestMappingTemplate: appsync.MappingTemplate.dynamoDbPutItem( appsync.PrimaryKey.partition('id').auto(), - appsync.Values.projecting('demo') + appsync.Values.projecting('input') ), responseMappingTemplate: appsync.MappingTemplate.dynamoDbResultItem(), }); @@ -107,16 +107,20 @@ const secret = new rds.DatabaseSecret(stack, 'AuroraSecret', { username: 'clusteradmin', }); -// Create the DB cluster, provide all values needed to customise the database. -const cluster = new rds.DatabaseCluster(stack, 'AuroraCluster', { - engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_2_07_1 }), +// The VPC to place the cluster in +const vpc = new ec2.Vpc(stack, 'AuroraVpc'); + +// Create the serverless cluster, provide all values needed to customise the database. +const cluster = new rds.ServerlessCluster(stack, 'AuroraCluster', { + engine: rds.DatabaseClusterEngine.AURORA_MYSQL, + vpc, credentials: { username: 'clusteradmin' }, clusterIdentifier: 'db-endpoint-test', defaultDatabaseName: 'demos', }); // Build a data source for AppSync to access the database. -const rdsDS = api.addRdsDataSource('rds', 'The rds data source', cluster, secret); +const rdsDS = api.addRdsDataSource('rds', cluster, secret, 'demos'); // Set up a resolver for an RDS query. rdsDS.createResolver({ diff --git a/packages/@aws-cdk/aws-appsync/lib/data-source.ts b/packages/@aws-cdk/aws-appsync/lib/data-source.ts index 21646e8573193..ac22771916400 100644 --- a/packages/@aws-cdk/aws-appsync/lib/data-source.ts +++ b/packages/@aws-cdk/aws-appsync/lib/data-source.ts @@ -1,7 +1,7 @@ import { ITable } from '@aws-cdk/aws-dynamodb'; import { Grant, IGrantable, IPrincipal, IRole, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; import { IFunction } from '@aws-cdk/aws-lambda'; -import { IDatabaseCluster } from '@aws-cdk/aws-rds'; +import { IServerlessCluster } from '@aws-cdk/aws-rds'; import { ISecret } from '@aws-cdk/aws-secretsmanager'; import { IResolvable, Lazy, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; @@ -126,7 +126,11 @@ export abstract class BaseDataSource extends CoreConstruct { * creates a new resolver for this datasource and API using the given properties */ public createResolver(props: BaseResolverProps): Resolver { - return this.api.createResolver({ dataSource: this, ...props }); + return new Resolver(this, `${props.typeName}${props.fieldName}Resolver`, { + api: this.api, + dataSource: this, + ...props, + }); } /** @@ -299,13 +303,19 @@ export class LambdaDataSource extends BackedDataSource { */ export interface RdsDataSourceProps extends BackedDataSourceProps { /** - * The database cluster to call to interact with this data source + * The serverless cluster to call to interact with this data source */ - readonly databaseCluster: IDatabaseCluster; + readonly serverlessCluster: IServerlessCluster; /** * The secret containing the credentials for the database */ readonly secretStore: ISecret; + /** + * The name of the database to use within the cluster + * + * @default - None + */ + readonly databaseName?: string; } /** @@ -317,23 +327,24 @@ export class RdsDataSource extends BackedDataSource { type: 'RELATIONAL_DATABASE', relationalDatabaseConfig: { rdsHttpEndpointConfig: { - awsRegion: props.databaseCluster.stack.region, + awsRegion: props.serverlessCluster.stack.region, dbClusterIdentifier: Lazy.string({ produce: () => { return Stack.of(this).formatArn({ service: 'rds', - resource: `cluster:${props.databaseCluster.clusterIdentifier}`, + resource: `cluster:${props.serverlessCluster.clusterIdentifier}`, }); }, }), awsSecretStoreArn: props.secretStore.secretArn, + databaseName: props.databaseName, }, relationalDatabaseSourceType: 'RDS_HTTP_ENDPOINT', }, }); const clusterArn = Stack.of(this).formatArn({ service: 'rds', - resource: `cluster:${props.databaseCluster.clusterIdentifier}`, + resource: `cluster:${props.serverlessCluster.clusterIdentifier}`, }); props.secretStore.grantRead(this); diff --git a/packages/@aws-cdk/aws-appsync/lib/graphqlapi-base.ts b/packages/@aws-cdk/aws-appsync/lib/graphqlapi-base.ts index 3b037101e97ee..060d57a34c276 100644 --- a/packages/@aws-cdk/aws-appsync/lib/graphqlapi-base.ts +++ b/packages/@aws-cdk/aws-appsync/lib/graphqlapi-base.ts @@ -1,6 +1,6 @@ import { ITable } from '@aws-cdk/aws-dynamodb'; import { IFunction } from '@aws-cdk/aws-lambda'; -import { IDatabaseCluster } from '@aws-cdk/aws-rds'; +import { IServerlessCluster } from '@aws-cdk/aws-rds'; import { ISecret } from '@aws-cdk/aws-secretsmanager'; import { CfnResource, IResource, Resource } from '@aws-cdk/core'; import { DynamoDbDataSource, HttpDataSource, LambdaDataSource, NoneDataSource, RdsDataSource, AwsIamConfig } from './data-source'; @@ -97,14 +97,16 @@ export interface IGraphqlApi extends IResource { * add a new Rds data source to this API * * @param id The data source's id - * @param databaseCluster The database cluster to interact with this data source - * @param secretStore The secret store that contains the username and password for the database cluster + * @param serverlessCluster The serverless cluster to interact with this data source + * @param secretStore The secret store that contains the username and password for the serverless cluster + * @param databaseName The optional name of the database to use within the cluster * @param options The optional configuration for this data source */ addRdsDataSource( id: string, - databaseCluster: IDatabaseCluster, + serverlessCluster: IServerlessCluster, secretStore: ISecret, + databaseName?: string, options?: DataSourceOptions ): RdsDataSource; @@ -204,22 +206,25 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi { /** * add a new Rds data source to this API * @param id The data source's id - * @param databaseCluster The database cluster to interact with this data source - * @param secretStore The secret store that contains the username and password for the database cluster + * @param serverlessCluster The serverless cluster to interact with this data source + * @param secretStore The secret store that contains the username and password for the serverless cluster + * @param databaseName The optional name of the database to use within the cluster * @param options The optional configuration for this data source */ public addRdsDataSource( id: string, - databaseCluster: IDatabaseCluster, + serverlessCluster: IServerlessCluster, secretStore: ISecret, + databaseName?: string, options?: DataSourceOptions, ): RdsDataSource { return new RdsDataSource(this, id, { api: this, name: options?.name, description: options?.description, - databaseCluster, + serverlessCluster, secretStore, + databaseName, }); } diff --git a/packages/@aws-cdk/aws-appsync/package.json b/packages/@aws-cdk/aws-appsync/package.json index 5e14842c6f758..f6bfb64813364 100644 --- a/packages/@aws-cdk/aws-appsync/package.json +++ b/packages/@aws-cdk/aws-appsync/package.json @@ -120,5 +120,8 @@ "maturity": "experimental", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-appsync/test/appsync-rds.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync-rds.test.ts index 97cea819de8f3..5a1b278dfc10f 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync-rds.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync-rds.test.ts @@ -1,7 +1,7 @@ import '@aws-cdk/assert/jest'; import * as path from 'path'; -import { Vpc, SecurityGroup, SubnetType, InstanceType, InstanceClass, InstanceSize } from '@aws-cdk/aws-ec2'; -import { DatabaseSecret, DatabaseCluster, DatabaseClusterEngine, AuroraMysqlEngineVersion } from '@aws-cdk/aws-rds'; +import { Vpc, SecurityGroup, SubnetType } from '@aws-cdk/aws-ec2'; +import { DatabaseSecret, DatabaseClusterEngine, AuroraMysqlEngineVersion, ServerlessCluster } from '@aws-cdk/aws-rds'; import * as cdk from '@aws-cdk/core'; import * as appsync from '../lib'; @@ -21,7 +21,7 @@ beforeEach(() => { describe('Rds Data Source configuration', () => { // GIVEN let secret: DatabaseSecret; - let cluster: DatabaseCluster; + let cluster: ServerlessCluster; beforeEach(() => { const vpc = new Vpc(stack, 'Vpc', { maxAzs: 2 }); const securityGroup = new SecurityGroup(stack, 'AuroraSecurityGroup', { @@ -31,16 +31,13 @@ describe('Rds Data Source configuration', () => { secret = new DatabaseSecret(stack, 'AuroraSecret', { username: 'clusteradmin', }); - cluster = new DatabaseCluster(stack, 'AuroraCluster', { + cluster = new ServerlessCluster(stack, 'AuroraCluster', { engine: DatabaseClusterEngine.auroraMysql({ version: AuroraMysqlEngineVersion.VER_2_07_1 }), credentials: { username: 'clusteradmin' }, clusterIdentifier: 'db-endpoint-test', - instanceProps: { - instanceType: InstanceType.of(InstanceClass.BURSTABLE2, InstanceSize.SMALL), - vpcSubnets: { subnetType: SubnetType.PRIVATE }, - vpc, - securityGroups: [securityGroup], - }, + vpc, + vpcSubnets: { subnetType: SubnetType.PRIVATE }, + securityGroups: [securityGroup], defaultDatabaseName: 'Animals', }); }); @@ -123,6 +120,34 @@ describe('Rds Data Source configuration', () => { }); }); + test('databaseName saved to RdsHttpEndpointConfig', () => { + // WHEN + const testDatabaseName = 'testDatabaseName'; + api.addRdsDataSource('ds', cluster, secret, testDatabaseName); + + // THEN + expect(stack).toHaveResourceLike('AWS::AppSync::DataSource', { + Type: 'RELATIONAL_DATABASE', + RelationalDatabaseConfig: { + RdsHttpEndpointConfig: { + AwsRegion: { Ref: 'AWS::Region' }, + AwsSecretStoreArn: { Ref: 'AuroraSecret41E6E877' }, + DbClusterIdentifier: { + 'Fn::Join': ['', ['arn:', + { Ref: 'AWS::Partition' }, + ':rds:', + { Ref: 'AWS::Region' }, + ':', + { Ref: 'AWS::AccountId' }, + ':cluster:', + { Ref: 'AuroraCluster23D869C0' }]], + }, + DatabaseName: testDatabaseName, + }, + }, + }); + }); + test('default configuration produces name identical to the id', () => { // WHEN api.addRdsDataSource('ds', cluster, secret); @@ -136,7 +161,7 @@ describe('Rds Data Source configuration', () => { test('appsync configures name correctly', () => { // WHEN - api.addRdsDataSource('ds', cluster, secret, { + api.addRdsDataSource('ds', cluster, secret, undefined, { name: 'custom', }); @@ -149,7 +174,7 @@ describe('Rds Data Source configuration', () => { test('appsync configures name and description correctly', () => { // WHEN - api.addRdsDataSource('ds', cluster, secret, { + api.addRdsDataSource('ds', cluster, secret, undefined, { name: 'custom', description: 'custom description', }); @@ -177,7 +202,7 @@ describe('Rds Data Source configuration', () => { describe('adding rds data source from imported api', () => { // GIVEN let secret: DatabaseSecret; - let cluster: DatabaseCluster; + let cluster: ServerlessCluster; beforeEach(() => { const vpc = new Vpc(stack, 'Vpc', { maxAzs: 2 }); const securityGroup = new SecurityGroup(stack, 'AuroraSecurityGroup', { @@ -187,16 +212,13 @@ describe('adding rds data source from imported api', () => { secret = new DatabaseSecret(stack, 'AuroraSecret', { username: 'clusteradmin', }); - cluster = new DatabaseCluster(stack, 'AuroraCluster', { + cluster = new ServerlessCluster(stack, 'AuroraCluster', { engine: DatabaseClusterEngine.auroraMysql({ version: AuroraMysqlEngineVersion.VER_2_07_1 }), credentials: { username: 'clusteradmin' }, clusterIdentifier: 'db-endpoint-test', - instanceProps: { - instanceType: InstanceType.of(InstanceClass.BURSTABLE2, InstanceSize.SMALL), - vpcSubnets: { subnetType: SubnetType.PRIVATE }, - vpc, - securityGroups: [securityGroup], - }, + vpc, + vpcSubnets: { subnetType: SubnetType.PRIVATE }, + securityGroups: [securityGroup], defaultDatabaseName: 'Animals', }); }); diff --git a/packages/@aws-cdk/aws-appsync/test/appsync.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync.test.ts index ca496e99afbff..f4ddfc3ba9da0 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync.test.ts @@ -55,8 +55,7 @@ test('appsync should error when creating pipeline resolver with data source', () // THEN expect(() => { - api.createResolver({ - dataSource: ds, + ds.createResolver({ typeName: 'test', fieldName: 'test2', pipelineConfig: [test1, test2], diff --git a/packages/@aws-cdk/aws-appsync/test/integ.api-import.expected.json b/packages/@aws-cdk/aws-appsync/test/integ.api-import.expected.json index 87f6776cc79d1..e4b54f04116fc 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.api-import.expected.json +++ b/packages/@aws-cdk/aws-appsync/test/integ.api-import.expected.json @@ -135,7 +135,7 @@ } } }, - "ApiQuerygetTestsResolver025B8E0A": { + "ApidsQuerygetTestsResolver952F49EE": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -152,7 +152,7 @@ "Apids0DB53FEA" ] }, - "ApiMutationaddTestResolver7A08AE91": { + "ApidsMutationaddTestResolverBCF0400B": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { diff --git a/packages/@aws-cdk/aws-appsync/test/integ.auth-apikey.expected.json b/packages/@aws-cdk/aws-appsync/test/integ.auth-apikey.expected.json index 390d55bd9bb38..2d1ef3f31504f 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.auth-apikey.expected.json +++ b/packages/@aws-cdk/aws-appsync/test/integ.auth-apikey.expected.json @@ -121,7 +121,7 @@ } } }, - "ApiQuerygetTestsResolver025B8E0A": { + "ApitestDataSourceQuerygetTestsResolverA3BBB672": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -142,7 +142,7 @@ "ApitestDataSource96AE54D5" ] }, - "ApiMutationaddTestResolver7A08AE91": { + "ApitestDataSourceMutationaddTestResolver36203D6B": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { diff --git a/packages/@aws-cdk/aws-appsync/test/integ.graphql-iam.expected.json b/packages/@aws-cdk/aws-appsync/test/integ.graphql-iam.expected.json index 4cd9043b28c4b..374a89dc33d14 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.graphql-iam.expected.json +++ b/packages/@aws-cdk/aws-appsync/test/integ.graphql-iam.expected.json @@ -28,7 +28,9 @@ "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } - } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" }, "ApiF70053CD": { "Type": "AWS::AppSync::GraphQLApi", @@ -150,7 +152,7 @@ } } }, - "ApiQuerygetTestResolver4C1F8B0C": { + "ApidsQuerygetTestResolverCCED7EC2": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -171,7 +173,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetTestsResolver025B8E0A": { + "ApidsQuerygetTestsResolver952F49EE": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -192,7 +194,7 @@ "ApiSchema510EECD7" ] }, - "ApiMutationaddTestResolver7A08AE91": { + "ApidsMutationaddTestResolverBCF0400B": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -400,14 +402,12 @@ ] } }, - "Handler": "iam-query.handler", "Role": { "Fn::GetAtt": [ "LambdaIAM687B49AF", "Arn" ] }, - "Runtime": "nodejs12.x", "Environment": { "Variables": { "APPSYNC_ENDPOINT": { @@ -417,7 +417,9 @@ ] } } - } + }, + "Handler": "iam-query.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "LambdaIAMDefaultPolicy96DEA124", @@ -496,14 +498,12 @@ ] } }, - "Handler": "iam-query.handler", "Role": { "Fn::GetAtt": [ "testFailServiceRole9FF22F85", "Arn" ] }, - "Runtime": "nodejs12.x", "Environment": { "Variables": { "APPSYNC_ENDPOINT": { @@ -513,7 +513,9 @@ ] } } - } + }, + "Handler": "iam-query.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "testFailServiceRole9FF22F85" diff --git a/packages/@aws-cdk/aws-appsync/test/integ.graphql.expected.json b/packages/@aws-cdk/aws-appsync/test/integ.graphql.expected.json index d540f3777ed00..6f9fd9c12d899 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.graphql.expected.json +++ b/packages/@aws-cdk/aws-appsync/test/integ.graphql.expected.json @@ -28,7 +28,9 @@ "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } - } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" }, "ApiF70053CD": { "Type": "AWS::AppSync::GraphQLApi", @@ -90,7 +92,7 @@ "Type": "NONE" } }, - "ApiQuerygetServiceVersionResolver269A74C1": { + "ApinoneQuerygetServiceVersionResolver336A3C2C": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -198,204 +200,7 @@ } } }, - "ApiorderDsServiceRoleCC2040C0": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "appsync.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - } - } - }, - "ApiorderDsServiceRoleDefaultPolicy3315FCF4": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "dynamodb:BatchGetItem", - "dynamodb:GetRecords", - "dynamodb:GetShardIterator", - "dynamodb:Query", - "dynamodb:GetItem", - "dynamodb:Scan", - "dynamodb:ConditionCheckItem", - "dynamodb:BatchWriteItem", - "dynamodb:PutItem", - "dynamodb:UpdateItem", - "dynamodb:DeleteItem" - ], - "Effect": "Allow", - "Resource": [ - { - "Fn::GetAtt": [ - "OrderTable416EB896", - "Arn" - ] - }, - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "OrderTable416EB896", - "Arn" - ] - }, - "/index/*" - ] - ] - } - ] - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "ApiorderDsServiceRoleDefaultPolicy3315FCF4", - "Roles": [ - { - "Ref": "ApiorderDsServiceRoleCC2040C0" - } - ] - } - }, - "ApiorderDsB50C8AAD": { - "Type": "AWS::AppSync::DataSource", - "Properties": { - "ApiId": { - "Fn::GetAtt": [ - "ApiF70053CD", - "ApiId" - ] - }, - "Name": "Order", - "Type": "AMAZON_DYNAMODB", - "DynamoDBConfig": { - "AwsRegion": { - "Ref": "AWS::Region" - }, - "TableName": { - "Ref": "OrderTable416EB896" - } - }, - "ServiceRoleArn": { - "Fn::GetAtt": [ - "ApiorderDsServiceRoleCC2040C0", - "Arn" - ] - } - } - }, - "ApipaymentDsServiceRole0DAC58D6": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "appsync.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - } - } - }, - "ApipaymentDsServiceRoleDefaultPolicy528E42B0": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "dynamodb:BatchGetItem", - "dynamodb:GetRecords", - "dynamodb:GetShardIterator", - "dynamodb:Query", - "dynamodb:GetItem", - "dynamodb:Scan", - "dynamodb:ConditionCheckItem", - "dynamodb:BatchWriteItem", - "dynamodb:PutItem", - "dynamodb:UpdateItem", - "dynamodb:DeleteItem" - ], - "Effect": "Allow", - "Resource": [ - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":dynamodb:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":table/PaymentTable" - ] - ] - }, - { - "Ref": "AWS::NoValue" - } - ] - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "ApipaymentDsServiceRoleDefaultPolicy528E42B0", - "Roles": [ - { - "Ref": "ApipaymentDsServiceRole0DAC58D6" - } - ] - } - }, - "ApipaymentDs95C7AC36": { - "Type": "AWS::AppSync::DataSource", - "Properties": { - "ApiId": { - "Fn::GetAtt": [ - "ApiF70053CD", - "ApiId" - ] - }, - "Name": "Payment", - "Type": "AMAZON_DYNAMODB", - "DynamoDBConfig": { - "AwsRegion": { - "Ref": "AWS::Region" - }, - "TableName": "PaymentTable" - }, - "ServiceRoleArn": { - "Fn::GetAtt": [ - "ApipaymentDsServiceRole0DAC58D6", - "Arn" - ] - } - } - }, - "ApiQuerygetCustomersResolver522EE433": { + "ApicustomerDsQuerygetCustomersResolverA74C8A2E": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -416,7 +221,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetCustomerResolver007520DC": { + "ApicustomerDsQuerygetCustomerResolver3649A130": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -437,7 +242,7 @@ "ApiSchema510EECD7" ] }, - "ApiMutationaddCustomerResolver53321A05": { + "ApicustomerDsMutationaddCustomerResolver4DE5B517": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -458,7 +263,7 @@ "ApiSchema510EECD7" ] }, - "ApiMutationsaveCustomerResolver85516C23": { + "ApicustomerDsMutationsaveCustomerResolver241DD231": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -479,7 +284,7 @@ "ApiSchema510EECD7" ] }, - "ApiMutationsaveCustomerWithFirstOrderResolver66DBDFD0": { + "ApicustomerDsMutationsaveCustomerWithFirstOrderResolver7DE2CBC8": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -500,7 +305,7 @@ "ApiSchema510EECD7" ] }, - "ApiMutationremoveCustomerResolver8435F803": { + "ApicustomerDsMutationremoveCustomerResolverAD3AE7F5": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -521,7 +326,105 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetCustomerOrdersEqResolver6DA88A11": { + "ApiorderDsServiceRoleCC2040C0": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "appsync.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "ApiorderDsServiceRoleDefaultPolicy3315FCF4": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "dynamodb:BatchGetItem", + "dynamodb:GetRecords", + "dynamodb:GetShardIterator", + "dynamodb:Query", + "dynamodb:GetItem", + "dynamodb:Scan", + "dynamodb:ConditionCheckItem", + "dynamodb:BatchWriteItem", + "dynamodb:PutItem", + "dynamodb:UpdateItem", + "dynamodb:DeleteItem" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "OrderTable416EB896", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "OrderTable416EB896", + "Arn" + ] + }, + "/index/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "ApiorderDsServiceRoleDefaultPolicy3315FCF4", + "Roles": [ + { + "Ref": "ApiorderDsServiceRoleCC2040C0" + } + ] + } + }, + "ApiorderDsB50C8AAD": { + "Type": "AWS::AppSync::DataSource", + "Properties": { + "ApiId": { + "Fn::GetAtt": [ + "ApiF70053CD", + "ApiId" + ] + }, + "Name": "Order", + "Type": "AMAZON_DYNAMODB", + "DynamoDBConfig": { + "AwsRegion": { + "Ref": "AWS::Region" + }, + "TableName": { + "Ref": "OrderTable416EB896" + } + }, + "ServiceRoleArn": { + "Fn::GetAtt": [ + "ApiorderDsServiceRoleCC2040C0", + "Arn" + ] + } + } + }, + "ApiorderDsQuerygetCustomerOrdersEqResolverEF9D5350": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -542,7 +445,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetOrderCustomersEqResolverA8612570": { + "ApiorderDsQuerygetOrderCustomersEqResolverE58570FF": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -563,7 +466,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetCustomerOrdersLtResolver284B37E8": { + "ApiorderDsQuerygetCustomerOrdersLtResolver909F3D8F": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -584,7 +487,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetOrderCustomersLtResolver618A88A9": { + "ApiorderDsQuerygetOrderCustomersLtResolver77468800": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -605,7 +508,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetCustomerOrdersLeResolverFB2A506A": { + "ApiorderDsQuerygetCustomerOrdersLeResolverF230A8BE": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -626,7 +529,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetOrderCustomersLeResolverFAA205B9": { + "ApiorderDsQuerygetOrderCustomersLeResolver836A0389": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -647,7 +550,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetCustomerOrdersGtResolver13F90EA5": { + "ApiorderDsQuerygetCustomerOrdersGtResolverF01F806B": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -668,7 +571,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetOrderCustomersGtResolver9487ECD9": { + "ApiorderDsQuerygetOrderCustomersGtResolver3197CCFE": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -689,7 +592,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetCustomerOrdersGeResolver2A181899": { + "ApiorderDsQuerygetCustomerOrdersGeResolver63CAD303": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -710,7 +613,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetOrderCustomersGeResolver8441E608": { + "ApiorderDsQuerygetOrderCustomersGeResolver0B78B0B4": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -731,7 +634,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetCustomerOrdersFilterResolver96245084": { + "ApiorderDsQuerygetCustomerOrdersFilterResolverCD2B8747": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -752,7 +655,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetCustomerOrdersBetweenResolver97B6D708": { + "ApiorderDsQuerygetCustomerOrdersBetweenResolver7DEE368E": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -773,7 +676,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetOrderCustomersFilterResolverF1015ABD": { + "ApiorderDsQuerygetOrderCustomersFilterResolver628CC68D": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -794,7 +697,7 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetOrderCustomersBetweenResolver92680CEC": { + "ApiorderDsQuerygetOrderCustomersBetweenResolver2048F3CB": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -815,7 +718,106 @@ "ApiSchema510EECD7" ] }, - "ApiQuerygetPaymentResolver29598AC3": { + "ApipaymentDsServiceRole0DAC58D6": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "appsync.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "ApipaymentDsServiceRoleDefaultPolicy528E42B0": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "dynamodb:BatchGetItem", + "dynamodb:GetRecords", + "dynamodb:GetShardIterator", + "dynamodb:Query", + "dynamodb:GetItem", + "dynamodb:Scan", + "dynamodb:ConditionCheckItem", + "dynamodb:BatchWriteItem", + "dynamodb:PutItem", + "dynamodb:UpdateItem", + "dynamodb:DeleteItem" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":dynamodb:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":table/PaymentTable" + ] + ] + }, + { + "Ref": "AWS::NoValue" + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "ApipaymentDsServiceRoleDefaultPolicy528E42B0", + "Roles": [ + { + "Ref": "ApipaymentDsServiceRole0DAC58D6" + } + ] + } + }, + "ApipaymentDs95C7AC36": { + "Type": "AWS::AppSync::DataSource", + "Properties": { + "ApiId": { + "Fn::GetAtt": [ + "ApiF70053CD", + "ApiId" + ] + }, + "Name": "Payment", + "Type": "AMAZON_DYNAMODB", + "DynamoDBConfig": { + "AwsRegion": { + "Ref": "AWS::Region" + }, + "TableName": "PaymentTable" + }, + "ServiceRoleArn": { + "Fn::GetAtt": [ + "ApipaymentDsServiceRole0DAC58D6", + "Arn" + ] + } + } + }, + "ApipaymentDsQuerygetPaymentResolverD172BFC9": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -836,7 +838,7 @@ "ApiSchema510EECD7" ] }, - "ApiMutationsavePaymentResolver03088E76": { + "ApipaymentDsMutationsavePaymentResolverE09FE5BB": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { @@ -896,7 +898,7 @@ } } }, - "ApiMutationdoPostOnAwsResolverEDACEA42": { + "ApidsMutationdoPostOnAwsResolver9583D8A3": { "Type": "AWS::AppSync::Resolver", "Properties": { "ApiId": { diff --git a/packages/@aws-cdk/aws-athena/package.json b/packages/@aws-cdk/aws-athena/package.json index 28960103e97cc..2a3cd7207b97f 100644 --- a/packages/@aws-cdk/aws-athena/package.json +++ b/packages/@aws-cdk/aws-athena/package.json @@ -94,5 +94,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-auditmanager/package.json b/packages/@aws-cdk/aws-auditmanager/package.json index b9446f72238c8..b263be5fd8c92 100644 --- a/packages/@aws-cdk/aws-auditmanager/package.json +++ b/packages/@aws-cdk/aws-auditmanager/package.json @@ -91,5 +91,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-autoscaling-common/package.json b/packages/@aws-cdk/aws-autoscaling-common/package.json index 2df11c25f3c32..644801e0dbc71 100644 --- a/packages/@aws-cdk/aws-autoscaling-common/package.json +++ b/packages/@aws-cdk/aws-autoscaling-common/package.json @@ -66,7 +66,7 @@ "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", - "fast-check": "^2.12.1", + "fast-check": "^2.13.0", "nodeunit": "^0.11.3", "pkglint": "0.0.0" }, @@ -114,5 +114,8 @@ "env": { "AWSLINT_BASE_CONSTRUCT": true } + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json b/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json index 0b40faf0fabec..b15364996c1f3 100644 --- a/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json +++ b/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json @@ -106,5 +106,8 @@ "env": { "AWSLINT_BASE_CONSTRUCT": true } + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-autoscaling/package.json b/packages/@aws-cdk/aws-autoscaling/package.json index cbb4534533ade..79a8b3e02b967 100644 --- a/packages/@aws-cdk/aws-autoscaling/package.json +++ b/packages/@aws-cdk/aws-autoscaling/package.json @@ -152,5 +152,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-autoscalingplans/package.json b/packages/@aws-cdk/aws-autoscalingplans/package.json index 186564ad5e31c..5674f715e2b80 100644 --- a/packages/@aws-cdk/aws-autoscalingplans/package.json +++ b/packages/@aws-cdk/aws-autoscalingplans/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-backup/package.json b/packages/@aws-cdk/aws-backup/package.json index 8f70998f41a1d..841f29f929f36 100644 --- a/packages/@aws-cdk/aws-backup/package.json +++ b/packages/@aws-cdk/aws-backup/package.json @@ -110,5 +110,8 @@ "maturity": "experimental", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-backup/test/integ.backup.expected.json b/packages/@aws-cdk/aws-backup/test/integ.backup.expected.json index 2ba1356211377..1ad2aefc7c46e 100644 --- a/packages/@aws-cdk/aws-backup/test/integ.backup.expected.json +++ b/packages/@aws-cdk/aws-backup/test/integ.backup.expected.json @@ -24,7 +24,9 @@ "DeletionPolicy": "Delete" }, "FileSystem": { - "Type": "AWS::EFS::FileSystem" + "Type": "AWS::EFS::FileSystem", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "Vault23237E5B": { "Type": "AWS::Backup::BackupVault", diff --git a/packages/@aws-cdk/aws-backup/test/integ.backup.ts b/packages/@aws-cdk/aws-backup/test/integ.backup.ts index bf71de03a1cb8..e04d3ba68671a 100644 --- a/packages/@aws-cdk/aws-backup/test/integ.backup.ts +++ b/packages/@aws-cdk/aws-backup/test/integ.backup.ts @@ -16,7 +16,8 @@ class TestStack extends Stack { removalPolicy: RemovalPolicy.DESTROY, }); - new efs.CfnFileSystem(this, 'FileSystem'); + const fs = new efs.CfnFileSystem(this, 'FileSystem'); + fs.applyRemovalPolicy(RemovalPolicy.DESTROY); const vault = new backup.BackupVault(this, 'Vault', { removalPolicy: RemovalPolicy.DESTROY, diff --git a/packages/@aws-cdk/aws-backup/test/selection.test.ts b/packages/@aws-cdk/aws-backup/test/selection.test.ts index b5523b963c20e..d801efb34894c 100644 --- a/packages/@aws-cdk/aws-backup/test/selection.test.ts +++ b/packages/@aws-cdk/aws-backup/test/selection.test.ts @@ -2,7 +2,7 @@ import '@aws-cdk/assert/jest'; import * as dynamodb from '@aws-cdk/aws-dynamodb'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as efs from '@aws-cdk/aws-efs'; -import { Stack } from '@aws-cdk/core'; +import { RemovalPolicy, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { BackupPlan, BackupResource, BackupSelection } from '../lib'; @@ -128,7 +128,8 @@ test('fromConstruct', () => { class EfsConstruct extends CoreConstruct { constructor(scope: Construct, id: string) { super(scope, id); - new efs.CfnFileSystem(this, 'FileSystem'); + const fs = new efs.CfnFileSystem(this, 'FileSystem'); + fs.applyRemovalPolicy(RemovalPolicy.DESTROY); } } class MyConstruct extends CoreConstruct { diff --git a/packages/@aws-cdk/aws-batch/package.json b/packages/@aws-cdk/aws-batch/package.json index f20ee3b682f21..0b8f4666ab077 100644 --- a/packages/@aws-cdk/aws-batch/package.json +++ b/packages/@aws-cdk/aws-batch/package.json @@ -106,5 +106,8 @@ "maturity": "experimental", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-budgets/package.json b/packages/@aws-cdk/aws-budgets/package.json index 924d2ec1ab5b8..3d8297269395f 100644 --- a/packages/@aws-cdk/aws-budgets/package.json +++ b/packages/@aws-cdk/aws-budgets/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-cassandra/package.json b/packages/@aws-cdk/aws-cassandra/package.json index 67abfdf545526..5b0a317a627d8 100644 --- a/packages/@aws-cdk/aws-cassandra/package.json +++ b/packages/@aws-cdk/aws-cassandra/package.json @@ -91,5 +91,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-ce/package.json b/packages/@aws-cdk/aws-ce/package.json index cb5b60b4242a7..07c5e186da907 100644 --- a/packages/@aws-cdk/aws-ce/package.json +++ b/packages/@aws-cdk/aws-ce/package.json @@ -91,5 +91,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package.json b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package.json index 53c05a822acd1..1e220d75e96a9 100644 --- a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package.json +++ b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package.json @@ -29,15 +29,15 @@ "devDependencies": { "aws-sdk": "^2.596.0", "aws-sdk-mock": "^5.1.0", - "eslint": "^7.19.0", + "eslint": "^7.20.0", "eslint-config-standard": "^14.1.1", "eslint-plugin-import": "^2.22.1", "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^4.2.1", + "eslint-plugin-promise": "^4.3.1", "eslint-plugin-standard": "^4.1.0", "jest": "^26.6.3", "lambda-tester": "^3.6.0", "nock": "^13.0.7", - "ts-jest": "^26.5.0" + "ts-jest": "^26.5.1" } } diff --git a/packages/@aws-cdk/aws-certificatemanager/package.json b/packages/@aws-cdk/aws-certificatemanager/package.json index 52afcdf0d0e83..96e0787fb06ec 100644 --- a/packages/@aws-cdk/aws-certificatemanager/package.json +++ b/packages/@aws-cdk/aws-certificatemanager/package.json @@ -104,5 +104,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-chatbot/package.json b/packages/@aws-cdk/aws-chatbot/package.json index 8368c18a90199..ab267bf8f1c0c 100644 --- a/packages/@aws-cdk/aws-chatbot/package.json +++ b/packages/@aws-cdk/aws-chatbot/package.json @@ -102,5 +102,8 @@ "maturity": "experimental", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-cloud9/package.json b/packages/@aws-cdk/aws-cloud9/package.json index 9a126f4afc5f6..e71b8c60f3bc0 100644 --- a/packages/@aws-cdk/aws-cloud9/package.json +++ b/packages/@aws-cdk/aws-cloud9/package.json @@ -107,5 +107,8 @@ "maturity": "experimental", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-cloudformation/package.json b/packages/@aws-cdk/aws-cloudformation/package.json index a3acf41a02170..550bc780b750d 100644 --- a/packages/@aws-cdk/aws-cloudformation/package.json +++ b/packages/@aws-cdk/aws-cloudformation/package.json @@ -73,7 +73,7 @@ "@aws-cdk/aws-sns-subscriptions": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", - "@types/aws-lambda": "^8.10.71", + "@types/aws-lambda": "^8.10.72", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", @@ -115,5 +115,8 @@ "awscdkio": { "announce": false }, - "maturity": "deprecated" + "maturity": "deprecated", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stack.expected.json b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stack.expected.json index 8626fa9281ca5..d290134fa1cb6 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stack.expected.json +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stack.expected.json @@ -1,7 +1,9 @@ { "Resources": { "SubscriberQueueC193DC66": { - "Type": "AWS::SQS::Queue" + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "SubscriberQueuePolicy25A0799E": { "Type": "AWS::SQS::QueuePolicy", @@ -196,7 +198,9 @@ "Ref": "SubscriberQueueC193DC66" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "NestedStack2NestedStackNestedStack2NestedStackResourceFDF82E43": { "Type": "AWS::CloudFormation::Stack", @@ -250,7 +254,9 @@ "Parameters": { "TopicNamePrefix": "Prefix2" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Parameters": { diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-assets.expected.json b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-assets.expected.json index d18d72744be00..45b52a4c8016d 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-assets.expected.json +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-assets.expected.json @@ -17,7 +17,7 @@ }, "/", { - "Ref": "AssetParameters28e3582cfc7c551f42435f44110c499fb2c415fe0f02a02a77139cf43edd1145S3BucketFDBB032A" + "Ref": "AssetParameters7bd7ccfde94a4ad94f13971f10733ee01020eb6d7538b7a5c2b05966db2c0aabS3Bucket2E4E0318" }, "/", { @@ -27,7 +27,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters28e3582cfc7c551f42435f44110c499fb2c415fe0f02a02a77139cf43edd1145S3VersionKey58263016" + "Ref": "AssetParameters7bd7ccfde94a4ad94f13971f10733ee01020eb6d7538b7a5c2b05966db2c0aabS3VersionKeyF6AB1DF2" } ] } @@ -40,7 +40,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters28e3582cfc7c551f42435f44110c499fb2c415fe0f02a02a77139cf43edd1145S3VersionKey58263016" + "Ref": "AssetParameters7bd7ccfde94a4ad94f13971f10733ee01020eb6d7538b7a5c2b05966db2c0aabS3VersionKeyF6AB1DF2" } ] } @@ -50,40 +50,42 @@ ] }, "Parameters": { - "referencetonestedstacksassetsAssetParametersb13aad60258df1fbe5fb1312a7b2f8f25c03b3e07113782f7c12f00e023e148aS3BucketE2268D38Ref": { - "Ref": "AssetParametersb13aad60258df1fbe5fb1312a7b2f8f25c03b3e07113782f7c12f00e023e148aS3BucketC5E2D427" + "referencetonestedstacksassetsAssetParametersbbe209afddb09a12327bab7a105e085758a29b769b5b4bf5b6320ac41b05fc51S3BucketFE27EEBCRef": { + "Ref": "AssetParametersbbe209afddb09a12327bab7a105e085758a29b769b5b4bf5b6320ac41b05fc51S3Bucket8C5997AB" }, - "referencetonestedstacksassetsAssetParametersb13aad60258df1fbe5fb1312a7b2f8f25c03b3e07113782f7c12f00e023e148aS3VersionKeyD31C6796Ref": { - "Ref": "AssetParametersb13aad60258df1fbe5fb1312a7b2f8f25c03b3e07113782f7c12f00e023e148aS3VersionKey31422F11" + "referencetonestedstacksassetsAssetParametersbbe209afddb09a12327bab7a105e085758a29b769b5b4bf5b6320ac41b05fc51S3VersionKey24D35F02Ref": { + "Ref": "AssetParametersbbe209afddb09a12327bab7a105e085758a29b769b5b4bf5b6320ac41b05fc51S3VersionKey81BEC7FB" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Parameters": { - "AssetParametersb13aad60258df1fbe5fb1312a7b2f8f25c03b3e07113782f7c12f00e023e148aS3BucketC5E2D427": { + "AssetParametersbbe209afddb09a12327bab7a105e085758a29b769b5b4bf5b6320ac41b05fc51S3Bucket8C5997AB": { "Type": "String", - "Description": "S3 bucket for asset \"b13aad60258df1fbe5fb1312a7b2f8f25c03b3e07113782f7c12f00e023e148a\"" + "Description": "S3 bucket for asset \"bbe209afddb09a12327bab7a105e085758a29b769b5b4bf5b6320ac41b05fc51\"" }, - "AssetParametersb13aad60258df1fbe5fb1312a7b2f8f25c03b3e07113782f7c12f00e023e148aS3VersionKey31422F11": { + "AssetParametersbbe209afddb09a12327bab7a105e085758a29b769b5b4bf5b6320ac41b05fc51S3VersionKey81BEC7FB": { "Type": "String", - "Description": "S3 key for asset version \"b13aad60258df1fbe5fb1312a7b2f8f25c03b3e07113782f7c12f00e023e148a\"" + "Description": "S3 key for asset version \"bbe209afddb09a12327bab7a105e085758a29b769b5b4bf5b6320ac41b05fc51\"" }, - "AssetParametersb13aad60258df1fbe5fb1312a7b2f8f25c03b3e07113782f7c12f00e023e148aArtifactHash2897446E": { + "AssetParametersbbe209afddb09a12327bab7a105e085758a29b769b5b4bf5b6320ac41b05fc51ArtifactHashB77349F4": { "Type": "String", - "Description": "Artifact hash for asset \"b13aad60258df1fbe5fb1312a7b2f8f25c03b3e07113782f7c12f00e023e148a\"" + "Description": "Artifact hash for asset \"bbe209afddb09a12327bab7a105e085758a29b769b5b4bf5b6320ac41b05fc51\"" }, - "AssetParameters28e3582cfc7c551f42435f44110c499fb2c415fe0f02a02a77139cf43edd1145S3BucketFDBB032A": { + "AssetParameters7bd7ccfde94a4ad94f13971f10733ee01020eb6d7538b7a5c2b05966db2c0aabS3Bucket2E4E0318": { "Type": "String", - "Description": "S3 bucket for asset \"28e3582cfc7c551f42435f44110c499fb2c415fe0f02a02a77139cf43edd1145\"" + "Description": "S3 bucket for asset \"7bd7ccfde94a4ad94f13971f10733ee01020eb6d7538b7a5c2b05966db2c0aab\"" }, - "AssetParameters28e3582cfc7c551f42435f44110c499fb2c415fe0f02a02a77139cf43edd1145S3VersionKey58263016": { + "AssetParameters7bd7ccfde94a4ad94f13971f10733ee01020eb6d7538b7a5c2b05966db2c0aabS3VersionKeyF6AB1DF2": { "Type": "String", - "Description": "S3 key for asset version \"28e3582cfc7c551f42435f44110c499fb2c415fe0f02a02a77139cf43edd1145\"" + "Description": "S3 key for asset version \"7bd7ccfde94a4ad94f13971f10733ee01020eb6d7538b7a5c2b05966db2c0aab\"" }, - "AssetParameters28e3582cfc7c551f42435f44110c499fb2c415fe0f02a02a77139cf43edd1145ArtifactHash592B4471": { + "AssetParameters7bd7ccfde94a4ad94f13971f10733ee01020eb6d7538b7a5c2b05966db2c0aabArtifactHash63670210": { "Type": "String", - "Description": "Artifact hash for asset \"28e3582cfc7c551f42435f44110c499fb2c415fe0f02a02a77139cf43edd1145\"" + "Description": "Artifact hash for asset \"7bd7ccfde94a4ad94f13971f10733ee01020eb6d7538b7a5c2b05966db2c0aab\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-multi-refs.expected.json b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-multi-refs.expected.json index bc546994b8e41..8e1abf0743734 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-multi-refs.expected.json +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-multi-refs.expected.json @@ -20,7 +20,7 @@ }, "/", { - "Ref": "AssetParametersad23da1cfc8b3fd7916c6ffc7debacadf084765e62fab8acf0b8b0a9b0289f95S3BucketDB605F9E" + "Ref": "AssetParameters2fa66e9dea71b1e05ebeed281df124cbaca34247ae93c767a533b6346cc17703S3BucketD17502DC" }, "/", { @@ -30,7 +30,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersad23da1cfc8b3fd7916c6ffc7debacadf084765e62fab8acf0b8b0a9b0289f95S3VersionKey26685906" + "Ref": "AssetParameters2fa66e9dea71b1e05ebeed281df124cbaca34247ae93c767a533b6346cc17703S3VersionKeyA042251F" } ] } @@ -43,7 +43,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersad23da1cfc8b3fd7916c6ffc7debacadf084765e62fab8acf0b8b0a9b0289f95S3VersionKey26685906" + "Ref": "AssetParameters2fa66e9dea71b1e05ebeed281df124cbaca34247ae93c767a533b6346cc17703S3VersionKeyA042251F" } ] } @@ -65,14 +65,16 @@ "referencetonestedstacksmultirefsAssetParameters495a6bc36c13a0adeb3778c921d18ac4a8205f5471108fcc199a291d14855c3aS3VersionKey5F9CF809Ref": { "Ref": "AssetParameters495a6bc36c13a0adeb3778c921d18ac4a8205f5471108fcc199a291d14855c3aS3VersionKey2CCE0573" }, - "referencetonestedstacksmultirefsAssetParameterscc623add53df153cf6a7df1cea4dc90740d7be087472579110754a633ec90847S3Bucket8F1E17B9Ref": { - "Ref": "AssetParameterscc623add53df153cf6a7df1cea4dc90740d7be087472579110754a633ec90847S3Bucket9A14AA6D" + "referencetonestedstacksmultirefsAssetParametersc2fbfb6df004b51bb870bd1f5cabda73830a59765a6c766aca0e906ec1e22441S3Bucket119ED767Ref": { + "Ref": "AssetParametersc2fbfb6df004b51bb870bd1f5cabda73830a59765a6c766aca0e906ec1e22441S3BucketAF9A3A0F" }, - "referencetonestedstacksmultirefsAssetParameterscc623add53df153cf6a7df1cea4dc90740d7be087472579110754a633ec90847S3VersionKey9EEEF950Ref": { - "Ref": "AssetParameterscc623add53df153cf6a7df1cea4dc90740d7be087472579110754a633ec90847S3VersionKeyF124C0D9" + "referencetonestedstacksmultirefsAssetParametersc2fbfb6df004b51bb870bd1f5cabda73830a59765a6c766aca0e906ec1e22441S3VersionKeyDCF85FE2Ref": { + "Ref": "AssetParametersc2fbfb6df004b51bb870bd1f5cabda73830a59765a6c766aca0e906ec1e22441S3VersionKey2F85340C" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Parameters": { @@ -88,29 +90,29 @@ "Type": "String", "Description": "Artifact hash for asset \"495a6bc36c13a0adeb3778c921d18ac4a8205f5471108fcc199a291d14855c3a\"" }, - "AssetParameterscc623add53df153cf6a7df1cea4dc90740d7be087472579110754a633ec90847S3Bucket9A14AA6D": { + "AssetParametersc2fbfb6df004b51bb870bd1f5cabda73830a59765a6c766aca0e906ec1e22441S3BucketAF9A3A0F": { "Type": "String", - "Description": "S3 bucket for asset \"cc623add53df153cf6a7df1cea4dc90740d7be087472579110754a633ec90847\"" + "Description": "S3 bucket for asset \"c2fbfb6df004b51bb870bd1f5cabda73830a59765a6c766aca0e906ec1e22441\"" }, - "AssetParameterscc623add53df153cf6a7df1cea4dc90740d7be087472579110754a633ec90847S3VersionKeyF124C0D9": { + "AssetParametersc2fbfb6df004b51bb870bd1f5cabda73830a59765a6c766aca0e906ec1e22441S3VersionKey2F85340C": { "Type": "String", - "Description": "S3 key for asset version \"cc623add53df153cf6a7df1cea4dc90740d7be087472579110754a633ec90847\"" + "Description": "S3 key for asset version \"c2fbfb6df004b51bb870bd1f5cabda73830a59765a6c766aca0e906ec1e22441\"" }, - "AssetParameterscc623add53df153cf6a7df1cea4dc90740d7be087472579110754a633ec90847ArtifactHashAF64C405": { + "AssetParametersc2fbfb6df004b51bb870bd1f5cabda73830a59765a6c766aca0e906ec1e22441ArtifactHash5D93ED07": { "Type": "String", - "Description": "Artifact hash for asset \"cc623add53df153cf6a7df1cea4dc90740d7be087472579110754a633ec90847\"" + "Description": "Artifact hash for asset \"c2fbfb6df004b51bb870bd1f5cabda73830a59765a6c766aca0e906ec1e22441\"" }, - "AssetParametersad23da1cfc8b3fd7916c6ffc7debacadf084765e62fab8acf0b8b0a9b0289f95S3BucketDB605F9E": { + "AssetParameters2fa66e9dea71b1e05ebeed281df124cbaca34247ae93c767a533b6346cc17703S3BucketD17502DC": { "Type": "String", - "Description": "S3 bucket for asset \"ad23da1cfc8b3fd7916c6ffc7debacadf084765e62fab8acf0b8b0a9b0289f95\"" + "Description": "S3 bucket for asset \"2fa66e9dea71b1e05ebeed281df124cbaca34247ae93c767a533b6346cc17703\"" }, - "AssetParametersad23da1cfc8b3fd7916c6ffc7debacadf084765e62fab8acf0b8b0a9b0289f95S3VersionKey26685906": { + "AssetParameters2fa66e9dea71b1e05ebeed281df124cbaca34247ae93c767a533b6346cc17703S3VersionKeyA042251F": { "Type": "String", - "Description": "S3 key for asset version \"ad23da1cfc8b3fd7916c6ffc7debacadf084765e62fab8acf0b8b0a9b0289f95\"" + "Description": "S3 key for asset version \"2fa66e9dea71b1e05ebeed281df124cbaca34247ae93c767a533b6346cc17703\"" }, - "AssetParametersad23da1cfc8b3fd7916c6ffc7debacadf084765e62fab8acf0b8b0a9b0289f95ArtifactHashAF8D54FC": { + "AssetParameters2fa66e9dea71b1e05ebeed281df124cbaca34247ae93c767a533b6346cc17703ArtifactHash8853E261": { "Type": "String", - "Description": "Artifact hash for asset \"ad23da1cfc8b3fd7916c6ffc7debacadf084765e62fab8acf0b8b0a9b0289f95\"" + "Description": "Artifact hash for asset \"2fa66e9dea71b1e05ebeed281df124cbaca34247ae93c767a533b6346cc17703\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-multi.expected.json b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-multi.expected.json index 6a10c9252c79a..0145629ff176e 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-multi.expected.json +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-multi.expected.json @@ -17,7 +17,7 @@ }, "/", { - "Ref": "AssetParametersf94d2259295147a175eeb7f8b31856e4beb5d4d4654f0bf956ee51d5e2ee5d8eS3Bucket0211CC54" + "Ref": "AssetParameters686794a6d724e01e517bba15106edebf9db8d4bb309f0c60d5ff55a11db4a856S3BucketDF3BC15F" }, "/", { @@ -27,7 +27,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersf94d2259295147a175eeb7f8b31856e4beb5d4d4654f0bf956ee51d5e2ee5d8eS3VersionKey5D85E7DD" + "Ref": "AssetParameters686794a6d724e01e517bba15106edebf9db8d4bb309f0c60d5ff55a11db4a856S3VersionKey1BCA0E57" } ] } @@ -40,7 +40,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersf94d2259295147a175eeb7f8b31856e4beb5d4d4654f0bf956ee51d5e2ee5d8eS3VersionKey5D85E7DD" + "Ref": "AssetParameters686794a6d724e01e517bba15106edebf9db8d4bb309f0c60d5ff55a11db4a856S3VersionKey1BCA0E57" } ] } @@ -57,7 +57,9 @@ "Ref": "AssetParameterse3410ccec04414535f1c8035ce0ea42f59eedf66d0e6d0eec8bc435c4a4e809dS3VersionKey8C8E79CA" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Parameters": { @@ -73,17 +75,17 @@ "Type": "String", "Description": "Artifact hash for asset \"e3410ccec04414535f1c8035ce0ea42f59eedf66d0e6d0eec8bc435c4a4e809d\"" }, - "AssetParametersf94d2259295147a175eeb7f8b31856e4beb5d4d4654f0bf956ee51d5e2ee5d8eS3Bucket0211CC54": { + "AssetParameters686794a6d724e01e517bba15106edebf9db8d4bb309f0c60d5ff55a11db4a856S3BucketDF3BC15F": { "Type": "String", - "Description": "S3 bucket for asset \"f94d2259295147a175eeb7f8b31856e4beb5d4d4654f0bf956ee51d5e2ee5d8e\"" + "Description": "S3 bucket for asset \"686794a6d724e01e517bba15106edebf9db8d4bb309f0c60d5ff55a11db4a856\"" }, - "AssetParametersf94d2259295147a175eeb7f8b31856e4beb5d4d4654f0bf956ee51d5e2ee5d8eS3VersionKey5D85E7DD": { + "AssetParameters686794a6d724e01e517bba15106edebf9db8d4bb309f0c60d5ff55a11db4a856S3VersionKey1BCA0E57": { "Type": "String", - "Description": "S3 key for asset version \"f94d2259295147a175eeb7f8b31856e4beb5d4d4654f0bf956ee51d5e2ee5d8e\"" + "Description": "S3 key for asset version \"686794a6d724e01e517bba15106edebf9db8d4bb309f0c60d5ff55a11db4a856\"" }, - "AssetParametersf94d2259295147a175eeb7f8b31856e4beb5d4d4654f0bf956ee51d5e2ee5d8eArtifactHashD0519824": { + "AssetParameters686794a6d724e01e517bba15106edebf9db8d4bb309f0c60d5ff55a11db4a856ArtifactHash9043932C": { "Type": "String", - "Description": "Artifact hash for asset \"f94d2259295147a175eeb7f8b31856e4beb5d4d4654f0bf956ee51d5e2ee5d8e\"" + "Description": "Artifact hash for asset \"686794a6d724e01e517bba15106edebf9db8d4bb309f0c60d5ff55a11db4a856\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-nested-export-to-sibling.expected.json b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-nested-export-to-sibling.expected.json index 3cac1b07eb420..115a1f9130ae3 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-nested-export-to-sibling.expected.json +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-nested-export-to-sibling.expected.json @@ -50,7 +50,9 @@ ] ] } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs1.expected.json b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs1.expected.json index cf2e508a0f8eb..299d5005eff0f 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs1.expected.json +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs1.expected.json @@ -70,7 +70,9 @@ ] ] } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Parameters": { diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs2.expected.json b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs2.expected.json index ee7be9113bdcb..c6e818da02313 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs2.expected.json +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs2.expected.json @@ -50,7 +50,9 @@ ] ] } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs3.expected.json b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs3.expected.json index 80a2f7712026c..2ef738be2c023 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs3.expected.json +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs3.expected.json @@ -49,7 +49,9 @@ ] ] } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "Nested2NestedStackNested2NestedStackResource877A1112": { "Type": "AWS::CloudFormation::Stack", @@ -108,7 +110,9 @@ ] } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Parameters": { diff --git a/packages/@aws-cdk/aws-cloudformation/test/test.nested-stack.ts b/packages/@aws-cdk/aws-cloudformation/test/test.nested-stack.ts index 64656faf0fca3..2149c48be5fd3 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/test.nested-stack.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/test.nested-stack.ts @@ -130,6 +130,8 @@ export = { Resources: { nestedstackNestedStacknestedstackNestedStackResource71CDD241: { Type: 'AWS::CloudFormation::Stack', + DeletionPolicy: 'Delete', + UpdateReplacePolicy: 'Delete', Properties: { TemplateURL: { 'Fn::Join': [ @@ -718,7 +720,10 @@ export = { }, }); - const middleStackHash = 'b2670b4c0c3fdf1d8fd9b9272bb8bf8173d18c0f67a888ba165cc569a248a84f'; + const middleStackHash = '7c426f7299a739900279ac1ece040397c1913cdf786f5228677b289f4d5e4c48'; + const bucketSuffix = 'C706B101'; + const versionSuffix = '4B193AA5'; + const hashSuffix = 'E28F0693'; // nested1 wires the nested2 template through parameters, so we expect those expect(nested1).to(haveResource('Resource::1')); @@ -735,9 +740,9 @@ export = { AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3BucketDE3B88D6: { Type: 'String', Description: 'S3 bucket for asset "8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235c"' }, AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3VersionKey3A62EFEA: { Type: 'String', Description: 'S3 key for asset version "8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235c"' }, AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cArtifactHash7DC546E0: { Type: 'String', Description: 'Artifact hash for asset "8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235c"' }, - [`AssetParameters${middleStackHash}S3Bucket3DB431CB`]: { Type: 'String', Description: `S3 bucket for asset "${middleStackHash}"` }, - [`AssetParameters${middleStackHash}S3VersionKeyBFFDABE9`]: { Type: 'String', Description: `S3 key for asset version "${middleStackHash}"` }, - [`AssetParameters${middleStackHash}ArtifactHash8EA52875`]: { Type: 'String', Description: `Artifact hash for asset "${middleStackHash}"` }, + [`AssetParameters${middleStackHash}S3Bucket${bucketSuffix}`]: { Type: 'String', Description: `S3 bucket for asset "${middleStackHash}"` }, + [`AssetParameters${middleStackHash}S3VersionKey${versionSuffix}`]: { Type: 'String', Description: `S3 key for asset version "${middleStackHash}"` }, + [`AssetParameters${middleStackHash}ArtifactHash${hashSuffix}`]: { Type: 'String', Description: `Artifact hash for asset "${middleStackHash}"` }, }); // proxy asset params to nested stack diff --git a/packages/@aws-cdk/aws-cloudfront-origins/lib/s3-origin.ts b/packages/@aws-cdk/aws-cloudfront-origins/lib/s3-origin.ts index 518e3e728ec1a..a0ac4037d9741 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/lib/s3-origin.ts +++ b/packages/@aws-cdk/aws-cloudfront-origins/lib/s3-origin.ts @@ -1,4 +1,5 @@ import * as cloudfront from '@aws-cdk/aws-cloudfront'; +import * as iam from '@aws-cdk/aws-iam'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import { HttpOrigin } from './http-origin'; @@ -68,7 +69,7 @@ class S3BucketOrigin extends cloudfront.OriginBase { public bind(scope: Construct, options: cloudfront.OriginBindOptions): cloudfront.OriginBindConfig { if (!this.originAccessIdentity) { // Using a bucket from another stack creates a cyclic reference with - // the bucket taking a dependency on the generated S3CanonicalUserId when `grantRead` is called, + // the bucket taking a dependency on the generated S3CanonicalUserId for the grant principal, // and the distribution having a dependency on the bucket's domain name. // Fix this by parenting the OAI in the bucket's stack when cross-stack usage is detected. const bucketStack = cdk.Stack.of(this.bucket); @@ -79,7 +80,16 @@ class S3BucketOrigin extends cloudfront.OriginBase { this.originAccessIdentity = new cloudfront.OriginAccessIdentity(oaiScope, oaiId, { comment: `Identity for ${options.originId}`, }); - this.bucket.grantRead(this.originAccessIdentity); + + // Used rather than `grantRead` because `grantRead` will grant overly-permissive policies. + // Only GetObject is needed to retrieve objects for the distribution. + // This also excludes KMS permissions; currently, OAI only supports SSE-S3 for buckets. + // Source: https://aws.amazon.com/blogs/networking-and-content-delivery/serving-sse-kms-encrypted-content-from-s3-using-cloudfront/ + this.bucket.addToResourcePolicy(new iam.PolicyStatement({ + resources: [this.bucket.arnForObjects('*')], + actions: ['s3:GetObject'], + principals: [this.originAccessIdentity.grantPrincipal], + })); } return super.bind(scope, options); } diff --git a/packages/@aws-cdk/aws-cloudfront-origins/package.json b/packages/@aws-cdk/aws-cloudfront-origins/package.json index c6c5e867e0471..d90ce2d097315 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/package.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/package.json @@ -71,7 +71,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", - "aws-sdk": "^2.830.0", + "aws-sdk": "^2.848.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "pkglint": "0.0.0" @@ -79,6 +79,7 @@ "dependencies": { "@aws-cdk/aws-cloudfront": "0.0.0", "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.2.0" @@ -88,8 +89,9 @@ "@aws-cdk/core": "0.0.0", "constructs": "^3.2.0", "@aws-cdk/aws-cloudfront": "0.0.0", - "@aws-cdk/aws-s3": "0.0.0", - "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0" + "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-s3": "0.0.0" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" @@ -98,5 +100,8 @@ "maturity": "stable", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.origin-group.expected.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.origin-group.expected.json index 8e123f87338d4..ecd2096329404 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.origin-group.expected.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.origin-group.expected.json @@ -14,11 +14,7 @@ "PolicyDocument": { "Statement": [ { - "Action": [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*" - ], + "Action": "s3:GetObject", "Effect": "Allow", "Principal": { "CanonicalUser": { @@ -28,28 +24,20 @@ ] } }, - "Resource": [ - { - "Fn::GetAtt": [ - "Bucket83908E77", - "Arn" - ] - }, - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "Bucket83908E77", - "Arn" - ] - }, - "/*" - ] + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "/*" ] - } - ] + ] + } } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin.expected.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin.expected.json index 5eb310b5b92d7..25461aa9cf7de 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin.expected.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin.expected.json @@ -14,11 +14,7 @@ "PolicyDocument": { "Statement": [ { - "Action": [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*" - ], + "Action": "s3:GetObject", "Effect": "Allow", "Principal": { "CanonicalUser": { @@ -28,28 +24,20 @@ ] } }, - "Resource": [ - { - "Fn::GetAtt": [ - "Bucket83908E77", - "Arn" - ] - }, - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "Bucket83908E77", - "Arn" - ] - }, - "/*" - ] + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "/*" ] - } - ] + ] + } } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/s3-origin.test.ts b/packages/@aws-cdk/aws-cloudfront-origins/test/s3-origin.test.ts index 54f9861685945..a502dd5cf4f46 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/s3-origin.test.ts +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/s3-origin.test.ts @@ -87,9 +87,13 @@ describe('With bucket', () => { expect(stack).toHaveResourceLike('AWS::S3::BucketPolicy', { PolicyDocument: { Statement: [{ + Action: 's3:GetObject', Principal: { CanonicalUser: { 'Fn::GetAtt': ['DistOrigin1S3Origin87D64058', 'S3CanonicalUserId'] }, }, + Resource: { + 'Fn::Join': ['', [{ 'Fn::GetAtt': ['Bucket83908E77', 'Arn'] }, '/*']], + }, }], }, }); diff --git a/packages/@aws-cdk/aws-cloudfront/README.md b/packages/@aws-cdk/aws-cloudfront/README.md index 3a5834d98d51f..34b0922913c4c 100644 --- a/packages/@aws-cdk/aws-cloudfront/README.md +++ b/packages/@aws-cdk/aws-cloudfront/README.md @@ -401,10 +401,10 @@ new cloudfront.Distribution(this, 'myDist', { // You can optionally log to a specific bucket, configure whether cookies are logged, and give the log files a prefix. new cloudfront.Distribution(this, 'myDist', { defaultBehavior: { origin: new origins.HttpOrigin('www.example.com') }, - enableLogging: true, // Optional, this is implied if loggingBucket is specified - loggingBucket: new s3.Bucket(this, 'LoggingBucket'), - loggingFilePrefix: 'distribution-access-logs/', - loggingIncludesCookies: true, + enableLogging: true, // Optional, this is implied if logBucket is specified + logBucket: new s3.Bucket(this, 'LogBucket'), + logFilePrefix: 'distribution-access-logs/', + logIncludesCookies: true, }); ``` diff --git a/packages/@aws-cdk/aws-cloudfront/lib/experimental/edge-function.ts b/packages/@aws-cdk/aws-cloudfront/lib/experimental/edge-function.ts index f97b7e176d874..33b0e070d144e 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/experimental/edge-function.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/experimental/edge-function.ts @@ -218,7 +218,10 @@ export class EdgeFunction extends Resource implements lambda.IVersion { let edgeStack = stage.node.tryFindChild(edgeStackId) as Stack; if (!edgeStack) { edgeStack = new Stack(stage, edgeStackId, { - env: { region: EdgeFunction.EDGE_REGION }, + env: { + region: EdgeFunction.EDGE_REGION, + account: Stack.of(this).account, + }, }); } this.stack.addDependency(edgeStack); diff --git a/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts index f191813dada2b..a678c82ba6087 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts @@ -1027,9 +1027,15 @@ export class CloudFrontWebDistribution extends cdk.Resource implements IDistribu // first case for backwards compatibility if (originConfig.s3OriginSource.originAccessIdentity) { // grant CloudFront OriginAccessIdentity read access to S3 bucket - originConfig.s3OriginSource.s3BucketSource.grantRead( - originConfig.s3OriginSource.originAccessIdentity, - ); + // Used rather than `grantRead` because `grantRead` will grant overly-permissive policies. + // Only GetObject is needed to retrieve objects for the distribution. + // This also excludes KMS permissions; currently, OAI only supports SSE-S3 for buckets. + // Source: https://aws.amazon.com/blogs/networking-and-content-delivery/serving-sse-kms-encrypted-content-from-s3-using-cloudfront/ + originConfig.s3OriginSource.s3BucketSource.addToResourcePolicy(new iam.PolicyStatement({ + resources: [originConfig.s3OriginSource.s3BucketSource.arnForObjects('*')], + actions: ['s3:GetObject'], + principals: [originConfig.s3OriginSource.originAccessIdentity.grantPrincipal], + })); s3OriginConfig = { originAccessIdentity: `origin-access-identity/cloudfront/${originConfig.s3OriginSource.originAccessIdentity.originAccessIdentityName}`, diff --git a/packages/@aws-cdk/aws-cloudfront/package.json b/packages/@aws-cdk/aws-cloudfront/package.json index c781a065bbc0a..75b18c5b95444 100644 --- a/packages/@aws-cdk/aws-cloudfront/package.json +++ b/packages/@aws-cdk/aws-cloudfront/package.json @@ -72,7 +72,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "aws-sdk": "^2.830.0", + "aws-sdk": "^2.848.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -160,5 +160,8 @@ }, "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-cloudfront/test/experimental/edge-function.test.ts b/packages/@aws-cdk/aws-cloudfront/test/experimental/edge-function.test.ts index 4154f79cabff2..7a743056dfcb7 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/experimental/edge-function.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/experimental/edge-function.test.ts @@ -102,6 +102,25 @@ describe('stacks', () => { }); }); + test('us-east-1 stack inherits account of parent stack', () => { + new cloudfront.experimental.EdgeFunction(stack, 'MyFn', defaultEdgeFunctionProps()); + + const fnStack = getFnStack(); + + expect(fnStack.account).toEqual('111111111111'); + }); + + test('us-east-1 stack inherits account of parent stack, when parent stack account is undefined', () => { + stack = new cdk.Stack(app, 'StackWithDefaultAccount', { + env: { region: 'testregion' }, + }); + new cloudfront.experimental.EdgeFunction(stack, 'MyFn', defaultEdgeFunctionProps()); + + const fnStack = getFnStack(); + + expect(fnStack.account).toEqual(cdk.Aws.ACCOUNT_ID); + }); + test('creates minimal constructs if scope region is us-east-1', () => { app = new cdk.App(); stack = new cdk.Stack(app, 'Stack', { diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3.expected.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3.expected.json index 8f6357e72272e..72ed767994cc0 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3.expected.json +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3.expected.json @@ -14,11 +14,7 @@ "PolicyDocument": { "Statement": [ { - "Action": [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*" - ], + "Action": "s3:GetObject", "Effect": "Allow", "Principal": { "AWS": { @@ -37,28 +33,20 @@ ] } }, - "Resource": [ - { - "Fn::GetAtt": [ - "Bucket83908E77", - "Arn" + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "/*" ] - }, - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "Bucket83908E77", - "Arn" - ] - }, - "/*" - ] - ] - } - ] + ] + } } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts b/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts index 8eea2cad5bc92..d24c7aa1220dc 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts @@ -10,6 +10,7 @@ import { GeoRestriction, KeyGroup, LambdaEdgeEventType, + OriginAccessIdentity, PublicKey, SecurityPolicyProtocol, SSLMethod, @@ -197,6 +198,59 @@ nodeunitShim({ test.done(); }, + 'distribution with bucket and OAI'(test: Test) { + const stack = new cdk.Stack(); + const s3BucketSource = new s3.Bucket(stack, 'Bucket'); + const originAccessIdentity = new OriginAccessIdentity(stack, 'OAI'); + + new CloudFrontWebDistribution(stack, 'AnAmazingWebsiteProbably', { + originConfigs: [{ + s3OriginSource: { s3BucketSource, originAccessIdentity }, + behaviors: [{ isDefaultBehavior: true }], + }], + }); + + expect(stack).to(haveResourceLike('AWS::CloudFront::Distribution', { + DistributionConfig: { + Origins: [ + { + ConnectionAttempts: 3, + ConnectionTimeout: 10, + DomainName: { + 'Fn::GetAtt': [ + 'Bucket83908E77', + 'RegionalDomainName', + ], + }, + Id: 'origin1', + S3OriginConfig: { + OriginAccessIdentity: { + 'Fn::Join': ['', ['origin-access-identity/cloudfront/', { Ref: 'OAIE1EFC67F' }]], + }, + }, + }, + ], + }, + })); + + expect(stack).to(haveResourceLike('AWS::S3::BucketPolicy', { + PolicyDocument: { + Statement: [{ + Action: 's3:GetObject', + Principal: { + CanonicalUser: { 'Fn::GetAtt': ['OAIE1EFC67F', 'S3CanonicalUserId'] }, + }, + Resource: { + 'Fn::Join': ['', [{ 'Fn::GetAtt': ['Bucket83908E77', 'Arn'] }, '/*']], + }, + }], + }, + })); + + test.done(); + }, + + 'distribution with trusted signers on default distribution'(test: Test) { const stack = new cdk.Stack(); const sourceBucket = new s3.Bucket(stack, 'Bucket'); diff --git a/packages/@aws-cdk/aws-cloudtrail/package.json b/packages/@aws-cdk/aws-cloudtrail/package.json index 2dd9a2fbc7971..ce2c1f2e647ed 100644 --- a/packages/@aws-cdk/aws-cloudtrail/package.json +++ b/packages/@aws-cdk/aws-cloudtrail/package.json @@ -72,7 +72,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "aws-sdk": "^2.830.0", + "aws-sdk": "^2.848.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -115,5 +115,8 @@ "maturity": "stable", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-cloudwatch-actions/package.json b/packages/@aws-cdk/aws-cloudwatch-actions/package.json index 72d8c10917954..04ed6918384c1 100644 --- a/packages/@aws-cdk/aws-cloudwatch-actions/package.json +++ b/packages/@aws-cdk/aws-cloudwatch-actions/package.json @@ -102,5 +102,8 @@ "env": { "AWSLINT_BASE_CONSTRUCT": true } + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-cloudwatch/package.json b/packages/@aws-cdk/aws-cloudwatch/package.json index 147793d66e74b..c974f8fe0199a 100644 --- a/packages/@aws-cdk/aws-cloudwatch/package.json +++ b/packages/@aws-cdk/aws-cloudwatch/package.json @@ -118,5 +118,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-codeartifact/package.json b/packages/@aws-cdk/aws-codeartifact/package.json index 8181c14bca256..e4b8ef3ffaad6 100644 --- a/packages/@aws-cdk/aws-codeartifact/package.json +++ b/packages/@aws-cdk/aws-codeartifact/package.json @@ -91,5 +91,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-codebuild/package.json b/packages/@aws-cdk/aws-codebuild/package.json index 31985a89b2f3c..7b268062d474f 100644 --- a/packages/@aws-cdk/aws-codebuild/package.json +++ b/packages/@aws-cdk/aws-codebuild/package.json @@ -78,7 +78,7 @@ "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@types/nodeunit": "^0.0.31", - "aws-sdk": "^2.830.0", + "aws-sdk": "^2.848.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -224,5 +224,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.caching.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.caching.expected.json index 248d2e31c9ac8..c1680ca40cea9 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.caching.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.caching.expected.json @@ -33,7 +33,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -171,4 +171,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.project-buildspec-artifacts.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.project-buildspec-artifacts.expected.json index b2101c7135f2f..9ad98f441d7a6 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.project-buildspec-artifacts.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.project-buildspec-artifacts.expected.json @@ -33,7 +33,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -163,4 +163,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.project-logging.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.project-logging.expected.json index e68bc6b47d2b4..722f076547ea3 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.project-logging.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.project-logging.expected.json @@ -38,7 +38,7 @@ { "Action": [ "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -220,4 +220,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.project-secondary-sources-artifacts.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.project-secondary-sources-artifacts.expected.json index 7d6a3f783c899..c346580c024f1 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.project-secondary-sources-artifacts.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.project-secondary-sources-artifacts.expected.json @@ -63,7 +63,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -215,4 +215,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-codecommit/lib/repository.ts b/packages/@aws-cdk/aws-codecommit/lib/repository.ts index c1bd88ff6d4f6..495be2f981d86 100644 --- a/packages/@aws-cdk/aws-codecommit/lib/repository.ts +++ b/packages/@aws-cdk/aws-codecommit/lib/repository.ts @@ -310,7 +310,10 @@ export class Repository extends RepositoryBase { public readonly repositoryCloneUrlGrc = makeCloneUrl(stack, repositoryName, 'grc', region); } - return new Import(scope, id); + return new Import(scope, id, { + account: arn.account, + region, + }); } public static fromRepositoryName(scope: Construct, id: string, repositoryName: string): IRepository { diff --git a/packages/@aws-cdk/aws-codecommit/package.json b/packages/@aws-cdk/aws-codecommit/package.json index 6f617c91a0183..0580fab198c85 100644 --- a/packages/@aws-cdk/aws-codecommit/package.json +++ b/packages/@aws-cdk/aws-codecommit/package.json @@ -78,7 +78,7 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@types/nodeunit": "^0.0.31", - "aws-sdk": "^2.830.0", + "aws-sdk": "^2.848.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -121,5 +121,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-codecommit/test/test.codecommit.ts b/packages/@aws-cdk/aws-codecommit/test/test.codecommit.ts index 954c48561758a..1f49f852b1e57 100644 --- a/packages/@aws-cdk/aws-codecommit/test/test.codecommit.ts +++ b/packages/@aws-cdk/aws-codecommit/test/test.codecommit.ts @@ -104,6 +104,9 @@ export = { test.deepEqual(stack.resolve(repo.repositoryCloneUrlGrc), 'codecommit::us-west-2://my-repo'); + test.deepEqual(repo.env.account, '585695036304'); + test.deepEqual(repo.env.region, 'us-west-2'); + test.done(); }, diff --git a/packages/@aws-cdk/aws-codedeploy/lib/server/deployment-group.ts b/packages/@aws-cdk/aws-codedeploy/lib/server/deployment-group.ts index e1108acb5205d..32a3ccb3e40d1 100644 --- a/packages/@aws-cdk/aws-codedeploy/lib/server/deployment-group.ts +++ b/packages/@aws-cdk/aws-codedeploy/lib/server/deployment-group.ts @@ -348,15 +348,20 @@ export class ServerDeploymentGroup extends ServerDeploymentGroupBase { switch (asg.osType) { case ec2.OperatingSystemType.LINUX: asg.addUserData( + 'set +e', // make sure we don't exit on the `which` failing 'PKG_CMD=`which yum 2>/dev/null`', + 'set -e', // continue with failing on error 'if [ -z "$PKG_CMD" ]; then', 'PKG_CMD=apt-get', 'else', 'PKG=CMD=yum', 'fi', '$PKG_CMD update -y', + 'set +e', // make sure we don't exit on the next command failing (we check its exit code below) '$PKG_CMD install -y ruby2.0', - 'if [ $? -ne 0 ]; then', + 'RUBY2_INSTALL=$?', + 'set -e', // continue with failing on error + 'if [ $RUBY2_INSTALL -ne 0 ]; then', '$PKG_CMD install -y ruby', 'fi', '$PKG_CMD install -y awscli', diff --git a/packages/@aws-cdk/aws-codedeploy/package.json b/packages/@aws-cdk/aws-codedeploy/package.json index 6ccc7bcf31bfa..257e001f0fdbe 100644 --- a/packages/@aws-cdk/aws-codedeploy/package.json +++ b/packages/@aws-cdk/aws-codedeploy/package.json @@ -173,5 +173,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } 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 c463bc84e8df3..e50bc6ef02f2b 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 @@ -659,7 +659,7 @@ "Fn::Join": [ "", [ - "#!/bin/bash\nPKG_CMD=`which yum 2>/dev/null`\nif [ -z \"$PKG_CMD\" ]; then\nPKG_CMD=apt-get\nelse\nPKG=CMD=yum\nfi\n$PKG_CMD update -y\n$PKG_CMD install -y ruby2.0\nif [ $? -ne 0 ]; then\n$PKG_CMD install -y ruby\nfi\n$PKG_CMD install -y awscli\nTMP_DIR=`mktemp -d`\ncd $TMP_DIR\naws s3 cp s3://aws-codedeploy-", + "#!/bin/bash\nset +e\nPKG_CMD=`which yum 2>/dev/null`\nset -e\nif [ -z \"$PKG_CMD\" ]; then\nPKG_CMD=apt-get\nelse\nPKG=CMD=yum\nfi\n$PKG_CMD update -y\nset +e\n$PKG_CMD install -y ruby2.0\nRUBY2_INSTALL=$?\nset -e\nif [ $RUBY2_INSTALL -ne 0 ]; then\n$PKG_CMD install -y ruby\nfi\n$PKG_CMD install -y awscli\nTMP_DIR=`mktemp -d`\ncd $TMP_DIR\naws s3 cp s3://aws-codedeploy-", { "Ref": "AWS::Region" }, @@ -884,4 +884,4 @@ "Default": "/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2" } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-codedeploy/test/server/test.deployment-group.ts b/packages/@aws-cdk/aws-codedeploy/test/server/test.deployment-group.ts index 761d0e38eb6a9..aebb3aa8a074f 100644 --- a/packages/@aws-cdk/aws-codedeploy/test/server/test.deployment-group.ts +++ b/packages/@aws-cdk/aws-codedeploy/test/server/test.deployment-group.ts @@ -62,7 +62,7 @@ export = { 'Fn::Join': [ '', [ - '#!/bin/bash\nPKG_CMD=`which yum 2>/dev/null`\nif [ -z "$PKG_CMD" ]; then\nPKG_CMD=apt-get\nelse\nPKG=CMD=yum\nfi\n$PKG_CMD update -y\n$PKG_CMD install -y ruby2.0\nif [ $? -ne 0 ]; then\n$PKG_CMD install -y ruby\nfi\n$PKG_CMD install -y awscli\nTMP_DIR=`mktemp -d`\ncd $TMP_DIR\naws s3 cp s3://aws-codedeploy-', + '#!/bin/bash\nset +e\nPKG_CMD=`which yum 2>/dev/null`\nset -e\nif [ -z "$PKG_CMD" ]; then\nPKG_CMD=apt-get\nelse\nPKG=CMD=yum\nfi\n$PKG_CMD update -y\nset +e\n$PKG_CMD install -y ruby2.0\nRUBY2_INSTALL=$?\nset -e\nif [ $RUBY2_INSTALL -ne 0 ]; then\n$PKG_CMD install -y ruby\nfi\n$PKG_CMD install -y awscli\nTMP_DIR=`mktemp -d`\ncd $TMP_DIR\naws s3 cp s3://aws-codedeploy-', { 'Ref': 'AWS::Region', }, diff --git a/packages/@aws-cdk/aws-codeguruprofiler/package.json b/packages/@aws-cdk/aws-codeguruprofiler/package.json index 8a23838477f9b..dd7c44d1a3527 100644 --- a/packages/@aws-cdk/aws-codeguruprofiler/package.json +++ b/packages/@aws-cdk/aws-codeguruprofiler/package.json @@ -96,5 +96,8 @@ "maturity": "stable", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-codegurureviewer/package.json b/packages/@aws-cdk/aws-codegurureviewer/package.json index 254ea4f99130c..1b75ae00b4682 100644 --- a/packages/@aws-cdk/aws-codegurureviewer/package.json +++ b/packages/@aws-cdk/aws-codegurureviewer/package.json @@ -91,5 +91,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/codebuild/build-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/codebuild/build-action.ts index 1fc1611bd9ff2..54735d4ec1d9d 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/codebuild/build-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/codebuild/build-action.ts @@ -156,7 +156,7 @@ export class CodeBuildAction extends Action { options.role.addToPolicy(new iam.PolicyStatement({ resources: [this.props.project.projectArn], actions: [ - 'codebuild:BatchGetBuilds', + `codebuild:${this.props.executeBatchBuild ? 'BatchGetBuildBatches' : 'BatchGetBuilds'}`, `codebuild:${this.props.executeBatchBuild ? 'StartBuildBatch' : 'StartBuild'}`, `codebuild:${this.props.executeBatchBuild ? 'StopBuildBatch' : 'StopBuild'}`, ], diff --git a/packages/@aws-cdk/aws-codepipeline-actions/package.json b/packages/@aws-cdk/aws-codepipeline-actions/package.json index 1e63ddf9854cd..76381cfdbbb47 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/package.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/package.json @@ -72,7 +72,7 @@ "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", - "lodash": "^4.17.20", + "lodash": "^4.17.21", "nodeunit": "^0.11.3", "pkglint": "0.0.0" }, @@ -180,5 +180,8 @@ "env": { "AWSLINT_BASE_CONSTRUCT": true } + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.cfn-template-from-repo.lit.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.cfn-template-from-repo.lit.expected.json index 9236ecca96b41..2ce8cf8f817bf 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.cfn-template-from-repo.lit.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.cfn-template-from-repo.lit.expected.json @@ -12,23 +12,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { @@ -49,76 +33,6 @@ } }, "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineRoleD68726F7", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineSourceCodePipelineActionRoleC6F9E7F5", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineDeployPrepareChangesRoleD28C853C", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineDeployPrepareChangesCodePipelineActionRole41931444", - "Arn" - ] - } - }, - "Resource": "*" } ], "Version": "2012-10-17" @@ -197,7 +111,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -478,7 +392,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -878,4 +792,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-deployed-through-codepipeline.lit.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-deployed-through-codepipeline.lit.expected.json index 023573c87412f..3605965c27ac5 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-deployed-through-codepipeline.lit.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-deployed-through-codepipeline.lit.expected.json @@ -6,23 +6,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { @@ -43,169 +27,6 @@ } }, "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineRoleD68726F7", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineSourceCdkCodeSourceCodePipelineActionRole237947B8", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineSourceLambdaCodeSourceCodePipelineActionRole4E89EF60", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "CdkBuildProjectRoleE0B6FEB0", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "CdkBuildProjectRoleE0B6FEB0", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "LambdaBuildProjectRoleD0C4F982", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "LambdaBuildProjectRoleD0C4F982", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineDeployLambdaCFNDeployRole89CA1043", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineDeployLambdaCFNDeployCodePipelineActionRoleF8A74488", - "Arn" - ] - } - }, - "Resource": "*" } ], "Version": "2012-10-17" @@ -284,7 +105,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -639,7 +460,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -752,7 +573,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -1481,7 +1302,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -1700,7 +1521,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-pipeline.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-pipeline.expected.json index 906a2ebb7ccbd..a273e176cd6e7 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-pipeline.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-pipeline.expected.json @@ -6,23 +6,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { @@ -43,43 +27,6 @@ } }, "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineRoleD68726F7", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*", - "kms:Decrypt" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineSourceCodePipelineActionRoleC6F9E7F5", - "Arn" - ] - } - }, - "Resource": "*" } ], "Version": "2012-10-17" @@ -158,7 +105,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -393,7 +340,7 @@ { "Action": [ "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -841,4 +788,4 @@ ] } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-alexa-deploy.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-alexa-deploy.expected.json index 262def042dc8a..8e0fde48bed21 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-alexa-deploy.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-alexa-deploy.expected.json @@ -16,23 +16,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { @@ -53,43 +37,6 @@ } }, "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineRoleD68726F7", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*", - "kms:Decrypt" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineSourceCodePipelineActionRoleC6F9E7F5", - "Arn" - ] - } - }, - "Resource": "*" } ], "Version": "2012-10-17" @@ -168,7 +115,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -392,7 +339,7 @@ { "Action": [ "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -446,4 +393,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn-cross-region.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn-cross-region.expected.json index 33fc6ee2f7b1e..127ce4b1fae86 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn-cross-region.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn-cross-region.expected.json @@ -38,7 +38,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -264,7 +264,7 @@ { "Action": [ "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -482,4 +482,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn-with-action-role.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn-with-action-role.expected.json index c9511c58846fa..9c3b1e1940fde 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn-with-action-role.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn-with-action-role.expected.json @@ -163,7 +163,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -383,7 +383,7 @@ { "Action": [ "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -485,4 +485,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn.expected.json index 3571c79c9a81f..4b54eb7757227 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn.expected.json @@ -6,23 +6,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { @@ -43,77 +27,6 @@ } }, "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineRoleD68726F7", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*", - "kms:Decrypt" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineSourceCodePipelineActionRoleC6F9E7F5", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*", - "kms:Decrypt" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineSourceAdditionalSourceCodePipelineActionRole0897461A", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineCFNDeployCFNCodePipelineActionRole444CF5DD", - "Arn" - ] - } - }, - "Resource": "*" } ], "Version": "2012-10-17" @@ -192,7 +105,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -479,7 +392,7 @@ { "Action": [ "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -602,7 +515,7 @@ { "Action": [ "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -818,4 +731,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-build-batch.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-build-batch.expected.json index 13357ba22c85b..67025b2e96c68 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-build-batch.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-build-batch.expected.json @@ -109,7 +109,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -164,7 +164,7 @@ }, { "Action": [ - "codebuild:BatchGetBuilds", + "codebuild:BatchGetBuildBatches", "codebuild:StartBuildBatch", "codebuild:StopBuildBatch" ], diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-build-multiple-inputs-outputs.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-build-multiple-inputs-outputs.expected.json index ce11844d4a671..c5041087d978a 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-build-multiple-inputs-outputs.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-build-multiple-inputs-outputs.expected.json @@ -109,7 +109,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -195,7 +195,7 @@ { "Action": [ "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -556,7 +556,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit-build.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit-build.expected.json index dbf8c85f91394..6292ae43e5811 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit-build.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit-build.expected.json @@ -91,7 +91,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -263,23 +263,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { @@ -300,97 +284,6 @@ } }, "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineRoleD68726F7", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelinesourceCodePipelineActionRoleB7E0306A", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "MyBuildProjectRole6B7E2258", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "MyBuildProjectRole6B7E2258", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "MyBuildProjectRole6B7E2258", - "Arn" - ] - } - }, - "Resource": "*" } ], "Version": "2012-10-17" @@ -469,7 +362,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -727,7 +620,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit.expected.json index 0561884b64bd3..fe71ea09ade8d 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit.expected.json @@ -77,23 +77,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { @@ -114,44 +98,6 @@ } }, "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineRoleD68726F7", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelinesourceCodePipelineActionRoleB7E0306A", - "Arn" - ] - } - }, - "Resource": "*" } ], "Version": "2012-10-17" @@ -230,7 +176,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -436,7 +382,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -599,4 +545,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-deploy-ecs.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-deploy-ecs.expected.json index bf74072797472..90ac50068841e 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-deploy-ecs.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-deploy-ecs.expected.json @@ -38,7 +38,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -257,7 +257,7 @@ { "Action": [ "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -470,4 +470,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-deploy.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-deploy.expected.json index 6f9ce9cbd417f..78e721477f5ce 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-deploy.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-deploy.expected.json @@ -123,7 +123,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -340,7 +340,7 @@ { "Action": [ "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -548,4 +548,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecr-source.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecr-source.expected.json index 9610c9c53705a..384e784a5ca76 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecr-source.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecr-source.expected.json @@ -33,7 +33,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -216,7 +216,7 @@ { "Action": [ "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -412,4 +412,4 @@ } } } -} \ No newline at end of file +} 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 90360e47b3b27..5704161a5f89c 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 @@ -426,7 +426,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -572,7 +572,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -839,7 +839,7 @@ { "Action": [ "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -1043,4 +1043,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecs-separate-source.lit.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecs-separate-source.lit.expected.json index 5b487d51f1219..e8cbcadeef665 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecs-separate-source.lit.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecs-separate-source.lit.expected.json @@ -393,7 +393,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -632,7 +632,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -955,7 +955,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -1052,7 +1052,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-events.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-events.expected.json index d2031a00a8252..7506be08efa70 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-events.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-events.expected.json @@ -6,23 +6,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { @@ -43,81 +27,6 @@ } }, "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "MyPipelineRoleC0D47CA4", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "MyPipelineSourceCodeCommitSourceCodePipelineActionRole0B6D0F4F", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "BuildProjectRoleAA92C755", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "BuildProjectRoleAA92C755", - "Arn" - ] - } - }, - "Resource": "*" } ], "Version": "2012-10-17" @@ -196,7 +105,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -417,7 +326,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -804,7 +713,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -933,4 +842,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-jenkins.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-jenkins.expected.json index 631c4bb0795a3..a77528a3a8240 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-jenkins.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-jenkins.expected.json @@ -38,7 +38,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -275,7 +275,7 @@ { "Action": [ "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -372,4 +372,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-manual-approval.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-manual-approval.expected.json index 5e1ea9110c95e..1730744a18c4d 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-manual-approval.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-manual-approval.expected.json @@ -33,7 +33,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -242,7 +242,7 @@ { "Action": [ "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -349,4 +349,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-s3-deploy.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-s3-deploy.expected.json index d37bdc0c6798c..6f0330fa93862 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-s3-deploy.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-s3-deploy.expected.json @@ -43,7 +43,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -260,7 +260,7 @@ { "Action": [ "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -338,7 +338,7 @@ { "Action": [ "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -425,4 +425,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-stepfunctions.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-stepfunctions.expected.json index 2d7df75522359..973a1d986205a 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-stepfunctions.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-stepfunctions.expected.json @@ -49,23 +49,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { @@ -86,43 +70,6 @@ } }, "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "MyPipelineRoleC0D47CA4", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*", - "kms:Decrypt" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "MyPipelineSourceCodePipelineActionRoleAA05D76F", - "Arn" - ] - } - }, - "Resource": "*" } ], "Version": "2012-10-17" @@ -201,7 +148,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -438,7 +385,7 @@ { "Action": [ "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -593,4 +540,4 @@ "DeletionPolicy": "Retain" } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-codepipeline/package.json b/packages/@aws-cdk/aws-codepipeline/package.json index d8f3dc77e7064..1cc830be83ec6 100644 --- a/packages/@aws-cdk/aws-codepipeline/package.json +++ b/packages/@aws-cdk/aws-codepipeline/package.json @@ -175,5 +175,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-codestar/package.json b/packages/@aws-cdk/aws-codestar/package.json index fb70800f217c9..01024a24b1248 100644 --- a/packages/@aws-cdk/aws-codestar/package.json +++ b/packages/@aws-cdk/aws-codestar/package.json @@ -101,5 +101,8 @@ "maturity": "experimental", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-codestarconnections/package.json b/packages/@aws-cdk/aws-codestarconnections/package.json index cc087ac2da2cc..66ab2aab76ea6 100644 --- a/packages/@aws-cdk/aws-codestarconnections/package.json +++ b/packages/@aws-cdk/aws-codestarconnections/package.json @@ -91,5 +91,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-codestarnotifications/package.json b/packages/@aws-cdk/aws-codestarnotifications/package.json index ca8438caaae4a..18667b45db8b1 100644 --- a/packages/@aws-cdk/aws-codestarnotifications/package.json +++ b/packages/@aws-cdk/aws-codestarnotifications/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts index d85199ee6507f..eff29527ab4af 100644 --- a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts @@ -1,6 +1,6 @@ import { IRole, PolicyDocument, PolicyStatement, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; import * as lambda from '@aws-cdk/aws-lambda'; -import { Duration, IResource, Lazy, Names, Resource, Stack, Token } from '@aws-cdk/core'; +import { Duration, IResource, Lazy, Names, RemovalPolicy, Resource, Stack, Token } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { toASCII as punycodeEncode } from 'punycode/'; import { CfnUserPool } from './cognito.generated'; @@ -567,6 +567,13 @@ export interface UserPoolProps { * @default AccountRecovery.PHONE_WITHOUT_MFA_AND_EMAIL */ readonly accountRecovery?: AccountRecovery; + + /** + * Policy to apply when the user pool is removed from the stack + * + * @default RemovalPolicy.RETAIN + */ + readonly removalPolicy?: RemovalPolicy; } /** @@ -756,6 +763,7 @@ export class UserPool extends UserPoolBase { }), accountRecoverySetting: this.accountRecovery(props), }); + userPool.applyRemovalPolicy(props.removalPolicy); this.userPoolId = userPool.ref; this.userPoolArn = userPool.attrArn; diff --git a/packages/@aws-cdk/aws-cognito/package.json b/packages/@aws-cdk/aws-cognito/package.json index 8f1c747c1dbc7..c9bae0f953907 100644 --- a/packages/@aws-cdk/aws-cognito/package.json +++ b/packages/@aws-cdk/aws-cognito/package.json @@ -127,5 +127,8 @@ ], "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-client-explicit-props.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-client-explicit-props.expected.json index 6d118b0cf046c..c2c5b4d18b269 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-client-explicit-props.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-client-explicit-props.expected.json @@ -27,7 +27,9 @@ "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "myuserpoolmyuserpoolclientAFB2274E": { "Type": "AWS::Cognito::UserPoolClient", @@ -64,9 +66,25 @@ "COGNITO" ], "WriteAttributes": [ - "address", "birthdate", "custom:attribute_one", "custom:attribute_two", "email", - "family_name", "gender", "given_name", "locale", "middle_name", "name", "nickname", "phone_number", - "picture", "preferred_username", "profile", "updated_at", "website", "zoneinfo" + "address", + "birthdate", + "custom:attribute_one", + "custom:attribute_two", + "email", + "family_name", + "gender", + "given_name", + "locale", + "middle_name", + "name", + "nickname", + "phone_number", + "picture", + "preferred_username", + "profile", + "updated_at", + "website", + "zoneinfo" ] } } diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-client-explicit-props.ts b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-client-explicit-props.ts index 2cd4557cdb48a..d8a058a86d9c8 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-client-explicit-props.ts +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-client-explicit-props.ts @@ -1,10 +1,12 @@ -import { App, Stack } from '@aws-cdk/core'; +import { App, RemovalPolicy, Stack } from '@aws-cdk/core'; import { OAuthScope, UserPool, ClientAttributes } from '../lib'; const app = new App(); const stack = new Stack(app, 'integ-user-pool-client-explicit-props'); -const userpool = new UserPool(stack, 'myuserpool'); +const userpool = new UserPool(stack, 'myuserpool', { + removalPolicy: RemovalPolicy.DESTROY, +}); userpool.addClient('myuserpoolclient', { userPoolClientName: 'myuserpoolclient', diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.expected.json index 5f3a61539ea8a..e9a67d39c9235 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.expected.json @@ -27,7 +27,9 @@ "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "UserPoolDomainD0EA232A": { "Type": "AWS::Cognito::UserPoolDomain", @@ -38,6 +40,27 @@ } } }, + "UserPoolDomainCloudFrontDomainNameCustomResourcePolicy7DE54188": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "cognito-idp:DescribeUserPoolDomain", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "UserPoolDomainCloudFrontDomainNameCustomResourcePolicy7DE54188", + "Roles": [ + { + "Ref": "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2" + } + ] + } + }, "UserPoolDomainCloudFrontDomainNameE213E594": { "Type": "Custom::UserPoolCloudFrontDomainName", "Properties": { @@ -77,11 +100,11 @@ }, "InstallLatestAwsSdk": true }, - "UpdateReplacePolicy": "Delete", - "DeletionPolicy": "Delete", "DependsOn": [ "UserPoolDomainCloudFrontDomainNameCustomResourcePolicy7DE54188" - ] + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2": { "Type": "AWS::IAM::Role", @@ -114,29 +137,12 @@ ] } }, - "UserPoolDomainCloudFrontDomainNameCustomResourcePolicy7DE54188": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ - { - "Action":"cognito-idp:DescribeUserPoolDomain", - "Effect":"Allow", - "Resource": "*" - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "UserPoolDomainCloudFrontDomainNameCustomResourcePolicy7DE54188", - "Roles": [{"Ref":"AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2"}] - } - }, "AWS679f53fac002430cb0da5b7982bd22872D164C4C": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersd731b1475f16a318a48a76c83d255f7422cfa5f025c5bff93537b8f0b8e94557S3BucketA250C084" + "Ref": "AssetParametersb64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94S3Bucket38F1BB8E" }, "S3Key": { "Fn::Join": [ @@ -149,7 +155,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersd731b1475f16a318a48a76c83d255f7422cfa5f025c5bff93537b8f0b8e94557S3VersionKeyDC4F0CD7" + "Ref": "AssetParametersb64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94S3VersionKeyCCDC67C0" } ] } @@ -162,7 +168,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersd731b1475f16a318a48a76c83d255f7422cfa5f025c5bff93537b8f0b8e94557S3VersionKeyDC4F0CD7" + "Ref": "AssetParametersb64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94S3VersionKeyCCDC67C0" } ] } @@ -172,13 +178,13 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs12.x", "Timeout": 120 }, @@ -203,17 +209,17 @@ } }, "Parameters": { - "AssetParametersd731b1475f16a318a48a76c83d255f7422cfa5f025c5bff93537b8f0b8e94557S3BucketA250C084": { + "AssetParametersb64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94S3Bucket38F1BB8E": { "Type": "String", - "Description": "S3 bucket for asset \"d731b1475f16a318a48a76c83d255f7422cfa5f025c5bff93537b8f0b8e94557\"" + "Description": "S3 bucket for asset \"b64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94\"" }, - "AssetParametersd731b1475f16a318a48a76c83d255f7422cfa5f025c5bff93537b8f0b8e94557S3VersionKeyDC4F0CD7": { + "AssetParametersb64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94S3VersionKeyCCDC67C0": { "Type": "String", - "Description": "S3 key for asset version \"d731b1475f16a318a48a76c83d255f7422cfa5f025c5bff93537b8f0b8e94557\"" + "Description": "S3 key for asset version \"b64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94\"" }, - "AssetParametersd731b1475f16a318a48a76c83d255f7422cfa5f025c5bff93537b8f0b8e94557ArtifactHash5701DE73": { + "AssetParametersb64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94ArtifactHash782948FC": { "Type": "String", - "Description": "Artifact hash for asset \"d731b1475f16a318a48a76c83d255f7422cfa5f025c5bff93537b8f0b8e94557\"" + "Description": "Artifact hash for asset \"b64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.ts b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.ts index 7a45e144ffc3c..2c646a52721ae 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.ts +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.ts @@ -1,5 +1,5 @@ /// !cdk-integ pragma:ignore-assets -import { App, CfnOutput, Stack } from '@aws-cdk/core'; +import { App, CfnOutput, RemovalPolicy, Stack } from '@aws-cdk/core'; import { UserPool } from '../lib'; /* @@ -10,7 +10,9 @@ import { UserPool } from '../lib'; const app = new App(); const stack = new Stack(app, 'integ-user-pool-domain-cfdist'); -const userpool = new UserPool(stack, 'UserPool'); +const userpool = new UserPool(stack, 'UserPool', { + removalPolicy: RemovalPolicy.DESTROY, +}); const domain = userpool.addDomain('Domain', { cognitoDomain: { diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-signinurl.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-signinurl.expected.json index 694cf43b5f5ea..f19f82379b701 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-signinurl.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-signinurl.expected.json @@ -27,7 +27,9 @@ "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "UserPoolDomainD0EA232A": { "Type": "AWS::Cognito::UserPoolDomain", diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-signinurl.ts b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-signinurl.ts index 7d55d08fe12bb..7b26359354f9b 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-signinurl.ts +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-signinurl.ts @@ -1,4 +1,4 @@ -import { App, CfnOutput, Stack } from '@aws-cdk/core'; +import { App, CfnOutput, RemovalPolicy, Stack } from '@aws-cdk/core'; import { UserPool } from '../lib'; /* @@ -10,7 +10,9 @@ import { UserPool } from '../lib'; const app = new App(); const stack = new Stack(app, 'integ-user-pool-domain-signinurl'); -const userpool = new UserPool(stack, 'UserPool'); +const userpool = new UserPool(stack, 'UserPool', { + removalPolicy: RemovalPolicy.DESTROY, +}); const domain = userpool.addDomain('Domain', { cognitoDomain: { diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.expected.json index ed77c3b7baa53..50da9815a769b 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.expected.json @@ -37,15 +37,15 @@ "Code": { "ZipFile": "foo" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "createAuthChallengeServiceRole611710B5", "Arn" ] }, - "Runtime": "nodejs12.x", - "FunctionName": "createAuthChallenge" + "FunctionName": "createAuthChallenge", + "Handler": "index.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "createAuthChallengeServiceRole611710B5" @@ -101,15 +101,15 @@ "Code": { "ZipFile": "foo" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "customMessageServiceRoleB4AE7F17", "Arn" ] }, - "Runtime": "nodejs12.x", - "FunctionName": "customMessage" + "FunctionName": "customMessage", + "Handler": "index.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "customMessageServiceRoleB4AE7F17" @@ -165,15 +165,15 @@ "Code": { "ZipFile": "foo" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "defineAuthChallengeServiceRole9E2D15DF", "Arn" ] }, - "Runtime": "nodejs12.x", - "FunctionName": "defineAuthChallenge" + "FunctionName": "defineAuthChallenge", + "Handler": "index.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "defineAuthChallengeServiceRole9E2D15DF" @@ -229,15 +229,15 @@ "Code": { "ZipFile": "foo" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "postAuthenticationServiceRole5B3B242A", "Arn" ] }, - "Runtime": "nodejs12.x", - "FunctionName": "postAuthentication" + "FunctionName": "postAuthentication", + "Handler": "index.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "postAuthenticationServiceRole5B3B242A" @@ -293,15 +293,15 @@ "Code": { "ZipFile": "foo" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "postConfirmationServiceRole864BE5F9", "Arn" ] }, - "Runtime": "nodejs12.x", - "FunctionName": "postConfirmation" + "FunctionName": "postConfirmation", + "Handler": "index.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "postConfirmationServiceRole864BE5F9" @@ -357,15 +357,15 @@ "Code": { "ZipFile": "foo" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "preAuthenticationServiceRole9712F4D8", "Arn" ] }, - "Runtime": "nodejs12.x", - "FunctionName": "preAuthentication" + "FunctionName": "preAuthentication", + "Handler": "index.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "preAuthenticationServiceRole9712F4D8" @@ -421,15 +421,15 @@ "Code": { "ZipFile": "foo" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "preSignUpServiceRole0A7E91EB", "Arn" ] }, - "Runtime": "nodejs12.x", - "FunctionName": "preSignUp" + "FunctionName": "preSignUp", + "Handler": "index.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "preSignUpServiceRole0A7E91EB" @@ -485,15 +485,15 @@ "Code": { "ZipFile": "foo" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "preTokenGenerationServiceRole430C3D14", "Arn" ] }, - "Runtime": "nodejs12.x", - "FunctionName": "preTokenGeneration" + "FunctionName": "preTokenGeneration", + "Handler": "index.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "preTokenGenerationServiceRole430C3D14" @@ -549,15 +549,15 @@ "Code": { "ZipFile": "foo" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "userMigrationServiceRole091766B0", "Arn" ] }, - "Runtime": "nodejs12.x", - "FunctionName": "userMigration" + "FunctionName": "userMigration", + "Handler": "index.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "userMigrationServiceRole091766B0" @@ -613,15 +613,15 @@ "Code": { "ZipFile": "foo" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "verifyAuthChallengeResponseServiceRole7077884C", "Arn" ] }, - "Runtime": "nodejs12.x", - "FunctionName": "verifyAuthChallengeResponse" + "FunctionName": "verifyAuthChallengeResponse", + "Handler": "index.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "verifyAuthChallengeResponseServiceRole7077884C" @@ -843,7 +843,9 @@ "EmailSubject": "verification email subject from the integ test", "SmsMessage": "verification sms message from the integ test. Code is {####}." } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "myuserpoolmyuserpooldomainEE1E11AF": { "Type": "AWS::Cognito::UserPoolDomain", diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.ts b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.ts index 261251e1e2592..1bc35003fa472 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.ts +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.ts @@ -1,11 +1,12 @@ import { Code, Function, IFunction, Runtime } from '@aws-cdk/aws-lambda'; -import { App, CfnOutput, Duration, Stack } from '@aws-cdk/core'; +import { App, CfnOutput, Duration, RemovalPolicy, Stack } from '@aws-cdk/core'; import { BooleanAttribute, DateTimeAttribute, Mfa, NumberAttribute, StringAttribute, UserPool } from '../lib'; const app = new App(); const stack = new Stack(app, 'integ-user-pool'); const userpool = new UserPool(stack, 'myuserpool', { + removalPolicy: RemovalPolicy.DESTROY, userPoolName: 'MyUserPool', userInvitation: { emailSubject: 'invitation email subject from the integ test', diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.amazon.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.amazon.expected.json index e68a262eb7ee3..dd2188ee4e517 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.amazon.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.amazon.expected.json @@ -27,7 +27,9 @@ "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "poolclient2623294C": { "Type": "AWS::Cognito::UserPoolClient", diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.amazon.ts b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.amazon.ts index 7252dfc0a8a40..77b95a5857330 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.amazon.ts +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.amazon.ts @@ -1,4 +1,4 @@ -import { App, CfnOutput, Stack } from '@aws-cdk/core'; +import { App, CfnOutput, RemovalPolicy, Stack } from '@aws-cdk/core'; import { ProviderAttribute, UserPool, UserPoolIdentityProviderAmazon } from '../lib'; /* @@ -9,7 +9,9 @@ import { ProviderAttribute, UserPool, UserPoolIdentityProviderAmazon } from '../ const app = new App(); const stack = new Stack(app, 'integ-user-pool-idp-amazon'); -const userpool = new UserPool(stack, 'pool'); +const userpool = new UserPool(stack, 'pool', { + removalPolicy: RemovalPolicy.DESTROY, +}); new UserPoolIdentityProviderAmazon(stack, 'amazon', { userPool: userpool, diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.google.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.google.expected.json index c767ee9d2d260..b90dd7faec0dd 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.google.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.google.expected.json @@ -27,7 +27,9 @@ "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "poolclient2623294C": { "Type": "AWS::Cognito::UserPoolClient", diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.google.ts b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.google.ts index fac20b8351d38..f4ea4d077286d 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.google.ts +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.google.ts @@ -1,4 +1,4 @@ -import { App, CfnOutput, Stack } from '@aws-cdk/core'; +import { App, CfnOutput, RemovalPolicy, Stack } from '@aws-cdk/core'; import { ProviderAttribute, UserPool, UserPoolIdentityProviderGoogle } from '../lib'; /* @@ -9,7 +9,9 @@ import { ProviderAttribute, UserPool, UserPoolIdentityProviderGoogle } from '../ const app = new App(); const stack = new Stack(app, 'integ-user-pool-idp-google'); -const userpool = new UserPool(stack, 'pool'); +const userpool = new UserPool(stack, 'pool', { + removalPolicy: RemovalPolicy.DESTROY, +}); new UserPoolIdentityProviderGoogle(stack, 'google', { userPool: userpool, diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-resource-server.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-resource-server.expected.json index ffc765b879357..36b033a51f2fb 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-resource-server.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-resource-server.expected.json @@ -28,7 +28,9 @@ "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "myuserpoolmyserver50C4D8E9": { "Type": "AWS::Cognito::UserPoolResourceServer", diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-resource-server.ts b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-resource-server.ts index 8610d7a3e1296..cd56612c65cd7 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-resource-server.ts +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-resource-server.ts @@ -1,4 +1,4 @@ -import { App, CfnOutput, Stack } from '@aws-cdk/core'; +import { App, CfnOutput, RemovalPolicy, Stack } from '@aws-cdk/core'; import { OAuthScope, ResourceServerScope, UserPool } from '../lib'; const app = new App(); @@ -14,6 +14,7 @@ const stack = new Stack(app, 'integ-user-pool-resource-server'); */ const userPool = new UserPool(stack, 'myuserpool', { userPoolName: 'MyUserPool', + removalPolicy: RemovalPolicy.DESTROY, }); const readScope = new ResourceServerScope({ scopeName: 'read', scopeDescription: 'read only' }); diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-code.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-code.expected.json index 5cc13052434f2..091b5f4cb7a8a 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-code.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-code.expected.json @@ -87,7 +87,9 @@ "EmailSubject": "integ-test: Verify your account", "SmsMessage": "integ-test: Account verification code is {####}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "myuserpoolclient8A58A3E4": { "Type": "AWS::Cognito::UserPoolClient", diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-code.ts b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-code.ts index 12e8c1d354ea3..9118b4c912adf 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-code.ts +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-code.ts @@ -1,4 +1,4 @@ -import { App, CfnOutput, Stack } from '@aws-cdk/core'; +import { App, CfnOutput, RemovalPolicy, Stack } from '@aws-cdk/core'; import { UserPool, UserPoolClient, VerificationEmailStyle } from '../lib'; /* @@ -15,6 +15,7 @@ const app = new App(); const stack = new Stack(app, 'integ-user-pool-signup-code'); const userpool = new UserPool(stack, 'myuserpool', { + removalPolicy: RemovalPolicy.DESTROY, userPoolName: 'MyUserPool', autoVerify: { email: true, diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-link.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-link.expected.json index 53c9f89ed8031..f5cca975e608b 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-link.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-link.expected.json @@ -85,7 +85,9 @@ "EmailSubjectByLink": "integ-test: Verify your account", "SmsMessage": "integ-test: Account verification code is {####}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "myuserpoolmyuserpooldomainEE1E11AF": { "Type": "AWS::Cognito::UserPoolDomain", diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-link.ts b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-link.ts index 92f0452010f22..b7121720ad940 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-link.ts +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-link.ts @@ -1,4 +1,4 @@ -import { App, CfnOutput, Stack } from '@aws-cdk/core'; +import { App, CfnOutput, RemovalPolicy, Stack } from '@aws-cdk/core'; import { UserPool, UserPoolClient, VerificationEmailStyle } from '../lib'; /* @@ -15,6 +15,7 @@ const app = new App(); const stack = new Stack(app, 'integ-user-pool-signup-link'); const userpool = new UserPool(stack, 'myuserpool', { + removalPolicy: RemovalPolicy.DESTROY, userPoolName: 'MyUserPool', autoVerify: { email: true, diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool.expected.json index 85214615c050d..a3a50d2f5287b 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool.expected.json @@ -28,7 +28,9 @@ "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool.ts b/packages/@aws-cdk/aws-cognito/test/integ.user-pool.ts index 565a6b1dd549e..5b587b8f94f75 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool.ts +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool.ts @@ -1,4 +1,4 @@ -import { App, CfnOutput, Stack } from '@aws-cdk/core'; +import { App, CfnOutput, RemovalPolicy, Stack } from '@aws-cdk/core'; import { UserPool } from '../lib'; const app = new App(); @@ -6,6 +6,7 @@ const stack = new Stack(app, 'integ-user-pool'); const userpool = new UserPool(stack, 'myuserpool', { userPoolName: 'MyUserPool', + removalPolicy: RemovalPolicy.DESTROY, }); new CfnOutput(stack, 'user-pool-id', { diff --git a/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts b/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts index a2199eecce800..6801e8ada2568 100644 --- a/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts +++ b/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts @@ -1,5 +1,5 @@ import '@aws-cdk/assert/jest'; -import { ABSENT } from '@aws-cdk/assert/lib/assertions/have-resource'; +import { ABSENT, ResourcePart } from '@aws-cdk/assert/lib/assertions/have-resource'; import { Role, ServicePrincipal } from '@aws-cdk/aws-iam'; import * as lambda from '@aws-cdk/aws-lambda'; import { CfnParameter, Duration, Stack, Tags } from '@aws-cdk/core'; @@ -32,6 +32,10 @@ describe('User Pool', () => { SmsConfiguration: ABSENT, lambdaTriggers: ABSENT, }); + + expect(stack).toHaveResource('AWS::Cognito::UserPool', { + DeletionPolicy: 'Retain', + }, ResourcePart.CompleteDefinition); }); test('self sign up option is correctly configured', () => { diff --git a/packages/@aws-cdk/aws-config/package.json b/packages/@aws-cdk/aws-config/package.json index 641207bcd1a6d..59055c7030216 100644 --- a/packages/@aws-cdk/aws-config/package.json +++ b/packages/@aws-cdk/aws-config/package.json @@ -113,5 +113,8 @@ ], "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-databrew/package.json b/packages/@aws-cdk/aws-databrew/package.json index 51d40a0f6e767..be8bdfacf71db 100644 --- a/packages/@aws-cdk/aws-databrew/package.json +++ b/packages/@aws-cdk/aws-databrew/package.json @@ -91,5 +91,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-datapipeline/package.json b/packages/@aws-cdk/aws-datapipeline/package.json index 4079f7aaf6f65..2e1f552ef864a 100644 --- a/packages/@aws-cdk/aws-datapipeline/package.json +++ b/packages/@aws-cdk/aws-datapipeline/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-datasync/package.json b/packages/@aws-cdk/aws-datasync/package.json index 9ec4b17a3cf8c..124d3871ae0c3 100644 --- a/packages/@aws-cdk/aws-datasync/package.json +++ b/packages/@aws-cdk/aws-datasync/package.json @@ -91,5 +91,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-dax/package.json b/packages/@aws-cdk/aws-dax/package.json index b6c4a91029939..83fecea8535ee 100644 --- a/packages/@aws-cdk/aws-dax/package.json +++ b/packages/@aws-cdk/aws-dax/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-detective/package.json b/packages/@aws-cdk/aws-detective/package.json index 41010df5668d7..741eade5dc9e2 100644 --- a/packages/@aws-cdk/aws-detective/package.json +++ b/packages/@aws-cdk/aws-detective/package.json @@ -91,5 +91,8 @@ "awscdkio": { "announce": false }, - "maturity": "cfn-only" + "maturity": "cfn-only", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-devopsguru/package.json b/packages/@aws-cdk/aws-devopsguru/package.json index c0c9653ca7c2b..7632ba1d35cea 100644 --- a/packages/@aws-cdk/aws-devopsguru/package.json +++ b/packages/@aws-cdk/aws-devopsguru/package.json @@ -91,5 +91,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-directoryservice/package.json b/packages/@aws-cdk/aws-directoryservice/package.json index e3d0354c6d391..9be65b5324fff 100644 --- a/packages/@aws-cdk/aws-directoryservice/package.json +++ b/packages/@aws-cdk/aws-directoryservice/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-dlm/package.json b/packages/@aws-cdk/aws-dlm/package.json index 3bce8f24787b6..5829ed6a34e11 100644 --- a/packages/@aws-cdk/aws-dlm/package.json +++ b/packages/@aws-cdk/aws-dlm/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-dms/package.json b/packages/@aws-cdk/aws-dms/package.json index b83918ab2640d..1c6f0a473b7b3 100644 --- a/packages/@aws-cdk/aws-dms/package.json +++ b/packages/@aws-cdk/aws-dms/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-docdb/lib/endpoint.ts b/packages/@aws-cdk/aws-docdb/lib/endpoint.ts index 229a0bf7f0e70..fcec7b3eb4a1a 100644 --- a/packages/@aws-cdk/aws-docdb/lib/endpoint.ts +++ b/packages/@aws-cdk/aws-docdb/lib/endpoint.ts @@ -40,7 +40,7 @@ export class Endpoint { public readonly port: number; /** - * The combination of "HOSTNAME:PORT" for this endpoint + * The combination of ``HOSTNAME:PORT`` for this endpoint. */ public readonly socketAddress: string; diff --git a/packages/@aws-cdk/aws-docdb/package.json b/packages/@aws-cdk/aws-docdb/package.json index de00eea1db9b8..658583ff0d644 100644 --- a/packages/@aws-cdk/aws-docdb/package.json +++ b/packages/@aws-cdk/aws-docdb/package.json @@ -108,5 +108,8 @@ "maturity": "experimental", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-docdb/test/integ.cluster.expected.json b/packages/@aws-cdk/aws-docdb/test/integ.cluster.expected.json index 69ced2a747f81..e8737956c6440 100644 --- a/packages/@aws-cdk/aws-docdb/test/integ.cluster.expected.json +++ b/packages/@aws-cdk/aws-docdb/test/integ.cluster.expected.json @@ -373,23 +373,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { @@ -522,4 +506,4 @@ "DeletionPolicy": "Delete" } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package.json b/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package.json index 0b3e525b4b74b..8d1e45ac66b83 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package.json +++ b/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package.json @@ -29,11 +29,11 @@ "devDependencies": { "aws-sdk": "^2.596.0", "aws-sdk-mock": "^5.1.0", - "eslint": "^7.19.0", + "eslint": "^7.20.0", "eslint-config-standard": "^14.1.1", "eslint-plugin-import": "^2.22.1", "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^4.2.1", + "eslint-plugin-promise": "^4.3.1", "eslint-plugin-standard": "^4.1.0", "jest": "^26.6.3", "lambda-tester": "^3.6.0", diff --git a/packages/@aws-cdk/aws-dynamodb-global/package.json b/packages/@aws-cdk/aws-dynamodb-global/package.json index 2b42ccaec9524..2a3a41bc29fbb 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/package.json +++ b/packages/@aws-cdk/aws-dynamodb-global/package.json @@ -93,5 +93,8 @@ "awscdkio": { "announce": false }, - "maturity": "deprecated" + "maturity": "deprecated", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-dynamodb/package.json b/packages/@aws-cdk/aws-dynamodb/package.json index 71c51a08038bb..6ca3616c33ac8 100644 --- a/packages/@aws-cdk/aws-dynamodb/package.json +++ b/packages/@aws-cdk/aws-dynamodb/package.json @@ -73,7 +73,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/jest": "^26.0.20", - "aws-sdk": "^2.830.0", + "aws-sdk": "^2.848.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", @@ -81,7 +81,7 @@ "jest": "^26.6.3", "pkglint": "0.0.0", "sinon": "^9.2.4", - "ts-jest": "^26.5.0" + "ts-jest": "^26.5.1" }, "dependencies": { "@aws-cdk/aws-applicationautoscaling": "0.0.0", @@ -111,5 +111,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts index 1a7116d73444f..768094c253213 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts @@ -1,9 +1,11 @@ -import { ABSENT, ResourcePart, SynthUtils } from '@aws-cdk/assert'; +import { arrayWith, ABSENT, 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, Aws, CfnDeletionPolicy, ConstructNode, Duration, PhysicalName, RemovalPolicy, Stack, Tags } from '@aws-cdk/core'; +import { App, Aws, CfnDeletionPolicy, ConstructNode, Duration, PhysicalName, RemovalPolicy, Resource, Stack, Tags } from '@aws-cdk/core'; +import { testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { Construct } from 'constructs'; import { Attribute, AttributeType, @@ -15,6 +17,7 @@ import { Table, TableEncryption, Operation, + CfnTable, } from '../lib'; /* eslint-disable quote-props */ @@ -486,154 +489,10 @@ test('fails if both replication regions used with customer managed CMK', () => { })).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': '*', - }, - { - '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(); +// this behaviour is only applicable without the future flag 'aws-kms:defaultKeyPolicies' +// see subsequent test for the updated behaviour +testLegacyBehavior('if an encryption key is included, encrypt/decrypt permissions are also added both ways', App, (app) => { + const stack = new Stack(app); const table = new Table(stack, 'Table A', { tableName: TABLE_NAME, partitionKey: TABLE_PARTITION_KEY, @@ -815,6 +674,38 @@ test('if an encryption key is included, encrypt/decrypt permissions are also add }); }); +test('if an encryption key is included, encrypt/decrypt permissions are added to the principal', () => { + 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).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': [ + 'kms:Decrypt', + 'kms:DescribeKey', + 'kms:Encrypt', + 'kms:ReEncrypt*', + 'kms:GenerateDataKey*', + ], + 'Effect': 'Allow', + 'Resource': { + 'Fn::GetAtt': [ + 'TableAKey07CC09EC', + 'Arn', + ], + }, + }), + }, + }); +}); + test('when specifying PAY_PER_REQUEST billing mode', () => { const stack = new Stack(); new Table(stack, CONSTRUCT_NAME, { @@ -2925,6 +2816,29 @@ describe('global', () => { }); }); +test('L1 inside L2 expects removalpolicy to have been set', () => { + // Check that the "stateful L1 validation generation" works. Do it here + // because we know DDB tables are stateful. + const app = new App(); + const stack = new Stack(app, 'Stack'); + + class FakeTableL2 extends Resource { + constructor(scope: Construct, id: string) { + super(scope, id); + + new CfnTable(this, 'Resource', { + keySchema: [{ attributeName: 'hash', keyType: 'S' }], + }); + } + } + + new FakeTableL2(stack, 'Table'); + + expect(() => { + SynthUtils.toCloudFormation(stack); + }).toThrow(/is a stateful resource type/); +}); + function testGrant(expectedActions: string[], invocation: (user: iam.IPrincipal, table: Table) => void) { // GIVEN const stack = new Stack(); diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.sse.expected.json b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.sse.expected.json index ee7c8f9988f9e..2f49a9b48157d 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.sse.expected.json +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.sse.expected.json @@ -6,23 +6,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { @@ -43,22 +27,6 @@ } }, "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "Role1ABCC5F0", - "Arn" - ] - } - }, - "Resource": "*" } ], "Version": "2012-10-17" @@ -358,23 +326,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { @@ -619,4 +571,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.global-replicas-provisioned.expected.json b/packages/@aws-cdk/aws-dynamodb/test/integ.global-replicas-provisioned.expected.json index ec15f88fdfea8..89a9c3807fc21 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.global-replicas-provisioned.expected.json +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.global-replicas-provisioned.expected.json @@ -302,7 +302,9 @@ "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Conditions": { diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json b/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json index 2301663780e86..a66dd3d965ed9 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json @@ -231,7 +231,7 @@ }, "/", { - "Ref": "AssetParameters51ac5fed1b824803906219cb11f0c17572739bd4fb019d961cdc1fbbfefc620eS3Bucket58C634A6" + "Ref": "AssetParametersf8cfc24954f0c95960d9a93888c01bf5e95802f26bfa5dc6fde5c913a1429ceaS3Bucket434BDB62" }, "/", { @@ -241,7 +241,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters51ac5fed1b824803906219cb11f0c17572739bd4fb019d961cdc1fbbfefc620eS3VersionKeyE8ACA4C1" + "Ref": "AssetParametersf8cfc24954f0c95960d9a93888c01bf5e95802f26bfa5dc6fde5c913a1429ceaS3VersionKey01638790" } ] } @@ -254,7 +254,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters51ac5fed1b824803906219cb11f0c17572739bd4fb019d961cdc1fbbfefc620eS3VersionKeyE8ACA4C1" + "Ref": "AssetParametersf8cfc24954f0c95960d9a93888c01bf5e95802f26bfa5dc6fde5c913a1429ceaS3VersionKey01638790" } ] } @@ -264,58 +264,60 @@ ] }, "Parameters": { - "referencetocdkdynamodbglobal20191121AssetParameters23c5f8cc1bdef276fc20dbb166d24d1b7d8cb516a5d5822ed0d38feec9631fd1S3BucketFE71C2D0Ref": { - "Ref": "AssetParameters23c5f8cc1bdef276fc20dbb166d24d1b7d8cb516a5d5822ed0d38feec9631fd1S3Bucket492F02B7" + "referencetocdkdynamodbglobal20191121AssetParametersf13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714S3Bucket71E24D5BRef": { + "Ref": "AssetParametersf13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714S3Bucket1C6779E0" }, - "referencetocdkdynamodbglobal20191121AssetParameters23c5f8cc1bdef276fc20dbb166d24d1b7d8cb516a5d5822ed0d38feec9631fd1S3VersionKey849A4FA5Ref": { - "Ref": "AssetParameters23c5f8cc1bdef276fc20dbb166d24d1b7d8cb516a5d5822ed0d38feec9631fd1S3VersionKeyC7F72494" + "referencetocdkdynamodbglobal20191121AssetParametersf13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714S3VersionKeyD88E8BACRef": { + "Ref": "AssetParametersf13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714S3VersionKey5C1D9275" }, - "referencetocdkdynamodbglobal20191121AssetParameters956c2f92ddbde06f551fdf914445c679dcadb21c6e8d1ee9c9632144ef5a2ad3S3Bucket80086951Ref": { - "Ref": "AssetParameters956c2f92ddbde06f551fdf914445c679dcadb21c6e8d1ee9c9632144ef5a2ad3S3Bucket0EEA1C2E" + "referencetocdkdynamodbglobal20191121AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketC7F3A147Ref": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" }, - "referencetocdkdynamodbglobal20191121AssetParameters956c2f92ddbde06f551fdf914445c679dcadb21c6e8d1ee9c9632144ef5a2ad3S3VersionKeyC3096D21Ref": { - "Ref": "AssetParameters956c2f92ddbde06f551fdf914445c679dcadb21c6e8d1ee9c9632144ef5a2ad3S3VersionKey7BCE18C9" + "referencetocdkdynamodbglobal20191121AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyB6346792Ref": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Parameters": { - "AssetParameters23c5f8cc1bdef276fc20dbb166d24d1b7d8cb516a5d5822ed0d38feec9631fd1S3Bucket492F02B7": { + "AssetParametersf13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714S3Bucket1C6779E0": { "Type": "String", - "Description": "S3 bucket for asset \"23c5f8cc1bdef276fc20dbb166d24d1b7d8cb516a5d5822ed0d38feec9631fd1\"" + "Description": "S3 bucket for asset \"f13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714\"" }, - "AssetParameters23c5f8cc1bdef276fc20dbb166d24d1b7d8cb516a5d5822ed0d38feec9631fd1S3VersionKeyC7F72494": { + "AssetParametersf13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714S3VersionKey5C1D9275": { "Type": "String", - "Description": "S3 key for asset version \"23c5f8cc1bdef276fc20dbb166d24d1b7d8cb516a5d5822ed0d38feec9631fd1\"" + "Description": "S3 key for asset version \"f13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714\"" }, - "AssetParameters23c5f8cc1bdef276fc20dbb166d24d1b7d8cb516a5d5822ed0d38feec9631fd1ArtifactHash43BB7053": { + "AssetParametersf13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714ArtifactHash477AAEA7": { "Type": "String", - "Description": "Artifact hash for asset \"23c5f8cc1bdef276fc20dbb166d24d1b7d8cb516a5d5822ed0d38feec9631fd1\"" + "Description": "Artifact hash for asset \"f13d472270faaa08099009152a8848a0e7434b14773f3c3f94acca6f6c3ae714\"" }, - "AssetParameters956c2f92ddbde06f551fdf914445c679dcadb21c6e8d1ee9c9632144ef5a2ad3S3Bucket0EEA1C2E": { + "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { "Type": "String", - "Description": "S3 bucket for asset \"956c2f92ddbde06f551fdf914445c679dcadb21c6e8d1ee9c9632144ef5a2ad3\"" + "Description": "S3 bucket for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" }, - "AssetParameters956c2f92ddbde06f551fdf914445c679dcadb21c6e8d1ee9c9632144ef5a2ad3S3VersionKey7BCE18C9": { + "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F": { "Type": "String", - "Description": "S3 key for asset version \"956c2f92ddbde06f551fdf914445c679dcadb21c6e8d1ee9c9632144ef5a2ad3\"" + "Description": "S3 key for asset version \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" }, - "AssetParameters956c2f92ddbde06f551fdf914445c679dcadb21c6e8d1ee9c9632144ef5a2ad3ArtifactHash2CBB11D2": { + "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1ArtifactHashA521A16F": { "Type": "String", - "Description": "Artifact hash for asset \"956c2f92ddbde06f551fdf914445c679dcadb21c6e8d1ee9c9632144ef5a2ad3\"" + "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" }, - "AssetParameters51ac5fed1b824803906219cb11f0c17572739bd4fb019d961cdc1fbbfefc620eS3Bucket58C634A6": { + "AssetParametersf8cfc24954f0c95960d9a93888c01bf5e95802f26bfa5dc6fde5c913a1429ceaS3Bucket434BDB62": { "Type": "String", - "Description": "S3 bucket for asset \"51ac5fed1b824803906219cb11f0c17572739bd4fb019d961cdc1fbbfefc620e\"" + "Description": "S3 bucket for asset \"f8cfc24954f0c95960d9a93888c01bf5e95802f26bfa5dc6fde5c913a1429cea\"" }, - "AssetParameters51ac5fed1b824803906219cb11f0c17572739bd4fb019d961cdc1fbbfefc620eS3VersionKeyE8ACA4C1": { + "AssetParametersf8cfc24954f0c95960d9a93888c01bf5e95802f26bfa5dc6fde5c913a1429ceaS3VersionKey01638790": { "Type": "String", - "Description": "S3 key for asset version \"51ac5fed1b824803906219cb11f0c17572739bd4fb019d961cdc1fbbfefc620e\"" + "Description": "S3 key for asset version \"f8cfc24954f0c95960d9a93888c01bf5e95802f26bfa5dc6fde5c913a1429cea\"" }, - "AssetParameters51ac5fed1b824803906219cb11f0c17572739bd4fb019d961cdc1fbbfefc620eArtifactHashDF827F41": { + "AssetParametersf8cfc24954f0c95960d9a93888c01bf5e95802f26bfa5dc6fde5c913a1429ceaArtifactHashD0E61C22": { "Type": "String", - "Description": "Artifact hash for asset \"51ac5fed1b824803906219cb11f0c17572739bd4fb019d961cdc1fbbfefc620e\"" + "Description": "Artifact hash for asset \"f8cfc24954f0c95960d9a93888c01bf5e95802f26bfa5dc6fde5c913a1429cea\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/lib/volume.ts b/packages/@aws-cdk/aws-ec2/lib/volume.ts index a23614b89ed63..64f920866a17b 100644 --- a/packages/@aws-cdk/aws-ec2/lib/volume.ts +++ b/packages/@aws-cdk/aws-ec2/lib/volume.ts @@ -2,7 +2,7 @@ import * as crypto from 'crypto'; import { AccountRootPrincipal, Grant, IGrantable } from '@aws-cdk/aws-iam'; import { IKey, ViaServicePrincipal } from '@aws-cdk/aws-kms'; -import { IResource, Resource, Size, SizeRoundingBehavior, Stack, Token, Tags, Names } from '@aws-cdk/core'; +import { IResource, Resource, Size, SizeRoundingBehavior, Stack, Token, Tags, Names, RemovalPolicy } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { CfnVolume } from './ec2.generated'; import { IInstance } from './instance'; @@ -431,6 +431,13 @@ export interface VolumeProps { * @default None -- Required for io1 and io2 volumes. The default for gp3 volumes is 3,000 IOPS if omitted. */ readonly iops?: number; + + /** + * Policy to apply when the volume is removed from the stack + * + * @default RemovalPolicy.RETAIN + */ + readonly removalPolicy?: RemovalPolicy; } /** @@ -605,6 +612,7 @@ export class Volume extends VolumeBase { snapshotId: props.snapshotId, volumeType: props.volumeType ?? EbsDeviceVolumeType.GENERAL_PURPOSE_SSD, }); + resource.applyRemovalPolicy(props.removalPolicy); this.volumeId = resource.ref; this.availabilityZone = props.availabilityZone; diff --git a/packages/@aws-cdk/aws-ec2/package.json b/packages/@aws-cdk/aws-ec2/package.json index 74ceca63c984f..97f9edc2c3300 100644 --- a/packages/@aws-cdk/aws-ec2/package.json +++ b/packages/@aws-cdk/aws-ec2/package.json @@ -485,5 +485,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-ec2/test/volume.test.ts b/packages/@aws-cdk/aws-ec2/test/volume.test.ts index 20271b20fa008..edd0323bc84ef 100644 --- a/packages/@aws-cdk/aws-ec2/test/volume.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/volume.test.ts @@ -1,4 +1,5 @@ import { + arrayWith, expect as cdkExpect, haveResource, haveResourceLike, @@ -10,6 +11,7 @@ import { } from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as cdk from '@aws-cdk/core'; +import { testFutureBehavior, testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; import { AmazonLinuxGeneration, EbsDeviceVolumeType, @@ -39,7 +41,9 @@ describe('volume', () => { VolumeType: 'gp2', }, ResourcePart.Properties)); - + cdkExpect(stack).to(haveResource('AWS::EC2::Volume', { + DeletionPolicy: 'Retain', + }, ResourcePart.CompleteDefinition)); }); test('fromVolumeAttributes', () => { @@ -206,9 +210,11 @@ describe('volume', () => { }); - test('encryption with kms from snapshot', () => { + // only enable for legacy behaviour + // see https://github.com/aws/aws-cdk/issues/12962 + testLegacyBehavior('encryption with kms from snapshot', cdk.App, (app) => { // GIVEN - const stack = new cdk.Stack(); + const stack = new cdk.Stack(app); const encryptionKey = new kms.Key(stack, 'Key'); // WHEN @@ -504,37 +510,91 @@ describe('volume', () => { }); - test('grantAttachVolume to any instance with encryption', () => { - // GIVEN - const stack = new cdk.Stack(); - const role = new Role(stack, 'Role', { assumedBy: new AccountRootPrincipal() }); - const encryptionKey = new kms.Key(stack, 'Key'); - const volume = new Volume(stack, 'Volume', { - availabilityZone: 'us-east-1a', - size: cdk.Size.gibibytes(8), - encrypted: true, - encryptionKey, - }); + describe('grantAttachVolume to any instance with encryption', () => { - // WHEN - volume.grantAttachVolume(role); + // This exact assertions here are only applicable when 'aws-kms:defaultKeyPolicies' feature flag is disabled. + // See subsequent test case for the updated behaviour + testLegacyBehavior('legacy', cdk.App, (app) => { + // GIVEN + const stack = new cdk.Stack(app); + const role = new Role(stack, 'Role', { assumedBy: new AccountRootPrincipal() }); + const encryptionKey = new kms.Key(stack, 'Key'); + const volume = new Volume(stack, 'Volume', { + availabilityZone: 'us-east-1a', + size: cdk.Size.gibibytes(8), + encrypted: true, + encryptionKey, + }); - // THEN - cdkExpect(stack).to(haveResourceLike('AWS::KMS::Key', { - KeyPolicy: { - Statement: [ - {}, - {}, - { - Effect: 'Allow', - Principal: { - AWS: { - 'Fn::GetAtt': [ - 'Role1ABCC5F0', - 'Arn', - ], + // WHEN + volume.grantAttachVolume(role); + + // THEN + cdkExpect(stack).to(haveResourceLike('AWS::KMS::Key', { + KeyPolicy: { + Statement: [ + {}, + {}, + { + Effect: 'Allow', + Principal: { + AWS: { + 'Fn::GetAtt': [ + 'Role1ABCC5F0', + 'Arn', + ], + }, }, + Action: 'kms:CreateGrant', + Condition: { + Bool: { + 'kms:GrantIsForAWSResource': true, + }, + StringEquals: { + 'kms:ViaService': { + 'Fn::Join': [ + '', + [ + 'ec2.', + { + Ref: 'AWS::Region', + }, + '.amazonaws.com', + ], + ], + }, + 'kms:GrantConstraintType': 'EncryptionContextSubset', + }, + }, + Resource: '*', }, + ], + }, + })); + + + }); + + testFutureBehavior('with future flag aws-kms:defaultKeyPolicies', { '@aws-cdk/aws-kms:defaultKeyPolicies': true }, cdk.App, (app) => { + // GIVEN + const stack = new cdk.Stack(app); + const role = new Role(stack, 'Role', { assumedBy: new AccountRootPrincipal() }); + const encryptionKey = new kms.Key(stack, 'Key'); + const volume = new Volume(stack, 'Volume', { + availabilityZone: 'us-east-1a', + size: cdk.Size.gibibytes(8), + encrypted: true, + encryptionKey, + }); + + // WHEN + volume.grantAttachVolume(role); + + // THEN + cdkExpect(stack).to(haveResourceLike('AWS::IAM::Policy', { + PolicyDocument: { + Statement: arrayWith({ + Effect: 'Allow', Action: 'kms:CreateGrant', Condition: { Bool: { @@ -556,13 +616,19 @@ describe('volume', () => { 'kms:GrantConstraintType': 'EncryptionContextSubset', }, }, - Resource: '*', - }, - ], - }, - })); + Resource: { + 'Fn::GetAtt': [ + 'Key961B73FD', + 'Arn', + ], + }, + }), + }, + })); + }); + }); test('grantAttachVolume to any instance with KMS.fromKeyArn() encryption', () => { diff --git a/packages/@aws-cdk/aws-ecr-assets/package.json b/packages/@aws-cdk/aws-ecr-assets/package.json index be4c4747d2408..3d8b54ee08122 100644 --- a/packages/@aws-cdk/aws-ecr-assets/package.json +++ b/packages/@aws-cdk/aws-ecr-assets/package.json @@ -112,5 +112,8 @@ "env": { "AWSLINT_BASE_CONSTRUCT": true } + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-ecr-assets/test/image-asset.test.ts b/packages/@aws-cdk/aws-ecr-assets/test/image-asset.test.ts index efa1498b41d90..83f27e16a3857 100644 --- a/packages/@aws-cdk/aws-ecr-assets/test/image-asset.test.ts +++ b/packages/@aws-cdk/aws-ecr-assets/test/image-asset.test.ts @@ -5,7 +5,6 @@ import * as iam from '@aws-cdk/aws-iam'; import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import { App, DefaultStackSynthesizer, IgnoreMode, Lazy, LegacyStackSynthesizer, Stack, Stage } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { nodeunitShim, Test } from 'nodeunit-shim'; import { DockerImageAsset } from '../lib'; /* eslint-disable quote-props */ @@ -24,8 +23,8 @@ beforeEach(() => { stack = new Stack(app, 'Stack'); }); -nodeunitShim({ - 'test instantiating Asset Image'(test: Test) { +describe('image asset', () => { + test('test instantiating Asset Image', () => { // WHEN new DockerImageAsset(stack, 'Image', { directory: path.join(__dirname, 'demo-image'), @@ -34,8 +33,8 @@ nodeunitShim({ // THEN const asm = app.synth(); const artifact = asm.getStackArtifact(stack.artifactId); - test.deepEqual(artifact.template, {}, 'template is empty'); - test.deepEqual(artifact.assets, [ + expect(artifact.template).toEqual({}); + expect(artifact.assets).toEqual([ { repositoryName: 'aws-cdk/assets', imageTag: 'b2c69bfbfe983b634456574587443159b3b7258849856a118ad3d2772238f1a5', @@ -45,10 +44,10 @@ nodeunitShim({ sourceHash: 'b2c69bfbfe983b634456574587443159b3b7258849856a118ad3d2772238f1a5', }, ]); - test.done(); - }, - 'with build args'(test: Test) { + }); + + test('with build args', () => { // WHEN new DockerImageAsset(stack, 'Image', { directory: path.join(__dirname, 'demo-image'), @@ -59,11 +58,11 @@ nodeunitShim({ // THEN const assetMetadata = stack.node.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); - test.deepEqual(assetMetadata && (assetMetadata.data as cxschema.ContainerImageAssetMetadataEntry).buildArgs, { a: 'b' }); - test.done(); - }, + expect(assetMetadata && (assetMetadata.data as cxschema.ContainerImageAssetMetadataEntry).buildArgs).toEqual({ a: 'b' }); - 'with target'(test: Test) { + }); + + test('with target', () => { // WHEN new DockerImageAsset(stack, 'Image', { directory: path.join(__dirname, 'demo-image'), @@ -75,11 +74,11 @@ nodeunitShim({ // THEN const assetMetadata = stack.node.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); - test.deepEqual(assetMetadata && (assetMetadata.data as cxschema.ContainerImageAssetMetadataEntry).target, 'a-target'); - test.done(); - }, + expect(assetMetadata && (assetMetadata.data as cxschema.ContainerImageAssetMetadataEntry).target).toEqual('a-target'); + + }); - 'with file'(test: Test) { + test('with file', () => { // GIVEN const directoryPath = path.join(__dirname, 'demo-image-custom-docker-file'); // WHEN @@ -90,11 +89,11 @@ nodeunitShim({ // THEN const assetMetadata = stack.node.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); - test.deepEqual(assetMetadata && (assetMetadata.data as cxschema.ContainerImageAssetMetadataEntry).file, 'Dockerfile.Custom'); - test.done(); - }, + expect(assetMetadata && (assetMetadata.data as cxschema.ContainerImageAssetMetadataEntry).file).toEqual('Dockerfile.Custom'); + + }); - 'asset.repository.grantPull can be used to grant a principal permissions to use the image'(test: Test) { + test('asset.repository.grantPull can be used to grant a principal permissions to use the image', () => { // GIVEN const user = new iam.User(stack, 'MyUser'); const asset = new DockerImageAsset(stack, 'Image', { @@ -152,61 +151,61 @@ nodeunitShim({ ], })); - test.done(); - }, - 'fails if the directory does not exist'(test: Test) { + }); + + test('fails if the directory does not exist', () => { // THEN - test.throws(() => { + expect(() => { new DockerImageAsset(stack, 'MyAsset', { directory: `/does/not/exist/${Math.floor(Math.random() * 9999)}`, }); - }, /Cannot find image directory at/); - test.done(); - }, + }).toThrow(/Cannot find image directory at/); - 'fails if the directory does not contain a Dockerfile'(test: Test) { + }); + + test('fails if the directory does not contain a Dockerfile', () => { // THEN - test.throws(() => { + expect(() => { new DockerImageAsset(stack, 'Asset', { directory: __dirname, }); - }, /Cannot find file at/); - test.done(); - }, + }).toThrow(/Cannot find file at/); - 'fails if the file does not exist'(test: Test) { + }); + + test('fails if the file does not exist', () => { // THEN - test.throws(() => { + expect(() => { new DockerImageAsset(stack, 'Asset', { directory: __dirname, file: 'doesnt-exist', }); - }, /Cannot find file at/); - test.done(); - }, + }).toThrow(/Cannot find file at/); - 'docker directory is staged if asset staging is enabled'(test: Test) { + }); + + test('docker directory is staged if asset staging is enabled', () => { const image = new DockerImageAsset(stack, 'MyAsset', { directory: path.join(__dirname, 'demo-image'), }); const session = app.synth(); - test.ok(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'Dockerfile'))); - test.ok(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'index.py'))); - test.done(); - }, + expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'Dockerfile'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'index.py'))).toBeDefined(); - 'docker directory is staged without files specified in .dockerignore'(test: Test) { - testDockerDirectoryIsStagedWithoutFilesSpecifiedInDockerignore(test); - }, + }); - 'docker directory is staged without files specified in .dockerignore with IgnoreMode.GLOB'(test: Test) { - testDockerDirectoryIsStagedWithoutFilesSpecifiedInDockerignore(test, IgnoreMode.GLOB); - }, + test('docker directory is staged without files specified in .dockerignore', () => { + testDockerDirectoryIsStagedWithoutFilesSpecifiedInDockerignore(); + }); - 'docker directory is staged with whitelisted files specified in .dockerignore'(test: Test) { + test('docker directory is staged without files specified in .dockerignore with IgnoreMode.GLOB', () => { + testDockerDirectoryIsStagedWithoutFilesSpecifiedInDockerignore(IgnoreMode.GLOB); + }); + + test('docker directory is staged with whitelisted files specified in .dockerignore', () => { const image = new DockerImageAsset(stack, 'MyAsset', { directory: path.join(__dirname, 'whitelisted-image'), }); @@ -214,61 +213,61 @@ nodeunitShim({ const session = app.synth(); // Only the files exempted above should be included. - test.ok(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, '.dockerignore'))); - test.ok(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'Dockerfile'))); - test.ok(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'index.py'))); - test.ok(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'foobar.txt'))); - test.ok(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'subdirectory'))); - test.ok(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'subdirectory', 'baz.txt'))); - test.ok(!fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'node_modules'))); - test.ok(!fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'node_modules', 'one'))); - test.ok(!fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'node_modules', 'some_dep'))); - test.ok(!fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'node_modules', 'some_dep', 'file'))); - - test.done(); - }, - - 'docker directory is staged without files specified in exclude option'(test: Test) { - testDockerDirectoryIsStagedWithoutFilesSpecifiedInExcludeOption(test); - }, - - 'docker directory is staged without files specified in exclude option with IgnoreMode.GLOB'(test: Test) { - testDockerDirectoryIsStagedWithoutFilesSpecifiedInExcludeOption(test, IgnoreMode.GLOB); - }, - - 'fails if using tokens in build args keys or values'(test: Test) { + expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, '.dockerignore'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'Dockerfile'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'index.py'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'foobar.txt'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'subdirectory'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'subdirectory', 'baz.txt'))).toBeDefined(); + expect(!fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'node_modules'))).toBeDefined(); + expect(!fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'node_modules', 'one'))).toBeDefined(); + expect(!fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'node_modules', 'some_dep'))).toBeDefined(); + expect(!fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'node_modules', 'some_dep', 'file'))).toBeDefined(); + + + }); + + test('docker directory is staged without files specified in exclude option', () => { + testDockerDirectoryIsStagedWithoutFilesSpecifiedInExcludeOption(); + }); + + test('docker directory is staged without files specified in exclude option with IgnoreMode.GLOB', () => { + testDockerDirectoryIsStagedWithoutFilesSpecifiedInExcludeOption(IgnoreMode.GLOB); + }); + + test('fails if using tokens in build args keys or values', () => { // GIVEN const token = Lazy.string({ produce: () => 'foo' }); const expected = /Cannot use tokens in keys or values of "buildArgs" since they are needed before deployment/; // THEN - test.throws(() => new DockerImageAsset(stack, 'MyAsset1', { + expect(() => new DockerImageAsset(stack, 'MyAsset1', { directory: path.join(__dirname, 'demo-image'), buildArgs: { [token]: 'value' }, - }), expected); + })).toThrow(expected); - test.throws(() => new DockerImageAsset(stack, 'MyAsset2', { + expect(() => new DockerImageAsset(stack, 'MyAsset2', { directory: path.join(__dirname, 'demo-image'), buildArgs: { key: token }, - }), expected); + })).toThrow(expected); - test.done(); - }, - 'fails if using token as repositoryName'(test: Test) { + }); + + test('fails if using token as repositoryName', () => { // GIVEN const token = Lazy.string({ produce: () => 'foo' }); // THEN - test.throws(() => new DockerImageAsset(stack, 'MyAsset1', { + expect(() => new DockerImageAsset(stack, 'MyAsset1', { directory: path.join(__dirname, 'demo-image'), repositoryName: token, - }), /Cannot use Token as value of 'repositoryName'/); + })).toThrow(/Cannot use Token as value of 'repositoryName'/); - test.done(); - }, - 'docker build options are included in the asset id'(test: Test) { + }); + + test('docker build options are included in the asset id', () => { // GIVEN const directory = path.join(__dirname, 'demo-image-custom-docker-file'); @@ -280,18 +279,18 @@ nodeunitShim({ const asset6 = new DockerImageAsset(stack, 'Asset6', { directory, extraHash: 'random-extra' }); const asset7 = new DockerImageAsset(stack, 'Asset7', { directory, repositoryName: 'foo' }); - test.deepEqual(asset1.sourceHash, 'ab01ecd4419f59e1ec0ac9e57a60dbb653be68a29af0223fa8cb24b4b747bc73'); - test.deepEqual(asset2.sourceHash, '7fb12f6148098e3f5c56c788a865d2af689125ead403b795fe6a262ec34384b3'); - test.deepEqual(asset3.sourceHash, 'fc3b6d802ba198ba2ee55079dbef27682bcd1288d5849eb5bbd5cd69038359b3'); - test.deepEqual(asset4.sourceHash, '30439ea6dfeb4ddfd9175097286895c78393ef52a78c68f92db08abc4513cad6'); - test.deepEqual(asset5.sourceHash, '5775170880e26ba31799745241b90d4340c674bb3b1c01d758e416ee3f1c386f'); - test.deepEqual(asset6.sourceHash, 'ba82fd351a4d3e3f5c5d948b9948e7e829badc3da90f97e00bb7724afbeacfd4'); - test.deepEqual(asset7.sourceHash, '26ec194928431cab6ec5af24ea9f01af2cf7b20e361128b07b2a7405d2951f95'); - test.done(); - }, + expect(asset1.sourceHash).toEqual('ab01ecd4419f59e1ec0ac9e57a60dbb653be68a29af0223fa8cb24b4b747bc73'); + expect(asset2.sourceHash).toEqual('7fb12f6148098e3f5c56c788a865d2af689125ead403b795fe6a262ec34384b3'); + expect(asset3.sourceHash).toEqual('fc3b6d802ba198ba2ee55079dbef27682bcd1288d5849eb5bbd5cd69038359b3'); + expect(asset4.sourceHash).toEqual('30439ea6dfeb4ddfd9175097286895c78393ef52a78c68f92db08abc4513cad6'); + expect(asset5.sourceHash).toEqual('5775170880e26ba31799745241b90d4340c674bb3b1c01d758e416ee3f1c386f'); + expect(asset6.sourceHash).toEqual('ba82fd351a4d3e3f5c5d948b9948e7e829badc3da90f97e00bb7724afbeacfd4'); + expect(asset7.sourceHash).toEqual('26ec194928431cab6ec5af24ea9f01af2cf7b20e361128b07b2a7405d2951f95'); + + }); }); -function testDockerDirectoryIsStagedWithoutFilesSpecifiedInDockerignore(test: Test, ignoreMode?: IgnoreMode) { +function testDockerDirectoryIsStagedWithoutFilesSpecifiedInDockerignore(ignoreMode?: IgnoreMode) { const image = new DockerImageAsset(stack, 'MyAsset', { ignoreMode, directory: path.join(__dirname, 'dockerignore-image'), @@ -300,17 +299,17 @@ function testDockerDirectoryIsStagedWithoutFilesSpecifiedInDockerignore(test: Te const session = app.synth(); // .dockerignore itself should be included in output to be processed during docker build - test.ok(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, '.dockerignore'))); - test.ok(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'Dockerfile'))); - test.ok(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'index.py'))); - test.ok(!fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'foobar.txt'))); - test.ok(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'subdirectory'))); - test.ok(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'subdirectory', 'baz.txt'))); - - test.done(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, '.dockerignore'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'Dockerfile'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'index.py'))).toBeDefined(); + expect(!fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'foobar.txt'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'subdirectory'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'subdirectory', 'baz.txt'))).toBeDefined(); + + } -function testDockerDirectoryIsStagedWithoutFilesSpecifiedInExcludeOption(test: Test, ignoreMode?: IgnoreMode) { +function testDockerDirectoryIsStagedWithoutFilesSpecifiedInExcludeOption(ignoreMode?: IgnoreMode) { const image = new DockerImageAsset(stack, 'MyAsset', { directory: path.join(__dirname, 'dockerignore-image'), exclude: ['subdirectory'], @@ -319,14 +318,14 @@ function testDockerDirectoryIsStagedWithoutFilesSpecifiedInExcludeOption(test: T const session = app.synth(); - test.ok(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, '.dockerignore'))); - test.ok(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'Dockerfile'))); - test.ok(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'index.py'))); - test.ok(!fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'foobar.txt'))); - test.ok(!fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'subdirectory'))); - test.ok(!fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'subdirectory', 'baz.txt'))); + expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, '.dockerignore'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'Dockerfile'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'index.py'))).toBeDefined(); + expect(!fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'foobar.txt'))).toBeDefined(); + expect(!fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'subdirectory'))).toBeDefined(); + expect(!fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'subdirectory', 'baz.txt'))).toBeDefined(); + - test.done(); } test('nested assemblies share assets: legacy synth edition', () => { diff --git a/packages/@aws-cdk/aws-ecr-assets/test/integ.nested-stacks-docker.expected.json b/packages/@aws-cdk/aws-ecr-assets/test/integ.nested-stacks-docker.expected.json index 779ad22187591..f86d0e5fea7ab 100644 --- a/packages/@aws-cdk/aws-ecr-assets/test/integ.nested-stacks-docker.expected.json +++ b/packages/@aws-cdk/aws-ecr-assets/test/integ.nested-stacks-docker.expected.json @@ -49,7 +49,9 @@ ] ] } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Parameters": { @@ -66,4 +68,4 @@ "Description": "Artifact hash for asset \"41589ef1a760129e41441e85e58fe02db5f019ed532b8a4a20729f3245b0593b\"" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecr/package.json b/packages/@aws-cdk/aws-ecr/package.json index c51fefa8ce7b4..95a78ae04c522 100644 --- a/packages/@aws-cdk/aws-ecr/package.json +++ b/packages/@aws-cdk/aws-ecr/package.json @@ -117,5 +117,8 @@ "maturity": "stable", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-ecs-patterns/README.md b/packages/@aws-cdk/aws-ecs-patterns/README.md index 38915031f4346..12f56a2b70102 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/README.md +++ b/packages/@aws-cdk/aws-ecs-patterns/README.md @@ -305,6 +305,7 @@ const ecsScheduledTask = new ScheduledEc2Task(stack, 'ScheduledTask', { environment: { name: 'TRIGGER', value: 'CloudWatch Events' }, }, schedule: events.Schedule.expression('rate(1 minute)'), + enabled: true, ruleName: 'sample-scheduled-task-rule' }); ``` @@ -393,6 +394,7 @@ const loadBalancedFargateService = new ApplicationLoadBalancedFargateService(sta }); ``` + ### Set deployment configuration on QueueProcessingService ```ts @@ -411,6 +413,29 @@ const queueProcessingFargateService = new QueueProcessingFargateService(stack, ' }); ``` +### Set taskSubnets and securityGroups for QueueProcessingFargateService + +```ts +const queueProcessingFargateService = new QueueProcessingFargateService(stack, 'Service', { + vpc, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + securityGroups: [securityGroup], + taskSubnets: { subnetType: ec2.SubnetType.ISOLATED }, +}); +``` + +### Define tasks with public IPs for QueueProcessingFargateService + +```ts +const queueProcessingFargateService = new QueueProcessingFargateService(stack, 'Service', { + vpc, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + assignPublicIp: true, +}); +``` + ### Select specific vpc subnets for ApplicationLoadBalancedFargateService ```ts diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/scheduled-task-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/scheduled-task-base.ts index 38ac4e30a79af..7dc6492f42919 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/scheduled-task-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/scheduled-task-base.ts @@ -38,6 +38,13 @@ export interface ScheduledTaskBaseProps { */ readonly schedule: Schedule; + /** + * Indicates whether the rule is enabled. + * + * @default true + */ + readonly enabled?: boolean; + /** * A name for the rule. * @@ -148,6 +155,7 @@ export abstract class ScheduledTaskBase extends CoreConstruct { this.eventRule = new Rule(this, 'ScheduledEventRule', { schedule: props.schedule, ruleName: props.ruleName, + enabled: props.enabled, }); } diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/queue-processing-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/queue-processing-fargate-service.ts index 68d0278c3e203..e3712b00ae4b1 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/queue-processing-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/queue-processing-fargate-service.ts @@ -1,3 +1,4 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; import { FargatePlatformVersion, FargateService, FargateTaskDefinition } from '@aws-cdk/aws-ecs'; import { Construct } from 'constructs'; import { QueueProcessingServiceBase, QueueProcessingServiceBaseProps } from '../base/queue-processing-service-base'; @@ -66,6 +67,29 @@ export interface QueueProcessingFargateServiceProps extends QueueProcessingServi * @default - QueueProcessingContainer */ readonly containerName?: string; + + /** + * The subnets to associate with the service. + * + * @default - Public subnets if `assignPublicIp` is set, otherwise the first available one of Private, Isolated, Public, in that order. + */ + readonly taskSubnets?: ec2.SubnetSelection; + + /** + * The security groups to associate with the service. If you do not specify a security group, the default security group for the VPC is used. + * + * @default - A new security group is created. + */ + readonly securityGroups?: ec2.ISecurityGroup[]; + + /** + * Specifies whether the task's elastic network interface receives a public IP address. + * + * If true, each task will receive a public IP address. + * + * @default false + */ + readonly assignPublicIp?: boolean; } /** @@ -117,6 +141,9 @@ export class QueueProcessingFargateService extends QueueProcessingServiceBase { enableECSManagedTags: props.enableECSManagedTags, platformVersion: props.platformVersion, deploymentController: props.deploymentController, + securityGroups: props.securityGroups, + vpcSubnets: props.taskSubnets, + assignPublicIp: props.assignPublicIp, }); this.configureAutoscalingForService(this.service); this.grantPermissionsToService(this.service); diff --git a/packages/@aws-cdk/aws-ecs-patterns/package.json b/packages/@aws-cdk/aws-ecs-patterns/package.json index c455df841fbae..bc2a816cd6b11 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/package.json +++ b/packages/@aws-cdk/aws-ecs-patterns/package.json @@ -125,5 +125,8 @@ "env": { "AWSLINT_BASE_CONSTRUCT": true } + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.scheduled-ecs-task.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.scheduled-ecs-task.ts index d96c8cd2edc7d..af262cd5de5ef 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.scheduled-ecs-task.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.scheduled-ecs-task.ts @@ -27,6 +27,7 @@ export = { // THEN expect(stack).to(haveResource('AWS::Events::Rule', { + State: 'ENABLED', Targets: [ { Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, @@ -78,6 +79,7 @@ export = { new ScheduledEc2Task(stack, 'ScheduledEc2Task', { cluster, + enabled: false, scheduledEc2TaskImageOptions: { image: ecs.ContainerImage.fromRegistry('henk'), memoryLimitMiB: 512, @@ -92,6 +94,7 @@ export = { // THEN expect(stack).to(haveResource('AWS::Events::Rule', { Name: 'sample-scheduled-task-rule', + State: 'DISABLED', Targets: [ { Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-isolated.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-isolated.expected.json new file mode 100644 index 0000000000000..b1d88ed107154 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-isolated.expected.json @@ -0,0 +1,1205 @@ +{ + "Resources": { + "VPCB9E5F0B4": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-isolated/VPC" + } + ] + } + }, + "VPCPublicSubnet1SubnetB4246D30": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/24", + "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-ecs-patterns-queue-isolated/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1RouteTableFEE4B781": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-isolated/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" + ] + }, + "VPCPublicSubnet2Subnet74179F39": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.1.0/24", + "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-ecs-patterns-queue-isolated/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2RouteTable6F1A15F1": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-isolated/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" + ] + }, + "VPCIsolatedSubnet1SubnetEBD00FC6": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.2.0/24", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Isolated" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Isolated" + }, + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-isolated/VPC/IsolatedSubnet1" + } + ] + } + }, + "VPCIsolatedSubnet1RouteTableEB156210": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-isolated/VPC/IsolatedSubnet1" + } + ] + } + }, + "VPCIsolatedSubnet1RouteTableAssociationA2D18F7C": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCIsolatedSubnet1RouteTableEB156210" + }, + "SubnetId": { + "Ref": "VPCIsolatedSubnet1SubnetEBD00FC6" + } + } + }, + "VPCIsolatedSubnet2Subnet4B1C8CAA": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.3.0/24", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Isolated" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Isolated" + }, + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-isolated/VPC/IsolatedSubnet2" + } + ] + } + }, + "VPCIsolatedSubnet2RouteTable9B4F78DC": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-isolated/VPC/IsolatedSubnet2" + } + ] + } + }, + "VPCIsolatedSubnet2RouteTableAssociation7BF8E0EB": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCIsolatedSubnet2RouteTable9B4F78DC" + }, + "SubnetId": { + "Ref": "VPCIsolatedSubnet2Subnet4B1C8CAA" + } + } + }, + "VPCIGWB7E252D3": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-isolated/VPC" + } + ] + } + }, + "VPCVPCGW99B986DC": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "InternetGatewayId": { + "Ref": "VPCIGWB7E252D3" + } + } + }, + "VPCS3Endpoint18C9C7CA": { + "Type": "AWS::EC2::VPCEndpoint", + "Properties": { + "ServiceName": { + "Fn::Join": [ + "", + [ + "com.amazonaws.", + { + "Ref": "AWS::Region" + }, + ".s3" + ] + ] + }, + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "RouteTableIds": [ + { + "Ref": "VPCIsolatedSubnet1RouteTableEB156210" + }, + { + "Ref": "VPCIsolatedSubnet2RouteTable9B4F78DC" + } + ], + "VpcEndpointType": "Gateway" + } + }, + "VPCSqsEndpointSecurityGroupAE06A78D": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-patterns-queue-isolated/VPC/SqsEndpoint/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "SecurityGroupIngress": [ + { + "CidrIp": { + "Fn::GetAtt": [ + "VPCB9E5F0B4", + "CidrBlock" + ] + }, + "Description": { + "Fn::Join": [ + "", + [ + "from ", + { + "Fn::GetAtt": [ + "VPCB9E5F0B4", + "CidrBlock" + ] + }, + ":443" + ] + ] + }, + "FromPort": 443, + "IpProtocol": "tcp", + "ToPort": 443 + } + ], + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-isolated/VPC" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCSqsEndpoint9A40D77F": { + "Type": "AWS::EC2::VPCEndpoint", + "Properties": { + "ServiceName": { + "Fn::Join": [ + "", + [ + "com.amazonaws.", + { + "Ref": "AWS::Region" + }, + ".sqs" + ] + ] + }, + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "PrivateDnsEnabled": true, + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "VPCSqsEndpointSecurityGroupAE06A78D", + "GroupId" + ] + } + ], + "SubnetIds": [ + { + "Ref": "VPCIsolatedSubnet1SubnetEBD00FC6" + }, + { + "Ref": "VPCIsolatedSubnet2Subnet4B1C8CAA" + } + ], + "VpcEndpointType": "Interface" + } + }, + "VPCEcrEndpointSecurityGroup50ED8BA4": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-patterns-queue-isolated/VPC/EcrEndpoint/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "SecurityGroupIngress": [ + { + "CidrIp": { + "Fn::GetAtt": [ + "VPCB9E5F0B4", + "CidrBlock" + ] + }, + "Description": { + "Fn::Join": [ + "", + [ + "from ", + { + "Fn::GetAtt": [ + "VPCB9E5F0B4", + "CidrBlock" + ] + }, + ":443" + ] + ] + }, + "FromPort": 443, + "IpProtocol": "tcp", + "ToPort": 443 + } + ], + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-isolated/VPC" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCEcrEndpointB4F98F37": { + "Type": "AWS::EC2::VPCEndpoint", + "Properties": { + "ServiceName": { + "Fn::Join": [ + "", + [ + "com.amazonaws.", + { + "Ref": "AWS::Region" + }, + ".ecr.api" + ] + ] + }, + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "PrivateDnsEnabled": true, + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "VPCEcrEndpointSecurityGroup50ED8BA4", + "GroupId" + ] + } + ], + "SubnetIds": [ + { + "Ref": "VPCIsolatedSubnet1SubnetEBD00FC6" + }, + { + "Ref": "VPCIsolatedSubnet2Subnet4B1C8CAA" + } + ], + "VpcEndpointType": "Interface" + } + }, + "VPCEcrImageEndpointSecurityGroup83621638": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-patterns-queue-isolated/VPC/EcrImageEndpoint/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "SecurityGroupIngress": [ + { + "CidrIp": { + "Fn::GetAtt": [ + "VPCB9E5F0B4", + "CidrBlock" + ] + }, + "Description": { + "Fn::Join": [ + "", + [ + "from ", + { + "Fn::GetAtt": [ + "VPCB9E5F0B4", + "CidrBlock" + ] + }, + ":443" + ] + ] + }, + "FromPort": 443, + "IpProtocol": "tcp", + "ToPort": 443 + } + ], + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-isolated/VPC" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCEcrImageEndpointD55381DC": { + "Type": "AWS::EC2::VPCEndpoint", + "Properties": { + "ServiceName": { + "Fn::Join": [ + "", + [ + "com.amazonaws.", + { + "Ref": "AWS::Region" + }, + ".ecr.dkr" + ] + ] + }, + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "PrivateDnsEnabled": true, + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "VPCEcrImageEndpointSecurityGroup83621638", + "GroupId" + ] + } + ], + "SubnetIds": [ + { + "Ref": "VPCIsolatedSubnet1SubnetEBD00FC6" + }, + { + "Ref": "VPCIsolatedSubnet2Subnet4B1C8CAA" + } + ], + "VpcEndpointType": "Interface" + } + }, + "VPCCloudWatchLogsEndpointSecurityGroup967DBC94": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-patterns-queue-isolated/VPC/CloudWatchLogsEndpoint/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "SecurityGroupIngress": [ + { + "CidrIp": { + "Fn::GetAtt": [ + "VPCB9E5F0B4", + "CidrBlock" + ] + }, + "Description": { + "Fn::Join": [ + "", + [ + "from ", + { + "Fn::GetAtt": [ + "VPCB9E5F0B4", + "CidrBlock" + ] + }, + ":443" + ] + ] + }, + "FromPort": 443, + "IpProtocol": "tcp", + "ToPort": 443 + } + ], + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-isolated/VPC" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCCloudWatchLogsEndpointE175AF65": { + "Type": "AWS::EC2::VPCEndpoint", + "Properties": { + "ServiceName": { + "Fn::Join": [ + "", + [ + "com.amazonaws.", + { + "Ref": "AWS::Region" + }, + ".logs" + ] + ] + }, + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "PrivateDnsEnabled": true, + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "VPCCloudWatchLogsEndpointSecurityGroup967DBC94", + "GroupId" + ] + } + ], + "SubnetIds": [ + { + "Ref": "VPCIsolatedSubnet1SubnetEBD00FC6" + }, + { + "Ref": "VPCIsolatedSubnet2Subnet4B1C8CAA" + } + ], + "VpcEndpointType": "Interface" + } + }, + "MyCustomSGDE27C661": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-patterns-queue-isolated/MyCustomSG", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "IsolatedQueueServiceEcsProcessingDeadLetterQueue7CC1D07D": { + "Type": "AWS::SQS::Queue", + "Properties": { + "MessageRetentionPeriod": 1209600 + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "IsolatedQueueServiceEcsProcessingQueueCCE172F1": { + "Type": "AWS::SQS::Queue", + "Properties": { + "RedrivePolicy": { + "deadLetterTargetArn": { + "Fn::GetAtt": [ + "IsolatedQueueServiceEcsProcessingDeadLetterQueue7CC1D07D", + "Arn" + ] + }, + "maxReceiveCount": 3 + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "IsolatedQueueServiceQueueProcessingTaskDefTaskRoleCFCB7511": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "IsolatedQueueServiceQueueProcessingTaskDefTaskRoleDefaultPolicyD52E156B": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "sqs:ReceiveMessage", + "sqs:ChangeMessageVisibility", + "sqs:GetQueueUrl", + "sqs:DeleteMessage", + "sqs:GetQueueAttributes" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "IsolatedQueueServiceEcsProcessingQueueCCE172F1", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "IsolatedQueueServiceQueueProcessingTaskDefTaskRoleDefaultPolicyD52E156B", + "Roles": [ + { + "Ref": "IsolatedQueueServiceQueueProcessingTaskDefTaskRoleCFCB7511" + } + ] + } + }, + "IsolatedQueueServiceQueueProcessingTaskDef0F0CE105": { + "Type": "AWS::ECS::TaskDefinition", + "Properties": { + "ContainerDefinitions": [ + { + "Environment": [ + { + "Name": "QUEUE_NAME", + "Value": { + "Fn::GetAtt": [ + "IsolatedQueueServiceEcsProcessingQueueCCE172F1", + "QueueName" + ] + } + } + ], + "Essential": true, + "Image": { + "Fn::Join": [ + "", + [ + { + "Ref": "AWS::AccountId" + }, + ".dkr.ecr.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/aws-cdk/assets:3a8ba3ad06ed212b075efa3157fb407649c5996812bc64eeb5209e220aab4be5" + ] + ] + }, + "LogConfiguration": { + "LogDriver": "awslogs", + "Options": { + "awslogs-group": { + "Ref": "IsolatedQueueServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupAEB959E6" + }, + "awslogs-stream-prefix": "IsolatedQueueService", + "awslogs-region": { + "Ref": "AWS::Region" + } + } + }, + "Name": "QueueProcessingContainer" + } + ], + "Cpu": "256", + "ExecutionRoleArn": { + "Fn::GetAtt": [ + "IsolatedQueueServiceQueueProcessingTaskDefExecutionRole1D7ACC77", + "Arn" + ] + }, + "Family": "awsecspatternsqueueisolatedIsolatedQueueServiceQueueProcessingTaskDef27DBAF49", + "Memory": "512", + "NetworkMode": "awsvpc", + "RequiresCompatibilities": [ + "FARGATE" + ], + "TaskRoleArn": { + "Fn::GetAtt": [ + "IsolatedQueueServiceQueueProcessingTaskDefTaskRoleCFCB7511", + "Arn" + ] + } + } + }, + "IsolatedQueueServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupAEB959E6": { + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "IsolatedQueueServiceQueueProcessingTaskDefExecutionRole1D7ACC77": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "IsolatedQueueServiceQueueProcessingTaskDefExecutionRoleDefaultPolicy5667D265": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ecr:BatchCheckLayerAvailability", + "ecr:GetDownloadUrlForLayer", + "ecr:BatchGetImage" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":ecr:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":repository/aws-cdk/assets" + ] + ] + } + }, + { + "Action": "ecr:GetAuthorizationToken", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "IsolatedQueueServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupAEB959E6", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "IsolatedQueueServiceQueueProcessingTaskDefExecutionRoleDefaultPolicy5667D265", + "Roles": [ + { + "Ref": "IsolatedQueueServiceQueueProcessingTaskDefExecutionRole1D7ACC77" + } + ] + } + }, + "IsolatedQueueServiceQueueProcessingFargateServiceE868AEE1": { + "Type": "AWS::ECS::Service", + "Properties": { + "Cluster": { + "Ref": "EcsDefaultClusterMnL3mNNYNVPC9C1EC7A3" + }, + "DeploymentConfiguration": { + "MaximumPercent": 200, + "MinimumHealthyPercent": 50 + }, + "DesiredCount": 1, + "EnableECSManagedTags": false, + "LaunchType": "FARGATE", + "NetworkConfiguration": { + "AwsvpcConfiguration": { + "AssignPublicIp": "DISABLED", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "MyCustomSGDE27C661", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "VPCIsolatedSubnet1SubnetEBD00FC6" + }, + { + "Ref": "VPCIsolatedSubnet2Subnet4B1C8CAA" + } + ] + } + }, + "TaskDefinition": { + "Ref": "IsolatedQueueServiceQueueProcessingTaskDef0F0CE105" + } + }, + "DependsOn": [ + "VPCCloudWatchLogsEndpointE175AF65", + "VPCCloudWatchLogsEndpointSecurityGroup967DBC94", + "VPCEcrEndpointB4F98F37", + "VPCEcrEndpointSecurityGroup50ED8BA4", + "VPCEcrImageEndpointD55381DC", + "VPCEcrImageEndpointSecurityGroup83621638", + "VPCSqsEndpoint9A40D77F", + "VPCSqsEndpointSecurityGroupAE06A78D" + ] + }, + "IsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetB06FD17D": { + "Type": "AWS::ApplicationAutoScaling::ScalableTarget", + "Properties": { + "MaxCapacity": 2, + "MinCapacity": 1, + "ResourceId": { + "Fn::Join": [ + "", + [ + "service/", + { + "Ref": "EcsDefaultClusterMnL3mNNYNVPC9C1EC7A3" + }, + "/", + { + "Fn::GetAtt": [ + "IsolatedQueueServiceQueueProcessingFargateServiceE868AEE1", + "Name" + ] + } + ] + ] + }, + "RoleARN": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService" + ] + ] + }, + "ScalableDimension": "ecs:service:DesiredCount", + "ServiceNamespace": "ecs" + }, + "DependsOn": [ + "VPCCloudWatchLogsEndpointE175AF65", + "VPCCloudWatchLogsEndpointSecurityGroup967DBC94", + "VPCEcrEndpointB4F98F37", + "VPCEcrEndpointSecurityGroup50ED8BA4", + "VPCEcrImageEndpointD55381DC", + "VPCEcrImageEndpointSecurityGroup83621638", + "VPCSqsEndpoint9A40D77F", + "VPCSqsEndpointSecurityGroupAE06A78D" + ] + }, + "IsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetCpuScaling2B518D9D": { + "Type": "AWS::ApplicationAutoScaling::ScalingPolicy", + "Properties": { + "PolicyName": "awsecspatternsqueueisolatedIsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetCpuScaling8B2FB6C4", + "PolicyType": "TargetTrackingScaling", + "ScalingTargetId": { + "Ref": "IsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetB06FD17D" + }, + "TargetTrackingScalingPolicyConfiguration": { + "PredefinedMetricSpecification": { + "PredefinedMetricType": "ECSServiceAverageCPUUtilization" + }, + "TargetValue": 50 + } + }, + "DependsOn": [ + "VPCCloudWatchLogsEndpointE175AF65", + "VPCCloudWatchLogsEndpointSecurityGroup967DBC94", + "VPCEcrEndpointB4F98F37", + "VPCEcrEndpointSecurityGroup50ED8BA4", + "VPCEcrImageEndpointD55381DC", + "VPCEcrImageEndpointSecurityGroup83621638", + "VPCSqsEndpoint9A40D77F", + "VPCSqsEndpointSecurityGroupAE06A78D" + ] + }, + "IsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingLowerPolicy960D4BA1": { + "Type": "AWS::ApplicationAutoScaling::ScalingPolicy", + "Properties": { + "PolicyName": "awsecspatternsqueueisolatedIsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingLowerPolicy5EFC8D1B", + "PolicyType": "StepScaling", + "ScalingTargetId": { + "Ref": "IsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetB06FD17D" + }, + "StepScalingPolicyConfiguration": { + "AdjustmentType": "ChangeInCapacity", + "MetricAggregationType": "Maximum", + "StepAdjustments": [ + { + "MetricIntervalUpperBound": 0, + "ScalingAdjustment": -1 + } + ] + } + }, + "DependsOn": [ + "VPCCloudWatchLogsEndpointE175AF65", + "VPCCloudWatchLogsEndpointSecurityGroup967DBC94", + "VPCEcrEndpointB4F98F37", + "VPCEcrEndpointSecurityGroup50ED8BA4", + "VPCEcrImageEndpointD55381DC", + "VPCEcrImageEndpointSecurityGroup83621638", + "VPCSqsEndpoint9A40D77F", + "VPCSqsEndpointSecurityGroupAE06A78D" + ] + }, + "IsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingLowerAlarm88D1A0F9": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "LessThanOrEqualToThreshold", + "EvaluationPeriods": 1, + "AlarmActions": [ + { + "Ref": "IsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingLowerPolicy960D4BA1" + } + ], + "AlarmDescription": "Lower threshold scaling alarm", + "Dimensions": [ + { + "Name": "QueueName", + "Value": { + "Fn::GetAtt": [ + "IsolatedQueueServiceEcsProcessingQueueCCE172F1", + "QueueName" + ] + } + } + ], + "MetricName": "ApproximateNumberOfMessagesVisible", + "Namespace": "AWS/SQS", + "Period": 300, + "Statistic": "Maximum", + "Threshold": 0 + }, + "DependsOn": [ + "VPCCloudWatchLogsEndpointE175AF65", + "VPCCloudWatchLogsEndpointSecurityGroup967DBC94", + "VPCEcrEndpointB4F98F37", + "VPCEcrEndpointSecurityGroup50ED8BA4", + "VPCEcrImageEndpointD55381DC", + "VPCEcrImageEndpointSecurityGroup83621638", + "VPCSqsEndpoint9A40D77F", + "VPCSqsEndpointSecurityGroupAE06A78D" + ] + }, + "IsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingUpperPolicyFAB35025": { + "Type": "AWS::ApplicationAutoScaling::ScalingPolicy", + "Properties": { + "PolicyName": "awsecspatternsqueueisolatedIsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingUpperPolicy51E582BF", + "PolicyType": "StepScaling", + "ScalingTargetId": { + "Ref": "IsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetB06FD17D" + }, + "StepScalingPolicyConfiguration": { + "AdjustmentType": "ChangeInCapacity", + "MetricAggregationType": "Maximum", + "StepAdjustments": [ + { + "MetricIntervalLowerBound": 0, + "MetricIntervalUpperBound": 400, + "ScalingAdjustment": 1 + }, + { + "MetricIntervalLowerBound": 400, + "ScalingAdjustment": 5 + } + ] + } + }, + "DependsOn": [ + "VPCCloudWatchLogsEndpointE175AF65", + "VPCCloudWatchLogsEndpointSecurityGroup967DBC94", + "VPCEcrEndpointB4F98F37", + "VPCEcrEndpointSecurityGroup50ED8BA4", + "VPCEcrImageEndpointD55381DC", + "VPCEcrImageEndpointSecurityGroup83621638", + "VPCSqsEndpoint9A40D77F", + "VPCSqsEndpointSecurityGroupAE06A78D" + ] + }, + "IsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingUpperAlarm351987F5": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "EvaluationPeriods": 1, + "AlarmActions": [ + { + "Ref": "IsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingUpperPolicyFAB35025" + } + ], + "AlarmDescription": "Upper threshold scaling alarm", + "Dimensions": [ + { + "Name": "QueueName", + "Value": { + "Fn::GetAtt": [ + "IsolatedQueueServiceEcsProcessingQueueCCE172F1", + "QueueName" + ] + } + } + ], + "MetricName": "ApproximateNumberOfMessagesVisible", + "Namespace": "AWS/SQS", + "Period": 300, + "Statistic": "Maximum", + "Threshold": 100 + }, + "DependsOn": [ + "VPCCloudWatchLogsEndpointE175AF65", + "VPCCloudWatchLogsEndpointSecurityGroup967DBC94", + "VPCEcrEndpointB4F98F37", + "VPCEcrEndpointSecurityGroup50ED8BA4", + "VPCEcrImageEndpointD55381DC", + "VPCEcrImageEndpointSecurityGroup83621638", + "VPCSqsEndpoint9A40D77F", + "VPCSqsEndpointSecurityGroupAE06A78D" + ] + }, + "EcsDefaultClusterMnL3mNNYNVPC9C1EC7A3": { + "Type": "AWS::ECS::Cluster" + } + }, + "Outputs": { + "IsolatedQueueServiceSQSDeadLetterQueue43D346B9": { + "Value": { + "Fn::GetAtt": [ + "IsolatedQueueServiceEcsProcessingDeadLetterQueue7CC1D07D", + "QueueName" + ] + } + }, + "IsolatedQueueServiceSQSDeadLetterQueueArnCE7C60F2": { + "Value": { + "Fn::GetAtt": [ + "IsolatedQueueServiceEcsProcessingDeadLetterQueue7CC1D07D", + "Arn" + ] + } + }, + "IsolatedQueueServiceSQSQueueA65E2641": { + "Value": { + "Fn::GetAtt": [ + "IsolatedQueueServiceEcsProcessingQueueCCE172F1", + "QueueName" + ] + } + }, + "IsolatedQueueServiceSQSQueueArn571FDB86": { + "Value": { + "Fn::GetAtt": [ + "IsolatedQueueServiceEcsProcessingQueueCCE172F1", + "Arn" + ] + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-isolated.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-isolated.ts new file mode 100644 index 0000000000000..f985ac8c9d564 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-isolated.ts @@ -0,0 +1,56 @@ +import * as path from 'path'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecs from '@aws-cdk/aws-ecs'; +import { App, Stack } from '@aws-cdk/core'; + +import { QueueProcessingFargateService } from '../../lib'; + +const app = new App(); +const stack = new Stack(app, 'aws-ecs-patterns-queue-isolated'); +const vpc = new ec2.Vpc(stack, 'VPC', { + maxAzs: 2, + subnetConfiguration: [ + { + cidrMask: 24, + name: 'Public', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'Isolated', + subnetType: ec2.SubnetType.ISOLATED, + }, + ], +}); + + +vpc.addS3Endpoint('S3Endpoint', [{ subnetType: ec2.SubnetType.ISOLATED }]); + +const securityGroup = new ec2.SecurityGroup(stack, 'MyCustomSG', { + vpc, +}); + +const queueProcessing = new QueueProcessingFargateService(stack, 'IsolatedQueueService', { + vpc, + memoryLimitMiB: 512, + image: new ecs.AssetImage(path.join(__dirname, '..', 'sqs-reader')), + securityGroups: [securityGroup], + taskSubnets: { subnetType: ec2.SubnetType.ISOLATED }, +}); + +queueProcessing.service.node.addDependency( + vpc.addInterfaceEndpoint('SqsEndpoint', { + service: ec2.InterfaceVpcEndpointAwsService.SQS, + }), + vpc.addInterfaceEndpoint('EcrEndpoint', { + service: ec2.InterfaceVpcEndpointAwsService.ECR, + }), + vpc.addInterfaceEndpoint('EcrImageEndpoint', { + service: ec2.InterfaceVpcEndpointAwsService.ECR_DOCKER, + }), + vpc.addInterfaceEndpoint('CloudWatchLogsEndpoint', { + service: ec2.InterfaceVpcEndpointAwsService.CLOUDWATCH_LOGS, + }), +); + +app.synth(); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-public.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-public.expected.json new file mode 100644 index 0000000000000..fd8f791e3a868 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-public.expected.json @@ -0,0 +1,1004 @@ +{ + "Resources": { + "VPCB9E5F0B4": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-public/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-ecs-patterns-queue-public/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1RouteTableFEE4B781": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-public/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-ecs-patterns-queue-public/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1NATGatewayE0556630": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet1EIP6AD938E8", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-public/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-ecs-patterns-queue-public/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2RouteTable6F1A15F1": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-public/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-ecs-patterns-queue-public/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2NATGateway3C070193": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet2EIP4947BC00", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-public/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-ecs-patterns-queue-public/VPC/PublicSubnet3" + } + ] + } + }, + "VPCPublicSubnet3RouteTable98AE0E14": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-public/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-ecs-patterns-queue-public/VPC/PublicSubnet3" + } + ] + } + }, + "VPCPublicSubnet3NATGatewayD3048F5C": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet3EIPAD4BC883", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-public/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-ecs-patterns-queue-public/VPC/PrivateSubnet1" + } + ] + } + }, + "VPCPrivateSubnet1RouteTableBE8A6027": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-public/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-ecs-patterns-queue-public/VPC/PrivateSubnet2" + } + ] + } + }, + "VPCPrivateSubnet2RouteTable0A19E10E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-public/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-ecs-patterns-queue-public/VPC/PrivateSubnet3" + } + ] + } + }, + "VPCPrivateSubnet3RouteTable192186F8": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-public/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-ecs-patterns-queue-public/VPC" + } + ] + } + }, + "VPCVPCGW99B986DC": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "InternetGatewayId": { + "Ref": "VPCIGWB7E252D3" + } + } + }, + "PublicQueueServiceEcsProcessingDeadLetterQueueBC492277": { + "Type": "AWS::SQS::Queue", + "Properties": { + "MessageRetentionPeriod": 1209600 + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "PublicQueueServiceEcsProcessingQueue84CD309D": { + "Type": "AWS::SQS::Queue", + "Properties": { + "RedrivePolicy": { + "deadLetterTargetArn": { + "Fn::GetAtt": [ + "PublicQueueServiceEcsProcessingDeadLetterQueueBC492277", + "Arn" + ] + }, + "maxReceiveCount": 3 + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "PublicQueueServiceQueueProcessingTaskDefTaskRole172D980F": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "PublicQueueServiceQueueProcessingTaskDefTaskRoleDefaultPolicy5417957C": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "sqs:ReceiveMessage", + "sqs:ChangeMessageVisibility", + "sqs:GetQueueUrl", + "sqs:DeleteMessage", + "sqs:GetQueueAttributes" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "PublicQueueServiceEcsProcessingQueue84CD309D", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PublicQueueServiceQueueProcessingTaskDefTaskRoleDefaultPolicy5417957C", + "Roles": [ + { + "Ref": "PublicQueueServiceQueueProcessingTaskDefTaskRole172D980F" + } + ] + } + }, + "PublicQueueServiceQueueProcessingTaskDef858327F6": { + "Type": "AWS::ECS::TaskDefinition", + "Properties": { + "ContainerDefinitions": [ + { + "Environment": [ + { + "Name": "QUEUE_NAME", + "Value": { + "Fn::GetAtt": [ + "PublicQueueServiceEcsProcessingQueue84CD309D", + "QueueName" + ] + } + } + ], + "Essential": true, + "Image": { + "Fn::Join": [ + "", + [ + { + "Ref": "AWS::AccountId" + }, + ".dkr.ecr.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/aws-cdk/assets:3a8ba3ad06ed212b075efa3157fb407649c5996812bc64eeb5209e220aab4be5" + ] + ] + }, + "LogConfiguration": { + "LogDriver": "awslogs", + "Options": { + "awslogs-group": { + "Ref": "PublicQueueServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupCFF67B64" + }, + "awslogs-stream-prefix": "PublicQueueService", + "awslogs-region": { + "Ref": "AWS::Region" + } + } + }, + "Name": "QueueProcessingContainer" + } + ], + "Cpu": "256", + "ExecutionRoleArn": { + "Fn::GetAtt": [ + "PublicQueueServiceQueueProcessingTaskDefExecutionRoleE22721BA", + "Arn" + ] + }, + "Family": "awsecspatternsqueuepublicPublicQueueServiceQueueProcessingTaskDefB3738118", + "Memory": "512", + "NetworkMode": "awsvpc", + "RequiresCompatibilities": [ + "FARGATE" + ], + "TaskRoleArn": { + "Fn::GetAtt": [ + "PublicQueueServiceQueueProcessingTaskDefTaskRole172D980F", + "Arn" + ] + } + } + }, + "PublicQueueServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupCFF67B64": { + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "PublicQueueServiceQueueProcessingTaskDefExecutionRoleE22721BA": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "PublicQueueServiceQueueProcessingTaskDefExecutionRoleDefaultPolicyD7FF680F": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ecr:BatchCheckLayerAvailability", + "ecr:GetDownloadUrlForLayer", + "ecr:BatchGetImage" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":ecr:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":repository/aws-cdk/assets" + ] + ] + } + }, + { + "Action": "ecr:GetAuthorizationToken", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "PublicQueueServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupCFF67B64", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PublicQueueServiceQueueProcessingTaskDefExecutionRoleDefaultPolicyD7FF680F", + "Roles": [ + { + "Ref": "PublicQueueServiceQueueProcessingTaskDefExecutionRoleE22721BA" + } + ] + } + }, + "PublicQueueServiceQueueProcessingFargateService7DE3D65B": { + "Type": "AWS::ECS::Service", + "Properties": { + "Cluster": { + "Ref": "EcsDefaultClusterMnL3mNNYNVPC9C1EC7A3" + }, + "DeploymentConfiguration": { + "MaximumPercent": 200, + "MinimumHealthyPercent": 50 + }, + "DesiredCount": 1, + "EnableECSManagedTags": false, + "LaunchType": "FARGATE", + "NetworkConfiguration": { + "AwsvpcConfiguration": { + "AssignPublicIp": "ENABLED", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "PublicQueueServiceQueueProcessingFargateServiceSecurityGroupFC07A65A", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, + { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + } + ] + } + }, + "TaskDefinition": { + "Ref": "PublicQueueServiceQueueProcessingTaskDef858327F6" + } + } + }, + "PublicQueueServiceQueueProcessingFargateServiceSecurityGroupFC07A65A": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-patterns-queue-public/PublicQueueService/QueueProcessingFargateService/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "PublicQueueServiceQueueProcessingFargateServiceTaskCountTargetE040C118": { + "Type": "AWS::ApplicationAutoScaling::ScalableTarget", + "Properties": { + "MaxCapacity": 2, + "MinCapacity": 1, + "ResourceId": { + "Fn::Join": [ + "", + [ + "service/", + { + "Ref": "EcsDefaultClusterMnL3mNNYNVPC9C1EC7A3" + }, + "/", + { + "Fn::GetAtt": [ + "PublicQueueServiceQueueProcessingFargateService7DE3D65B", + "Name" + ] + } + ] + ] + }, + "RoleARN": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService" + ] + ] + }, + "ScalableDimension": "ecs:service:DesiredCount", + "ServiceNamespace": "ecs" + } + }, + "PublicQueueServiceQueueProcessingFargateServiceTaskCountTargetCpuScaling559C41BF": { + "Type": "AWS::ApplicationAutoScaling::ScalingPolicy", + "Properties": { + "PolicyName": "awsecspatternsqueuepublicPublicQueueServiceQueueProcessingFargateServiceTaskCountTargetCpuScalingF36D44B7", + "PolicyType": "TargetTrackingScaling", + "ScalingTargetId": { + "Ref": "PublicQueueServiceQueueProcessingFargateServiceTaskCountTargetE040C118" + }, + "TargetTrackingScalingPolicyConfiguration": { + "PredefinedMetricSpecification": { + "PredefinedMetricType": "ECSServiceAverageCPUUtilization" + }, + "TargetValue": 50 + } + } + }, + "PublicQueueServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingLowerPolicyB2B27FF9": { + "Type": "AWS::ApplicationAutoScaling::ScalingPolicy", + "Properties": { + "PolicyName": "awsecspatternsqueuepublicPublicQueueServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingLowerPolicy2DB1A503", + "PolicyType": "StepScaling", + "ScalingTargetId": { + "Ref": "PublicQueueServiceQueueProcessingFargateServiceTaskCountTargetE040C118" + }, + "StepScalingPolicyConfiguration": { + "AdjustmentType": "ChangeInCapacity", + "MetricAggregationType": "Maximum", + "StepAdjustments": [ + { + "MetricIntervalUpperBound": 0, + "ScalingAdjustment": -1 + } + ] + } + } + }, + "PublicQueueServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingLowerAlarm5782C233": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "LessThanOrEqualToThreshold", + "EvaluationPeriods": 1, + "AlarmActions": [ + { + "Ref": "PublicQueueServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingLowerPolicyB2B27FF9" + } + ], + "AlarmDescription": "Lower threshold scaling alarm", + "Dimensions": [ + { + "Name": "QueueName", + "Value": { + "Fn::GetAtt": [ + "PublicQueueServiceEcsProcessingQueue84CD309D", + "QueueName" + ] + } + } + ], + "MetricName": "ApproximateNumberOfMessagesVisible", + "Namespace": "AWS/SQS", + "Period": 300, + "Statistic": "Maximum", + "Threshold": 0 + } + }, + "PublicQueueServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingUpperPolicyDCB40C8A": { + "Type": "AWS::ApplicationAutoScaling::ScalingPolicy", + "Properties": { + "PolicyName": "awsecspatternsqueuepublicPublicQueueServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingUpperPolicy89C3D196", + "PolicyType": "StepScaling", + "ScalingTargetId": { + "Ref": "PublicQueueServiceQueueProcessingFargateServiceTaskCountTargetE040C118" + }, + "StepScalingPolicyConfiguration": { + "AdjustmentType": "ChangeInCapacity", + "MetricAggregationType": "Maximum", + "StepAdjustments": [ + { + "MetricIntervalLowerBound": 0, + "MetricIntervalUpperBound": 400, + "ScalingAdjustment": 1 + }, + { + "MetricIntervalLowerBound": 400, + "ScalingAdjustment": 5 + } + ] + } + } + }, + "PublicQueueServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingUpperAlarm5D67333D": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "EvaluationPeriods": 1, + "AlarmActions": [ + { + "Ref": "PublicQueueServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingUpperPolicyDCB40C8A" + } + ], + "AlarmDescription": "Upper threshold scaling alarm", + "Dimensions": [ + { + "Name": "QueueName", + "Value": { + "Fn::GetAtt": [ + "PublicQueueServiceEcsProcessingQueue84CD309D", + "QueueName" + ] + } + } + ], + "MetricName": "ApproximateNumberOfMessagesVisible", + "Namespace": "AWS/SQS", + "Period": 300, + "Statistic": "Maximum", + "Threshold": 100 + } + }, + "EcsDefaultClusterMnL3mNNYNVPC9C1EC7A3": { + "Type": "AWS::ECS::Cluster" + } + }, + "Outputs": { + "PublicQueueServiceSQSDeadLetterQueueBCE86DBC": { + "Value": { + "Fn::GetAtt": [ + "PublicQueueServiceEcsProcessingDeadLetterQueueBC492277", + "QueueName" + ] + } + }, + "PublicQueueServiceSQSDeadLetterQueueArn6E134EA4": { + "Value": { + "Fn::GetAtt": [ + "PublicQueueServiceEcsProcessingDeadLetterQueueBC492277", + "Arn" + ] + } + }, + "PublicQueueServiceSQSQueue4D3FBD5C": { + "Value": { + "Fn::GetAtt": [ + "PublicQueueServiceEcsProcessingQueue84CD309D", + "QueueName" + ] + } + }, + "PublicQueueServiceSQSQueueArn38014FDC": { + "Value": { + "Fn::GetAtt": [ + "PublicQueueServiceEcsProcessingQueue84CD309D", + "Arn" + ] + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-public.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-public.ts new file mode 100644 index 0000000000000..5b0d74f9e3ceb --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-public.ts @@ -0,0 +1,19 @@ +import * as path from 'path'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecs from '@aws-cdk/aws-ecs'; +import { App, Stack } from '@aws-cdk/core'; + +import { QueueProcessingFargateService } from '../../lib'; + +const app = new App(); +const stack = new Stack(app, 'aws-ecs-patterns-queue-public'); +const vpc = new ec2.Vpc(stack, 'VPC'); + +new QueueProcessingFargateService(stack, 'PublicQueueService', { + vpc, + memoryLimitMiB: 512, + image: new ecs.AssetImage(path.join(__dirname, '..', 'sqs-reader')), + assignPublicIp: true, +}); + +app.synth(); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.expected.json new file mode 100644 index 0000000000000..889eeefcd985e --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.expected.json @@ -0,0 +1,842 @@ +{ + "Resources": { + "VPCB9E5F0B4": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue/VPC" + } + ] + } + }, + "VPCPublicSubnet1SubnetB4246D30": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/18", + "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-ecs-patterns-queue/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1RouteTableFEE4B781": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue/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-ecs-patterns-queue/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1NATGatewayE0556630": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet1EIP6AD938E8", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet2Subnet74179F39": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/18", + "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-ecs-patterns-queue/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2RouteTable6F1A15F1": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue/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-ecs-patterns-queue/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2NATGateway3C070193": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet2EIP4947BC00", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPrivateSubnet1Subnet8BCA10E0": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/18", + "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-ecs-patterns-queue/VPC/PrivateSubnet1" + } + ] + } + }, + "VPCPrivateSubnet1RouteTableBE8A6027": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue/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.192.0/18", + "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-ecs-patterns-queue/VPC/PrivateSubnet2" + } + ] + } + }, + "VPCPrivateSubnet2RouteTable0A19E10E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue/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" + } + } + }, + "VPCIGWB7E252D3": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue/VPC" + } + ] + } + }, + "VPCVPCGW99B986DC": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "InternetGatewayId": { + "Ref": "VPCIGWB7E252D3" + } + } + }, + "QueueProcessingServiceEcsProcessingDeadLetterQueueD47A7C6B": { + "Type": "AWS::SQS::Queue", + "Properties": { + "MessageRetentionPeriod": 1209600 + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "QueueProcessingServiceEcsProcessingQueue552F0B37": { + "Type": "AWS::SQS::Queue", + "Properties": { + "RedrivePolicy": { + "deadLetterTargetArn": { + "Fn::GetAtt": [ + "QueueProcessingServiceEcsProcessingDeadLetterQueueD47A7C6B", + "Arn" + ] + }, + "maxReceiveCount": 3 + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "QueueProcessingServiceQueueProcessingTaskDefTaskRole782B79A6": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "QueueProcessingServiceQueueProcessingTaskDefTaskRoleDefaultPolicyAE808B19": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "sqs:ReceiveMessage", + "sqs:ChangeMessageVisibility", + "sqs:GetQueueUrl", + "sqs:DeleteMessage", + "sqs:GetQueueAttributes" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "QueueProcessingServiceEcsProcessingQueue552F0B37", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "QueueProcessingServiceQueueProcessingTaskDefTaskRoleDefaultPolicyAE808B19", + "Roles": [ + { + "Ref": "QueueProcessingServiceQueueProcessingTaskDefTaskRole782B79A6" + } + ] + } + }, + "QueueProcessingServiceQueueProcessingTaskDef4982F68B": { + "Type": "AWS::ECS::TaskDefinition", + "Properties": { + "ContainerDefinitions": [ + { + "Environment": [ + { + "Name": "QUEUE_NAME", + "Value": { + "Fn::GetAtt": [ + "QueueProcessingServiceEcsProcessingQueue552F0B37", + "QueueName" + ] + } + } + ], + "Essential": true, + "Image": { + "Fn::Join": [ + "", + [ + { + "Ref": "AWS::AccountId" + }, + ".dkr.ecr.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/aws-cdk/assets:3a8ba3ad06ed212b075efa3157fb407649c5996812bc64eeb5209e220aab4be5" + ] + ] + }, + "LogConfiguration": { + "LogDriver": "awslogs", + "Options": { + "awslogs-group": { + "Ref": "QueueProcessingServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupCC92448A" + }, + "awslogs-stream-prefix": "QueueProcessingService", + "awslogs-region": { + "Ref": "AWS::Region" + } + } + }, + "Name": "QueueProcessingContainer" + } + ], + "Cpu": "256", + "ExecutionRoleArn": { + "Fn::GetAtt": [ + "QueueProcessingServiceQueueProcessingTaskDefExecutionRole37838985", + "Arn" + ] + }, + "Family": "awsecspatternsqueueQueueProcessingServiceQueueProcessingTaskDef2D9F8C2B", + "Memory": "512", + "NetworkMode": "awsvpc", + "RequiresCompatibilities": [ + "FARGATE" + ], + "TaskRoleArn": { + "Fn::GetAtt": [ + "QueueProcessingServiceQueueProcessingTaskDefTaskRole782B79A6", + "Arn" + ] + } + } + }, + "QueueProcessingServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupCC92448A": { + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "QueueProcessingServiceQueueProcessingTaskDefExecutionRole37838985": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "QueueProcessingServiceQueueProcessingTaskDefExecutionRoleDefaultPolicyA83D332D": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ecr:BatchCheckLayerAvailability", + "ecr:GetDownloadUrlForLayer", + "ecr:BatchGetImage" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":ecr:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":repository/aws-cdk/assets" + ] + ] + } + }, + { + "Action": "ecr:GetAuthorizationToken", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "QueueProcessingServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupCC92448A", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "QueueProcessingServiceQueueProcessingTaskDefExecutionRoleDefaultPolicyA83D332D", + "Roles": [ + { + "Ref": "QueueProcessingServiceQueueProcessingTaskDefExecutionRole37838985" + } + ] + } + }, + "QueueProcessingServiceQueueProcessingFargateService0340DB9F": { + "Type": "AWS::ECS::Service", + "Properties": { + "Cluster": { + "Ref": "EcsDefaultClusterMnL3mNNYNVPC9C1EC7A3" + }, + "DeploymentConfiguration": { + "MaximumPercent": 200, + "MinimumHealthyPercent": 50 + }, + "DesiredCount": 1, + "EnableECSManagedTags": false, + "LaunchType": "FARGATE", + "NetworkConfiguration": { + "AwsvpcConfiguration": { + "AssignPublicIp": "DISABLED", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "QueueProcessingServiceQueueProcessingFargateServiceSecurityGroup8FDF413D", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + }, + { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + ] + } + }, + "TaskDefinition": { + "Ref": "QueueProcessingServiceQueueProcessingTaskDef4982F68B" + } + } + }, + "QueueProcessingServiceQueueProcessingFargateServiceSecurityGroup8FDF413D": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-patterns-queue/QueueProcessingService/QueueProcessingFargateService/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "QueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetA9D54444": { + "Type": "AWS::ApplicationAutoScaling::ScalableTarget", + "Properties": { + "MaxCapacity": 2, + "MinCapacity": 1, + "ResourceId": { + "Fn::Join": [ + "", + [ + "service/", + { + "Ref": "EcsDefaultClusterMnL3mNNYNVPC9C1EC7A3" + }, + "/", + { + "Fn::GetAtt": [ + "QueueProcessingServiceQueueProcessingFargateService0340DB9F", + "Name" + ] + } + ] + ] + }, + "RoleARN": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService" + ] + ] + }, + "ScalableDimension": "ecs:service:DesiredCount", + "ServiceNamespace": "ecs" + } + }, + "QueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetCpuScaling330150E9": { + "Type": "AWS::ApplicationAutoScaling::ScalingPolicy", + "Properties": { + "PolicyName": "awsecspatternsqueueQueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetCpuScaling374CE648", + "PolicyType": "TargetTrackingScaling", + "ScalingTargetId": { + "Ref": "QueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetA9D54444" + }, + "TargetTrackingScalingPolicyConfiguration": { + "PredefinedMetricSpecification": { + "PredefinedMetricType": "ECSServiceAverageCPUUtilization" + }, + "TargetValue": 50 + } + } + }, + "QueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingLowerPolicy332E2644": { + "Type": "AWS::ApplicationAutoScaling::ScalingPolicy", + "Properties": { + "PolicyName": "awsecspatternsqueueQueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingLowerPolicy74582401", + "PolicyType": "StepScaling", + "ScalingTargetId": { + "Ref": "QueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetA9D54444" + }, + "StepScalingPolicyConfiguration": { + "AdjustmentType": "ChangeInCapacity", + "MetricAggregationType": "Maximum", + "StepAdjustments": [ + { + "MetricIntervalUpperBound": 0, + "ScalingAdjustment": -1 + } + ] + } + } + }, + "QueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingLowerAlarm20C30A06": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "LessThanOrEqualToThreshold", + "EvaluationPeriods": 1, + "AlarmActions": [ + { + "Ref": "QueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingLowerPolicy332E2644" + } + ], + "AlarmDescription": "Lower threshold scaling alarm", + "Dimensions": [ + { + "Name": "QueueName", + "Value": { + "Fn::GetAtt": [ + "QueueProcessingServiceEcsProcessingQueue552F0B37", + "QueueName" + ] + } + } + ], + "MetricName": "ApproximateNumberOfMessagesVisible", + "Namespace": "AWS/SQS", + "Period": 300, + "Statistic": "Maximum", + "Threshold": 0 + } + }, + "QueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingUpperPolicy84DD739A": { + "Type": "AWS::ApplicationAutoScaling::ScalingPolicy", + "Properties": { + "PolicyName": "awsecspatternsqueueQueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingUpperPolicy23C5F983", + "PolicyType": "StepScaling", + "ScalingTargetId": { + "Ref": "QueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetA9D54444" + }, + "StepScalingPolicyConfiguration": { + "AdjustmentType": "ChangeInCapacity", + "MetricAggregationType": "Maximum", + "StepAdjustments": [ + { + "MetricIntervalLowerBound": 0, + "MetricIntervalUpperBound": 400, + "ScalingAdjustment": 1 + }, + { + "MetricIntervalLowerBound": 400, + "ScalingAdjustment": 5 + } + ] + } + } + }, + "QueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingUpperAlarm2660BEDF": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "EvaluationPeriods": 1, + "AlarmActions": [ + { + "Ref": "QueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingUpperPolicy84DD739A" + } + ], + "AlarmDescription": "Upper threshold scaling alarm", + "Dimensions": [ + { + "Name": "QueueName", + "Value": { + "Fn::GetAtt": [ + "QueueProcessingServiceEcsProcessingQueue552F0B37", + "QueueName" + ] + } + } + ], + "MetricName": "ApproximateNumberOfMessagesVisible", + "Namespace": "AWS/SQS", + "Period": 300, + "Statistic": "Maximum", + "Threshold": 100 + } + }, + "EcsDefaultClusterMnL3mNNYNVPC9C1EC7A3": { + "Type": "AWS::ECS::Cluster" + } + }, + "Outputs": { + "QueueProcessingServiceSQSDeadLetterQueueE9058015": { + "Value": { + "Fn::GetAtt": [ + "QueueProcessingServiceEcsProcessingDeadLetterQueueD47A7C6B", + "QueueName" + ] + } + }, + "QueueProcessingServiceSQSDeadLetterQueueArnF7C6D3A8": { + "Value": { + "Fn::GetAtt": [ + "QueueProcessingServiceEcsProcessingDeadLetterQueueD47A7C6B", + "Arn" + ] + } + }, + "QueueProcessingServiceSQSQueue1AD9CD9C": { + "Value": { + "Fn::GetAtt": [ + "QueueProcessingServiceEcsProcessingQueue552F0B37", + "QueueName" + ] + } + }, + "QueueProcessingServiceSQSQueueArn8C4AE4AE": { + "Value": { + "Fn::GetAtt": [ + "QueueProcessingServiceEcsProcessingQueue552F0B37", + "Arn" + ] + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.ts new file mode 100644 index 0000000000000..540b8d2302e9a --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.ts @@ -0,0 +1,20 @@ +import * as path from 'path'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecs from '@aws-cdk/aws-ecs'; +import { App, Stack } from '@aws-cdk/core'; + +import { QueueProcessingFargateService } from '../../lib'; + +const app = new App(); +const stack = new Stack(app, 'aws-ecs-patterns-queue'); +const vpc = new ec2.Vpc(stack, 'VPC', { + maxAzs: 2, +}); + +new QueueProcessingFargateService(stack, 'QueueProcessingService', { + vpc, + memoryLimitMiB: 512, + image: new ecs.AssetImage(path.join(__dirname, '..', 'sqs-reader')), +}); + +app.synth(); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts index a0c09d572343f..9d2d5dd0747a6 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts @@ -310,4 +310,103 @@ export = { test.done(); }, + + 'can set custom networking options'(test: Test) { + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC', { + subnetConfiguration: [ + { + cidrMask: 24, + name: 'Public', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'Isolated', + subnetType: ec2.SubnetType.ISOLATED, + }, + ], + }); + const securityGroup = new ec2.SecurityGroup(stack, 'MyCustomSG', { + vpc, + }); + + // WHEN - SecurityGroups and taskSubnets selection is defined + new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { + vpc, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + securityGroups: [securityGroup], + taskSubnets: { subnetType: ec2.SubnetType.ISOLATED }, + }); + + // THEN - NetworkConfiguration is created with the specific security groups and selected subnets + expect(stack).to(haveResource('AWS::ECS::Service', { + LaunchType: 'FARGATE', + NetworkConfiguration: { + AwsvpcConfiguration: { + AssignPublicIp: 'DISABLED', + SecurityGroups: [ + { + 'Fn::GetAtt': [ + 'MyCustomSGDE27C661', + 'GroupId', + ], + }, + ], + Subnets: [ + { + Ref: 'VPCIsolatedSubnet1SubnetEBD00FC6', + }, + { + Ref: 'VPCIsolatedSubnet2Subnet4B1C8CAA', + }, + ], + }, + }, + })); + + test.done(); + }, + + 'can set use public IP'(test: Test) { + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN - Assign Public IP is set to True + new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { + vpc, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + assignPublicIp: true, + }); + + // THEN - The Subnets defaults to Public and AssignPublicIp settings change to ENABLED + expect(stack).to(haveResource('AWS::ECS::Service', { + LaunchType: 'FARGATE', + NetworkConfiguration: { + AwsvpcConfiguration: { + AssignPublicIp: 'ENABLED', + SecurityGroups: [ + { + 'Fn::GetAtt': [ + 'ServiceQueueProcessingFargateServiceSecurityGroup6E981512', + 'GroupId', + ], + }, + ], + Subnets: [ + { + Ref: 'VPCPublicSubnet1SubnetB4246D30', + }, + { + Ref: 'VPCPublicSubnet2Subnet74179F39', + }, + ], + }, + }, + })); + + test.done(); + }, }; diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.scheduled-fargate-task.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.scheduled-fargate-task.ts index fa62f079862f1..9496288f3b235 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.scheduled-fargate-task.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.scheduled-fargate-task.ts @@ -24,6 +24,7 @@ export = { // THEN expect(stack).to(haveResource('AWS::Events::Rule', { + State: 'ENABLED', Targets: [ { Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, @@ -90,6 +91,7 @@ export = { new ScheduledFargateTask(stack, 'ScheduledFargateTask', { cluster, + enabled: false, scheduledFargateTaskImageOptions: { image: ecs.ContainerImage.fromRegistry('henk'), memoryLimitMiB: 512, @@ -104,6 +106,7 @@ export = { // THEN expect(stack).to(haveResource('AWS::Events::Rule', { Name: 'sample-scheduled-task-rule', + State: 'DISABLED', Targets: [ { Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/sqs-reader/Dockerfile b/packages/@aws-cdk/aws-ecs-patterns/test/sqs-reader/Dockerfile new file mode 100644 index 0000000000000..e6618640549e2 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/sqs-reader/Dockerfile @@ -0,0 +1,10 @@ +FROM python:3.6 + +RUN pip3 install boto3 + +ENV QUEUE_NAME $QUEUE_NAME + +WORKDIR /src +ADD . /src + +CMD python3 index.py diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/sqs-reader/index.py b/packages/@aws-cdk/aws-ecs-patterns/test/sqs-reader/index.py new file mode 100644 index 0000000000000..8b53f5149cb24 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/sqs-reader/index.py @@ -0,0 +1,22 @@ +#!/usr/bin/python +import os +import boto3 + +QUEUE_NAME = os.environ.get('QUEUE_NAME') +print('QUEUE_NAME ' + QUEUE_NAME) + +if __name__ == '__main__': + client = boto3.client('sqs') + queue_url = client.get_queue_url(QueueName=QUEUE_NAME)['QueueUrl'] + print('queue_url ' + queue_url) + while True: + response = client.receive_message( + QueueUrl=queue_url, + WaitTimeSeconds=10, + ) + if response and 'Messages' in response: + for msg in response['Messages']: + print(msg['Body']) + entries = [{'Id': x['MessageId'], 'ReceiptHandle': x['ReceiptHandle']} for x in response['Messages']] + client.delete_message_batch(QueueUrl=queue_url, Entries=entries) + diff --git a/packages/@aws-cdk/aws-ecs/.gitignore b/packages/@aws-cdk/aws-ecs/.gitignore index 255c76b856cb1..52228730a371f 100644 --- a/packages/@aws-cdk/aws-ecs/.gitignore +++ b/packages/@aws-cdk/aws-ecs/.gitignore @@ -16,4 +16,5 @@ nyc.config.js *.snk !.eslintrc.js -junit.xml \ No newline at end of file +junit.xml +!jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/.npmignore b/packages/@aws-cdk/aws-ecs/.npmignore index 40fbede1f02dc..6c1b9b8c69ec6 100644 --- a/packages/@aws-cdk/aws-ecs/.npmignore +++ b/packages/@aws-cdk/aws-ecs/.npmignore @@ -23,4 +23,5 @@ tsconfig.json # exclude cdk artifacts **/cdk.out junit.xml -test/ \ No newline at end of file +test/ +jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/README.md b/packages/@aws-cdk/aws-ecs/README.md index f2056229c6bf5..438f63e14e009 100644 --- a/packages/@aws-cdk/aws-ecs/README.md +++ b/packages/@aws-cdk/aws-ecs/README.md @@ -670,3 +670,50 @@ taskDefinition.addContainer('TheContainer', { }) }); ``` + +## Capacity Providers + +Currently, only `FARGATE` and `FARGATE_SPOT` capacity providers are supported. + +To enable capacity providers on your cluster, set the `capacityProviders` field +to [`FARGATE`, `FARGATE_SPOT`]. Then, specify capacity provider strategies on +the `capacityProviderStrategies` field for your Fargate Service. + +```ts +import * as cdk from '@aws-cdk/core'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecs from '../../lib'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-ecs-integ-capacity-provider'); + +const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 2 }); + +const cluster = new ecs.Cluster(stack, 'FargateCPCluster', { + vpc, + capacityProviders: ['FARGATE', 'FARGATE_SPOT'], +}); + +const taskDefinition = new ecs.FargateTaskDefinition(stack, 'TaskDef'); + +taskDefinition.addContainer('web', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), +}); + +new ecs.FargateService(stack, 'FargateService', { + cluster, + taskDefinition, + capacityProviderStrategies: [ + { + capacityProvider: 'FARGATE_SPOT', + weight: 2, + }, + { + capacityProvider: 'FARGATE', + weight: 1, + } + ], +}); + +app.synth(); +``` diff --git a/packages/@aws-cdk/aws-ecs/jest.config.js b/packages/@aws-cdk/aws-ecs/jest.config.js new file mode 100644 index 0000000000000..f5d5c4c8ad18f --- /dev/null +++ b/packages/@aws-cdk/aws-ecs/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts b/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts index 5c5160a849835..8e2483f98838f 100644 --- a/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts +++ b/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts @@ -8,7 +8,7 @@ import * as cloudmap from '@aws-cdk/aws-servicediscovery'; import { Annotations, Duration, IResolvable, IResource, Lazy, Resource, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { LoadBalancerTargetOptions, NetworkMode, TaskDefinition } from '../base/task-definition'; -import { ICluster } from '../cluster'; +import { ICluster, CapacityProviderStrategy } from '../cluster'; import { Protocol } from '../container-definition'; import { CfnService } from '../ecs.generated'; import { ScalableTaskCount } from './scalable-task-count'; @@ -181,6 +181,14 @@ export interface BaseServiceOptions { * @default - disabled */ readonly circuitBreaker?: DeploymentCircuitBreaker; + + /** + * A list of Capacity Provider strategies used to place a service. + * + * @default - undefined + * + */ + readonly capacityProviderStrategies?: CapacityProviderStrategy[]; } /** @@ -191,6 +199,10 @@ export interface BaseServiceProps extends BaseServiceOptions { /** * The launch type on which to run your service. * + * LaunchType will be omitted if capacity provider strategies are specified on the service. + * + * @see - https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-service.html#cfn-ecs-service-capacityproviderstrategy + * * Valid values are: LaunchType.ECS or LaunchType.FARGATE */ readonly launchType: LaunchType; @@ -356,6 +368,11 @@ export abstract class BaseService extends Resource this.taskDefinition = taskDefinition; + // launchType will set to undefined if using external DeploymentController or capacityProviderStrategies + const launchType = props.deploymentController?.type === DeploymentControllerType.EXTERNAL || + props.capacityProviderStrategies !== undefined ? + undefined : props.launchType; + this.resource = new CfnService(this, 'Service', { desiredCount: props.desiredCount, serviceName: this.physicalName, @@ -371,7 +388,8 @@ export abstract class BaseService extends Resource propagateTags: props.propagateTags === PropagatedTagSource.NONE ? undefined : props.propagateTags, enableEcsManagedTags: props.enableECSManagedTags ?? false, deploymentController: props.deploymentController, - launchType: props.deploymentController?.type === DeploymentControllerType.EXTERNAL ? undefined : props.launchType, + launchType: launchType, + capacityProviderStrategy: props.capacityProviderStrategies, healthCheckGracePeriodSeconds: this.evaluateHealthGracePeriod(props.healthCheckGracePeriod), /* role: never specified, supplanted by Service Linked Role */ networkConfiguration: Lazy.any({ produce: () => this.networkConfiguration }, { omitEmptyArray: true }), diff --git a/packages/@aws-cdk/aws-ecs/lib/cluster.ts b/packages/@aws-cdk/aws-ecs/lib/cluster.ts index ca84679e7b970..c60fc9f4b1dee 100644 --- a/packages/@aws-cdk/aws-ecs/lib/cluster.ts +++ b/packages/@aws-cdk/aws-ecs/lib/cluster.ts @@ -5,7 +5,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as cloudmap from '@aws-cdk/aws-servicediscovery'; import * as ssm from '@aws-cdk/aws-ssm'; -import { Duration, IResource, Resource, Stack } from '@aws-cdk/core'; +import { Duration, Lazy, IResource, Resource, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { InstanceDrainHook } from './drain-hook/instance-drain-hook'; import { ECSMetrics } from './ecs-canned-metrics.generated'; @@ -48,6 +48,13 @@ export interface ClusterProps { */ readonly capacity?: AddCapacityOptions; + /** + * The capacity providers to add to the cluster + * + * @default - None. Currently only FARGATE and FARGATE_SPOT are supported. + */ + readonly capacityProviders?: string[]; + /** * If true CloudWatch Container Insights will be enabled for the cluster * @@ -101,6 +108,13 @@ export class Cluster extends Resource implements ICluster { */ public readonly clusterName: string; + /** + * The capacity providers associated with the cluster. + * + * Currently only FARGATE and FARGATE_SPOT are supported. + */ + private _capacityProviders: string[] = []; + /** * The AWS Cloud Map namespace to associate with the cluster. */ @@ -134,9 +148,12 @@ export class Cluster extends Resource implements ICluster { clusterSettings = [{ name: 'containerInsights', value: props.containerInsights ? ContainerInsights.ENABLED : ContainerInsights.DISABLED }]; } + this._capacityProviders = props.capacityProviders ?? []; + const cluster = new CfnCluster(this, 'Resource', { clusterName: this.physicalName, clusterSettings, + capacityProviders: Lazy.list({ produce: () => this._capacityProviders }, { omitEmpty: true }), }); this.clusterArn = this.getResourceArnAttribute(cluster.attrArn, { @@ -148,6 +165,7 @@ export class Cluster extends Resource implements ICluster { this.vpc = props.vpc || new ec2.Vpc(this, 'Vpc', { maxAzs: 2 }); + this._defaultCloudMapNamespace = props.defaultCloudMapNamespace !== undefined ? this.addDefaultCloudMapNamespace(props.defaultCloudMapNamespace) : undefined; @@ -323,6 +341,21 @@ export class Cluster extends Resource implements ICluster { } } + /** + * addCapacityProvider adds the name of a capacityProvider to the list of supproted capacityProviders for a cluster. + * + * @param provider the capacity provider to add to this cluster. + */ + public addCapacityProvider(provider: string) { + if (!(provider === 'FARGATE' || provider === 'FARGATE_SPOT')) { + throw new Error('CapacityProvider not supported'); + } + + if (!this._capacityProviders.includes(provider)) { + this._capacityProviders.push(provider); + } + } + private configureWindowsAutoScalingGroup(autoScalingGroup: autoscaling.AutoScalingGroup, options: AddAutoScalingGroupCapacityOptions = {}) { // clear the cache of the agent autoScalingGroup.addUserData('Remove-Item -Recurse C:\\ProgramData\\Amazon\\ECS\\Cache'); @@ -934,3 +967,33 @@ enum ContainerInsights { */ DISABLED = 'disabled', } + +/** + * A Capacity Provider strategy to use for the service. + * + * NOTE: defaultCapacityProviderStrategy on cluster not currently supported. + */ +export interface CapacityProviderStrategy { + /** + * The name of the Capacity Provider. Currently only FARGATE and FARGATE_SPOT are supported. + */ + readonly capacityProvider: string; + + /** + * The base value designates how many tasks, at a minimum, to run on the specified capacity provider. Only one + * capacity provider in a capacity provider strategy can have a base defined. If no value is specified, the default + * value of 0 is used. + * + * @default - none + */ + readonly base?: number; + + /** + * The weight value designates the relative percentage of the total number of tasks launched that should use the + * specified +capacity provider. The weight value is taken into consideration after the base value, if defined, is satisfied. + * + * @default - 0 + */ + readonly weight?: number; +} diff --git a/packages/@aws-cdk/aws-ecs/lib/fargate/fargate-service.ts b/packages/@aws-cdk/aws-ecs/lib/fargate/fargate-service.ts index 01a9f75665c57..1db94fc5286e0 100644 --- a/packages/@aws-cdk/aws-ecs/lib/fargate/fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs/lib/fargate/fargate-service.ts @@ -67,6 +67,7 @@ export interface FargateServiceProps extends BaseServiceOptions { * @default PropagatedTagSource.NONE */ readonly propagateTaskTagsFrom?: PropagatedTagSource; + } /** @@ -153,6 +154,7 @@ export class FargateService extends BaseService implements IFargateService { ...props, desiredCount: props.desiredCount, launchType: LaunchType.FARGATE, + capacityProviderStrategies: props.capacityProviderStrategies, propagateTags: propagateTagsFromSource, enableECSManagedTags: props.enableECSManagedTags, }, { diff --git a/packages/@aws-cdk/aws-ecs/package.json b/packages/@aws-cdk/aws-ecs/package.json index 86da4b1cfde8e..f7408e518f2fe 100644 --- a/packages/@aws-cdk/aws-ecs/package.json +++ b/packages/@aws-cdk/aws-ecs/package.json @@ -53,6 +53,7 @@ }, "cdk-build": { "cloudformation": "AWS::ECS", + "jest": "true", "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -77,7 +78,7 @@ "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "nodeunit": "^0.11.3", + "nodeunit-shim": "0.0.0", "pkglint": "0.0.0", "proxyquire": "^2.1.3" }, @@ -271,5 +272,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-ecs/test/test.app-mesh-proxy-configuration.ts b/packages/@aws-cdk/aws-ecs/test/app-mesh-proxy-configuration.test.ts similarity index 98% rename from packages/@aws-cdk/aws-ecs/test/test.app-mesh-proxy-configuration.ts rename to packages/@aws-cdk/aws-ecs/test/app-mesh-proxy-configuration.test.ts index 1633d90234ee0..69f3d30e9b865 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.app-mesh-proxy-configuration.ts +++ b/packages/@aws-cdk/aws-ecs/test/app-mesh-proxy-configuration.test.ts @@ -1,9 +1,9 @@ import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; -export = { +nodeunitShim({ 'correctly sets all appMeshProxyConfiguration'(test: Test) { // GIVEN const stack = new cdk.Stack(); @@ -204,4 +204,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/test.aws-log-driver.ts b/packages/@aws-cdk/aws-ecs/test/aws-log-driver.test.ts similarity index 98% rename from packages/@aws-cdk/aws-ecs/test/test.aws-log-driver.ts rename to packages/@aws-cdk/aws-ecs/test/aws-log-driver.test.ts index a4d5c9af9c53d..d36fb943e8b2d 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.aws-log-driver.ts +++ b/packages/@aws-cdk/aws-ecs/test/aws-log-driver.test.ts @@ -1,14 +1,14 @@ import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; import * as logs from '@aws-cdk/aws-logs'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; let stack: cdk.Stack; let td: ecs.TaskDefinition; const image = ecs.ContainerImage.fromRegistry('test-image'); -export = { +nodeunitShim({ 'setUp'(cb: () => void) { stack = new cdk.Stack(); td = new ecs.FargateTaskDefinition(stack, 'TaskDefinition'); @@ -154,4 +154,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/test.container-definition.ts b/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts similarity index 82% rename from packages/@aws-cdk/aws-ecs/test/test.container-definition.ts rename to packages/@aws-cdk/aws-ecs/test/container-definition.test.ts index e994a9174f51d..c167720e362cf 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.container-definition.ts +++ b/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts @@ -1,16 +1,17 @@ +import '@aws-cdk/assert/jest'; import * as path from 'path'; -import { expect, haveResource, haveResourceLike, InspectionFailure } from '@aws-cdk/assert'; +import { InspectionFailure } from '@aws-cdk/assert'; import * as ecr_assets from '@aws-cdk/aws-ecr-assets'; import * as s3 from '@aws-cdk/aws-s3'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; import * as ssm from '@aws-cdk/aws-ssm'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; import * as ecs from '../lib'; -export = { - 'When creating a Task Definition': { - 'add a container using default props'(test: Test) { +describe('container definition', () => { + describe('When creating a Task Definition', () => { + test('add a container using default props', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -22,7 +23,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Essential: true, @@ -31,12 +32,12 @@ export = { Name: 'Container', }, ], - })); + }); + - test.done(); - }, + }); - 'add a container using all props'(test: Test) { + test('add a container using all props', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -85,7 +86,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Command: [ @@ -219,31 +220,31 @@ export = { WorkingDirectory: 'a/b/c', }, ], - })); + }); - test.done(); - }, - 'throws when MemoryLimit is less than MemoryReservationLimit'(test: Test) { + }); + + test('throws when MemoryLimit is less than MemoryReservationLimit', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); // THEN - test.throws(() => { + expect(() => { new ecs.ContainerDefinition(stack, 'Container', { image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), taskDefinition, memoryLimitMiB: 512, memoryReservationMiB: 1024, }); - }, /MemoryLimitMiB should not be less than MemoryReservationMiB./); + }).toThrow(/MemoryLimitMiB should not be less than MemoryReservationMiB./); + - test.done(); - }, + }); - 'With network mode AwsVpc': { - 'throws when Host port is different from container port'(test: Test) { + describe('With network mode AwsVpc', () => { + test('throws when Host port is different from container port', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -256,17 +257,17 @@ export = { }); // THEN - test.throws(() => { + expect(() => { container.addPortMappings({ containerPort: 8080, hostPort: 8081, }); - }); + }).toThrow(); - test.done(); - }, - 'Host port is the same as container port'(test: Test) { + }); + + test('Host port is the same as container port', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -284,10 +285,10 @@ export = { }); // THEN no exception raised - test.done(); - }, - 'Host port can be empty '(test: Test) { + }); + + test('Host port can be empty ', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -305,12 +306,12 @@ export = { }); // THEN no exception raised - test.done(); - }, - }, - 'With network mode Host ': { - 'throws when Host port is different from container port'(test: Test) { + }); + }); + + describe('With network mode Host ', () => { + test('throws when Host port is different from container port', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -323,17 +324,17 @@ export = { }); // THEN - test.throws(() => { + expect(() => { container.addPortMappings({ containerPort: 8080, hostPort: 8081, }); - }); + }).toThrow(); - test.done(); - }, - 'when host port is the same as container port'(test: Test) { + }); + + test('when host port is the same as container port', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -351,10 +352,10 @@ export = { }); // THEN no exception raised - test.done(); - }, - 'Host port can be empty '(test: Test) { + }); + + test('Host port can be empty ', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -372,10 +373,10 @@ export = { }); // THEN no exception raised - test.done(); - }, - 'errors when adding links'(test: Test) { + }); + + test('errors when adding links', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -393,16 +394,16 @@ export = { }); // THEN - test.throws(() => { + expect(() => { container.addLink(logger); - }); + }).toThrow(); - test.done(); - }, - }, - 'With network mode Bridge': { - 'when Host port is empty '(test: Test) { + }); + }); + + describe('With network mode Bridge', () => { + test('when Host port is empty ', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -419,10 +420,10 @@ export = { }); // THEN no exception raises - test.done(); - }, - 'when Host port is not empty '(test: Test) { + }); + + test('when Host port is not empty ', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -440,10 +441,10 @@ export = { }); // THEN no exception raises - test.done(); - }, - 'allows adding links'(test: Test) { + }); + + test('allows adding links', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -463,12 +464,12 @@ export = { // THEN container.addLink(logger); - test.done(); - }, - }, - 'With network mode NAT': { - 'produces undefined CF networkMode property'(test: Test) { + }); + }); + + describe('With network mode NAT', () => { + test('produces undefined CF networkMode property', () => { // GIVEN const stack = new cdk.Stack(); @@ -479,22 +480,22 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', (props: any, inspection: InspectionFailure) => { + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', (props: any, inspection: InspectionFailure) => { if (props.NetworkMode === undefined) { return true; } inspection.failureReason = 'CF template should not have NetworkMode defined for a task definition that relies on NAT network mode.'; return false; - })); + }); - test.done(); - }, - }, - }, - 'Container Port': { - 'should return the first container port in PortMappings'(test: Test) { + }); + }); + }); + + describe('Container Port', () => { + test('should return the first container port in PortMappings', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -518,11 +519,11 @@ export = { // THEN const expected = 8080; - test.equal(actual, expected, 'containerPort should return the first container port in PortMappings'); - test.done(); - }, + expect(actual).toEqual(expected); - 'throws when calling containerPort with no PortMappings'(test: Test) { + }); + + test('throws when calling containerPort with no PortMappings', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -535,19 +536,19 @@ export = { }); // THEN - test.throws(() => { + expect(() => { const actual = container.containerPort; const expected = 8080; - test.equal(actual, expected); - }, /Container MyContainer hasn't defined any ports. Call addPortMappings()./); + expect(actual).toEqual(expected); + }).toThrow(/Container MyContainer hasn't defined any ports. Call addPortMappings()./); + - test.done(); - }, - }, + }); + }); - 'Ingress Port': { - 'With network mode AwsVpc': { - 'Ingress port should be the same as container port'(test: Test) { + describe('Ingress Port', () => { + describe('With network mode AwsVpc', () => { + test('Ingress port should be the same as container port', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -567,11 +568,11 @@ export = { // THEN const expected = 8080; - test.equal(actual, expected, 'Ingress port should be the same as container port'); - test.done(); - }, + expect(actual).toEqual(expected); - 'throws when calling ingressPort with no PortMappings'(test: Test) { + }); + + test('throws when calling ingressPort with no PortMappings', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -584,18 +585,18 @@ export = { }); // THEN - test.throws(() => { + expect(() => { const actual = container.ingressPort; const expected = 8080; - test.equal(actual, expected); - }, /Container MyContainer hasn't defined any ports. Call addPortMappings()./); + expect(actual).toEqual(expected); + }).toThrow(/Container MyContainer hasn't defined any ports. Call addPortMappings()./); - test.done(); - }, - }, - 'With network mode Host ': { - 'Ingress port should be the same as container port'(test: Test) { + }); + }); + + describe('With network mode Host ', () => { + test('Ingress port should be the same as container port', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -615,13 +616,13 @@ export = { // THEN const expected = 8080; - test.equal(actual, expected); - test.done(); - }, - }, + expect(actual).toEqual( expected); - 'With network mode Bridge': { - 'Ingress port should be the same as host port if supplied'(test: Test) { + }); + }); + + describe('With network mode Bridge', () => { + test('Ingress port should be the same as host port if supplied', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -642,11 +643,11 @@ export = { // THEN const expected = 8081; - test.equal(actual, expected); - test.done(); - }, + expect(actual).toEqual( expected); + + }); - 'Ingress port should be 0 if not supplied'(test: Test) { + test('Ingress port should be 0 if not supplied', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { @@ -666,13 +667,13 @@ export = { // THEN const expected = 0; - test.equal(actual, expected); - test.done(); - }, - }, - }, + expect(actual).toEqual(expected); + + }); + }); + }); - 'can add environment variables to the container definition'(test: Test) { + test('can add environment variables to the container definition', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -687,7 +688,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Environment: [{ @@ -696,15 +697,14 @@ export = { }], }, ], - })); + }); - test.done(); - }, + }); - 'Environment Files': { - 'with EC2 task definitions': { - 'can add asset environment file to the container definition'(test: Test) { + describe('Environment Files', () => { + describe('with EC2 task definitions', () => { + test('can add asset environment file to the container definition', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -717,7 +717,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { EnvironmentFiles: [{ @@ -763,11 +763,11 @@ export = { }], }, ], - })); + }); - test.done(); - }, - 'can add s3 bucket environment file to the container definition'(test: Test) { + + }); + test('can add s3 bucket environment file to the container definition', () => { // GIVEN const stack = new cdk.Stack(); const bucket = new s3.Bucket(stack, 'Bucket', { @@ -783,7 +783,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { EnvironmentFiles: [{ @@ -803,13 +803,13 @@ export = { }], }, ], - })); + }); - test.done(); - }, - }, - 'with Fargate task definitions': { - 'can add asset environment file to the container definition'(test: Test) { + + }); + }); + describe('with Fargate task definitions', () => { + test('can add asset environment file to the container definition', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.FargateTaskDefinition(stack, 'TaskDef'); @@ -822,7 +822,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { EnvironmentFiles: [{ @@ -868,11 +868,11 @@ export = { }], }, ], - })); + }); - test.done(); - }, - 'can add s3 bucket environment file to the container definition'(test: Test) { + + }); + test('can add s3 bucket environment file to the container definition', () => { // GIVEN const stack = new cdk.Stack(); const bucket = new s3.Bucket(stack, 'Bucket', { @@ -888,7 +888,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { EnvironmentFiles: [{ @@ -908,15 +908,15 @@ export = { }], }, ], - })); + }); - test.done(); - }, - }, - }, - 'Given GPU count parameter': { - 'will add resource requirements to container definition'(test: Test) { + }); + }); + }); + + describe('Given GPU count parameter', () => { + test('will add resource requirements to container definition', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -929,7 +929,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Image: 'test', @@ -941,13 +941,13 @@ export = { ], }, ], - })); + }); - test.done(); - }, - }, - 'can add secret environment variables to the container definition'(test: Test) { + }); + }); + + test('can add secret environment variables to the container definition', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -969,7 +969,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Secrets: [ @@ -1005,9 +1005,9 @@ export = { ], }, ], - })); + }); - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -1052,13 +1052,12 @@ export = { ], Version: '2012-10-17', }, - })); + }); - test.done(); - }, + }); - 'use a specific secret JSON key as environment variable'(test: Test) { + test('use a specific secret JSON key as environment variable', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1075,7 +1074,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Secrets: [ @@ -1096,13 +1095,12 @@ export = { ], }, ], - })); + }); - test.done(); - }, + }); - 'use a specific secret JSON field as environment variable for a Fargate task'(test: Test) { + test('use a specific secret JSON field as environment variable for a Fargate task', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.FargateTaskDefinition(stack, 'TaskDef'); @@ -1119,7 +1117,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Secrets: [ @@ -1140,12 +1138,12 @@ export = { ], }, ], - })); + }); + - test.done(); - }, + }); - 'can add AWS logging to container definition'(test: Test) { + test('can add AWS logging to container definition', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1158,7 +1156,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { LogConfiguration: { @@ -1171,9 +1169,9 @@ export = { }, }, ], - })); + }); - expect(stack).to(haveResource('AWS::IAM::Policy', { + expect(stack).toHaveResource('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -1184,12 +1182,12 @@ export = { ], Version: '2012-10-17', }, - })); + }); - test.done(); - }, - 'can set Health Check with defaults'(test: Test) { + }); + + test('can set Health Check with defaults', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1205,7 +1203,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { HealthCheck: { @@ -1216,12 +1214,12 @@ export = { }, }, ], - })); + }); - test.done(); - }, - 'throws when setting Health Check with no commands'(test: Test) { + }); + + test('throws when setting Health Check with no commands', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1236,8 +1234,8 @@ export = { }); // THEN - test.throws(() => { - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(() => { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { HealthCheck: { @@ -1248,13 +1246,13 @@ export = { }, }, ], - })); - }, /At least one argument must be supplied for health check command./); + }); + }).toThrow(/At least one argument must be supplied for health check command./); - test.done(); - }, - 'can specify Health Check values in shell form'(test: Test) { + }); + + test('can specify Health Check values in shell form', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1273,7 +1271,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { HealthCheck: { @@ -1285,12 +1283,12 @@ export = { }, }, ], - })); + }); - test.done(); - }, - 'can specify Health Check values in array form starting with CMD-SHELL'(test: Test) { + }); + + test('can specify Health Check values in array form starting with CMD-SHELL', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1309,7 +1307,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { HealthCheck: { @@ -1321,12 +1319,12 @@ export = { }, }, ], - })); + }); + - test.done(); - }, + }); - 'can specify Health Check values in array form starting with CMD'(test: Test) { + test('can specify Health Check values in array form starting with CMD', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1345,7 +1343,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { HealthCheck: { @@ -1357,12 +1355,12 @@ export = { }, }, ], - })); + }); + - test.done(); - }, + }); - 'can specify private registry credentials'(test: Test) { + test('can specify private registry credentials', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1379,7 +1377,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Image: 'user-x/my-app', @@ -1388,9 +1386,9 @@ export = { }, }, ], - })); + }); - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -1403,13 +1401,13 @@ export = { }, ], }, - })); + }); - test.done(); - }, - '_linkContainer works properly': { - 'when the props passed in is an essential container'(test: Test) { + }); + + describe('_linkContainer works properly', () => { + test('when the props passed in is an essential container', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1422,12 +1420,12 @@ export = { }); // THEN - test.equal(taskDefinition.defaultContainer, container); + expect(taskDefinition.defaultContainer).toEqual( container); + - test.done(); - }, + }); - 'when the props passed in is not an essential container'(test: Test) { + test('when the props passed in is not an essential container', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1440,14 +1438,14 @@ export = { }); // THEN - test.equal(taskDefinition.defaultContainer, undefined); + expect(taskDefinition.defaultContainer).toEqual( undefined); + - test.done(); - }, - }, + }); + }); - 'Can specify linux parameters': { - 'with only required properties set, it correctly sets default properties'(test: Test) { + describe('Can specify linux parameters', () => { + test('with only required properties set, it correctly sets default properties', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1462,7 +1460,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Image: 'test', @@ -1471,12 +1469,12 @@ export = { }, }, ], - })); + }); - test.done(); - }, - 'before calling addContainer'(test: Test) { + }); + + test('before calling addContainer', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1497,7 +1495,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Image: 'test', @@ -1511,12 +1509,12 @@ export = { }, }, ], - })); + }); - test.done(); - }, - 'after calling addContainer'(test: Test) { + }); + + test('after calling addContainer', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1539,7 +1537,7 @@ export = { linuxParameters.dropCapabilities(ecs.Capability.SETUID); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Image: 'test', @@ -1553,12 +1551,12 @@ export = { }, }, ], - })); + }); + - test.done(); - }, + }); - 'with one or more host devices'(test: Test) { + test('with one or more host devices', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1580,7 +1578,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Image: 'test', @@ -1595,12 +1593,12 @@ export = { }, }, ], - })); + }); - test.done(); - }, - 'with the tmpfs mount for a container'(test: Test) { + }); + + test('with the tmpfs mount for a container', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1623,7 +1621,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Image: 'test', @@ -1639,19 +1637,14 @@ export = { }, }, ], - })); + }); - test.done(); - }, - }, - 'can use a DockerImageAsset directly for a container image'(test: Test) { - // GIVEN - const app = new cdk.App({ - context: { - '@aws-cdk/aws-ecr-assets:dockerIgnoreSupport': true, - }, }); + }); + + testFutureBehavior('can use a DockerImageAsset directly for a container image', { '@aws-cdk/aws-ecr-assets:dockerIgnoreSupport': true }, cdk.App, (app) => { + // GIVEN const stack = new cdk.Stack(app, 'Stack'); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); const asset = new ecr_assets.DockerImageAsset(stack, 'MyDockerImage', { @@ -1665,7 +1658,7 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Essential: true, @@ -1686,8 +1679,8 @@ export = { Name: 'default', }, ], - })); - expect(stack).to(haveResource('AWS::IAM::Policy', { + }); + expect(stack).toHaveResource('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -1712,17 +1705,12 @@ export = { ], Version: '2012-10-17', }, - })); - test.done(); - }, + }); - 'docker image asset options can be used when using container image'(test: Test) { + }); + + testFutureBehavior('docker image asset options can be used when using container image', { '@aws-cdk/aws-ecr-assets:dockerIgnoreSupport': true }, cdk.App, (app) => { // GIVEN - const app = new cdk.App({ - context: { - '@aws-cdk/aws-ecr-assets:dockerIgnoreSupport': true, - }, - }); const stack = new cdk.Stack(app, 'MyStack'); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); @@ -1737,7 +1725,7 @@ export = { // THEN const asm = app.synth(); - test.deepEqual(asm.getStackArtifact(stack.artifactId).assets[0], { + expect(asm.getStackArtifact(stack.artifactId).assets[0]).toEqual({ repositoryName: 'aws-cdk/assets', imageTag: 'ce3419d7c5d2d44e2789b13ccbd2d54ddf682557669f68bcee753231f5f1c0a5', id: 'ce3419d7c5d2d44e2789b13ccbd2d54ddf682557669f68bcee753231f5f1c0a5', @@ -1747,6 +1735,6 @@ export = { target: 'build-target', file: 'index.py', }); - test.done(); - }, -}; + + }); +}); diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/test.cross-stack.ts b/packages/@aws-cdk/aws-ecs/test/ec2/cross-stack.test.ts similarity index 97% rename from packages/@aws-cdk/aws-ecs/test/ec2/test.cross-stack.ts rename to packages/@aws-cdk/aws-ecs/test/ec2/cross-stack.test.ts index 5eb7c61a6d346..12d908957fc88 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/test.cross-stack.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/cross-stack.test.ts @@ -2,7 +2,7 @@ import { expect, haveResource } from '@aws-cdk/assert'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import { App, Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../../lib'; // Test various cross-stack Cluster/Service/ALB scenario's @@ -13,7 +13,7 @@ let stack2: Stack; let cluster: ecs.Cluster; let service: ecs.Ec2Service; -export = { +nodeunitShim({ 'setUp'(cb: () => void) { app = new App(); @@ -89,7 +89,7 @@ export = { test.done(); }, -}; +}); function expectIngress(stack: Stack) { expect(stack).to(haveResource('AWS::EC2::SecurityGroupIngress', { diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-service.ts b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-service.test.ts similarity index 99% rename from packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-service.ts rename to packages/@aws-cdk/aws-ecs/test/ec2/ec2-service.test.ts index c4b2816234595..2279245aebaa4 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-service.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-service.test.ts @@ -4,12 +4,12 @@ import * as elb from '@aws-cdk/aws-elasticloadbalancing'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import * as cloudmap from '@aws-cdk/aws-servicediscovery'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../../lib'; import { DeploymentControllerType, LaunchType, PropagatedTagSource } from '../../lib/base/base-service'; import { PlacementConstraint, PlacementStrategy } from '../../lib/placement'; -export = { +nodeunitShim({ 'When creating an EC2 Service': { 'with only required properties set, it correctly sets default properties'(test: Test) { // GIVEN @@ -2269,4 +2269,4 @@ export = { test.done(); }, }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-task-definition.ts b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts similarity index 84% rename from packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-task-definition.ts rename to packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts index 9264c47e4550c..bea2e3c0733e5 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-task-definition.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts @@ -1,33 +1,33 @@ +import '@aws-cdk/assert/jest'; import * as path from 'path'; -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; import { Protocol } from '@aws-cdk/aws-ec2'; import { Repository } from '@aws-cdk/aws-ecr'; import * as iam from '@aws-cdk/aws-iam'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; import * as ssm from '@aws-cdk/aws-ssm'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; import * as ecs from '../../lib'; -export = { - 'When creating an ECS TaskDefinition': { - 'with only required properties set, it correctly sets default properties'(test: Test) { +describe('ec2 task definition', () => { + describe('When creating an ECS TaskDefinition', () => { + test('with only required properties set, it correctly sets default properties', () => { // GIVEN const stack = new cdk.Stack(); new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef'); // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { Family: 'Ec2TaskDef', NetworkMode: ecs.NetworkMode.BRIDGE, RequiresCompatibilities: ['EC2'], - })); + }); // test error if no container defs? - test.done(); - }, - 'with all properties set'(test: Test) { + }); + + test('with all properties set', () => { // GIVEN const stack = new cdk.Stack(); new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { @@ -55,7 +55,7 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { ExecutionRoleArn: { 'Fn::GetAtt': [ 'ExecutionRole605A040B', @@ -89,12 +89,12 @@ export = { Name: 'scratch', }, ], - })); + }); - test.done(); - }, - 'correctly sets placement constraint'(test: Test) { + }); + + test('correctly sets placement constraint', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef'); @@ -103,7 +103,7 @@ export = { taskDefinition.addPlacementConstraint(ecs.PlacementConstraint.memberOf('attribute:ecs.instance-type =~ t2.*')); // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { PlacementConstraints: [ { Expression: 'attribute:ecs.instance-type =~ t2.*', @@ -111,12 +111,12 @@ export = { }, ], - })); + }); - test.done(); - }, - 'correctly sets network mode'(test: Test) { + }); + + test('correctly sets network mode', () => { // GIVEN const stack = new cdk.Stack(); new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { @@ -124,14 +124,14 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { NetworkMode: ecs.NetworkMode.AWS_VPC, - })); + }); + - test.done(); - }, + }); - 'correctly sets ipc mode'(test: Test) { + test('correctly sets ipc mode', () => { // GIVEN const stack = new cdk.Stack(); new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { @@ -139,14 +139,14 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { IpcMode: ecs.IpcMode.TASK, - })); + }); + - test.done(); - }, + }); - 'correctly sets pid mode'(test: Test) { + test('correctly sets pid mode', () => { // GIVEN const stack = new cdk.Stack(); new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { @@ -154,14 +154,14 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { PidMode: ecs.PidMode.HOST, - })); + }); + - test.done(); - }, + }); - 'correctly sets containers'(test: Test) { + test('correctly sets containers', () => { // GIVEN const stack = new cdk.Stack(); @@ -193,7 +193,7 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { Family: 'Ec2TaskDef', ContainerDefinitions: [{ Essential: true, @@ -219,9 +219,9 @@ export = { }, ], }], - })); + }); - expect(stack).to(haveResource('AWS::IAM::Policy', { + expect(stack).toHaveResource('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [ @@ -232,12 +232,12 @@ export = { }, ], }, - })); + }); - test.done(); - }, - 'all container definition options defined'(test: Test) { + }); + + test('all container definition options defined', () => { // GIVEN const stack = new cdk.Stack(); @@ -287,7 +287,7 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { Family: 'Ec2TaskDef', ContainerDefinitions: [ { @@ -434,12 +434,12 @@ export = { WorkingDirectory: 'app/', }, ], - })); + }); - test.done(); - }, - 'correctly sets containers from ECR repository using all props'(test: Test) { + }); + + test('correctly sets containers from ECR repository using all props', () => { // GIVEN const stack = new cdk.Stack(); @@ -460,16 +460,16 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', { + expect(stack).toHaveResource('AWS::ECR::Repository', { LifecyclePolicy: { // eslint-disable-next-line max-len LifecyclePolicyText: '{"rules":[{"rulePriority":10,"selection":{"tagStatus":"tagged","tagPrefixList":["abc"],"countType":"imageCountMoreThan","countNumber":1},"action":{"type":"expire"}}]}', RegistryId: '123456789101', }, RepositoryName: 'project-a/amazon-ecs-sample', - })); + }); - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { Family: 'Ec2TaskDef', ContainerDefinitions: [{ Essential: true, @@ -525,12 +525,12 @@ export = { }, Name: 'web', }], - })); + }); + - test.done(); - }, + }); - 'correctly sets containers from ECR repository using default props'(test: Test) { + test('correctly sets containers from ECR repository using default props', () => { // GIVEN const stack = new cdk.Stack(); @@ -543,12 +543,12 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', {})); + expect(stack).toHaveResource('AWS::ECR::Repository', {}); + - test.done(); - }, + }); - 'warns when setting containers from ECR repository using fromRegistry method'(test: Test) { + test('warns when setting containers from ECR repository using fromRegistry method', () => { // GIVEN const stack = new cdk.Stack(); @@ -561,11 +561,11 @@ export = { }); // THEN - test.deepEqual(container.node.metadata[0].data, "Proper policies need to be attached before pulling from ECR repository, or use 'fromEcrRepository'."); - test.done(); - }, + expect(container.node.metadata[0].data).toEqual("Proper policies need to be attached before pulling from ECR repository, or use 'fromEcrRepository'."); - 'warns when setting containers from ECR repository by creating a RepositoryImage class'(test: Test) { + }); + + test('warns when setting containers from ECR repository by creating a RepositoryImage class', () => { // GIVEN const stack = new cdk.Stack(); @@ -580,18 +580,13 @@ export = { }); // THEN - test.deepEqual(container.node.metadata[0].data, "Proper policies need to be attached before pulling from ECR repository, or use 'fromEcrRepository'."); + expect(container.node.metadata[0].data).toEqual("Proper policies need to be attached before pulling from ECR repository, or use 'fromEcrRepository'."); + - test.done(); - }, + }); - 'correctly sets containers from asset using default props'(test: Test) { + testFutureBehavior('correctly sets containers from asset using default props', { '@aws-cdk/aws-ecr-assets:dockerIgnoreSupport': true }, cdk.App, (app) => { // GIVEN - const app = new cdk.App({ - context: { - '@aws-cdk/aws-ecr-assets:dockerIgnoreSupport': true, - }, - }); const stack = new cdk.Stack(app, 'Stack'); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef'); @@ -603,7 +598,7 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { Family: 'StackEc2TaskDefF03698CF', ContainerDefinitions: [ { @@ -631,12 +626,12 @@ export = { Name: 'web', }, ], - })); + }); + - test.done(); - }, + }); - 'correctly sets containers from asset using all props'(test: Test) { + test('correctly sets containers from asset using all props', () => { // GIVEN const stack = new cdk.Stack(); @@ -649,10 +644,10 @@ export = { memoryLimitMiB: 512, }); - test.done(); - }, - 'correctly sets scratch space'(test: Test) { + }); + + test('correctly sets scratch space', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef'); @@ -670,7 +665,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { Family: 'Ec2TaskDef', ContainerDefinitions: [{ MountPoints: [ @@ -687,11 +682,11 @@ export = { }, Name: 'scratch', }], - })); + }); - test.done(); - }, - 'correctly sets container dependenices'(test: Test) { + + }); + test('correctly sets container dependenices', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef'); @@ -721,7 +716,7 @@ export = { ); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { Family: 'Ec2TaskDef', ContainerDefinitions: [{ Name: 'dependency1', @@ -740,11 +735,11 @@ export = { ContainerName: 'dependency2', }], }], - })); + }); + - test.done(); - }, - 'correctly sets links'(test: Test) { + }); + test('correctly sets links', () => { const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { @@ -770,7 +765,7 @@ export = { container.addLink(linkedContainer2); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [ { Links: [ @@ -786,12 +781,12 @@ export = { Name: 'linked2', }, ], - })); + }); + - test.done(); - }, + }); - 'correctly set policy statement to the task IAM role'(test: Test) { + test('correctly set policy statement to the task IAM role', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef'); @@ -803,7 +798,7 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::IAM::Policy', { + expect(stack).toHaveResource('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [ @@ -814,11 +809,11 @@ export = { }, ], }, - })); + }); + - test.done(); - }, - 'correctly sets volumes from'(test: Test) { + }); + test('correctly sets volumes from', () => { const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', {}); @@ -834,7 +829,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { ContainerDefinitions: [{ VolumesFrom: [ { @@ -843,12 +838,12 @@ export = { }, ], }], - })); + }); - test.done(); - }, - 'correctly set policy statement to the task execution IAM role'(test: Test) { + }); + + test('correctly set policy statement to the task execution IAM role', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef'); @@ -860,7 +855,7 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::IAM::Policy', { + expect(stack).toHaveResource('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [ @@ -871,12 +866,12 @@ export = { }, ], }, - })); + }); + - test.done(); - }, + }); - 'correctly sets volumes'(test: Test) { + test('correctly sets volumes', () => { // GIVEN const stack = new cdk.Stack(); const volume = { @@ -904,7 +899,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { Family: 'Ec2TaskDef', ContainerDefinitions: [{ MountPoints: [ @@ -921,12 +916,12 @@ export = { }, Name: 'scratch', }], - })); + }); - test.done(); - }, - 'correctly sets placement constraints'(test: Test) { + }); + + test('correctly sets placement constraints', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { @@ -941,19 +936,19 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { PlacementConstraints: [ { Expression: 'attribute:ecs.instance-type =~ t2.*', Type: 'memberOf', }, ], - })); + }); - test.done(); - }, - 'correctly sets taskRole'(test: Test) { + }); + + test('correctly sets taskRole', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { @@ -968,27 +963,27 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { TaskRoleArn: stack.resolve(taskDefinition.taskRole.roleArn), - })); + }); - test.done(); - }, - 'automatically sets taskRole by default'(test: Test) { + }); + + test('automatically sets taskRole by default', () => { // GIVEN const stack = new cdk.Stack(); const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef'); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { TaskRoleArn: stack.resolve(taskDefinition.taskRole.roleArn), - })); + }); + - test.done(); - }, + }); - 'correctly sets dockerVolumeConfiguration'(test: Test) { + test('correctly sets dockerVolumeConfiguration', () => { // GIVEN const stack = new cdk.Stack(); const volume = { @@ -1012,7 +1007,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { Family: 'Ec2TaskDef', Volumes: [{ Name: 'scratch', @@ -1024,12 +1019,12 @@ export = { }, }, }], - })); + }); + - test.done(); - }, + }); - 'correctly sets efsVolumeConfiguration'(test: Test) { + test('correctly sets efsVolumeConfiguration', () => { // GIVEN const stack = new cdk.Stack(); const volume = { @@ -1049,7 +1044,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { Family: 'Ec2TaskDef', Volumes: [{ Name: 'scratch', @@ -1057,13 +1052,13 @@ export = { FileSystemId: 'local', }, }], - })); + }); - test.done(); - }, - }, - 'throws when setting proxyConfiguration without networkMode AWS_VPC'(test: Test) { + }); + }); + + test('throws when setting proxyConfiguration without networkMode AWS_VPC', () => { // GIVEN const stack = new cdk.Stack(); @@ -1079,10 +1074,10 @@ export = { }); // THEN - test.throws(() => { + expect(() => { new ecs.Ec2TaskDefinition(stack, 'TaskDef', { networkMode: ecs.NetworkMode.BRIDGE, proxyConfiguration }); - }, /ProxyConfiguration can only be used with AwsVpc network mode, got: bridge/); + }).toThrow(/ProxyConfiguration can only be used with AwsVpc network mode, got: bridge/); + - test.done(); - }, -}; + }); +}); diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.expected.json index 176bf38d788a5..7a40a11d952ca 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 @@ -698,14 +698,12 @@ "Code": { "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, - "Handler": "index.lambda_handler", "Role": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", "Arn" ] }, - "Runtime": "python3.6", "Environment": { "Variables": { "CLUSTER": { @@ -713,6 +711,8 @@ } } }, + "Handler": "index.lambda_handler", + "Runtime": "python3.6", "Tags": [ { "Key": "Name", diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.bottlerocket.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.bottlerocket.expected.json index 3644a517b73af..23ba70a23584d 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.bottlerocket.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.bottlerocket.expected.json @@ -692,14 +692,12 @@ "Code": { "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, - "Handler": "index.lambda_handler", "Role": { "Fn::GetAtt": [ "EcsClusterbottlerocketasgDrainECSHookFunctionServiceRole2F16AFAB", "Arn" ] }, - "Runtime": "python3.6", "Environment": { "Variables": { "CLUSTER": { @@ -707,6 +705,8 @@ } } }, + "Handler": "index.lambda_handler", + "Runtime": "python3.6", "Tags": [ { "Key": "Name", 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 67289e175fa8b..3a323b0d36eff 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 @@ -719,14 +719,12 @@ "Code": { "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, - "Handler": "index.lambda_handler", "Role": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", "Arn" ] }, - "Runtime": "python3.6", "Environment": { "Variables": { "CLUSTER": { @@ -734,6 +732,8 @@ } } }, + "Handler": "index.lambda_handler", + "Runtime": "python3.6", "Tags": [ { "Key": "Name", diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json index 9376c507c20cf..b287e6ffc33fa 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json @@ -1176,7 +1176,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -1385,4 +1385,4 @@ "Description": "Artifact hash for asset \"872561bf078edd1685d50c9ff821cdd60d2b2ddfb0013c4087e79bf2bb50724d\"" } } -} \ No newline at end of file +} 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 d76ccbf580d80..967d38891c487 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 @@ -698,14 +698,12 @@ "Code": { "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, - "Handler": "index.lambda_handler", "Role": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", "Arn" ] }, - "Runtime": "python3.6", "Environment": { "Variables": { "CLUSTER": { @@ -713,6 +711,8 @@ } } }, + "Handler": "index.lambda_handler", + "Runtime": "python3.6", "Tags": [ { "Key": "Name", 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 a8f0ceeeebb15..90fd28f84cef2 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 @@ -698,14 +698,12 @@ "Code": { "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, - "Handler": "index.lambda_handler", "Role": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", "Arn" ] }, - "Runtime": "python3.6", "Environment": { "Variables": { "CLUSTER": { @@ -713,6 +711,8 @@ } } }, + "Handler": "index.lambda_handler", + "Runtime": "python3.6", "Tags": [ { "Key": "Name", 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 2b0faf9e340f1..0737785f5fea4 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 @@ -719,14 +719,12 @@ "Code": { "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, - "Handler": "index.lambda_handler", "Role": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", "Arn" ] }, - "Runtime": "python3.6", "Environment": { "Variables": { "CLUSTER": { @@ -734,6 +732,8 @@ } } }, + "Handler": "index.lambda_handler", + "Runtime": "python3.6", "Tags": [ { "Key": "Name", 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 3cc8789e3021a..b4e2c72807b0e 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 @@ -698,14 +698,12 @@ "Code": { "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, - "Handler": "index.lambda_handler", "Role": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", "Arn" ] }, - "Runtime": "python3.6", "Environment": { "Variables": { "CLUSTER": { @@ -713,6 +711,8 @@ } } }, + "Handler": "index.lambda_handler", + "Runtime": "python3.6", "Tags": [ { "Key": "Name", 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 49e99b166b764..ef42895037361 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 @@ -698,14 +698,12 @@ "Code": { "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, - "Handler": "index.lambda_handler", "Role": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", "Arn" ] }, - "Runtime": "python3.6", "Environment": { "Variables": { "CLUSTER": { @@ -713,6 +711,8 @@ } } }, + "Handler": "index.lambda_handler", + "Runtime": "python3.6", "Tags": [ { "Key": "Name", 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 ae30eab9d2419..77acf122d0168 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 @@ -700,14 +700,12 @@ "Code": { "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, - "Handler": "index.lambda_handler", "Role": { "Fn::GetAtt": [ "EcsClusterasgSpotDrainECSHookFunctionServiceRole8EEDDFE0", "Arn" ] }, - "Runtime": "python3.6", "Environment": { "Variables": { "CLUSTER": { @@ -715,6 +713,8 @@ } } }, + "Handler": "index.lambda_handler", + "Runtime": "python3.6", "Tags": [ { "Key": "Name", @@ -1181,14 +1181,12 @@ "Code": { "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, - "Handler": "index.lambda_handler", "Role": { "Fn::GetAtt": [ "EcsClusterasgOdDrainECSHookFunctionServiceRoleFC088D55", "Arn" ] }, - "Runtime": "python3.6", "Environment": { "Variables": { "CLUSTER": { @@ -1196,6 +1194,8 @@ } } }, + "Handler": "index.lambda_handler", + "Runtime": "python3.6", "Tags": [ { "Key": "Name", diff --git a/packages/@aws-cdk/aws-ecs/test/test.ecs-cluster.ts b/packages/@aws-cdk/aws-ecs/test/ecs-cluster.test.ts similarity index 97% rename from packages/@aws-cdk/aws-ecs/test/test.ecs-cluster.ts rename to packages/@aws-cdk/aws-ecs/test/ecs-cluster.test.ts index 71a5fc23081d4..119e6d11a93ce 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.ecs-cluster.ts +++ b/packages/@aws-cdk/aws-ecs/test/ecs-cluster.test.ts @@ -9,10 +9,10 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as kms from '@aws-cdk/aws-kms'; import * as cloudmap from '@aws-cdk/aws-servicediscovery'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; -export = { +nodeunitShim({ 'When creating an ECS Cluster': { 'with no properties set, it correctly sets default properties'(test: Test) { // GIVEN @@ -1666,6 +1666,7 @@ export = { ); test.done(); }, + 'throws when machineImage and machineImageType both specified'(test: Test) { // GIVEN const app = new cdk.App(); @@ -1682,4 +1683,52 @@ export = { }, /You can only specify either machineImage or machineImageType, not both./); test.done(); }, -}; + + 'allows specifying capacityProviders'(test: Test) { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'test'); + + // WHEN + new ecs.Cluster(stack, 'EcsCluster', { capacityProviders: ['FARGATE_SPOT'] }); + + // THEN + expect(stack).to(haveResource('AWS::ECS::Cluster', { + CapacityProviders: ['FARGATE_SPOT'], + })); + + test.done(); + }, + + 'allows adding capacityProviders post-construction'(test: Test) { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'test'); + const cluster = new ecs.Cluster(stack, 'EcsCluster'); + + // WHEN + cluster.addCapacityProvider('FARGATE'); + cluster.addCapacityProvider('FARGATE'); // does not add twice + + // THEN + expect(stack).to(haveResource('AWS::ECS::Cluster', { + CapacityProviders: ['FARGATE'], + })); + + test.done(); + }, + + 'throws for unsupported capacity providers'(test: Test) { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'test'); + const cluster = new ecs.Cluster(stack, 'EcsCluster'); + + // THEN + test.throws(() => { + cluster.addCapacityProvider('HONK'); + }, /CapacityProvider not supported/); + + test.done(); + }, +}); diff --git a/packages/@aws-cdk/aws-ecs/test/test.environment-file.ts b/packages/@aws-cdk/aws-ecs/test/environment-file.test.ts similarity index 96% rename from packages/@aws-cdk/aws-ecs/test/test.environment-file.ts rename to packages/@aws-cdk/aws-ecs/test/environment-file.test.ts index a0d6fc29d3aed..e80651cbbd65b 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.environment-file.ts +++ b/packages/@aws-cdk/aws-ecs/test/environment-file.test.ts @@ -1,11 +1,11 @@ import * as path from 'path'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; /* eslint-disable dot-notation */ -export = { +nodeunitShim({ 'ecs.EnvironmentFile.fromAsset': { 'fails if asset is not a single file'(test: Test) { // GIVEN @@ -45,7 +45,7 @@ export = { test.done(); }, }, -}; +}); function defineContainerDefinition(stack: cdk.Stack, environmentFile: ecs.EnvironmentFile) { const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/test.fargate-service.ts b/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts similarity index 96% rename from packages/@aws-cdk/aws-ecs/test/fargate/test.fargate-service.ts rename to packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts index 85ddcd6a07176..acddf713d6d0a 100644 --- a/packages/@aws-cdk/aws-ecs/test/fargate/test.fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts @@ -6,11 +6,11 @@ import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; import * as cloudmap from '@aws-cdk/aws-servicediscovery'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../../lib'; import { DeploymentControllerType, LaunchType } from '../../lib/base/base-service'; -export = { +nodeunitShim({ 'When creating a Fargate Service': { 'with only required properties set, it correctly sets default properties'(test: Test) { // GIVEN @@ -110,6 +110,91 @@ export = { test.done(); }, + 'does not set launchType when capacity provider strategies specified'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'MyVpc', {}); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { + vpc, + capacityProviders: ['FARGATE', 'FARGATE_SPOT'], + }); + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); + + const container = taskDefinition.addContainer('web', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 512, + }); + container.addPortMappings({ containerPort: 8000 }); + + new ecs.FargateService(stack, 'FargateService', { + cluster, + taskDefinition, + capacityProviderStrategies: [ + { + capacityProvider: 'FARGATE_SPOT', + weight: 2, + }, + { + capacityProvider: 'FARGATE', + weight: 1, + }, + ], + }); + + // THEN + expect(stack).to(haveResource('AWS::ECS::Cluster', { + CapacityProviders: ['FARGATE', 'FARGATE_SPOT'], + })); + + expect(stack).to(haveResource('AWS::ECS::Service', { + TaskDefinition: { + Ref: 'FargateTaskDefC6FB60B4', + }, + Cluster: { + Ref: 'EcsCluster97242B84', + }, + DeploymentConfiguration: { + MaximumPercent: 200, + MinimumHealthyPercent: 50, + }, + // no launch type + CapacityProviderStrategy: [ + { + CapacityProvider: 'FARGATE_SPOT', + Weight: 2, + }, + { + CapacityProvider: 'FARGATE', + Weight: 1, + }, + ], + EnableECSManagedTags: false, + NetworkConfiguration: { + AwsvpcConfiguration: { + AssignPublicIp: 'DISABLED', + SecurityGroups: [ + { + 'Fn::GetAtt': [ + 'FargateServiceSecurityGroup0A0E79CB', + 'GroupId', + ], + }, + ], + Subnets: [ + { + Ref: 'MyVpcPrivateSubnet1Subnet5057CF7E', + }, + { + Ref: 'MyVpcPrivateSubnet2Subnet0040C983', + }, + ], + }, + }, + })); + + test.done(); + }, + 'with custom cloudmap namespace'(test: Test) { // GIVEN const stack = new cdk.Stack(); @@ -1850,4 +1935,4 @@ export = { test.done(); }, }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/test.fargate-task-definition.ts b/packages/@aws-cdk/aws-ecs/test/fargate/fargate-task-definition.test.ts similarity index 97% rename from packages/@aws-cdk/aws-ecs/test/fargate/test.fargate-task-definition.ts rename to packages/@aws-cdk/aws-ecs/test/fargate/fargate-task-definition.test.ts index 99aeb6da886f9..00ec0028ef1a3 100644 --- a/packages/@aws-cdk/aws-ecs/test/fargate/test.fargate-task-definition.ts +++ b/packages/@aws-cdk/aws-ecs/test/fargate/fargate-task-definition.test.ts @@ -1,10 +1,10 @@ import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../../lib'; -export = { +nodeunitShim({ 'When creating an Fargate TaskDefinition': { 'with only required properties set, it correctly sets default properties'(test: Test) { // GIVEN @@ -114,4 +114,4 @@ export = { test.done(); }, }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/integ.capacity-providers.expected.json b/packages/@aws-cdk/aws-ecs/test/fargate/integ.capacity-providers.expected.json new file mode 100644 index 0000000000000..c0281dc8e14ae --- /dev/null +++ b/packages/@aws-cdk/aws-ecs/test/fargate/integ.capacity-providers.expected.json @@ -0,0 +1,473 @@ +{ + "Resources": { + "Vpc8378EB38": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-capacity-provider/Vpc" + } + ] + } + }, + "VpcPublicSubnet1Subnet5C2D37C4": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "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-ecs-integ-capacity-provider/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1RouteTable6C95E38E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-capacity-provider/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1RouteTableAssociation97140677": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + } + } + }, + "VpcPublicSubnet1DefaultRoute3DA9E72A": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet1EIPD7E02669": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-capacity-provider/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1NATGateway4D7517AA": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet1EIPD7E02669", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-capacity-provider/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet2Subnet691E08A3": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "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-ecs-integ-capacity-provider/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2RouteTable94F7E489": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-capacity-provider/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2RouteTableAssociationDD5762D8": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + } + } + }, + "VpcPublicSubnet2DefaultRoute97F91067": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet2EIP3C605A87": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-capacity-provider/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2NATGateway9182C01D": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet2EIP3C605A87", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-capacity-provider/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPrivateSubnet1Subnet536B997A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "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-ecs-integ-capacity-provider/Vpc/PrivateSubnet1" + } + ] + } + }, + "VpcPrivateSubnet1RouteTableB2C5B500": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-capacity-provider/Vpc/PrivateSubnet1" + } + ] + } + }, + "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + } + } + }, + "VpcPrivateSubnet1DefaultRouteBE02A9ED": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + } + } + }, + "VpcPrivateSubnet2Subnet3788AAA1": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.192.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "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-ecs-integ-capacity-provider/Vpc/PrivateSubnet2" + } + ] + } + }, + "VpcPrivateSubnet2RouteTableA678073B": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-capacity-provider/Vpc/PrivateSubnet2" + } + ] + } + }, + "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + } + }, + "VpcPrivateSubnet2DefaultRoute060D2087": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet2NATGateway9182C01D" + } + } + }, + "VpcIGWD7BA715C": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-capacity-provider/Vpc" + } + ] + } + }, + "VpcVPCGWBF912B6E": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "InternetGatewayId": { + "Ref": "VpcIGWD7BA715C" + } + } + }, + "FargateCPCluster668E71F2": { + "Type": "AWS::ECS::Cluster", + "Properties": { + "CapacityProviders": [ + "FARGATE", + "FARGATE_SPOT" + ] + } + }, + "TaskDefTaskRole1EDB4A67": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "TaskDef54694570": { + "Type": "AWS::ECS::TaskDefinition", + "Properties": { + "ContainerDefinitions": [ + { + "Essential": true, + "Image": "amazon/amazon-ecs-sample", + "Name": "web" + } + ], + "Cpu": "256", + "Family": "awsecsintegcapacityproviderTaskDef80D341CB", + "Memory": "512", + "NetworkMode": "awsvpc", + "RequiresCompatibilities": [ + "FARGATE" + ], + "TaskRoleArn": { + "Fn::GetAtt": [ + "TaskDefTaskRole1EDB4A67", + "Arn" + ] + } + } + }, + "FargateServiceAC2B3B85": { + "Type": "AWS::ECS::Service", + "Properties": { + "CapacityProviderStrategy": [ + { + "CapacityProvider": "FARGATE_SPOT", + "Weight": 2 + }, + { + "CapacityProvider": "FARGATE", + "Weight": 1 + } + ], + "Cluster": { + "Ref": "FargateCPCluster668E71F2" + }, + "DeploymentConfiguration": { + "MaximumPercent": 200, + "MinimumHealthyPercent": 50 + }, + "EnableECSManagedTags": false, + "NetworkConfiguration": { + "AwsvpcConfiguration": { + "AssignPublicIp": "DISABLED", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "FargateServiceSecurityGroup0A0E79CB", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + }, + { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + ] + } + }, + "TaskDefinition": { + "Ref": "TaskDef54694570" + } + } + }, + "FargateServiceSecurityGroup0A0E79CB": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-integ-capacity-provider/FargateService/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/integ.capacity-providers.ts b/packages/@aws-cdk/aws-ecs/test/fargate/integ.capacity-providers.ts new file mode 100644 index 0000000000000..673b15284a577 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs/test/fargate/integ.capacity-providers.ts @@ -0,0 +1,37 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as cdk from '@aws-cdk/core'; +import * as ecs from '../../lib'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-ecs-integ-capacity-provider'); + +const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 2 }); + +const cluster = new ecs.Cluster(stack, 'FargateCPCluster', { + vpc, + capacityProviders: ['FARGATE', 'FARGATE_SPOT'], +}); + +const taskDefinition = new ecs.FargateTaskDefinition(stack, 'TaskDef'); + +taskDefinition.addContainer('web', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), +}); + +new ecs.FargateService(stack, 'FargateService', { + cluster, + taskDefinition, + capacityProviderStrategies: [ + { + capacityProvider: 'FARGATE_SPOT', + weight: 2, + }, + { + capacityProvider: 'FARGATE', + weight: 1, + }, + ], +}); + +app.synth(); + diff --git a/packages/@aws-cdk/aws-ecs/test/test.firelens-log-driver.ts b/packages/@aws-cdk/aws-ecs/test/firelens-log-driver.test.ts similarity index 98% rename from packages/@aws-cdk/aws-ecs/test/test.firelens-log-driver.ts rename to packages/@aws-cdk/aws-ecs/test/firelens-log-driver.test.ts index 3a1fb264d6b34..99a1c6b935b64 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.firelens-log-driver.ts +++ b/packages/@aws-cdk/aws-ecs/test/firelens-log-driver.test.ts @@ -1,13 +1,13 @@ import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; let stack: cdk.Stack; let td: ecs.TaskDefinition; const image = ecs.ContainerImage.fromRegistry('test-image'); -export = { +nodeunitShim({ 'setUp'(cb: () => void) { stack = new cdk.Stack(); td = new ecs.Ec2TaskDefinition(stack, 'TaskDefinition'); @@ -229,4 +229,4 @@ export = { test.done(); }, }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/test.fluentd-log-driver.ts b/packages/@aws-cdk/aws-ecs/test/fluentd-log-driver.test.ts similarity index 97% rename from packages/@aws-cdk/aws-ecs/test/test.fluentd-log-driver.ts rename to packages/@aws-cdk/aws-ecs/test/fluentd-log-driver.test.ts index 5d451ec365683..a317699d1075d 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.fluentd-log-driver.ts +++ b/packages/@aws-cdk/aws-ecs/test/fluentd-log-driver.test.ts @@ -1,13 +1,13 @@ import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; let stack: cdk.Stack; let td: ecs.TaskDefinition; const image = ecs.ContainerImage.fromRegistry('test-image'); -export = { +nodeunitShim({ 'setUp'(cb: () => void) { stack = new cdk.Stack(); td = new ecs.Ec2TaskDefinition(stack, 'TaskDefinition'); @@ -138,4 +138,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/test.gelf-log-driver.ts b/packages/@aws-cdk/aws-ecs/test/gelf-log-driver.test.ts similarity index 95% rename from packages/@aws-cdk/aws-ecs/test/test.gelf-log-driver.ts rename to packages/@aws-cdk/aws-ecs/test/gelf-log-driver.test.ts index f62941f010f59..7907b0532b0ac 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.gelf-log-driver.ts +++ b/packages/@aws-cdk/aws-ecs/test/gelf-log-driver.test.ts @@ -1,13 +1,13 @@ import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; let stack: cdk.Stack; let td: ecs.TaskDefinition; const image = ecs.ContainerImage.fromRegistry('test-image'); -export = { +nodeunitShim({ 'setUp'(cb: () => void) { stack = new cdk.Stack(); td = new ecs.Ec2TaskDefinition(stack, 'TaskDefinition'); @@ -68,4 +68,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/images/test.tag-parameter-container-image.ts b/packages/@aws-cdk/aws-ecs/test/images/tag-parameter-container-image.test.ts similarity index 91% rename from packages/@aws-cdk/aws-ecs/test/images/test.tag-parameter-container-image.ts rename to packages/@aws-cdk/aws-ecs/test/images/tag-parameter-container-image.test.ts index 2a96c471b1417..d0fe101252e26 100644 --- a/packages/@aws-cdk/aws-ecs/test/images/test.tag-parameter-container-image.ts +++ b/packages/@aws-cdk/aws-ecs/test/images/tag-parameter-container-image.test.ts @@ -1,10 +1,10 @@ import { SynthUtils } from '@aws-cdk/assert'; import * as ecr from '@aws-cdk/aws-ecr'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../../lib'; -export = { +nodeunitShim({ 'TagParameter container image': { 'throws an error when tagParameterName() is used without binding the image'(test: Test) { // GIVEN @@ -22,4 +22,4 @@ export = { test.done(); }, }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/test.journald-log-driver.ts b/packages/@aws-cdk/aws-ecs/test/journald-log-driver.test.ts similarity index 96% rename from packages/@aws-cdk/aws-ecs/test/test.journald-log-driver.ts rename to packages/@aws-cdk/aws-ecs/test/journald-log-driver.test.ts index f71d796b6d380..31bec4a42e47f 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.journald-log-driver.ts +++ b/packages/@aws-cdk/aws-ecs/test/journald-log-driver.test.ts @@ -1,13 +1,13 @@ import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; let stack: cdk.Stack; let td: ecs.TaskDefinition; const image = ecs.ContainerImage.fromRegistry('test-image'); -export = { +nodeunitShim({ 'setUp'(cb: () => void) { stack = new cdk.Stack(); td = new ecs.Ec2TaskDefinition(stack, 'TaskDefinition'); @@ -86,4 +86,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/test.json-file-log-driver.ts b/packages/@aws-cdk/aws-ecs/test/json-file-log-driver.test.ts similarity index 96% rename from packages/@aws-cdk/aws-ecs/test/test.json-file-log-driver.ts rename to packages/@aws-cdk/aws-ecs/test/json-file-log-driver.test.ts index c7e3f6acec377..e75ff398eeb03 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.json-file-log-driver.ts +++ b/packages/@aws-cdk/aws-ecs/test/json-file-log-driver.test.ts @@ -1,13 +1,13 @@ import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; let stack: cdk.Stack; let td: ecs.TaskDefinition; const image = ecs.ContainerImage.fromRegistry('test-image'); -export = { +nodeunitShim({ 'setUp'(cb: () => void) { stack = new cdk.Stack(); td = new ecs.Ec2TaskDefinition(stack, 'TaskDefinition'); @@ -86,4 +86,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/test.splunk-log-driver.ts b/packages/@aws-cdk/aws-ecs/test/splunk-log-driver.test.ts similarity index 97% rename from packages/@aws-cdk/aws-ecs/test/test.splunk-log-driver.ts rename to packages/@aws-cdk/aws-ecs/test/splunk-log-driver.test.ts index 960f3b749f183..c8afd01daade1 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.splunk-log-driver.ts +++ b/packages/@aws-cdk/aws-ecs/test/splunk-log-driver.test.ts @@ -1,13 +1,13 @@ import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; let stack: cdk.Stack; let td: ecs.TaskDefinition; const image = ecs.ContainerImage.fromRegistry('test-image'); -export = { +nodeunitShim({ 'setUp'(cb: () => void) { stack = new cdk.Stack(); td = new ecs.Ec2TaskDefinition(stack, 'TaskDefinition'); @@ -103,4 +103,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/test.syslog-log-driver.ts b/packages/@aws-cdk/aws-ecs/test/syslog-log-driver.test.ts similarity index 96% rename from packages/@aws-cdk/aws-ecs/test/test.syslog-log-driver.ts rename to packages/@aws-cdk/aws-ecs/test/syslog-log-driver.test.ts index cde1a2a6b1b63..b14c05a5b3234 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.syslog-log-driver.ts +++ b/packages/@aws-cdk/aws-ecs/test/syslog-log-driver.test.ts @@ -1,13 +1,13 @@ import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; let stack: cdk.Stack; let td: ecs.TaskDefinition; const image = ecs.ContainerImage.fromRegistry('test-image'); -export = { +nodeunitShim({ 'setUp'(cb: () => void) { stack = new cdk.Stack(); td = new ecs.Ec2TaskDefinition(stack, 'TaskDefinition'); @@ -86,4 +86,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-ecs/test/test.task-definition.ts b/packages/@aws-cdk/aws-ecs/test/task-definition.test.ts similarity index 88% rename from packages/@aws-cdk/aws-ecs/test/test.task-definition.ts rename to packages/@aws-cdk/aws-ecs/test/task-definition.test.ts index 299e2f81b0651..34a7306106d66 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.task-definition.ts +++ b/packages/@aws-cdk/aws-ecs/test/task-definition.test.ts @@ -1,9 +1,9 @@ import { expect, haveResource } from '@aws-cdk/assert'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; -export = { +nodeunitShim({ 'A task definition with both compatibilities defaults to networkmode AwsVpc'(test: Test) { // GIVEN const stack = new cdk.Stack(); @@ -22,4 +22,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-efs/package.json b/packages/@aws-cdk/aws-efs/package.json index a909287fbec25..6a7cef054b6a2 100644 --- a/packages/@aws-cdk/aws-efs/package.json +++ b/packages/@aws-cdk/aws-efs/package.json @@ -107,5 +107,8 @@ "maturity": "experimental", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-eks-legacy/package.json b/packages/@aws-cdk/aws-eks-legacy/package.json index 32c6b684fa2c6..67078e5830dcf 100644 --- a/packages/@aws-cdk/aws-eks-legacy/package.json +++ b/packages/@aws-cdk/aws-eks-legacy/package.json @@ -127,5 +127,8 @@ "awscdkio": { "announce": false }, - "maturity": "deprecated" + "maturity": "deprecated", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-eks/README.md b/packages/@aws-cdk/aws-eks/README.md index efe50404a2ffa..59909c9ea9a0b 100644 --- a/packages/@aws-cdk/aws-eks/README.md +++ b/packages/@aws-cdk/aws-eks/README.md @@ -49,7 +49,7 @@ This example defines an Amazon EKS cluster with the following configuration: ```ts // provisiong a cluster const cluster = new eks.Cluster(this, 'hello-eks', { - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, }); // apply a kubernetes manifest to the cluster @@ -142,7 +142,7 @@ Creating a new cluster is done using the `Cluster` or `FargateCluster` construct ```ts new eks.Cluster(this, 'HelloEKS', { - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, }); ``` @@ -150,7 +150,7 @@ You can also use `FargateCluster` to provision a cluster that uses only fargate ```ts new eks.FargateCluster(this, 'HelloEKS', { - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, }); ``` @@ -174,7 +174,7 @@ At cluster instantiation time, you can customize the number of instances and the ```ts new eks.Cluster(this, 'HelloEKS', { - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, defaultCapacity: 5, defaultCapacityInstance: ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.SMALL), }); @@ -186,7 +186,7 @@ Additional customizations are available post instantiation. To apply them, set t ```ts const cluster = new eks.Cluster(this, 'HelloEKS', { - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, defaultCapacity: 0, }); @@ -322,7 +322,7 @@ The following code defines an Amazon EKS cluster with a default Fargate Profile ```ts const cluster = new eks.FargateCluster(this, 'MyCluster', { - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, }); ``` @@ -381,7 +381,7 @@ You can also configure the cluster to use an auto-scaling group as the default c ```ts cluster = new eks.Cluster(this, 'HelloEKS', { - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, defaultCapacityType: eks.DefaultCapacityType.EC2, }); ``` @@ -461,11 +461,13 @@ You can configure the [cluster endpoint access](https://docs.aws.amazon.com/eks/ ```ts const cluster = new eks.Cluster(this, 'hello-eks', { - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, endpointAccess: eks.EndpointAccess.PRIVATE // No access outside of your VPC. }); ``` +The default value is `eks.EndpointAccess.PUBLIC_AND_PRIVATE`. Which means the cluster endpoint is accessible from outside of your VPC, but worker node traffic and `kubectl` commands issued by this library stay within your VPC. + ### VPC Support You can specify the VPC of the cluster using the `vpc` and `vpcSubnets` properties: @@ -474,7 +476,7 @@ You can specify the VPC of the cluster using the `vpc` and `vpcSubnets` properti const vpc = new ec2.Vpc(this, 'Vpc'); new eks.Cluster(this, 'HelloEKS', { - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, vpc, vpcSubnets: [{ subnetType: ec2.SubnetType.PRIVATE }] }); @@ -513,7 +515,7 @@ You can configure the environment of this function by specifying it at cluster i ```ts const cluster = new eks.Cluster(this, 'hello-eks', { - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, clusterHandlerEnvironment: { 'http_proxy': 'http://proxy.myproxy.com' } @@ -530,7 +532,7 @@ You can configure the environment of this function by specifying it at cluster i ```ts const cluster = new eks.Cluster(this, 'hello-eks', { - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, kubectlEnvironment: { 'http_proxy': 'http://proxy.myproxy.com' } @@ -620,7 +622,7 @@ When you create a cluster, you can specify a `mastersRole`. The `Cluster` constr ```ts const role = new iam.Role(...); new eks.Cluster(this, 'HelloEKS', { - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, mastersRole: role, }); ``` @@ -634,8 +636,6 @@ $ aws eks update-kubeconfig --name cluster-xxxxx --role-arn arn:aws:iam::1122334 Added new context arn:aws:eks:rrrrr:112233445566:cluster/cluster-xxxxx to /home/boom/.kube/config ``` -The default value is `eks.EndpointAccess.PUBLIC_AND_PRIVATE`. Which means the cluster endpoint is accessible from outside of your VPC, but worker node traffic and `kubectl` commands issued by this library stay within your VPC. - ### Encryption When you create an Amazon EKS cluster, envelope encryption of Kubernetes secrets using the AWS Key Management Service (AWS KMS) can be enabled. diff --git a/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts b/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts index 5d89741026aa9..e134601aef73d 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts @@ -142,14 +142,6 @@ export class ClusterResource extends CoreConstruct { : '*', }); - creationRole.addToPolicy(new iam.PolicyStatement({ - actions: [ - 'ec2:DescribeSubnets', - 'ec2:DescribeRouteTables', - ], - resources: ['*'], - })); - creationRole.addToPolicy(new iam.PolicyStatement({ actions: [ 'eks:CreateCluster', @@ -181,13 +173,19 @@ export class ClusterResource extends CoreConstruct { })); // see https://github.com/aws/aws-cdk/issues/9027 + // these actions are the combined 'ec2:Describe*' actions taken from the EKS SLR policies. + // (AWSServiceRoleForAmazonEKS, AWSServiceRoleForAmazonEKSForFargate, AWSServiceRoleForAmazonEKSNodegroup) creationRole.addToPolicy(new iam.PolicyStatement({ - actions: ['ec2:DescribeVpcs'], - resources: [stack.formatArn({ - service: 'ec2', - resource: 'vpc', - resourceName: props.vpc.vpcId, - })], + actions: [ + 'ec2:DescribeInstances', + 'ec2:DescribeNetworkInterfaces', + 'ec2:DescribeSecurityGroups', + 'ec2:DescribeSubnets', + 'ec2:DescribeRouteTables', + 'ec2:DescribeDhcpOptions', + 'ec2:DescribeVpcs', + ], + resources: ['*'], })); // grant cluster creation role sufficient permission to access the specified key diff --git a/packages/@aws-cdk/aws-eks/lib/cluster.ts b/packages/@aws-cdk/aws-eks/lib/cluster.ts index 706a23720c157..c578b90fa388b 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster.ts @@ -634,6 +634,11 @@ export class KubernetesVersion { */ public static readonly V1_18 = KubernetesVersion.of('1.18'); + /** + * Kubernetes version 1.19 + */ + public static readonly V1_19 = KubernetesVersion.of('1.19'); + /** * Custom cluster version * @param version custom version number diff --git a/packages/@aws-cdk/aws-eks/lib/kubectl-provider.ts b/packages/@aws-cdk/aws-eks/lib/kubectl-provider.ts index e4c71cfda381c..b5bd8ed51b876 100644 --- a/packages/@aws-cdk/aws-eks/lib/kubectl-provider.ts +++ b/packages/@aws-cdk/aws-eks/lib/kubectl-provider.ts @@ -106,6 +106,7 @@ export class KubectlProvider extends NestedStack { onEventHandler: handler, vpc: cluster.kubectlPrivateSubnets ? cluster.vpc : undefined, vpcSubnets: cluster.kubectlPrivateSubnets ? { subnets: cluster.kubectlPrivateSubnets } : undefined, + securityGroups: cluster.kubectlSecurityGroup ? [cluster.kubectlSecurityGroup] : undefined, }); this.serviceToken = provider.serviceToken; diff --git a/packages/@aws-cdk/aws-eks/package.json b/packages/@aws-cdk/aws-eks/package.json index 1a27466d1b92b..4d27cbfaac281 100644 --- a/packages/@aws-cdk/aws-eks/package.json +++ b/packages/@aws-cdk/aws-eks/package.json @@ -73,7 +73,7 @@ "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", "@types/yaml": "1.9.6", - "aws-sdk": "^2.830.0", + "aws-sdk": "^2.848.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -127,5 +127,8 @@ "maturity": "stable", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-eks/test/example.ssh-into-nodes.lit.ts b/packages/@aws-cdk/aws-eks/test/example.ssh-into-nodes.lit.ts index ac924ac20038d..14780774ca44f 100644 --- a/packages/@aws-cdk/aws-eks/test/example.ssh-into-nodes.lit.ts +++ b/packages/@aws-cdk/aws-eks/test/example.ssh-into-nodes.lit.ts @@ -10,7 +10,7 @@ class EksClusterStack extends cdk.Stack { const cluster = new eks.Cluster(this, 'EKSCluster', { vpc, - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, }); /// !show diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.expected.json index 82488919bedb9..e7e1f394cdc7f 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.expected.json @@ -711,14 +711,6 @@ ] } }, - { - "Action": [ - "ec2:DescribeSubnets", - "ec2:DescribeRouteTables" - ], - "Effect": "Allow", - "Resource": "*" - }, { "Action": [ "eks:CreateCluster", @@ -758,23 +750,17 @@ "Resource": "*" }, { - "Action": "ec2:DescribeVpcs", + "Action": [ + "ec2:DescribeInstances", + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", + "ec2:DescribeRouteTables", + "ec2:DescribeDhcpOptions", + "ec2:DescribeVpcs" + ], "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":ec2:test-region:12345678:vpc/", - { - "Ref": "EksAllHandlersInVpcStackDefaultVpcBE11D4AE" - } - ] - ] - } + "Resource": "*" } ], "Version": "2012-10-17" @@ -832,7 +818,7 @@ ] }, "Config": { - "version": "1.18", + "version": "1.19", "roleArn": { "Fn::GetAtt": [ "EksAllHandlersInVpcStackRoleC36F09F0", @@ -1129,7 +1115,7 @@ }, "/", { - "Ref": "AssetParameters1a2bf12b9f0cf5ab2c838e7dd9be4d485bbf32056d6d5333bce57e49d12a172cS3Bucket151BE34C" + "Ref": "AssetParameters70396475d85a52e5c6ccad77894979d07433a207ea3c2668b929f3e70ffde081S3BucketFCD070AE" }, "/", { @@ -1139,7 +1125,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters1a2bf12b9f0cf5ab2c838e7dd9be4d485bbf32056d6d5333bce57e49d12a172cS3VersionKey89E7CC67" + "Ref": "AssetParameters70396475d85a52e5c6ccad77894979d07433a207ea3c2668b929f3e70ffde081S3VersionKeyD47BE42B" } ] } @@ -1152,7 +1138,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters1a2bf12b9f0cf5ab2c838e7dd9be4d485bbf32056d6d5333bce57e49d12a172cS3VersionKey89E7CC67" + "Ref": "AssetParameters70396475d85a52e5c6ccad77894979d07433a207ea3c2668b929f3e70ffde081S3VersionKeyD47BE42B" } ] } @@ -1193,7 +1179,9 @@ "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "awscdkawseksKubectlProviderNestedStackawscdkawseksKubectlProviderNestedStackResourceA7AEBA6B": { "Type": "AWS::CloudFormation::Stack", @@ -1208,7 +1196,7 @@ }, "/", { - "Ref": "AssetParameters11ba420a0c99f0c77f563fb974e76d6110b4445114137af1fe1b69b0d366d2d7S3BucketE510C342" + "Ref": "AssetParameters93bb4c1c6bbced2c1adce602d7643d5475c6e463f4f57f4cd863e064d82a3d82S3Bucket8670C328" }, "/", { @@ -1218,7 +1206,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters11ba420a0c99f0c77f563fb974e76d6110b4445114137af1fe1b69b0d366d2d7S3VersionKeyD31A83B6" + "Ref": "AssetParameters93bb4c1c6bbced2c1adce602d7643d5475c6e463f4f57f4cd863e064d82a3d82S3VersionKeyCEFB3AF5" } ] } @@ -1231,7 +1219,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters11ba420a0c99f0c77f563fb974e76d6110b4445114137af1fe1b69b0d366d2d7S3VersionKeyD31A83B6" + "Ref": "AssetParameters93bb4c1c6bbced2c1adce602d7643d5475c6e463f4f57f4cd863e064d82a3d82S3VersionKeyCEFB3AF5" } ] } @@ -1274,20 +1262,17 @@ "ClusterSecurityGroupId" ] }, - "referencetoawscdkekshandlersinvpctestAssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3BucketC0281AE8Ref": { - "Ref": "AssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3Bucket6DACDE73" + "referencetoawscdkekshandlersinvpctestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3Bucket124CC58FRef": { + "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" }, - "referencetoawscdkekshandlersinvpctestAssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3VersionKeyD6BA7117Ref": { - "Ref": "AssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3VersionKey015AEA61" + "referencetoawscdkekshandlersinvpctestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyF4C27F59Ref": { + "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" }, - "referencetoawscdkekshandlersinvpctestAssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3Bucket88622CD5Ref": { - "Ref": "AssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3Bucket7EE7EA15" + "referencetoawscdkekshandlersinvpctestAssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket68F78FB6Ref": { + "Ref": "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket6ABE1927" }, - "referencetoawscdkekshandlersinvpctestAssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3VersionKey1C342D31Ref": { - "Ref": "AssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3VersionKey6C948E78" - }, - "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStackDefaultVpcE40EA7ACRef": { - "Ref": "EksAllHandlersInVpcStackDefaultVpcBE11D4AE" + "referencetoawscdkekshandlersinvpctestAssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyCE91E7FDRef": { + "Ref": "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyF55A2EA9" }, "referencetoawscdkekshandlersinvpctestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket9D7E9998Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" @@ -1296,7 +1281,9 @@ "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Outputs": { @@ -1378,53 +1365,53 @@ "Type": "String", "Description": "Artifact hash for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" }, - "AssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3Bucket6DACDE73": { + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { "Type": "String", - "Description": "S3 bucket for asset \"efd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1\"" + "Description": "S3 bucket for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" }, - "AssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3VersionKey015AEA61": { + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F": { "Type": "String", - "Description": "S3 key for asset version \"efd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1\"" + "Description": "S3 key for asset version \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" }, - "AssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1ArtifactHashC9FD06BA": { + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68ArtifactHashD9A515C3": { "Type": "String", - "Description": "Artifact hash for asset \"efd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1\"" + "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" }, - "AssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3Bucket7EE7EA15": { + "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket6ABE1927": { "Type": "String", - "Description": "S3 bucket for asset \"b61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449f\"" + "Description": "S3 bucket for asset \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" }, - "AssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3VersionKey6C948E78": { + "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyF55A2EA9": { "Type": "String", - "Description": "S3 key for asset version \"b61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449f\"" + "Description": "S3 key for asset version \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" }, - "AssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fArtifactHash7E705796": { + "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0ArtifactHash1D7A2D6E": { "Type": "String", - "Description": "Artifact hash for asset \"b61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449f\"" + "Description": "Artifact hash for asset \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" }, - "AssetParameters1a2bf12b9f0cf5ab2c838e7dd9be4d485bbf32056d6d5333bce57e49d12a172cS3Bucket151BE34C": { + "AssetParameters70396475d85a52e5c6ccad77894979d07433a207ea3c2668b929f3e70ffde081S3BucketFCD070AE": { "Type": "String", - "Description": "S3 bucket for asset \"1a2bf12b9f0cf5ab2c838e7dd9be4d485bbf32056d6d5333bce57e49d12a172c\"" + "Description": "S3 bucket for asset \"70396475d85a52e5c6ccad77894979d07433a207ea3c2668b929f3e70ffde081\"" }, - "AssetParameters1a2bf12b9f0cf5ab2c838e7dd9be4d485bbf32056d6d5333bce57e49d12a172cS3VersionKey89E7CC67": { + "AssetParameters70396475d85a52e5c6ccad77894979d07433a207ea3c2668b929f3e70ffde081S3VersionKeyD47BE42B": { "Type": "String", - "Description": "S3 key for asset version \"1a2bf12b9f0cf5ab2c838e7dd9be4d485bbf32056d6d5333bce57e49d12a172c\"" + "Description": "S3 key for asset version \"70396475d85a52e5c6ccad77894979d07433a207ea3c2668b929f3e70ffde081\"" }, - "AssetParameters1a2bf12b9f0cf5ab2c838e7dd9be4d485bbf32056d6d5333bce57e49d12a172cArtifactHashAEE8C2AB": { + "AssetParameters70396475d85a52e5c6ccad77894979d07433a207ea3c2668b929f3e70ffde081ArtifactHashF56FF52E": { "Type": "String", - "Description": "Artifact hash for asset \"1a2bf12b9f0cf5ab2c838e7dd9be4d485bbf32056d6d5333bce57e49d12a172c\"" + "Description": "Artifact hash for asset \"70396475d85a52e5c6ccad77894979d07433a207ea3c2668b929f3e70ffde081\"" }, - "AssetParameters11ba420a0c99f0c77f563fb974e76d6110b4445114137af1fe1b69b0d366d2d7S3BucketE510C342": { + "AssetParameters93bb4c1c6bbced2c1adce602d7643d5475c6e463f4f57f4cd863e064d82a3d82S3Bucket8670C328": { "Type": "String", - "Description": "S3 bucket for asset \"11ba420a0c99f0c77f563fb974e76d6110b4445114137af1fe1b69b0d366d2d7\"" + "Description": "S3 bucket for asset \"93bb4c1c6bbced2c1adce602d7643d5475c6e463f4f57f4cd863e064d82a3d82\"" }, - "AssetParameters11ba420a0c99f0c77f563fb974e76d6110b4445114137af1fe1b69b0d366d2d7S3VersionKeyD31A83B6": { + "AssetParameters93bb4c1c6bbced2c1adce602d7643d5475c6e463f4f57f4cd863e064d82a3d82S3VersionKeyCEFB3AF5": { "Type": "String", - "Description": "S3 key for asset version \"11ba420a0c99f0c77f563fb974e76d6110b4445114137af1fe1b69b0d366d2d7\"" + "Description": "S3 key for asset version \"93bb4c1c6bbced2c1adce602d7643d5475c6e463f4f57f4cd863e064d82a3d82\"" }, - "AssetParameters11ba420a0c99f0c77f563fb974e76d6110b4445114137af1fe1b69b0d366d2d7ArtifactHash1C37295C": { + "AssetParameters93bb4c1c6bbced2c1adce602d7643d5475c6e463f4f57f4cd863e064d82a3d82ArtifactHashBEC324DA": { "Type": "String", - "Description": "Artifact hash for asset \"11ba420a0c99f0c77f563fb974e76d6110b4445114137af1fe1b69b0d366d2d7\"" + "Description": "Artifact hash for asset \"93bb4c1c6bbced2c1adce602d7643d5475c6e463f4f57f4cd863e064d82a3d82\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.ts b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.ts index ec9fe15d081da..cd1682a30d318 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.ts +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.ts @@ -3,7 +3,7 @@ import { App } from '@aws-cdk/core'; import * as eks from '../lib'; import { TestStack } from './util'; -const CLUSTER_VERSION = eks.KubernetesVersion.V1_18; +const CLUSTER_VERSION = eks.KubernetesVersion.V1_19; class EksAllHandlersInVpcStack extends TestStack { @@ -22,4 +22,4 @@ const app = new App(); new EksAllHandlersInVpcStack(app, 'aws-cdk-eks-handlers-in-vpc-test'); -app.synth(); \ No newline at end of file +app.synth(); diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.expected.json index f76e62c73ee73..acbe47374bead 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.expected.json @@ -655,14 +655,6 @@ ] } }, - { - "Action": [ - "ec2:DescribeSubnets", - "ec2:DescribeRouteTables" - ], - "Effect": "Allow", - "Resource": "*" - }, { "Action": [ "eks:CreateCluster", @@ -702,23 +694,17 @@ "Resource": "*" }, { - "Action": "ec2:DescribeVpcs", + "Action": [ + "ec2:DescribeInstances", + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", + "ec2:DescribeRouteTables", + "ec2:DescribeDhcpOptions", + "ec2:DescribeVpcs" + ], "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":ec2:test-region:12345678:vpc/", - { - "Ref": "Vpc8378EB38" - } - ] - ] - } + "Resource": "*" } ], "Version": "2012-10-17" @@ -772,7 +758,7 @@ ] }, "Config": { - "version": "1.18", + "version": "1.19", "roleArn": { "Fn::GetAtt": [ "ClusterRoleFA261979", @@ -1062,7 +1048,7 @@ }, "/", { - "Ref": "AssetParameters84ba29b05aaf6a233dbb97b37e48eb1300f9d014f270252e29a8b2c22d6a08beS3Bucket9E737267" + "Ref": "AssetParameters75667ab2bbef2c8efc57fb73bf352f345af1d471fb09cb11f5b7bc27d009b609S3BucketA8C94679" }, "/", { @@ -1072,7 +1058,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters84ba29b05aaf6a233dbb97b37e48eb1300f9d014f270252e29a8b2c22d6a08beS3VersionKeyD5E002BC" + "Ref": "AssetParameters75667ab2bbef2c8efc57fb73bf352f345af1d471fb09cb11f5b7bc27d009b609S3VersionKey3777DB64" } ] } @@ -1085,7 +1071,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters84ba29b05aaf6a233dbb97b37e48eb1300f9d014f270252e29a8b2c22d6a08beS3VersionKeyD5E002BC" + "Ref": "AssetParameters75667ab2bbef2c8efc57fb73bf352f345af1d471fb09cb11f5b7bc27d009b609S3VersionKey3777DB64" } ] } @@ -1114,7 +1100,9 @@ "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "awscdkawseksKubectlProviderNestedStackawscdkawseksKubectlProviderNestedStackResourceA7AEBA6B": { "Type": "AWS::CloudFormation::Stack", @@ -1129,7 +1117,7 @@ }, "/", { - "Ref": "AssetParameters2e2ec0fae5975d4ee5f3580e522c46615c1bd344e0302bc5d2df7501b7bb1ad0S3Bucket8FBFE327" + "Ref": "AssetParameters8d4ffe9194a1ca97e2e9377049ddbeb3adbdaa984c8a90c08a5d8d6b328bdf7cS3BucketFEA5F85E" }, "/", { @@ -1139,7 +1127,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters2e2ec0fae5975d4ee5f3580e522c46615c1bd344e0302bc5d2df7501b7bb1ad0S3VersionKeyF5A05918" + "Ref": "AssetParameters8d4ffe9194a1ca97e2e9377049ddbeb3adbdaa984c8a90c08a5d8d6b328bdf7cS3VersionKey226CF52C" } ] } @@ -1152,7 +1140,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters2e2ec0fae5975d4ee5f3580e522c46615c1bd344e0302bc5d2df7501b7bb1ad0S3VersionKeyF5A05918" + "Ref": "AssetParameters8d4ffe9194a1ca97e2e9377049ddbeb3adbdaa984c8a90c08a5d8d6b328bdf7cS3VersionKey226CF52C" } ] } @@ -1195,20 +1183,17 @@ "ClusterSecurityGroupId" ] }, - "referencetoawscdkeksclusterprivateendpointtestAssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3Bucket4A0D6BE2Ref": { - "Ref": "AssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3Bucket6DACDE73" - }, - "referencetoawscdkeksclusterprivateendpointtestAssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3VersionKey6D9B8A02Ref": { - "Ref": "AssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3VersionKey015AEA61" + "referencetoawscdkeksclusterprivateendpointtestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketFD6C4D26Ref": { + "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" }, - "referencetoawscdkeksclusterprivateendpointtestAssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3BucketD44FB215Ref": { - "Ref": "AssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3Bucket7EE7EA15" + "referencetoawscdkeksclusterprivateendpointtestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKey69E4725CRef": { + "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" }, - "referencetoawscdkeksclusterprivateendpointtestAssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3VersionKey6C30661CRef": { - "Ref": "AssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3VersionKey6C948E78" + "referencetoawscdkeksclusterprivateendpointtestAssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket5323F34ARef": { + "Ref": "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket6ABE1927" }, - "referencetoawscdkeksclusterprivateendpointtestVpcFCD064BFRef": { - "Ref": "Vpc8378EB38" + "referencetoawscdkeksclusterprivateendpointtestAssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKey548D79B4Ref": { + "Ref": "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyF55A2EA9" }, "referencetoawscdkeksclusterprivateendpointtestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket7DDAFC04Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" @@ -1217,7 +1202,9 @@ "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Outputs": { @@ -1299,53 +1286,53 @@ "Type": "String", "Description": "Artifact hash for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" }, - "AssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3Bucket6DACDE73": { + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { "Type": "String", - "Description": "S3 bucket for asset \"efd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1\"" + "Description": "S3 bucket for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" }, - "AssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3VersionKey015AEA61": { + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F": { "Type": "String", - "Description": "S3 key for asset version \"efd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1\"" + "Description": "S3 key for asset version \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" }, - "AssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1ArtifactHashC9FD06BA": { + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68ArtifactHashD9A515C3": { "Type": "String", - "Description": "Artifact hash for asset \"efd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1\"" + "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" }, - "AssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3Bucket7EE7EA15": { + "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket6ABE1927": { "Type": "String", - "Description": "S3 bucket for asset \"b61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449f\"" + "Description": "S3 bucket for asset \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" }, - "AssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3VersionKey6C948E78": { + "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyF55A2EA9": { "Type": "String", - "Description": "S3 key for asset version \"b61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449f\"" + "Description": "S3 key for asset version \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" }, - "AssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fArtifactHash7E705796": { + "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0ArtifactHash1D7A2D6E": { "Type": "String", - "Description": "Artifact hash for asset \"b61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449f\"" + "Description": "Artifact hash for asset \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" }, - "AssetParameters84ba29b05aaf6a233dbb97b37e48eb1300f9d014f270252e29a8b2c22d6a08beS3Bucket9E737267": { + "AssetParameters75667ab2bbef2c8efc57fb73bf352f345af1d471fb09cb11f5b7bc27d009b609S3BucketA8C94679": { "Type": "String", - "Description": "S3 bucket for asset \"84ba29b05aaf6a233dbb97b37e48eb1300f9d014f270252e29a8b2c22d6a08be\"" + "Description": "S3 bucket for asset \"75667ab2bbef2c8efc57fb73bf352f345af1d471fb09cb11f5b7bc27d009b609\"" }, - "AssetParameters84ba29b05aaf6a233dbb97b37e48eb1300f9d014f270252e29a8b2c22d6a08beS3VersionKeyD5E002BC": { + "AssetParameters75667ab2bbef2c8efc57fb73bf352f345af1d471fb09cb11f5b7bc27d009b609S3VersionKey3777DB64": { "Type": "String", - "Description": "S3 key for asset version \"84ba29b05aaf6a233dbb97b37e48eb1300f9d014f270252e29a8b2c22d6a08be\"" + "Description": "S3 key for asset version \"75667ab2bbef2c8efc57fb73bf352f345af1d471fb09cb11f5b7bc27d009b609\"" }, - "AssetParameters84ba29b05aaf6a233dbb97b37e48eb1300f9d014f270252e29a8b2c22d6a08beArtifactHashDF0A0444": { + "AssetParameters75667ab2bbef2c8efc57fb73bf352f345af1d471fb09cb11f5b7bc27d009b609ArtifactHash14CC8C95": { "Type": "String", - "Description": "Artifact hash for asset \"84ba29b05aaf6a233dbb97b37e48eb1300f9d014f270252e29a8b2c22d6a08be\"" + "Description": "Artifact hash for asset \"75667ab2bbef2c8efc57fb73bf352f345af1d471fb09cb11f5b7bc27d009b609\"" }, - "AssetParameters2e2ec0fae5975d4ee5f3580e522c46615c1bd344e0302bc5d2df7501b7bb1ad0S3Bucket8FBFE327": { + "AssetParameters8d4ffe9194a1ca97e2e9377049ddbeb3adbdaa984c8a90c08a5d8d6b328bdf7cS3BucketFEA5F85E": { "Type": "String", - "Description": "S3 bucket for asset \"2e2ec0fae5975d4ee5f3580e522c46615c1bd344e0302bc5d2df7501b7bb1ad0\"" + "Description": "S3 bucket for asset \"8d4ffe9194a1ca97e2e9377049ddbeb3adbdaa984c8a90c08a5d8d6b328bdf7c\"" }, - "AssetParameters2e2ec0fae5975d4ee5f3580e522c46615c1bd344e0302bc5d2df7501b7bb1ad0S3VersionKeyF5A05918": { + "AssetParameters8d4ffe9194a1ca97e2e9377049ddbeb3adbdaa984c8a90c08a5d8d6b328bdf7cS3VersionKey226CF52C": { "Type": "String", - "Description": "S3 key for asset version \"2e2ec0fae5975d4ee5f3580e522c46615c1bd344e0302bc5d2df7501b7bb1ad0\"" + "Description": "S3 key for asset version \"8d4ffe9194a1ca97e2e9377049ddbeb3adbdaa984c8a90c08a5d8d6b328bdf7c\"" }, - "AssetParameters2e2ec0fae5975d4ee5f3580e522c46615c1bd344e0302bc5d2df7501b7bb1ad0ArtifactHashDFBC9DE7": { + "AssetParameters8d4ffe9194a1ca97e2e9377049ddbeb3adbdaa984c8a90c08a5d8d6b328bdf7cArtifactHashA6BF0EB3": { "Type": "String", - "Description": "Artifact hash for asset \"2e2ec0fae5975d4ee5f3580e522c46615c1bd344e0302bc5d2df7501b7bb1ad0\"" + "Description": "Artifact hash for asset \"8d4ffe9194a1ca97e2e9377049ddbeb3adbdaa984c8a90c08a5d8d6b328bdf7c\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.ts b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.ts index 0a0c9a61230e9..a9cb68866e5d8 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.ts +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.ts @@ -5,7 +5,7 @@ import { App } from '@aws-cdk/core'; import * as eks from '../lib'; import { TestStack } from './util'; -const CLUSTER_VERSION = eks.KubernetesVersion.V1_18; +const CLUSTER_VERSION = eks.KubernetesVersion.V1_19; class EksClusterStack extends TestStack { 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 5c0b4bf402a5b..c157211d73f87 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json @@ -34,23 +34,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { @@ -807,14 +791,6 @@ ] } }, - { - "Action": [ - "ec2:DescribeSubnets", - "ec2:DescribeRouteTables" - ], - "Effect": "Allow", - "Resource": "*" - }, { "Action": [ "eks:CreateCluster", @@ -854,23 +830,17 @@ "Resource": "*" }, { - "Action": "ec2:DescribeVpcs", + "Action": [ + "ec2:DescribeInstances", + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", + "ec2:DescribeRouteTables", + "ec2:DescribeDhcpOptions", + "ec2:DescribeVpcs" + ], "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":ec2:test-region:12345678:vpc/", - { - "Ref": "Vpc8378EB38" - } - ] - ] - } + "Resource": "*" }, { "Action": [ @@ -949,7 +919,7 @@ ] }, "Config": { - "version": "1.18", + "version": "1.19", "roleArn": { "Fn::GetAtt": [ "ClusterRoleFA261979", @@ -1683,7 +1653,7 @@ "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { "ImageId": { - "Ref": "SsmParameterValueawsserviceeksoptimizedami118amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + "Ref": "SsmParameterValueawsserviceeksoptimizedami119amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" }, "InstanceType": "t2.medium", "IamInstanceProfile": { @@ -1994,7 +1964,7 @@ "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { "ImageId": { - "Ref": "SsmParameterValueawsserviceeksoptimizedami118amazonlinux2arm64recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + "Ref": "SsmParameterValueawsserviceeksoptimizedami119amazonlinux2arm64recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" }, "InstanceType": "m6g.medium", "IamInstanceProfile": { @@ -2305,7 +2275,7 @@ "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { "ImageId": { - "Ref": "SsmParameterValueawsservicebottlerocketawsk8s118x8664latestimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + "Ref": "SsmParameterValueawsservicebottlerocketawsk8s119x8664latestimageidC96584B6F00A464EAD1953AFF4B05118Parameter" }, "InstanceType": "t3.small", "IamInstanceProfile": { @@ -2630,7 +2600,7 @@ "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { "ImageId": { - "Ref": "SsmParameterValueawsserviceeksoptimizedami118amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + "Ref": "SsmParameterValueawsserviceeksoptimizedami119amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" }, "InstanceType": "t3.large", "IamInstanceProfile": { @@ -2974,7 +2944,7 @@ "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { "ImageId": { - "Ref": "SsmParameterValueawsserviceeksoptimizedami118amazonlinux2gpurecommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + "Ref": "SsmParameterValueawsserviceeksoptimizedami119amazonlinux2gpurecommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" }, "InstanceType": "inf1.2xlarge", "IamInstanceProfile": { @@ -3277,6 +3247,7 @@ } ], "AmiType": "AL2_x86_64", + "CapacityType": "SPOT", "ForceUpdateEnabled": true, "InstanceTypes": [ "c5.large", @@ -3287,8 +3258,7 @@ "DesiredSize": 3, "MaxSize": 3, "MinSize": 3 - }, - "CapacityType": "SPOT" + } } }, "ClusterNodegroupextrangarmNodeGroupRoleADF5749F": { @@ -3840,7 +3810,7 @@ }, "/", { - "Ref": "AssetParametersa69aadbed84d554dd9f2eb7987ffe5d8f76b53a86f1909059df07050e57bef0cS3Bucket1CB7A187" + "Ref": "AssetParameters264acf17cbf0c643f47bec1f4dbaed805e3bd1bad3f018c093d16fb936227daaS3Bucket862E8D6F" }, "/", { @@ -3850,7 +3820,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersa69aadbed84d554dd9f2eb7987ffe5d8f76b53a86f1909059df07050e57bef0cS3VersionKey7C13F243" + "Ref": "AssetParameters264acf17cbf0c643f47bec1f4dbaed805e3bd1bad3f018c093d16fb936227daaS3VersionKey9466BE3D" } ] } @@ -3863,7 +3833,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersa69aadbed84d554dd9f2eb7987ffe5d8f76b53a86f1909059df07050e57bef0cS3VersionKey7C13F243" + "Ref": "AssetParameters264acf17cbf0c643f47bec1f4dbaed805e3bd1bad3f018c093d16fb936227daaS3VersionKey9466BE3D" } ] } @@ -3892,7 +3862,9 @@ "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "awscdkawseksKubectlProviderNestedStackawscdkawseksKubectlProviderNestedStackResourceA7AEBA6B": { "Type": "AWS::CloudFormation::Stack", @@ -3907,7 +3879,7 @@ }, "/", { - "Ref": "AssetParameters6b9ad3782e5bfd49d7a58fc915b6151dbed2e24d824730d7720bc8237ba252c8S3Bucket0B8E3806" + "Ref": "AssetParameterse00474136b86298d67c0ad626f1dafe622c51168233097531c5ba6791d43aba3S3Bucket5829AD66" }, "/", { @@ -3917,7 +3889,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6b9ad3782e5bfd49d7a58fc915b6151dbed2e24d824730d7720bc8237ba252c8S3VersionKey862F0970" + "Ref": "AssetParameterse00474136b86298d67c0ad626f1dafe622c51168233097531c5ba6791d43aba3S3VersionKey44FDB4A8" } ] } @@ -3930,7 +3902,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6b9ad3782e5bfd49d7a58fc915b6151dbed2e24d824730d7720bc8237ba252c8S3VersionKey862F0970" + "Ref": "AssetParameterse00474136b86298d67c0ad626f1dafe622c51168233097531c5ba6791d43aba3S3VersionKey44FDB4A8" } ] } @@ -3985,9 +3957,6 @@ "referencetoawscdkeksclustertestAssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKey1CADE360Ref": { "Ref": "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyF55A2EA9" }, - "referencetoawscdkeksclustertestVpc9A302ADDRef": { - "Ref": "Vpc8378EB38" - }, "referencetoawscdkeksclustertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket0815E7B5Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" }, @@ -3995,14 +3964,16 @@ "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "LaunchTemplate": { "Type": "AWS::EC2::LaunchTemplate", "Properties": { "LaunchTemplateData": { "ImageId": { - "Ref": "SsmParameterValueawsserviceeksoptimizedami114amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + "Ref": "SsmParameterValueawsserviceeksoptimizedami119amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" }, "InstanceType": "t3.small", "UserData": { @@ -4347,13 +4318,13 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "ServicePingerFunctionServiceRole3120191B", "Arn" ] }, + "Handler": "index.handler", "Runtime": "python3.6", "Timeout": 600, "VpcConfig": { @@ -4480,14 +4451,12 @@ ] } }, - "Handler": "framework.onEvent", "Role": { "Fn::GetAtt": [ "ServicePingerProviderframeworkonEventServiceRole3DB083B7", "Arn" ] }, - "Runtime": "nodejs10.x", "Description": "AWS CDK resource provider framework - onEvent (aws-cdk-eks-cluster-test/ServicePinger/Provider)", "Environment": { "Variables": { @@ -4499,6 +4468,8 @@ } } }, + "Handler": "framework.onEvent", + "Runtime": "nodejs10.x", "Timeout": 900 }, "DependsOn": [ @@ -4727,49 +4698,45 @@ "Type": "String", "Description": "Artifact hash for asset \"5f49893093e1ad14831626016699156d48da5f0890f19eb930bc3c46cf5f636d\"" }, - "AssetParametersa69aadbed84d554dd9f2eb7987ffe5d8f76b53a86f1909059df07050e57bef0cS3Bucket1CB7A187": { + "AssetParameters264acf17cbf0c643f47bec1f4dbaed805e3bd1bad3f018c093d16fb936227daaS3Bucket862E8D6F": { "Type": "String", - "Description": "S3 bucket for asset \"a69aadbed84d554dd9f2eb7987ffe5d8f76b53a86f1909059df07050e57bef0c\"" + "Description": "S3 bucket for asset \"264acf17cbf0c643f47bec1f4dbaed805e3bd1bad3f018c093d16fb936227daa\"" }, - "AssetParametersa69aadbed84d554dd9f2eb7987ffe5d8f76b53a86f1909059df07050e57bef0cS3VersionKey7C13F243": { + "AssetParameters264acf17cbf0c643f47bec1f4dbaed805e3bd1bad3f018c093d16fb936227daaS3VersionKey9466BE3D": { "Type": "String", - "Description": "S3 key for asset version \"a69aadbed84d554dd9f2eb7987ffe5d8f76b53a86f1909059df07050e57bef0c\"" + "Description": "S3 key for asset version \"264acf17cbf0c643f47bec1f4dbaed805e3bd1bad3f018c093d16fb936227daa\"" }, - "AssetParametersa69aadbed84d554dd9f2eb7987ffe5d8f76b53a86f1909059df07050e57bef0cArtifactHashBADE945D": { + "AssetParameters264acf17cbf0c643f47bec1f4dbaed805e3bd1bad3f018c093d16fb936227daaArtifactHashC5F5158C": { "Type": "String", - "Description": "Artifact hash for asset \"a69aadbed84d554dd9f2eb7987ffe5d8f76b53a86f1909059df07050e57bef0c\"" + "Description": "Artifact hash for asset \"264acf17cbf0c643f47bec1f4dbaed805e3bd1bad3f018c093d16fb936227daa\"" }, - "AssetParameters6b9ad3782e5bfd49d7a58fc915b6151dbed2e24d824730d7720bc8237ba252c8S3Bucket0B8E3806": { + "AssetParameterse00474136b86298d67c0ad626f1dafe622c51168233097531c5ba6791d43aba3S3Bucket5829AD66": { "Type": "String", - "Description": "S3 bucket for asset \"6b9ad3782e5bfd49d7a58fc915b6151dbed2e24d824730d7720bc8237ba252c8\"" + "Description": "S3 bucket for asset \"e00474136b86298d67c0ad626f1dafe622c51168233097531c5ba6791d43aba3\"" }, - "AssetParameters6b9ad3782e5bfd49d7a58fc915b6151dbed2e24d824730d7720bc8237ba252c8S3VersionKey862F0970": { + "AssetParameterse00474136b86298d67c0ad626f1dafe622c51168233097531c5ba6791d43aba3S3VersionKey44FDB4A8": { "Type": "String", - "Description": "S3 key for asset version \"6b9ad3782e5bfd49d7a58fc915b6151dbed2e24d824730d7720bc8237ba252c8\"" + "Description": "S3 key for asset version \"e00474136b86298d67c0ad626f1dafe622c51168233097531c5ba6791d43aba3\"" }, - "AssetParameters6b9ad3782e5bfd49d7a58fc915b6151dbed2e24d824730d7720bc8237ba252c8ArtifactHashAAFBAA4D": { + "AssetParameterse00474136b86298d67c0ad626f1dafe622c51168233097531c5ba6791d43aba3ArtifactHashB6A3908A": { "Type": "String", - "Description": "Artifact hash for asset \"6b9ad3782e5bfd49d7a58fc915b6151dbed2e24d824730d7720bc8237ba252c8\"" - }, - "SsmParameterValueawsserviceeksoptimizedami118amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { - "Type": "AWS::SSM::Parameter::Value", - "Default": "/aws/service/eks/optimized-ami/1.18/amazon-linux-2/recommended/image_id" + "Description": "Artifact hash for asset \"e00474136b86298d67c0ad626f1dafe622c51168233097531c5ba6791d43aba3\"" }, - "SsmParameterValueawsserviceeksoptimizedami118amazonlinux2arm64recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "SsmParameterValueawsserviceeksoptimizedami119amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { "Type": "AWS::SSM::Parameter::Value", - "Default": "/aws/service/eks/optimized-ami/1.18/amazon-linux-2-arm64/recommended/image_id" + "Default": "/aws/service/eks/optimized-ami/1.19/amazon-linux-2/recommended/image_id" }, - "SsmParameterValueawsservicebottlerocketawsk8s118x8664latestimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "SsmParameterValueawsserviceeksoptimizedami119amazonlinux2arm64recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { "Type": "AWS::SSM::Parameter::Value", - "Default": "/aws/service/bottlerocket/aws-k8s-1.18/x86_64/latest/image_id" + "Default": "/aws/service/eks/optimized-ami/1.19/amazon-linux-2-arm64/recommended/image_id" }, - "SsmParameterValueawsserviceeksoptimizedami118amazonlinux2gpurecommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "SsmParameterValueawsservicebottlerocketawsk8s119x8664latestimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { "Type": "AWS::SSM::Parameter::Value", - "Default": "/aws/service/eks/optimized-ami/1.18/amazon-linux-2-gpu/recommended/image_id" + "Default": "/aws/service/bottlerocket/aws-k8s-1.19/x86_64/latest/image_id" }, - "SsmParameterValueawsserviceeksoptimizedami114amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "SsmParameterValueawsserviceeksoptimizedami119amazonlinux2gpurecommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { "Type": "AWS::SSM::Parameter::Value", - "Default": "/aws/service/eks/optimized-ami/1.14/amazon-linux-2/recommended/image_id" + "Default": "/aws/service/eks/optimized-ami/1.19/amazon-linux-2-gpu/recommended/image_id" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.ts b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.ts index 12c7334bd96a5..080cd744a57f0 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.ts +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.ts @@ -35,7 +35,7 @@ class EksClusterStack extends TestStack { vpc: this.vpc, mastersRole, defaultCapacity: 2, - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, secretsEncryptionKey, }); @@ -187,7 +187,9 @@ class EksClusterStack extends TestStack { ); const lt = new ec2.CfnLaunchTemplate(this, 'LaunchTemplate', { launchTemplateData: { - imageId: new eks.EksOptimizedImage().getImage(this).imageId, + imageId: new eks.EksOptimizedImage({ + kubernetesVersion: eks.KubernetesVersion.V1_19.version, + }).getImage(this).imageId, instanceType: new ec2.InstanceType('t3.small').toString(), userData: Fn.base64(userData.render()), }, diff --git a/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.expected.json b/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.expected.json index 5d6efed26b63f..441cac51ffd69 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.expected.json @@ -711,14 +711,6 @@ ] } }, - { - "Action": [ - "ec2:DescribeSubnets", - "ec2:DescribeRouteTables" - ], - "Effect": "Allow", - "Resource": "*" - }, { "Action": [ "eks:CreateCluster", @@ -758,23 +750,17 @@ "Resource": "*" }, { - "Action": "ec2:DescribeVpcs", + "Action": [ + "ec2:DescribeInstances", + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", + "ec2:DescribeRouteTables", + "ec2:DescribeDhcpOptions", + "ec2:DescribeVpcs" + ], "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":ec2:test-region:12345678:vpc/", - { - "Ref": "FargateClusterDefaultVpcE69D3A13" - } - ] - ] - } + "Resource": "*" }, { "Action": "iam:PassRole", @@ -842,7 +828,7 @@ ] }, "Config": { - "version": "1.18", + "version": "1.19", "roleArn": { "Fn::GetAtt": [ "FargateClusterRole8E36B33A", @@ -1139,7 +1125,7 @@ }, "/", { - "Ref": "AssetParametersae946640aaf0743990584e4a1cf45ddebbaddcaf60611f572e80100a02162f48S3BucketDA5FB24D" + "Ref": "AssetParameters3d252d05ccf0ae2934dd20707e8a709b466b2b8ea00c04ee8735667f90b17ac1S3Bucket01B07207" }, "/", { @@ -1149,7 +1135,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersae946640aaf0743990584e4a1cf45ddebbaddcaf60611f572e80100a02162f48S3VersionKey798A3941" + "Ref": "AssetParameters3d252d05ccf0ae2934dd20707e8a709b466b2b8ea00c04ee8735667f90b17ac1S3VersionKey3EEF52BA" } ] } @@ -1162,7 +1148,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersae946640aaf0743990584e4a1cf45ddebbaddcaf60611f572e80100a02162f48S3VersionKey798A3941" + "Ref": "AssetParameters3d252d05ccf0ae2934dd20707e8a709b466b2b8ea00c04ee8735667f90b17ac1S3VersionKey3EEF52BA" } ] } @@ -1191,7 +1177,9 @@ "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "awscdkawseksKubectlProviderNestedStackawscdkawseksKubectlProviderNestedStackResourceA7AEBA6B": { "Type": "AWS::CloudFormation::Stack", @@ -1206,7 +1194,7 @@ }, "/", { - "Ref": "AssetParameters7449e3c4cf21a811d1d6612d2f1a806025f018320ebc8c1d8037eb34f0d0e98dS3BucketF39EF776" + "Ref": "AssetParametersedcd50bb250cf7cf664a737720e623ad66ada9b9e609205686c476e516cf2f23S3Bucket586F6135" }, "/", { @@ -1216,7 +1204,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters7449e3c4cf21a811d1d6612d2f1a806025f018320ebc8c1d8037eb34f0d0e98dS3VersionKeyE6E734A4" + "Ref": "AssetParametersedcd50bb250cf7cf664a737720e623ad66ada9b9e609205686c476e516cf2f23S3VersionKey6EFBFC1D" } ] } @@ -1229,7 +1217,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters7449e3c4cf21a811d1d6612d2f1a806025f018320ebc8c1d8037eb34f0d0e98dS3VersionKeyE6E734A4" + "Ref": "AssetParametersedcd50bb250cf7cf664a737720e623ad66ada9b9e609205686c476e516cf2f23S3VersionKey6EFBFC1D" } ] } @@ -1272,20 +1260,17 @@ "ClusterSecurityGroupId" ] }, - "referencetoawscdkeksfargateclustertestAssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3Bucket9D3BB190Ref": { - "Ref": "AssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3Bucket6DACDE73" - }, - "referencetoawscdkeksfargateclustertestAssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3VersionKey3BB3C6F5Ref": { - "Ref": "AssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3VersionKey015AEA61" + "referencetoawscdkeksfargateclustertestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3Bucket4F20F642Ref": { + "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" }, - "referencetoawscdkeksfargateclustertestAssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3Bucket99BFDD36Ref": { - "Ref": "AssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3Bucket7EE7EA15" + "referencetoawscdkeksfargateclustertestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyB82BAEF8Ref": { + "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" }, - "referencetoawscdkeksfargateclustertestAssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3VersionKeyEEC9E8C1Ref": { - "Ref": "AssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3VersionKey6C948E78" + "referencetoawscdkeksfargateclustertestAssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket9ED34BB4Ref": { + "Ref": "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket6ABE1927" }, - "referencetoawscdkeksfargateclustertestFargateClusterDefaultVpcBD3C976FRef": { - "Ref": "FargateClusterDefaultVpcE69D3A13" + "referencetoawscdkeksfargateclustertestAssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyFE6D1F78Ref": { + "Ref": "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyF55A2EA9" }, "referencetoawscdkeksfargateclustertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket8EEF0922Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" @@ -1294,7 +1279,9 @@ "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" } } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Outputs": { @@ -1376,53 +1363,53 @@ "Type": "String", "Description": "Artifact hash for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" }, - "AssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3Bucket6DACDE73": { + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { "Type": "String", - "Description": "S3 bucket for asset \"efd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1\"" + "Description": "S3 bucket for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" }, - "AssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3VersionKey015AEA61": { + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F": { "Type": "String", - "Description": "S3 key for asset version \"efd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1\"" + "Description": "S3 key for asset version \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" }, - "AssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1ArtifactHashC9FD06BA": { + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68ArtifactHashD9A515C3": { "Type": "String", - "Description": "Artifact hash for asset \"efd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1\"" + "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" }, - "AssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3Bucket7EE7EA15": { + "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket6ABE1927": { "Type": "String", - "Description": "S3 bucket for asset \"b61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449f\"" + "Description": "S3 bucket for asset \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" }, - "AssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3VersionKey6C948E78": { + "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyF55A2EA9": { "Type": "String", - "Description": "S3 key for asset version \"b61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449f\"" + "Description": "S3 key for asset version \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" }, - "AssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fArtifactHash7E705796": { + "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0ArtifactHash1D7A2D6E": { "Type": "String", - "Description": "Artifact hash for asset \"b61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449f\"" + "Description": "Artifact hash for asset \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" }, - "AssetParametersae946640aaf0743990584e4a1cf45ddebbaddcaf60611f572e80100a02162f48S3BucketDA5FB24D": { + "AssetParameters3d252d05ccf0ae2934dd20707e8a709b466b2b8ea00c04ee8735667f90b17ac1S3Bucket01B07207": { "Type": "String", - "Description": "S3 bucket for asset \"ae946640aaf0743990584e4a1cf45ddebbaddcaf60611f572e80100a02162f48\"" + "Description": "S3 bucket for asset \"3d252d05ccf0ae2934dd20707e8a709b466b2b8ea00c04ee8735667f90b17ac1\"" }, - "AssetParametersae946640aaf0743990584e4a1cf45ddebbaddcaf60611f572e80100a02162f48S3VersionKey798A3941": { + "AssetParameters3d252d05ccf0ae2934dd20707e8a709b466b2b8ea00c04ee8735667f90b17ac1S3VersionKey3EEF52BA": { "Type": "String", - "Description": "S3 key for asset version \"ae946640aaf0743990584e4a1cf45ddebbaddcaf60611f572e80100a02162f48\"" + "Description": "S3 key for asset version \"3d252d05ccf0ae2934dd20707e8a709b466b2b8ea00c04ee8735667f90b17ac1\"" }, - "AssetParametersae946640aaf0743990584e4a1cf45ddebbaddcaf60611f572e80100a02162f48ArtifactHash865DB842": { + "AssetParameters3d252d05ccf0ae2934dd20707e8a709b466b2b8ea00c04ee8735667f90b17ac1ArtifactHash812ED4D5": { "Type": "String", - "Description": "Artifact hash for asset \"ae946640aaf0743990584e4a1cf45ddebbaddcaf60611f572e80100a02162f48\"" + "Description": "Artifact hash for asset \"3d252d05ccf0ae2934dd20707e8a709b466b2b8ea00c04ee8735667f90b17ac1\"" }, - "AssetParameters7449e3c4cf21a811d1d6612d2f1a806025f018320ebc8c1d8037eb34f0d0e98dS3BucketF39EF776": { + "AssetParametersedcd50bb250cf7cf664a737720e623ad66ada9b9e609205686c476e516cf2f23S3Bucket586F6135": { "Type": "String", - "Description": "S3 bucket for asset \"7449e3c4cf21a811d1d6612d2f1a806025f018320ebc8c1d8037eb34f0d0e98d\"" + "Description": "S3 bucket for asset \"edcd50bb250cf7cf664a737720e623ad66ada9b9e609205686c476e516cf2f23\"" }, - "AssetParameters7449e3c4cf21a811d1d6612d2f1a806025f018320ebc8c1d8037eb34f0d0e98dS3VersionKeyE6E734A4": { + "AssetParametersedcd50bb250cf7cf664a737720e623ad66ada9b9e609205686c476e516cf2f23S3VersionKey6EFBFC1D": { "Type": "String", - "Description": "S3 key for asset version \"7449e3c4cf21a811d1d6612d2f1a806025f018320ebc8c1d8037eb34f0d0e98d\"" + "Description": "S3 key for asset version \"edcd50bb250cf7cf664a737720e623ad66ada9b9e609205686c476e516cf2f23\"" }, - "AssetParameters7449e3c4cf21a811d1d6612d2f1a806025f018320ebc8c1d8037eb34f0d0e98dArtifactHash93FFAA4A": { + "AssetParametersedcd50bb250cf7cf664a737720e623ad66ada9b9e609205686c476e516cf2f23ArtifactHashB34EB8FE": { "Type": "String", - "Description": "Artifact hash for asset \"7449e3c4cf21a811d1d6612d2f1a806025f018320ebc8c1d8037eb34f0d0e98d\"" + "Description": "Artifact hash for asset \"edcd50bb250cf7cf664a737720e623ad66ada9b9e609205686c476e516cf2f23\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.ts b/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.ts index a97389ce4622e..957b60ee23e3b 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.ts +++ b/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.ts @@ -3,7 +3,7 @@ import { App } from '@aws-cdk/core'; import * as eks from '../lib'; import { TestStack } from './util'; -const CLUSTER_VERSION = eks.KubernetesVersion.V1_18; +const CLUSTER_VERSION = eks.KubernetesVersion.V1_19; class EksFargateClusterStack extends TestStack { diff --git a/packages/@aws-cdk/aws-eks/test/test.cluster.ts b/packages/@aws-cdk/aws-eks/test/test.cluster.ts index 7e7f01d7ede84..46554d34dceb0 100644 --- a/packages/@aws-cdk/aws-eks/test/test.cluster.ts +++ b/packages/@aws-cdk/aws-eks/test/test.cluster.ts @@ -17,7 +17,7 @@ import { testFixture, testFixtureNoVpc } from './util'; /* eslint-disable max-len */ -const CLUSTER_VERSION = eks.KubernetesVersion.V1_18; +const CLUSTER_VERSION = eks.KubernetesVersion.V1_19; export = { @@ -85,7 +85,7 @@ export = { vpc: vpc, vpcSubnets: [{ subnetType: ec2.SubnetType.PUBLIC }, { subnetType: ec2.SubnetType.PRIVATE }], defaultCapacity: 0, - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, }), /cannot select multiple subnet groups/); test.done(); @@ -97,7 +97,7 @@ export = { vpc: vpc, vpcSubnets: [{ subnetType: ec2.SubnetType.PUBLIC }], defaultCapacity: 0, - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, }); // THEN @@ -629,7 +629,7 @@ export = { expect(stack).to(haveResourceLike('Custom::AWSCDK-EKS-Cluster', { Config: { roleArn: { 'Fn::GetAtt': ['ClusterRoleFA261979', 'Arn'] }, - version: '1.18', + version: '1.19', resourcesVpcConfig: { securityGroupIds: [{ 'Fn::GetAtt': ['ClusterControlPlaneSecurityGroupD274242C', 'GroupId'] }], subnetIds: [ @@ -1462,7 +1462,7 @@ export = { const { app, stack } = testFixtureNoVpc(); // WHEN - new eks.EksOptimizedImage({ kubernetesVersion: '1.18' }).getImage(stack); + new eks.EksOptimizedImage({ kubernetesVersion: '1.19' }).getImage(stack); // THEN const assembly = app.synth(); @@ -1473,7 +1473,7 @@ export = { ), 'EKS STANDARD AMI should be in ssm parameters'); test.ok(Object.entries(parameters).some( ([k, v]) => k.startsWith('SsmParameterValueawsserviceeksoptimizedami') && - (v as any).Default.includes('/1.18/'), + (v as any).Default.includes('/1.19/'), ), 'kubernetesVersion should be in ssm parameters'); test.done(); }, @@ -1611,7 +1611,7 @@ export = { const { app, stack } = testFixtureNoVpc(); // WHEN - new BottleRocketImage({ kubernetesVersion: '1.18' }).getImage(stack); + new BottleRocketImage({ kubernetesVersion: '1.19' }).getImage(stack); // THEN const assembly = app.synth(); @@ -1622,7 +1622,7 @@ export = { ), 'BottleRocket AMI should be in ssm parameters'); test.ok(Object.entries(parameters).some( ([k, v]) => k.startsWith('SsmParameterValueawsservicebottlerocketaws') && - (v as any).Default.includes('/aws-k8s-1.18/'), + (v as any).Default.includes('/aws-k8s-1.19/'), ), 'kubernetesVersion should be in ssm parameters'); test.done(); }, @@ -1643,7 +1643,7 @@ export = { Config: { name: 'my-cluster-name', roleArn: { 'Fn::GetAtt': ['MyClusterRoleBA20FE72', 'Arn'] }, - version: '1.18', + version: '1.19', resourcesVpcConfig: { securityGroupIds: [ { 'Fn::GetAtt': ['MyClusterControlPlaneSecurityGroup6B658F79', 'GroupId'] }, @@ -1695,14 +1695,6 @@ export = { ], }, }, - { - Action: [ - 'ec2:DescribeSubnets', - 'ec2:DescribeRouteTables', - ], - Effect: 'Allow', - Resource: '*', - }, { Action: [ 'eks:CreateCluster', @@ -1782,27 +1774,17 @@ export = { Resource: '*', }, { - Action: 'ec2:DescribeVpcs', + Action: [ + 'ec2:DescribeInstances', + 'ec2:DescribeNetworkInterfaces', + 'ec2:DescribeSecurityGroups', + 'ec2:DescribeSubnets', + 'ec2:DescribeRouteTables', + 'ec2:DescribeDhcpOptions', + 'ec2:DescribeVpcs', + ], Effect: 'Allow', - Resource: { - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':ec2:us-east-1:', - { - Ref: 'AWS::AccountId', - }, - ':vpc/', - { - Ref: 'MyClusterDefaultVpc76C24A38', - }, - ], - ], - }, + Resource: '*', }, ], Version: '2012-10-17', @@ -1832,14 +1814,6 @@ export = { ], }, }, - { - Action: [ - 'ec2:DescribeSubnets', - 'ec2:DescribeRouteTables', - ], - Effect: 'Allow', - Resource: '*', - }, { Action: [ 'eks:CreateCluster', @@ -1874,27 +1848,17 @@ export = { Resource: '*', }, { - Action: 'ec2:DescribeVpcs', + Action: [ + 'ec2:DescribeInstances', + 'ec2:DescribeNetworkInterfaces', + 'ec2:DescribeSecurityGroups', + 'ec2:DescribeSubnets', + 'ec2:DescribeRouteTables', + 'ec2:DescribeDhcpOptions', + 'ec2:DescribeVpcs', + ], Effect: 'Allow', - Resource: { - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':ec2:us-east-1:', - { - Ref: 'AWS::AccountId', - }, - ':vpc/', - { - Ref: 'MyClusterDefaultVpc76C24A38', - }, - ], - ], - }, + Resource: '*', }, ], Version: '2012-10-17', @@ -2119,6 +2083,27 @@ export = { }, + 'kubectl provider passes security group to provider'(test: Test) { + + const { stack } = testFixture(); + + new eks.Cluster(stack, 'Cluster1', { + version: CLUSTER_VERSION, + prune: false, + endpointAccess: eks.EndpointAccess.PRIVATE, + kubectlEnvironment: { + Foo: 'Bar', + }, + }); + + // the kubectl provider is inside a nested stack. + const nested = stack.node.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; + test.deepEqual(expect(nested).value.Resources.ProviderframeworkonEvent83C1D0A7.Properties.VpcConfig.SecurityGroupIds, + [{ Ref: 'referencetoStackCluster18DFEAC17ClusterSecurityGroupId' }]); + + test.done(); + }, + 'kubectl provider passes environment to lambda'(test: Test) { const { stack } = testFixture(); diff --git a/packages/@aws-cdk/aws-eks/test/test.fargate.ts b/packages/@aws-cdk/aws-eks/test/test.fargate.ts index a606a5cfe7496..ee17950915e9d 100644 --- a/packages/@aws-cdk/aws-eks/test/test.fargate.ts +++ b/packages/@aws-cdk/aws-eks/test/test.fargate.ts @@ -5,7 +5,7 @@ import { Stack, Tags } from '@aws-cdk/core'; import { Test } from 'nodeunit'; import * as eks from '../lib'; -const CLUSTER_VERSION = eks.KubernetesVersion.V1_16; +const CLUSTER_VERSION = eks.KubernetesVersion.V1_19; export = { 'can be added to a cluster'(test: Test) { @@ -364,14 +364,6 @@ export = { ], }, }, - { - Action: [ - 'ec2:DescribeSubnets', - 'ec2:DescribeRouteTables', - ], - Effect: 'Allow', - Resource: '*', - }, { Action: [ 'eks:CreateCluster', @@ -408,31 +400,17 @@ export = { Resource: '*', }, { - Action: 'ec2:DescribeVpcs', + Action: [ + 'ec2:DescribeInstances', + 'ec2:DescribeNetworkInterfaces', + 'ec2:DescribeSecurityGroups', + 'ec2:DescribeSubnets', + 'ec2:DescribeRouteTables', + 'ec2:DescribeDhcpOptions', + 'ec2:DescribeVpcs', + ], Effect: 'Allow', - Resource: { - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':ec2:', - { - Ref: 'AWS::Region', - }, - ':', - { - Ref: 'AWS::AccountId', - }, - ':vpc/', - { - Ref: 'FargateClusterDefaultVpcE69D3A13', - }, - ], - ], - }, + Resource: '*', }, { Action: 'iam:PassRole', diff --git a/packages/@aws-cdk/aws-eks/test/test.nodegroup.ts b/packages/@aws-cdk/aws-eks/test/test.nodegroup.ts index 241482d469c65..0599c349f6190 100644 --- a/packages/@aws-cdk/aws-eks/test/test.nodegroup.ts +++ b/packages/@aws-cdk/aws-eks/test/test.nodegroup.ts @@ -7,7 +7,7 @@ import { testFixture } from './util'; /* eslint-disable max-len */ -const CLUSTER_VERSION = eks.KubernetesVersion.V1_18; +const CLUSTER_VERSION = eks.KubernetesVersion.V1_19; export = { diff --git a/packages/@aws-cdk/aws-elasticache/package.json b/packages/@aws-cdk/aws-elasticache/package.json index aa85b7db2ecfd..f0b728276adda 100644 --- a/packages/@aws-cdk/aws-elasticache/package.json +++ b/packages/@aws-cdk/aws-elasticache/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-elasticbeanstalk/package.json b/packages/@aws-cdk/aws-elasticbeanstalk/package.json index bb500913fc817..31472f9e21d51 100644 --- a/packages/@aws-cdk/aws-elasticbeanstalk/package.json +++ b/packages/@aws-cdk/aws-elasticbeanstalk/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/package.json b/packages/@aws-cdk/aws-elasticloadbalancing/package.json index 3fc6fd2bb62ba..24f25fb2470f8 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancing/package.json @@ -120,5 +120,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json index 2018764c662af..dc606985d7c17 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json @@ -100,5 +100,8 @@ "env": { "AWSLINT_BASE_CONSTRUCT": true } + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/integ.cognito.lit.expected.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/integ.cognito.lit.expected.json index 7aeccb623d6dd..206ab8458383d 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/integ.cognito.lit.expected.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/integ.cognito.lit.expected.json @@ -450,22 +450,28 @@ "LoadBalancerArn": { "Ref": "LB8A12904C" }, - "Port": 443, - "Protocol": "HTTPS", "Certificates": [ { "CertificateArn": "" } - ] + ], + "Port": 443, + "Protocol": "HTTPS" } }, "UserPool6BA7E5F2": { "Type": "AWS::Cognito::UserPool", "Properties": { - "AccountRecoverySetting": { + "AccountRecoverySetting": { "RecoveryMechanisms": [ - { "Name": "verified_phone_number", "Priority": 1 }, - { "Name": "verified_email", "Priority": 2 } + { + "Name": "verified_phone_number", + "Priority": 1 + }, + { + "Name": "verified_email", + "Priority": 2 + } ] }, "AdminCreateUserConfig": { @@ -480,7 +486,9 @@ "EmailSubject": "Verify your new account", "SmsMessage": "The verification code to your new account is {####}" } - } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" }, "Client4A7F64DF": { "Type": "AWS::Cognito::UserPoolClient", @@ -544,4 +552,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json index 0d5a3abc474d8..51ae07a4caaa7 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json @@ -105,5 +105,8 @@ "env": { "AWSLINT_BASE_CONSTRUCT": true } + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json index 269f18af95f12..745b87fb4453f 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json @@ -142,5 +142,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-elasticsearch/lib/domain.ts b/packages/@aws-cdk/aws-elasticsearch/lib/domain.ts index 28728e6cdf58f..905ea5360f139 100644 --- a/packages/@aws-cdk/aws-elasticsearch/lib/domain.ts +++ b/packages/@aws-cdk/aws-elasticsearch/lib/domain.ts @@ -569,6 +569,13 @@ export interface DomainProps { */ readonly enableVersionUpgrade?: boolean; + /** + * Policy to apply when the domain is removed from the stack + * + * @default RemovalPolicy.RETAIN + */ + readonly removalPolicy?: cdk.RemovalPolicy; + /** * To configure a custom domain configure these options * @@ -1663,6 +1670,7 @@ export class Domain extends DomainBase implements IDomain { } : undefined, }); + this.domain.applyRemovalPolicy(props.removalPolicy); if (props.enableVersionUpgrade) { this.domain.cfnOptions.updatePolicy = { diff --git a/packages/@aws-cdk/aws-elasticsearch/package.json b/packages/@aws-cdk/aws-elasticsearch/package.json index 89fa4f885f478..df7d8934559ea 100644 --- a/packages/@aws-cdk/aws-elasticsearch/package.json +++ b/packages/@aws-cdk/aws-elasticsearch/package.json @@ -117,5 +117,8 @@ ], "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-elasticsearch/test/domain.test.ts b/packages/@aws-cdk/aws-elasticsearch/test/domain.test.ts index 98a6f350d6f34..afd5bf6b45430 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/domain.test.ts +++ b/packages/@aws-cdk/aws-elasticsearch/test/domain.test.ts @@ -30,6 +30,16 @@ const readWriteActions = [ ...writeActions, ]; +test('default removalpolicy is retain', () => { + new Domain(stack, 'Domain', { + version: ElasticsearchVersion.V7_1, + }); + + expect(stack).toHaveResource('AWS::Elasticsearch::Domain', { + DeletionPolicy: 'Retain', + }, assert.ResourcePart.CompleteDefinition); +}); + test('grants kms permissions if needed', () => { const key = new kms.Key(stack, 'Key'); diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.advancedsecurity.expected.json b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.advancedsecurity.expected.json index dac2d95d68b54..84333cb6005d7 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.advancedsecurity.expected.json +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.advancedsecurity.expected.json @@ -44,7 +44,9 @@ "NodeToNodeEncryptionOptions": { "Enabled": true } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.advancedsecurity.ts b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.advancedsecurity.ts index 5baf8f4e1b99d..828a5c9fe75e7 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.advancedsecurity.ts +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.advancedsecurity.ts @@ -1,5 +1,5 @@ import { User } from '@aws-cdk/aws-iam'; -import { App, Stack, StackProps } from '@aws-cdk/core'; +import { App, RemovalPolicy, Stack, StackProps } from '@aws-cdk/core'; import { Construct } from 'constructs'; import * as es from '../lib'; @@ -10,6 +10,7 @@ class TestStack extends Stack { const user = new User(this, 'User'); new es.Domain(this, 'Domain', { + removalPolicy: RemovalPolicy.DESTROY, version: es.ElasticsearchVersion.V7_1, fineGrainedAccessControl: { masterUserArn: user.userArn, diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.expected.json b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.expected.json index 201e3d81bd99d..309d8c2831e8d 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.expected.json +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.expected.json @@ -6,23 +6,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { @@ -237,7 +221,9 @@ "DependsOn": [ "DomainESLogGroupPolicyc82ca7bfe2f2589b859ebab89e88da2efd284adfadCustomResourcePolicy0B41F6DF", "DomainESLogGroupPolicyc82ca7bfe2f2589b859ebab89e88da2efd284adfadA70E756D" - ] + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "DomainESAccessPolicyCustomResourcePolicy9747FC42": { "Type": "AWS::IAM::Policy", @@ -436,13 +422,13 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs12.x", "Timeout": 120 }, @@ -466,4 +452,4 @@ "Description": "Artifact hash for asset \"b64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94\"" } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.ts b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.ts index 57152d5c70d5c..24bb07e4660ff 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.ts +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.ts @@ -1,7 +1,7 @@ import { EbsDeviceVolumeType } from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; -import { App, Stack, StackProps } from '@aws-cdk/core'; +import { App, RemovalPolicy, Stack, StackProps } from '@aws-cdk/core'; import { Construct } from 'constructs'; import * as es from '../lib'; @@ -12,6 +12,7 @@ class TestStack extends Stack { const key = new kms.Key(this, 'Key'); const domainProps: es.DomainProps = { + removalPolicy: RemovalPolicy.DESTROY, version: es.ElasticsearchVersion.V7_1, ebs: { volumeSize: 10, diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.expected.json b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.expected.json index e43b6bb5f62e6..e510eb3534625 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.expected.json +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.expected.json @@ -183,7 +183,9 @@ "DependsOn": [ "Domain1ESLogGroupPolicyc8858d5dba055f677469d76cb6ad538fd732ba69a6CustomResourcePolicy24436E05", "Domain1ESLogGroupPolicyc8858d5dba055f677469d76cb6ad538fd732ba69a6D8BDCF36" - ] + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "Domain1ESAccessPolicyCustomResourcePolicyC04432B6": { "Type": "AWS::IAM::Policy", @@ -352,13 +354,13 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs12.x", "Timeout": 120 }, @@ -549,7 +551,9 @@ "DependsOn": [ "Domain2ESLogGroupPolicyc8405238e455eeabd840cf6933e1814efc51d2de71CustomResourcePolicy77691A33", "Domain2ESLogGroupPolicyc8405238e455eeabd840cf6933e1814efc51d2de71F1DE93A1" - ] + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "Domain2ESAccessPolicyCustomResourcePolicy8EED1F24": { "Type": "AWS::IAM::Policy", diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ts b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ts index 4a6232d3ab130..448896e321957 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ts +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ts @@ -1,6 +1,6 @@ import { EbsDeviceVolumeType } from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; -import { App, Stack, StackProps } from '@aws-cdk/core'; +import { App, RemovalPolicy, Stack, StackProps } from '@aws-cdk/core'; import { Construct } from 'constructs'; import * as es from '../lib'; @@ -9,6 +9,7 @@ class TestStack extends Stack { super(scope, id, props); const domainProps: es.DomainProps = { + removalPolicy: RemovalPolicy.DESTROY, version: es.ElasticsearchVersion.V7_1, ebs: { volumeSize: 10, diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ultrawarm.expected.json b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ultrawarm.expected.json index c24aeb2f30740..702d302029600 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ultrawarm.expected.json +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ultrawarm.expected.json @@ -34,7 +34,9 @@ "NodeToNodeEncryptionOptions": { "Enabled": false } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ultrawarm.ts b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ultrawarm.ts index 259f43fe0cef2..c7c581252fc7e 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ultrawarm.ts +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ultrawarm.ts @@ -1,4 +1,4 @@ -import { App, Stack, StackProps } from '@aws-cdk/core'; +import { App, RemovalPolicy, Stack, StackProps } from '@aws-cdk/core'; import { Construct } from 'constructs'; import * as es from '../lib'; @@ -7,6 +7,7 @@ class TestStack extends Stack { super(scope, id, props); new es.Domain(this, 'Domain', { + removalPolicy: RemovalPolicy.DESTROY, version: es.ElasticsearchVersion.V7_1, capacity: { masterNodes: 2, diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.expected.json b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.expected.json index b55ac9e14df69..065e569573421 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.expected.json +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.expected.json @@ -58,7 +58,9 @@ "NodeToNodeEncryptionOptions": { "Enabled": true } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "DomainESAccessPolicyCustomResourcePolicy9747FC42": { "Type": "AWS::IAM::Policy", @@ -255,13 +257,13 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs12.x", "Timeout": 120 }, diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.ts b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.ts index 8844e5937305c..5e7fb2787972d 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.ts +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.ts @@ -1,4 +1,4 @@ -import { App, Stack, StackProps } from '@aws-cdk/core'; +import { App, RemovalPolicy, Stack, StackProps } from '@aws-cdk/core'; import { Construct } from 'constructs'; import * as es from '../lib'; @@ -7,6 +7,7 @@ class TestStack extends Stack { super(scope, id, props); new es.Domain(this, 'Domain', { + removalPolicy: RemovalPolicy.DESTROY, version: es.ElasticsearchVersion.V7_1, useUnsignedBasicAuth: true, }); diff --git a/packages/@aws-cdk/aws-emr/package.json b/packages/@aws-cdk/aws-emr/package.json index 09b7d70c7ece6..0865f9a31783d 100644 --- a/packages/@aws-cdk/aws-emr/package.json +++ b/packages/@aws-cdk/aws-emr/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-emrcontainers/package.json b/packages/@aws-cdk/aws-emrcontainers/package.json index ecd7363f54aad..c1e102c6a81e6 100644 --- a/packages/@aws-cdk/aws-emrcontainers/package.json +++ b/packages/@aws-cdk/aws-emrcontainers/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-events-targets/package.json b/packages/@aws-cdk/aws-events-targets/package.json index 2fbad9a4cd421..a4eee23c9a028 100644 --- a/packages/@aws-cdk/aws-events-targets/package.json +++ b/packages/@aws-cdk/aws-events-targets/package.json @@ -74,7 +74,7 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", - "aws-sdk": "^2.830.0", + "aws-sdk": "^2.848.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", @@ -140,5 +140,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.expected.json b/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.expected.json index c9efaffc51134..007503de08383 100644 --- a/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.expected.json @@ -340,7 +340,9 @@ } }, "MyQueueE6CA6235": { - "Type": "AWS::SQS::Queue" + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "MyQueuePolicy6BBEDDAC": { "Type": "AWS::SQS::QueuePolicy", @@ -422,4 +424,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-events-targets/test/codepipeline/integ.pipeline-event-target.expected.json b/packages/@aws-cdk/aws-events-targets/test/codepipeline/integ.pipeline-event-target.expected.json index f2ed2f2752e75..85af1bfde21c1 100644 --- a/packages/@aws-cdk/aws-events-targets/test/codepipeline/integ.pipeline-event-target.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/codepipeline/integ.pipeline-event-target.expected.json @@ -12,23 +12,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { @@ -49,25 +33,6 @@ } }, "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "pipelinePipeline22F2A91DRole58B7B05E", - "Arn" - ] - } - }, - "Resource": "*" } ], "Version": "2012-10-17" @@ -146,7 +111,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -474,4 +439,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-events-targets/test/kinesis-firehose/integ.kinesis-firehose-stream.expected.json b/packages/@aws-cdk/aws-events-targets/test/kinesis-firehose/integ.kinesis-firehose-stream.expected.json index 8cc4f2c5bbe65..6b76a3d96a32e 100644 --- a/packages/@aws-cdk/aws-events-targets/test/kinesis-firehose/integ.kinesis-firehose-stream.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/kinesis-firehose/integ.kinesis-firehose-stream.expected.json @@ -33,7 +33,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -161,4 +161,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-events-targets/test/sns/integ.sns-event-rule-target.expected.json b/packages/@aws-cdk/aws-events-targets/test/sns/integ.sns-event-rule-target.expected.json index f4aea52c23274..37a78f010d792 100644 --- a/packages/@aws-cdk/aws-events-targets/test/sns/integ.sns-event-rule-target.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/sns/integ.sns-event-rule-target.expected.json @@ -45,7 +45,9 @@ } }, "MyQueueE6CA6235": { - "Type": "AWS::SQS::Queue" + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "MyQueuePolicy6BBEDDAC": { "Type": "AWS::SQS::QueuePolicy", diff --git a/packages/@aws-cdk/aws-events-targets/test/sqs/integ.sqs-event-rule-target.expected.json b/packages/@aws-cdk/aws-events-targets/test/sqs/integ.sqs-event-rule-target.expected.json index 645845bc1f44b..eebbc3a996344 100644 --- a/packages/@aws-cdk/aws-events-targets/test/sqs/integ.sqs-event-rule-target.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/sqs/integ.sqs-event-rule-target.expected.json @@ -19,7 +19,9 @@ } }, "MyQueueE6CA6235": { - "Type": "AWS::SQS::Queue" + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "MyQueuePolicy6BBEDDAC": { "Type": "AWS::SQS::QueuePolicy", diff --git a/packages/@aws-cdk/aws-events/package.json b/packages/@aws-cdk/aws-events/package.json index 624ff18646bb6..4c8d4fe304598 100644 --- a/packages/@aws-cdk/aws-events/package.json +++ b/packages/@aws-cdk/aws-events/package.json @@ -108,5 +108,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-eventschemas/package.json b/packages/@aws-cdk/aws-eventschemas/package.json index 179f02a568a31..c141a1a389382 100644 --- a/packages/@aws-cdk/aws-eventschemas/package.json +++ b/packages/@aws-cdk/aws-eventschemas/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-fms/package.json b/packages/@aws-cdk/aws-fms/package.json index 2e85eba2e9ffe..352a762f1e877 100644 --- a/packages/@aws-cdk/aws-fms/package.json +++ b/packages/@aws-cdk/aws-fms/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-fsx/lib/file-system.ts b/packages/@aws-cdk/aws-fsx/lib/file-system.ts index 22b4f64d8cd3b..d19c0e7686151 100644 --- a/packages/@aws-cdk/aws-fsx/lib/file-system.ts +++ b/packages/@aws-cdk/aws-fsx/lib/file-system.ts @@ -1,6 +1,6 @@ import { Connections, IConnectable, ISecurityGroup, IVpc } from '@aws-cdk/aws-ec2'; import { IKey } from '@aws-cdk/aws-kms'; -import { Resource } from '@aws-cdk/core'; +import { RemovalPolicy, Resource } from '@aws-cdk/core'; /** * Interface to implement FSx File Systems. @@ -52,6 +52,13 @@ export interface FileSystemProps { * For SCRATCH_2 and PERSISTENT_1 types, valid values are 1,200, 2,400, then continuing in increments of 2,400 GiB. */ readonly storageCapacityGiB: number; + + /** + * Policy to apply when the file system is removed from the stack + * + * @default RemovalPolicy.RETAIN + */ + readonly removalPolicy?: RemovalPolicy; } /** diff --git a/packages/@aws-cdk/aws-fsx/lib/lustre-file-system.ts b/packages/@aws-cdk/aws-fsx/lib/lustre-file-system.ts index 9d27da5bca3cd..2206bb31dfad3 100644 --- a/packages/@aws-cdk/aws-fsx/lib/lustre-file-system.ts +++ b/packages/@aws-cdk/aws-fsx/lib/lustre-file-system.ts @@ -198,6 +198,7 @@ export class LustreFileSystem extends FileSystemBase { securityGroupIds: [securityGroup.securityGroupId], storageCapacity: props.storageCapacityGiB, }); + this.fileSystem.applyRemovalPolicy(props.removalPolicy); this.fileSystemId = this.fileSystem.ref; this.dnsName = `${this.fileSystemId}.fsx.${this.stack.region}.${Aws.URL_SUFFIX}`; diff --git a/packages/@aws-cdk/aws-fsx/package.json b/packages/@aws-cdk/aws-fsx/package.json index 7f03e65a80b11..f004ef50dc8b4 100644 --- a/packages/@aws-cdk/aws-fsx/package.json +++ b/packages/@aws-cdk/aws-fsx/package.json @@ -106,5 +106,8 @@ "maturity": "experimental", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-fsx/test/integ.lustre-file-system.expected.json b/packages/@aws-cdk/aws-fsx/test/integ.lustre-file-system.expected.json index 0164e2f1f0067..c5826b996a6bf 100644 --- a/packages/@aws-cdk/aws-fsx/test/integ.lustre-file-system.expected.json +++ b/packages/@aws-cdk/aws-fsx/test/integ.lustre-file-system.expected.json @@ -593,7 +593,9 @@ } ], "StorageCapacity": 1200 - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "instInstanceSecurityGroup54790689": { "Type": "AWS::EC2::SecurityGroup", diff --git a/packages/@aws-cdk/aws-fsx/test/integ.lustre-file-system.ts b/packages/@aws-cdk/aws-fsx/test/integ.lustre-file-system.ts index 00b32cea3b297..5202df62b2d08 100644 --- a/packages/@aws-cdk/aws-fsx/test/integ.lustre-file-system.ts +++ b/packages/@aws-cdk/aws-fsx/test/integ.lustre-file-system.ts @@ -1,5 +1,5 @@ import { AmazonLinuxGeneration, AmazonLinuxImage, Instance, InstanceClass, InstanceSize, InstanceType, SubnetType, Vpc } from '@aws-cdk/aws-ec2'; -import { App, Stack } from '@aws-cdk/core'; +import { App, RemovalPolicy, Stack } from '@aws-cdk/core'; import { LustreDeploymentType, LustreFileSystem } from '../lib'; const app = new App(); @@ -17,6 +17,7 @@ const fs = new LustreFileSystem(stack, 'FsxLustreFileSystem', { storageCapacityGiB: storageCapacity, vpc, vpcSubnet: vpc.privateSubnets[0], + removalPolicy: RemovalPolicy.DESTROY, }); const inst = new Instance(stack, 'inst', { diff --git a/packages/@aws-cdk/aws-fsx/test/lustre-file-system.test.ts b/packages/@aws-cdk/aws-fsx/test/lustre-file-system.test.ts index 43541cd858fce..fe0159a212140 100644 --- a/packages/@aws-cdk/aws-fsx/test/lustre-file-system.test.ts +++ b/packages/@aws-cdk/aws-fsx/test/lustre-file-system.test.ts @@ -1,5 +1,5 @@ import { strictEqual } from 'assert'; -import { expect as expectCDK, haveResource } from '@aws-cdk/assert'; +import { expect as expectCDK, haveResource, ResourcePart } from '@aws-cdk/assert'; import { ISubnet, Port, SecurityGroup, Subnet, Vpc } from '@aws-cdk/aws-ec2'; import { Key } from '@aws-cdk/aws-kms'; import { Aws, Stack, Token } from '@aws-cdk/core'; @@ -40,6 +40,10 @@ describe('FSx for Lustre File System', () => { strictEqual( fileSystem.dnsName, `${fileSystem.fileSystemId}.fsx.${stack.region}.${Aws.URL_SUFFIX}`); + + expectCDK(stack).to(haveResource('AWS::FSx::FileSystem', { + DeletionPolicy: 'Retain', + }, ResourcePart.CompleteDefinition)); }); test('file system is created correctly when security group is provided', () => { diff --git a/packages/@aws-cdk/aws-gamelift/package.json b/packages/@aws-cdk/aws-gamelift/package.json index 0f866c675bacf..9ce7dd38156cb 100644 --- a/packages/@aws-cdk/aws-gamelift/package.json +++ b/packages/@aws-cdk/aws-gamelift/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-globalaccelerator/package.json b/packages/@aws-cdk/aws-globalaccelerator/package.json index 84f457cd0fcce..44d8895ed30a3 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/package.json +++ b/packages/@aws-cdk/aws-globalaccelerator/package.json @@ -99,5 +99,8 @@ "maturity": "experimental", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-glue/README.md b/packages/@aws-cdk/aws-glue/README.md index 77ee00834ddd7..20e08d7c14e31 100644 --- a/packages/@aws-cdk/aws-glue/README.md +++ b/packages/@aws-cdk/aws-glue/README.md @@ -23,6 +23,24 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. +## Connection + +A `Connection` allows Glue jobs, crawlers and development endpoints to access certain types of data stores. For example, to create a network connection to connect to a data source within a VPC: + +```ts +new glue.Connection(stack, 'MyConnection', { + connectionType: glue.ConnectionTypes.NETWORK, + // The security groups granting AWS Glue inbound access to the data source within the VPC + securityGroups: [securityGroup], + // The VPC subnet which contains the data source + subnet, +}); +``` + +If you need to use a connection type that doesn't exist as a static member on `ConnectionType`, you can instantiate a `ConnectionType` object, e.g: `new glue.ConnectionType('NEW_TYPE')`. + +See [Adding a Connection to Your Data Store](https://docs.aws.amazon.com/glue/latest/dg/populate-add-connection.html) and [Connection Structure](https://docs.aws.amazon.com/glue/latest/dg/aws-glue-api-catalog-connections.html#aws-glue-api-catalog-connections-Connection) documentation for more information on the supported data stores and their configurations. + ## Database A `Database` is a logical grouping of `Tables` in the Glue Catalog. @@ -33,6 +51,40 @@ new glue.Database(stack, 'MyDatabase', { }); ``` +## SecurityConfiguration + +A `SecurityConfiguration` is a set of security properties that can be used by AWS Glue to encrypt data at rest. + +```ts +new glue.SecurityConfiguration(stack, 'MySecurityConfiguration', { + securityConfigurationName: 'name', + cloudWatchEncryption: { + mode: glue.CloudWatchEncryptionMode.KMS, + }, + jobBookmarksEncryption: { + mode: glue.JobBookmarksEncryptionMode.CLIENT_SIDE_KMS, + }, + s3Encryption: { + mode: glue.S3EncryptionMode.KMS, + }, +}); +``` + +By default, a shared KMS key is created for use with the encryption configurations that require one. You can also supply your own key for each encryption config, for example, for CloudWatch encryption: + +```ts +new glue.SecurityConfiguration(stack, 'MySecurityConfiguration', { + securityConfigurationName: 'name', + cloudWatchEncryption: { + mode: glue.CloudWatchEncryptionMode.KMS, + kmsKey: key, + }, +}); +``` + +See [documentation](https://docs.aws.amazon.com/glue/latest/dg/encryption-security-configuration.html) for more info for Glue encrypting data written by Crawlers, Jobs, and Development Endpoints. + + ## Table A Glue table describes a table of data in S3: its structure (column names and types), location of data (S3 objects with a common prefix in a S3 bucket), and format for the files (Json, Avro, Parquet, etc.): diff --git a/packages/@aws-cdk/aws-glue/lib/connection.ts b/packages/@aws-cdk/aws-glue/lib/connection.ts new file mode 100644 index 0000000000000..56cd115e4c6f9 --- /dev/null +++ b/packages/@aws-cdk/aws-glue/lib/connection.ts @@ -0,0 +1,216 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as cdk from '@aws-cdk/core'; +import * as constructs from 'constructs'; +import { CfnConnection } from './glue.generated'; + +/** + * The type of the glue connection + * + * If you need to use a connection type that doesn't exist as a static member, you + * can instantiate a `ConnectionType` object, e.g: `new ConnectionType('NEW_TYPE')`. + */ +export class ConnectionType { + + /** + * Designates a connection to a database through Java Database Connectivity (JDBC). + */ + public static readonly JDBC = new ConnectionType('JDBC'); + + /** + * Designates a connection to an Apache Kafka streaming platform. + */ + public static readonly KAFKA = new ConnectionType('KAFKA'); + + /** + * Designates a connection to a MongoDB document database. + */ + public static readonly MONGODB = new ConnectionType('MONGODB'); + + /** + * Designates a network connection to a data source within an Amazon Virtual Private Cloud environment (Amazon VPC). + */ + public static readonly NETWORK = new ConnectionType('NETWORK'); + + /** + * The name of this ConnectionType, as expected by Connection resource. + */ + public readonly name: string; + + constructor(name: string) { + this.name = name; + } + + /** + * The connection type name as expected by Connection resource. + */ + public toString(): string { + return this.name; + } +} + +/** + * Interface representing a created or an imported {@link Connection} + */ +export interface IConnection extends cdk.IResource { + /** + * The name of the connection + * @attribute + */ + readonly connectionName: string; + + /** + * The ARN of the connection + * @attribute + */ + readonly connectionArn: string; +} + +/** + * Base Connection Options + */ +export interface ConnectionOptions { + /** + * The name of the connection + * @default cloudformation generated name + */ + readonly connectionName?: string; + + /** + * The description of the connection. + * @default no description + */ + readonly description?: string; + + /** + * Key-Value pairs that define parameters for the connection. + * @default empty properties + * @see https://docs.aws.amazon.com/glue/latest/dg/aws-glue-programming-etl-connect.html + */ + readonly properties?: { [key: string]: string }; + + /** + * A list of criteria that can be used in selecting this connection. + * This is useful for filtering the results of https://awscli.amazonaws.com/v2/documentation/api/latest/reference/glue/get-connections.html + * @default no match criteria + */ + readonly matchCriteria?: string[]; + + /** + * The list of security groups needed to successfully make this connection e.g. to successfully connect to VPC. + * @default no security group + */ + readonly securityGroups?: ec2.ISecurityGroup[]; + + /** + * The VPC subnet to connect to resources within a VPC. See more at https://docs.aws.amazon.com/glue/latest/dg/start-connecting.html. + * @default no subnet + */ + readonly subnet?: ec2.ISubnet; +} + +/** + * Construction properties for {@link Connection} + */ +export interface ConnectionProps extends ConnectionOptions { + /** + * The type of the connection + */ + readonly type: ConnectionType; +} + +/** + * An AWS Glue connection to a data source. + */ +export class Connection extends cdk.Resource implements IConnection { + + /** + * Creates a Connection construct that represents an external connection. + * + * @param scope The scope creating construct (usually `this`). + * @param id The construct's id. + * @param connectionArn arn of external connection. + */ + public static fromConnectionArn(scope: constructs.Construct, id: string, connectionArn: string): IConnection { + class Import extends cdk.Resource implements IConnection { + public readonly connectionName = cdk.Arn.extractResourceName(connectionArn, 'connection'); + public readonly connectionArn = connectionArn; + } + + return new Import(scope, id); + } + + /** + * Creates a Connection construct that represents an external connection. + * + * @param scope The scope creating construct (usually `this`). + * @param id The construct's id. + * @param connectionName name of external connection. + */ + public static fromConnectionName(scope: constructs.Construct, id: string, connectionName: string): IConnection { + class Import extends cdk.Resource implements IConnection { + public readonly connectionName = connectionName; + public readonly connectionArn = Connection.buildConnectionArn(scope, connectionName); + } + + return new Import(scope, id); + } + + private static buildConnectionArn(scope: constructs.Construct, connectionName: string) : string { + return cdk.Stack.of(scope).formatArn({ + service: 'glue', + resource: 'connection', + resourceName: connectionName, + }); + } + + /** + * The ARN of the connection + */ + public readonly connectionArn: string; + + /** + * The name of the connection + */ + public readonly connectionName: string; + + private readonly properties: {[key: string]: string}; + + constructor(scope: constructs.Construct, id: string, props: ConnectionProps) { + super(scope, id, { + physicalName: props.connectionName, + }); + + this.properties = props.properties || {}; + + const physicalConnectionRequirements = props.subnet || props.securityGroups ? { + availabilityZone: props.subnet ? props.subnet.availabilityZone : undefined, + subnetId: props.subnet ? props.subnet.subnetId : undefined, + securityGroupIdList: props.securityGroups ? props.securityGroups.map(sg => sg.securityGroupId) : undefined, + } : undefined; + + const connectionResource = new CfnConnection(this, 'Resource', { + catalogId: cdk.Stack.of(this).account, + connectionInput: { + connectionProperties: cdk.Lazy.any({ produce: () => Object.keys(this.properties).length > 0 ? this.properties : undefined }), + connectionType: props.type.name, + description: props.description, + matchCriteria: props.matchCriteria, + name: props.connectionName, + physicalConnectionRequirements, + }, + }); + + const resourceName = this.getResourceNameAttribute(connectionResource.ref); + this.connectionArn = Connection.buildConnectionArn(this, resourceName); + this.connectionName = resourceName; + } + + /** + * Add additional connection parameters + * @param key parameter key + * @param value parameter value + */ + public addProperty(key: string, value: string): void { + this.properties[key] = value; + } +} diff --git a/packages/@aws-cdk/aws-glue/lib/index.ts b/packages/@aws-cdk/aws-glue/lib/index.ts index f0370c21041b2..a3dfa85b3be71 100644 --- a/packages/@aws-cdk/aws-glue/lib/index.ts +++ b/packages/@aws-cdk/aws-glue/lib/index.ts @@ -1,7 +1,9 @@ // AWS::Glue CloudFormation Resources: export * from './glue.generated'; +export * from './connection'; +export * from './data-format'; export * from './database'; export * from './schema'; -export * from './data-format'; +export * from './security-configuration'; export * from './table'; \ No newline at end of file diff --git a/packages/@aws-cdk/aws-glue/lib/security-configuration.ts b/packages/@aws-cdk/aws-glue/lib/security-configuration.ts new file mode 100644 index 0000000000000..f1e7297147794 --- /dev/null +++ b/packages/@aws-cdk/aws-glue/lib/security-configuration.ts @@ -0,0 +1,243 @@ +import * as kms from '@aws-cdk/aws-kms'; +import * as cdk from '@aws-cdk/core'; +import * as constructs from 'constructs'; +import { CfnSecurityConfiguration } from './glue.generated'; + +/** + * Interface representing a created or an imported {@link SecurityConfiguration}. + */ +export interface ISecurityConfiguration extends cdk.IResource { + /** + * The name of the security configuration. + * @attribute + */ + readonly securityConfigurationName: string; +} + +/** + * Encryption mode for S3. + * @see https://docs.aws.amazon.com/glue/latest/webapi/API_S3Encryption.html#Glue-Type-S3Encryption-S3EncryptionMode + */ +export enum S3EncryptionMode { + /** + * Server side encryption (SSE) with an Amazon S3-managed key. + * + * @see https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingServerSideEncryption.html + */ + S3_MANAGED = 'SSE-S3', + + /** + * Server-side encryption (SSE) with an AWS KMS key managed by the account owner. + * + * @see https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingKMSEncryption.html + */ + KMS = 'SSE-KMS', +} + +/** + * Encryption mode for CloudWatch Logs. + * @see https://docs.aws.amazon.com/glue/latest/webapi/API_CloudWatchEncryption.html#Glue-Type-CloudWatchEncryption-CloudWatchEncryptionMode + */ +export enum CloudWatchEncryptionMode { + /** + * Server-side encryption (SSE) with an AWS KMS key managed by the account owner. + * + * @see https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingKMSEncryption.html + */ + KMS = 'SSE-KMS', +} + +/** + * Encryption mode for Job Bookmarks. + * @see https://docs.aws.amazon.com/glue/latest/webapi/API_JobBookmarksEncryption.html#Glue-Type-JobBookmarksEncryption-JobBookmarksEncryptionMode + */ +export enum JobBookmarksEncryptionMode { + /** + * Client-side encryption (CSE) with an AWS KMS key managed by the account owner. + * + * @see https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingClientSideEncryption.html + */ + CLIENT_SIDE_KMS = 'CSE-KMS', +} + +/** + * S3 encryption configuration. + */ +export interface S3Encryption { + /** + * Encryption mode. + */ + readonly mode: S3EncryptionMode, + + /** + * The KMS key to be used to encrypt the data. + * @default no kms key if mode = S3_MANAGED. A key will be created if one is not provided and mode = KMS. + */ + readonly kmsKey?: kms.IKey, +} + +/** + * CloudWatch Logs encryption configuration. + */ +export interface CloudWatchEncryption { + /** + * Encryption mode + */ + readonly mode: CloudWatchEncryptionMode; + + /** + * The KMS key to be used to encrypt the data. + * @default A key will be created if one is not provided. + */ + readonly kmsKey?: kms.IKey, +} + +/** + * Job bookmarks encryption configuration. + */ +export interface JobBookmarksEncryption { + /** + * Encryption mode. + */ + readonly mode: JobBookmarksEncryptionMode; + + /** + * The KMS key to be used to encrypt the data. + * @default A key will be created if one is not provided. + */ + readonly kmsKey?: kms.IKey, +} + +/** + * Constructions properties of {@link SecurityConfiguration}. + */ +export interface SecurityConfigurationProps { + /** + * The name of the security configuration. + */ + readonly securityConfigurationName: string; + + /** + * The encryption configuration for Amazon CloudWatch Logs. + * @default no cloudwatch logs encryption. + */ + readonly cloudWatchEncryption?: CloudWatchEncryption, + + /** + * The encryption configuration for Glue Job Bookmarks. + * @default no job bookmarks encryption. + */ + readonly jobBookmarksEncryption?: JobBookmarksEncryption, + + /** + * The encryption configuration for Amazon Simple Storage Service (Amazon S3) data. + * @default no s3 encryption. + */ + readonly s3Encryption?: S3Encryption, +} + +/** + * A security configuration is a set of security properties that can be used by AWS Glue to encrypt data at rest. + * + * The following scenarios show some of the ways that you can use a security configuration. + * - Attach a security configuration to an AWS Glue crawler to write encrypted Amazon CloudWatch Logs. + * - Attach a security configuration to an extract, transform, and load (ETL) job to write encrypted Amazon Simple Storage Service (Amazon S3) targets and encrypted CloudWatch Logs. + * - Attach a security configuration to an ETL job to write its jobs bookmarks as encrypted Amazon S3 data. + * - Attach a security configuration to a development endpoint to write encrypted Amazon S3 targets. + */ +export class SecurityConfiguration extends cdk.Resource implements ISecurityConfiguration { + + /** + * Creates a Connection construct that represents an external security configuration. + * + * @param scope The scope creating construct (usually `this`). + * @param id The construct's id. + * @param securityConfigurationName name of external security configuration. + */ + public static fromSecurityConfigurationName(scope: constructs.Construct, id: string, + securityConfigurationName: string): ISecurityConfiguration { + + class Import extends cdk.Resource implements ISecurityConfiguration { + public readonly securityConfigurationName = securityConfigurationName; + } + return new Import(scope, id); + } + + /** + * The name of the security configuration. + * @attribute + */ + public readonly securityConfigurationName: string; + + /** + * The KMS key used in CloudWatch encryption if it requires a kms key. + */ + public readonly cloudWatchEncryptionKey?: kms.IKey; + + /** + * The KMS key used in job bookmarks encryption if it requires a kms key. + */ + public readonly jobBookmarksEncryptionKey?: kms.IKey; + + /** + * The KMS key used in S3 encryption if it requires a kms key. + */ + public readonly s3EncryptionKey?: kms.IKey; + + constructor(scope: constructs.Construct, id: string, props: SecurityConfigurationProps) { + super(scope, id, { + physicalName: props.securityConfigurationName, + }); + + if (!props.s3Encryption && !props.cloudWatchEncryption && !props.jobBookmarksEncryption) { + throw new Error('One of cloudWatchEncryption, jobBookmarksEncryption or s3Encryption must be defined'); + } + + const kmsKeyCreationRequired = + (props.s3Encryption && props.s3Encryption.mode === S3EncryptionMode.KMS && !props.s3Encryption.kmsKey) || + (props.cloudWatchEncryption && !props.cloudWatchEncryption.kmsKey) || + (props.jobBookmarksEncryption && !props.jobBookmarksEncryption.kmsKey); + const autoCreatedKmsKey = kmsKeyCreationRequired ? new kms.Key(this, 'Key') : undefined; + + let cloudWatchEncryption; + if (props.cloudWatchEncryption) { + this.cloudWatchEncryptionKey = props.cloudWatchEncryption.kmsKey || autoCreatedKmsKey; + cloudWatchEncryption = { + cloudWatchEncryptionMode: props.cloudWatchEncryption.mode, + kmsKeyArn: this.cloudWatchEncryptionKey?.keyArn, + }; + } + + let jobBookmarksEncryption; + if (props.jobBookmarksEncryption) { + this.jobBookmarksEncryptionKey = props.jobBookmarksEncryption.kmsKey || autoCreatedKmsKey; + jobBookmarksEncryption = { + jobBookmarksEncryptionMode: props.jobBookmarksEncryption.mode, + kmsKeyArn: this.jobBookmarksEncryptionKey?.keyArn, + }; + } + + let s3Encryptions; + if (props.s3Encryption) { + if (props.s3Encryption.mode === S3EncryptionMode.KMS) { + this.s3EncryptionKey = props.s3Encryption.kmsKey || autoCreatedKmsKey; + } + // NOTE: CloudFormations errors out if array is of length > 1. That's why the props don't expose an array + s3Encryptions = [{ + s3EncryptionMode: props.s3Encryption.mode, + kmsKeyArn: this.s3EncryptionKey?.keyArn, + }]; + } + + const resource = new CfnSecurityConfiguration(this, 'Resource', { + name: props.securityConfigurationName, + encryptionConfiguration: { + cloudWatchEncryption, + jobBookmarksEncryption, + s3Encryptions, + }, + }); + + this.securityConfigurationName = this.getResourceNameAttribute(resource.ref); + } +} diff --git a/packages/@aws-cdk/aws-glue/package.json b/packages/@aws-cdk/aws-glue/package.json index ca6ed1bb731a5..0eaa0ba607b63 100644 --- a/packages/@aws-cdk/aws-glue/package.json +++ b/packages/@aws-cdk/aws-glue/package.json @@ -80,6 +80,7 @@ "pkglint": "0.0.0" }, "dependencies": { + "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", @@ -88,6 +89,7 @@ }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { + "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", @@ -142,5 +144,8 @@ }, "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-glue/test/connection.test.ts b/packages/@aws-cdk/aws-glue/test/connection.test.ts new file mode 100644 index 0000000000000..5846bf161fa69 --- /dev/null +++ b/packages/@aws-cdk/aws-glue/test/connection.test.ts @@ -0,0 +1,159 @@ +import * as cdkassert from '@aws-cdk/assert'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as cdk from '@aws-cdk/core'; +import '@aws-cdk/assert/jest'; +import * as glue from '../lib'; + +test('a connection with connection properties', () => { + const stack = new cdk.Stack(); + new glue.Connection(stack, 'Connection', { + type: glue.ConnectionType.JDBC, + properties: { + JDBC_CONNECTION_URL: 'jdbc:server://server:443/connection', + USERNAME: 'username', + PASSWORD: 'password', + }, + }); + + cdkassert.expect(stack).to(cdkassert.haveResource('AWS::Glue::Connection', { + CatalogId: { + Ref: 'AWS::AccountId', + }, + ConnectionInput: { + ConnectionProperties: { + JDBC_CONNECTION_URL: 'jdbc:server://server:443/connection', + USERNAME: 'username', + PASSWORD: 'password', + }, + ConnectionType: 'JDBC', + }, + })); +}); + +test('a connection with a subnet and security group', () => { + const stack = new cdk.Stack(); + const subnet = ec2.Subnet.fromSubnetAttributes(stack, 'subnet', { + subnetId: 'subnetId', + availabilityZone: 'azId', + }); + const securityGroup = ec2.SecurityGroup.fromSecurityGroupId(stack, 'securityGroup', 'sgId'); + new glue.Connection(stack, 'Connection', { + type: glue.ConnectionType.NETWORK, + securityGroups: [securityGroup], + subnet, + }); + + cdkassert.expect(stack).to(cdkassert.haveResource('AWS::Glue::Connection', { + CatalogId: { + Ref: 'AWS::AccountId', + }, + ConnectionInput: { + ConnectionType: 'NETWORK', + PhysicalConnectionRequirements: { + AvailabilityZone: 'azId', + SubnetId: 'subnetId', + SecurityGroupIdList: ['sgId'], + }, + }, + })); +}); + +test('a connection with a name and description', () => { + const stack = new cdk.Stack(); + new glue.Connection(stack, 'Connection', { + connectionName: 'name', + description: 'description', + type: glue.ConnectionType.NETWORK, + }); + + cdkassert.expect(stack).to(cdkassert.haveResource('AWS::Glue::Connection', { + CatalogId: { + Ref: 'AWS::AccountId', + }, + ConnectionInput: { + ConnectionType: 'NETWORK', + Name: 'name', + Description: 'description', + }, + })); +}); + +test('a connection with a custom type', () => { + const stack = new cdk.Stack(); + new glue.Connection(stack, 'Connection', { + connectionName: 'name', + description: 'description', + type: new glue.ConnectionType('CUSTOM_TYPE'), + }); + + cdkassert.expect(stack).to(cdkassert.haveResource('AWS::Glue::Connection', { + CatalogId: { + Ref: 'AWS::AccountId', + }, + ConnectionInput: { + ConnectionType: 'CUSTOM_TYPE', + Name: 'name', + Description: 'description', + }, + })); +}); + +test('a connection with match criteria', () => { + const stack = new cdk.Stack(); + new glue.Connection(stack, 'Connection', { + type: glue.ConnectionType.NETWORK, + matchCriteria: ['c1', 'c2'], + }); + + cdkassert.expect(stack).to(cdkassert.haveResource('AWS::Glue::Connection', { + CatalogId: { + Ref: 'AWS::AccountId', + }, + ConnectionInput: { + ConnectionType: 'NETWORK', + MatchCriteria: ['c1', 'c2'], + }, + })); +}); + +test('addProperty', () => { + const stack = new cdk.Stack(); + const connection = new glue.Connection(stack, 'Connection', { + type: glue.ConnectionType.NETWORK, + }); + connection.addProperty('SomeKey', 'SomeValue'); + + cdkassert.expect(stack).to(cdkassert.haveResource('AWS::Glue::Connection', { + CatalogId: { + Ref: 'AWS::AccountId', + }, + ConnectionInput: { + ConnectionType: 'NETWORK', + ConnectionProperties: { + SomeKey: 'SomeValue', + }, + }, + })); +}); + +test('fromConnectionName', () => { + const connectionName = 'name'; + const stack = new cdk.Stack(); + const connection = glue.Connection.fromConnectionName(stack, 'ImportedConnection', connectionName); + + expect(connection.connectionName).toEqual(connectionName); + expect(connection.connectionArn).toEqual(stack.formatArn({ + service: 'glue', + resource: 'connection', + resourceName: connectionName, + })); +}); + +test('fromConnectionArn', () => { + const connectionArn = 'arn:aws:glue:region:account-id:connection/name'; + const stack = new cdk.Stack(); + const connection = glue.Connection.fromConnectionArn(stack, 'ImportedConnection', connectionArn); + + expect(connection.connectionName).toEqual('name'); + expect(connection.connectionArn).toEqual(connectionArn); +}); diff --git a/packages/@aws-cdk/aws-glue/test/integ.connection.expected.json b/packages/@aws-cdk/aws-glue/test/integ.connection.expected.json new file mode 100644 index 0000000000000..3422ce4ff408b --- /dev/null +++ b/packages/@aws-cdk/aws-glue/test/integ.connection.expected.json @@ -0,0 +1,559 @@ +{ + "Resources": { + "Vpc8378EB38": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc" + } + ] + } + }, + "VpcPublicSubnet1Subnet5C2D37C4": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/19", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "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-glue-connection/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1RouteTable6C95E38E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1RouteTableAssociation97140677": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + } + } + }, + "VpcPublicSubnet1DefaultRoute3DA9E72A": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet1EIPD7E02669": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1NATGateway4D7517AA": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet1EIPD7E02669", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet2Subnet691E08A3": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.32.0/19", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "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-glue-connection/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2RouteTable94F7E489": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2RouteTableAssociationDD5762D8": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + } + } + }, + "VpcPublicSubnet2DefaultRoute97F91067": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet2EIP3C605A87": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2NATGateway9182C01D": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet2EIP3C605A87", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet3SubnetBE12F0B6": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/19", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "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-glue-connection/Vpc/PublicSubnet3" + } + ] + } + }, + "VpcPublicSubnet3RouteTable93458DBB": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PublicSubnet3" + } + ] + } + }, + "VpcPublicSubnet3RouteTableAssociation1F1EDF02": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet3RouteTable93458DBB" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet3SubnetBE12F0B6" + } + } + }, + "VpcPublicSubnet3DefaultRoute4697774F": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet3RouteTable93458DBB" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet3EIP3A666A23": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PublicSubnet3" + } + ] + } + }, + "VpcPublicSubnet3NATGateway7640CD1D": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet3EIP3A666A23", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VpcPublicSubnet3SubnetBE12F0B6" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PublicSubnet3" + } + ] + } + }, + "VpcPrivateSubnet1Subnet536B997A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.96.0/19", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "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-glue-connection/Vpc/PrivateSubnet1" + } + ] + } + }, + "VpcPrivateSubnet1RouteTableB2C5B500": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PrivateSubnet1" + } + ] + } + }, + "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + } + } + }, + "VpcPrivateSubnet1DefaultRouteBE02A9ED": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + } + } + }, + "VpcPrivateSubnet2Subnet3788AAA1": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/19", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "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-glue-connection/Vpc/PrivateSubnet2" + } + ] + } + }, + "VpcPrivateSubnet2RouteTableA678073B": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PrivateSubnet2" + } + ] + } + }, + "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + } + }, + "VpcPrivateSubnet2DefaultRoute060D2087": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet2NATGateway9182C01D" + } + } + }, + "VpcPrivateSubnet3SubnetF258B56E": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.160.0/19", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "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-glue-connection/Vpc/PrivateSubnet3" + } + ] + } + }, + "VpcPrivateSubnet3RouteTableD98824C7": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PrivateSubnet3" + } + ] + } + }, + "VpcPrivateSubnet3RouteTableAssociation16BDDC43": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet3RouteTableD98824C7" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet3SubnetF258B56E" + } + } + }, + "VpcPrivateSubnet3DefaultRoute94B74F0D": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet3RouteTableD98824C7" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet3NATGateway7640CD1D" + } + } + }, + "VpcIGWD7BA715C": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc" + } + ] + } + }, + "VpcVPCGWBF912B6E": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "InternetGatewayId": { + "Ref": "VpcIGWD7BA715C" + } + } + }, + "SecurityGroupDD263621": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-glue-connection/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "NetworkConnection2B07B7E5": { + "Type": "AWS::Glue::Connection", + "Properties": { + "CatalogId": { + "Ref": "AWS::AccountId" + }, + "ConnectionInput": { + "ConnectionType": "NETWORK", + "PhysicalConnectionRequirements": { + "AvailabilityZone": "test-region-1a", + "SecurityGroupIdList": [ + { + "Fn::GetAtt": [ + "SecurityGroupDD263621", + "GroupId" + ] + } + ], + "SubnetId": { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + } + } + } + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-glue/test/integ.connection.ts b/packages/@aws-cdk/aws-glue/test/integ.connection.ts new file mode 100644 index 0000000000000..3d586f97c85c0 --- /dev/null +++ b/packages/@aws-cdk/aws-glue/test/integ.connection.ts @@ -0,0 +1,20 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as cdk from '@aws-cdk/core'; +import * as glue from '../lib'; + +const app = new cdk.App(); + +const stack = new cdk.Stack(app, 'aws-glue-connection'); + +const vpc = new ec2.Vpc(stack, 'Vpc'); + +const sg = new ec2.SecurityGroup(stack, 'SecurityGroup', { + vpc, +}); + +// Network connection +new glue.Connection(stack, 'NetworkConnection', { + type: glue.ConnectionType.NETWORK, + subnet: vpc.privateSubnets[0], + securityGroups: [sg], +}); diff --git a/packages/@aws-cdk/aws-glue/test/integ.security-configuration.expected.json b/packages/@aws-cdk/aws-glue/test/integ.security-configuration.expected.json new file mode 100644 index 0000000000000..8d8dd30dab49d --- /dev/null +++ b/packages/@aws-cdk/aws-glue/test/integ.security-configuration.expected.json @@ -0,0 +1,161 @@ +{ + "Resources": { + "Key961B73FD": { + "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" + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "KeyedSC862A23F3": { + "Type": "AWS::Glue::SecurityConfiguration", + "Properties": { + "EncryptionConfiguration": { + "CloudWatchEncryption": { + "CloudWatchEncryptionMode": "SSE-KMS", + "KmsKeyArn": { + "Fn::GetAtt": [ + "Key961B73FD", + "Arn" + ] + } + }, + "JobBookmarksEncryption": { + "JobBookmarksEncryptionMode": "CSE-KMS", + "KmsKeyArn": { + "Fn::GetAtt": [ + "Key961B73FD", + "Arn" + ] + } + }, + "S3Encryptions": [ + { + "KmsKeyArn": { + "Fn::GetAtt": [ + "Key961B73FD", + "Arn" + ] + }, + "S3EncryptionMode": "SSE-KMS" + } + ] + }, + "Name": "KeyedSC" + } + }, + "KeylessSCKey4D3DE803": { + "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" + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "KeylessSC42E312EC": { + "Type": "AWS::Glue::SecurityConfiguration", + "Properties": { + "EncryptionConfiguration": { + "CloudWatchEncryption": { + "CloudWatchEncryptionMode": "SSE-KMS", + "KmsKeyArn": { + "Fn::GetAtt": [ + "KeylessSCKey4D3DE803", + "Arn" + ] + } + }, + "JobBookmarksEncryption": { + "JobBookmarksEncryptionMode": "CSE-KMS", + "KmsKeyArn": { + "Fn::GetAtt": [ + "KeylessSCKey4D3DE803", + "Arn" + ] + } + }, + "S3Encryptions": [ + { + "KmsKeyArn": { + "Fn::GetAtt": [ + "KeylessSCKey4D3DE803", + "Arn" + ] + }, + "S3EncryptionMode": "SSE-KMS" + } + ] + }, + "Name": "KeylessSC" + } + }, + "S3SCE31C83BE": { + "Type": "AWS::Glue::SecurityConfiguration", + "Properties": { + "EncryptionConfiguration": { + "S3Encryptions": [ + { + "S3EncryptionMode": "SSE-S3" + } + ] + }, + "Name": "S3SC" + } + } + } +} diff --git a/packages/@aws-cdk/aws-glue/test/integ.security-configuration.ts b/packages/@aws-cdk/aws-glue/test/integ.security-configuration.ts new file mode 100644 index 0000000000000..e10ef4d140adc --- /dev/null +++ b/packages/@aws-cdk/aws-glue/test/integ.security-configuration.ts @@ -0,0 +1,50 @@ +import * as kms from '@aws-cdk/aws-kms'; +import * as cdk from '@aws-cdk/core'; +import * as glue from '../lib'; + +const app = new cdk.App(); + +const stack = new cdk.Stack(app, 'aws-glue-security-configuration'); + +const key = new kms.Key(stack, 'Key'); + +// SecurityConfiguration for all 3 (s3, cloudwatch and job bookmarks) in modes requiring kms keys +new glue.SecurityConfiguration(stack, 'KeyedSC', { + securityConfigurationName: 'KeyedSC', + jobBookmarksEncryption: { + mode: glue.JobBookmarksEncryptionMode.CLIENT_SIDE_KMS, + kmsKey: key, + }, + cloudWatchEncryption: { + mode: glue.CloudWatchEncryptionMode.KMS, + kmsKey: key, + }, + s3Encryption: { + mode: glue.S3EncryptionMode.KMS, + kmsKey: key, + }, +}); + +// SecurityConfiguration for all 3 (s3, cloudwatch and job bookmarks) in modes requiring kms keys without one provided +new glue.SecurityConfiguration(stack, 'KeylessSC', { + securityConfigurationName: 'KeylessSC', + jobBookmarksEncryption: { + mode: glue.JobBookmarksEncryptionMode.CLIENT_SIDE_KMS, + }, + cloudWatchEncryption: { + mode: glue.CloudWatchEncryptionMode.KMS, + }, + s3Encryption: { + mode: glue.S3EncryptionMode.KMS, + }, +}); + +// SecurityConfiguration for s3 not requiring kms key +new glue.SecurityConfiguration(stack, 'S3SC', { + securityConfigurationName: 'S3SC', + s3Encryption: { + mode: glue.S3EncryptionMode.S3_MANAGED, + }, +}); + +app.synth(); diff --git a/packages/@aws-cdk/aws-glue/test/integ.table.expected.json b/packages/@aws-cdk/aws-glue/test/integ.table.expected.json index d9f6d7f602195..9d00dcfffab63 100644 --- a/packages/@aws-cdk/aws-glue/test/integ.table.expected.json +++ b/packages/@aws-cdk/aws-glue/test/integ.table.expected.json @@ -302,23 +302,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { @@ -339,25 +323,6 @@ } }, "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" @@ -517,7 +482,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -595,7 +560,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -708,7 +673,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -837,4 +802,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-glue/test/security-configuration.test.ts b/packages/@aws-cdk/aws-glue/test/security-configuration.test.ts new file mode 100644 index 0000000000000..cd94a660dfcb3 --- /dev/null +++ b/packages/@aws-cdk/aws-glue/test/security-configuration.test.ts @@ -0,0 +1,122 @@ +import * as cdkassert from '@aws-cdk/assert'; +import * as kms from '@aws-cdk/aws-kms'; +import * as cdk from '@aws-cdk/core'; +import '@aws-cdk/assert/jest'; +import * as glue from '../lib'; + +test('throws when a security configuration has no encryption config', () => { + const stack = new cdk.Stack(); + + expect(() => new glue.SecurityConfiguration(stack, 'SecurityConfiguration', { + securityConfigurationName: 'name', + })).toThrowError(/One of cloudWatchEncryption, jobBookmarksEncryption or s3Encryption must be defined/); +}); + +test('a security configuration with encryption configuration requiring kms key and providing an explicit one', () => { + const stack = new cdk.Stack(); + const keyArn = 'arn:aws:kms:us-west-2:111122223333:key/test-key'; + const key = kms.Key.fromKeyArn(stack, 'ImportedKey', keyArn); + + const securityConfiguration = new glue.SecurityConfiguration(stack, 'SecurityConfiguration', { + securityConfigurationName: 'name', + cloudWatchEncryption: { + mode: glue.CloudWatchEncryptionMode.KMS, + kmsKey: key, + }, + }); + + expect(securityConfiguration.cloudWatchEncryptionKey?.keyArn).toEqual(keyArn); + expect(securityConfiguration.jobBookmarksEncryptionKey).toBeUndefined(); + expect(securityConfiguration.s3EncryptionKey).toBeUndefined(); + + cdkassert.expect(stack).to(cdkassert.haveResource('AWS::Glue::SecurityConfiguration', { + Name: 'name', + EncryptionConfiguration: { + CloudWatchEncryption: { + CloudWatchEncryptionMode: 'SSE-KMS', + KmsKeyArn: keyArn, + }, + }, + })); +}); + +test('a security configuration with an encryption configuration requiring kms key but not providing an explicit one', () => { + const stack = new cdk.Stack(); + + const securityConfiguration = new glue.SecurityConfiguration(stack, 'SecurityConfiguration', { + securityConfigurationName: 'name', + cloudWatchEncryption: { + mode: glue.CloudWatchEncryptionMode.KMS, + }, + }); + + expect(securityConfiguration.cloudWatchEncryptionKey).toBeDefined(); + expect(securityConfiguration.jobBookmarksEncryptionKey).toBeUndefined(); + expect(securityConfiguration.s3EncryptionKey).toBeUndefined(); + + cdkassert.expect(stack).to(cdkassert.haveResource('AWS::KMS::Key')); + + cdkassert.expect(stack).to(cdkassert.haveResource('AWS::Glue::SecurityConfiguration', { + Name: 'name', + EncryptionConfiguration: { + CloudWatchEncryption: { + CloudWatchEncryptionMode: 'SSE-KMS', + KmsKeyArn: stack.resolve(securityConfiguration.cloudWatchEncryptionKey?.keyArn), + }, + }, + })); +}); + +test('a security configuration with all encryption configs and mixed kms key inputs', () => { + const stack = new cdk.Stack(); + const keyArn = 'arn:aws:kms:us-west-2:111122223333:key/test-key'; + const key = kms.Key.fromKeyArn(stack, 'ImportedKey', keyArn); + + const securityConfiguration = new glue.SecurityConfiguration(stack, 'SecurityConfiguration', { + securityConfigurationName: 'name', + cloudWatchEncryption: { + mode: glue.CloudWatchEncryptionMode.KMS, + }, + jobBookmarksEncryption: { + mode: glue.JobBookmarksEncryptionMode.CLIENT_SIDE_KMS, + kmsKey: key, + }, + s3Encryption: { + mode: glue.S3EncryptionMode.S3_MANAGED, + }, + }); + + expect(securityConfiguration.cloudWatchEncryptionKey).toBeDefined(); + expect(securityConfiguration.jobBookmarksEncryptionKey?.keyArn).toEqual(keyArn); + expect(securityConfiguration.s3EncryptionKey).toBeUndefined(); + + cdkassert.expect(stack).to(cdkassert.haveResource('AWS::KMS::Key')); + + cdkassert.expect(stack).to(cdkassert.haveResource('AWS::Glue::SecurityConfiguration', { + Name: 'name', + EncryptionConfiguration: { + CloudWatchEncryption: { + CloudWatchEncryptionMode: 'SSE-KMS', + // auto-created kms key + KmsKeyArn: stack.resolve(securityConfiguration.cloudWatchEncryptionKey?.keyArn), + }, + JobBookmarksEncryption: { + JobBookmarksEncryptionMode: 'CSE-KMS', + // explicitly provided kms key + KmsKeyArn: keyArn, + }, + S3Encryptions: [{ + S3EncryptionMode: 'SSE-S3', + }], + }, + })); +}); + +test('fromSecurityConfigurationName', () => { + const stack = new cdk.Stack(); + const name = 'name'; + + const securityConfiguration = glue.SecurityConfiguration.fromSecurityConfigurationName(stack, 'ImportedSecurityConfiguration', name); + + expect(securityConfiguration.securityConfigurationName).toEqual(name); +}); diff --git a/packages/@aws-cdk/aws-greengrass/package.json b/packages/@aws-cdk/aws-greengrass/package.json index 3ecb652d79f37..666c2f02b99f3 100644 --- a/packages/@aws-cdk/aws-greengrass/package.json +++ b/packages/@aws-cdk/aws-greengrass/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-greengrassv2/package.json b/packages/@aws-cdk/aws-greengrassv2/package.json index be7357654ce55..68d9557122c34 100644 --- a/packages/@aws-cdk/aws-greengrassv2/package.json +++ b/packages/@aws-cdk/aws-greengrassv2/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-guardduty/package.json b/packages/@aws-cdk/aws-guardduty/package.json index 11e01410f2509..2d772252718cb 100644 --- a/packages/@aws-cdk/aws-guardduty/package.json +++ b/packages/@aws-cdk/aws-guardduty/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-iam/package.json b/packages/@aws-cdk/aws-iam/package.json index 2500a54acd9b9..6455688b5c006 100644 --- a/packages/@aws-cdk/aws-iam/package.json +++ b/packages/@aws-cdk/aws-iam/package.json @@ -113,5 +113,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-imagebuilder/package.json b/packages/@aws-cdk/aws-imagebuilder/package.json index a05909901d105..25cf2f2c92657 100644 --- a/packages/@aws-cdk/aws-imagebuilder/package.json +++ b/packages/@aws-cdk/aws-imagebuilder/package.json @@ -91,5 +91,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-inspector/package.json b/packages/@aws-cdk/aws-inspector/package.json index d61b15d3c8b21..a94beb9c3ab2e 100644 --- a/packages/@aws-cdk/aws-inspector/package.json +++ b/packages/@aws-cdk/aws-inspector/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-iot/package.json b/packages/@aws-cdk/aws-iot/package.json index 57e349ab43059..baec64baf8142 100644 --- a/packages/@aws-cdk/aws-iot/package.json +++ b/packages/@aws-cdk/aws-iot/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-iot1click/package.json b/packages/@aws-cdk/aws-iot1click/package.json index 7206bea590918..4000a6cd6721d 100644 --- a/packages/@aws-cdk/aws-iot1click/package.json +++ b/packages/@aws-cdk/aws-iot1click/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-iotanalytics/package.json b/packages/@aws-cdk/aws-iotanalytics/package.json index 9ccf98c8c45b3..e3b33ffa331b8 100644 --- a/packages/@aws-cdk/aws-iotanalytics/package.json +++ b/packages/@aws-cdk/aws-iotanalytics/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-iotevents/package.json b/packages/@aws-cdk/aws-iotevents/package.json index eed3b7f8cde17..d0ecd71421f76 100644 --- a/packages/@aws-cdk/aws-iotevents/package.json +++ b/packages/@aws-cdk/aws-iotevents/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-iotsitewise/package.json b/packages/@aws-cdk/aws-iotsitewise/package.json index 1f6d59ceaf8a2..e7301a75e3f49 100644 --- a/packages/@aws-cdk/aws-iotsitewise/package.json +++ b/packages/@aws-cdk/aws-iotsitewise/package.json @@ -91,5 +91,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-iotthingsgraph/package.json b/packages/@aws-cdk/aws-iotthingsgraph/package.json index 7f861b23c861b..59c5396d37c79 100644 --- a/packages/@aws-cdk/aws-iotthingsgraph/package.json +++ b/packages/@aws-cdk/aws-iotthingsgraph/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-iotwireless/package.json b/packages/@aws-cdk/aws-iotwireless/package.json index 68730c1aaebd6..df0a35c2bd8fe 100644 --- a/packages/@aws-cdk/aws-iotwireless/package.json +++ b/packages/@aws-cdk/aws-iotwireless/package.json @@ -91,5 +91,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-ivs/package.json b/packages/@aws-cdk/aws-ivs/package.json index e89ed75d3c82f..ce179233a9efa 100644 --- a/packages/@aws-cdk/aws-ivs/package.json +++ b/packages/@aws-cdk/aws-ivs/package.json @@ -104,5 +104,8 @@ "maturity": "experimental", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-kendra/package.json b/packages/@aws-cdk/aws-kendra/package.json index c8992330a0419..0ce7d188ea30f 100644 --- a/packages/@aws-cdk/aws-kendra/package.json +++ b/packages/@aws-cdk/aws-kendra/package.json @@ -91,5 +91,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-kinesis/package.json b/packages/@aws-cdk/aws-kinesis/package.json index a8b384d677161..e8153880812db 100644 --- a/packages/@aws-cdk/aws-kinesis/package.json +++ b/packages/@aws-cdk/aws-kinesis/package.json @@ -99,5 +99,8 @@ "maturity": "stable", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json b/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json index 80dbdfd4aeb76..2d28b8fd4df7e 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json +++ b/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json @@ -111,5 +111,8 @@ "env": { "AWSLINT_BASE_CONSTRUCT": true } + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-kinesisanalytics/package.json b/packages/@aws-cdk/aws-kinesisanalytics/package.json index bbd35a2c47cd2..c6b67502056e0 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics/package.json +++ b/packages/@aws-cdk/aws-kinesisanalytics/package.json @@ -95,5 +95,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-kinesisfirehose/package.json b/packages/@aws-cdk/aws-kinesisfirehose/package.json index b4e0dd9e8487f..ae2d309ed8e24 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose/package.json +++ b/packages/@aws-cdk/aws-kinesisfirehose/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-kms/lib/key.ts b/packages/@aws-cdk/aws-kms/lib/key.ts index 4e18d228fe38e..2176d28f5b5bc 100644 --- a/packages/@aws-cdk/aws-kms/lib/key.ts +++ b/packages/@aws-cdk/aws-kms/lib/key.ts @@ -285,7 +285,7 @@ export interface KeyProps { /** * Custom policy document to attach to the KMS key. * - * NOTE - If the '@aws-cdk/aws-kms:defaultKeyPolicies' feature flag is set (the default for new projects), + * NOTE - If the `@aws-cdk/aws-kms:defaultKeyPolicies` feature flag is set (the default for new projects), * this policy will *override* the default key policy and become the only key policy for the key. If the * feature flag is not set, this policy will be appended to the default key policy. * @@ -322,12 +322,12 @@ export interface KeyProps { * to how it works for other AWS resources). This matches the default behavior * when creating KMS keys via the API or console. * - * If the '@aws-cdk/aws-kms:defaultKeyPolicies' feature flag is set (the default for new projects), + * If the `@aws-cdk/aws-kms:defaultKeyPolicies` feature flag is set (the default for new projects), * this flag will always be treated as 'true' and does not need to be explicitly set. * - * @default - false, unless the '@aws-cdk/aws-kms:defaultKeyPolicies' feature flag is set. + * @default - false, unless the `@aws-cdk/aws-kms:defaultKeyPolicies` feature flag is set. * @see https://docs.aws.amazon.com/kms/latest/developerguide/key-policies.html#key-policy-default-allow-root-enable-iam - * @deprecated redundant with the '@aws-cdk/aws-kms:defaultKeyPolicies' feature flag + * @deprecated redundant with the `@aws-cdk/aws-kms:defaultKeyPolicies` feature flag */ readonly trustAccountIdentities?: boolean; @@ -471,7 +471,7 @@ export class Key extends KeyBase { * Grants the account admin privileges -- not full account access -- plus the GenerateDataKey action. * The GenerateDataKey action was added for interop with S3 in https://github.com/aws/aws-cdk/issues/3458. * - * This policy is discouraged and deprecated by the '@aws-cdk/aws-kms:defaultKeyPolicies' feature flag. + * This policy is discouraged and deprecated by the `@aws-cdk/aws-kms:defaultKeyPolicies` feature flag. * * @link https://docs.aws.amazon.com/kms/latest/developerguide/key-policies.html#key-policy-default * @deprecated diff --git a/packages/@aws-cdk/aws-kms/package.json b/packages/@aws-cdk/aws-kms/package.json index d4b3f10a58e3f..272c610530357 100644 --- a/packages/@aws-cdk/aws-kms/package.json +++ b/packages/@aws-cdk/aws-kms/package.json @@ -102,5 +102,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-kms/test/integ.key-sharing.lit.expected.json b/packages/@aws-cdk/aws-kms/test/integ.key-sharing.lit.expected.json index 1a2290cc9bce4..24704085b587e 100644 --- a/packages/@aws-cdk/aws-kms/test/integ.key-sharing.lit.expected.json +++ b/packages/@aws-cdk/aws-kms/test/integ.key-sharing.lit.expected.json @@ -7,23 +7,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { diff --git a/packages/@aws-cdk/aws-kms/test/integ.key.expected.json b/packages/@aws-cdk/aws-kms/test/integ.key.expected.json index a11ff1abc7e94..6ed1da4638a2f 100644 --- a/packages/@aws-cdk/aws-kms/test/integ.key.expected.json +++ b/packages/@aws-cdk/aws-kms/test/integ.key.expected.json @@ -6,23 +6,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { diff --git a/packages/@aws-cdk/aws-lakeformation/package.json b/packages/@aws-cdk/aws-lakeformation/package.json index d2dfab5e2df22..8c3f72401111d 100644 --- a/packages/@aws-cdk/aws-lakeformation/package.json +++ b/packages/@aws-cdk/aws-lakeformation/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-lambda-destinations/package.json b/packages/@aws-cdk/aws-lambda-destinations/package.json index 6f46b2a23fd6c..096ee2f6fc12f 100644 --- a/packages/@aws-cdk/aws-lambda-destinations/package.json +++ b/packages/@aws-cdk/aws-lambda-destinations/package.json @@ -104,5 +104,8 @@ "env": { "AWSLINT_BASE_CONSTRUCT": true } + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-lambda-destinations/test/integ.destinations.expected.json b/packages/@aws-cdk/aws-lambda-destinations/test/integ.destinations.expected.json index c9c1d8cd64563..510fe8cef21a8 100644 --- a/packages/@aws-cdk/aws-lambda-destinations/test/integ.destinations.expected.json +++ b/packages/@aws-cdk/aws-lambda-destinations/test/integ.destinations.expected.json @@ -4,7 +4,9 @@ "Type": "AWS::SNS::Topic" }, "Queue4A7E3555": { - "Type": "AWS::SQS::Queue" + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "SnsSqsServiceRole869866F7": { "Type": "AWS::IAM::Role", @@ -80,13 +82,13 @@ "Code": { "ZipFile": "exports.handler = async (event) => {\n if (event === 'OK') return 'success';\n throw new Error('failure');\n };" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "SnsSqsServiceRole869866F7", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs10.x" }, "DependsOn": [ @@ -165,13 +167,13 @@ "Code": { "ZipFile": "exports.handler = async (event) => {\n console.log(event);\n };" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "OnSuccesServiceRole75E399CF", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs10.x" }, "DependsOn": [ @@ -246,13 +248,13 @@ "Code": { "ZipFile": "exports.handler = async (event) => {\n if (event === 'OK') return 'success';\n throw new Error('failure');\n };" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "EventBusLambdaServiceRole9BC8901F", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs10.x" }, "DependsOn": [ diff --git a/packages/@aws-cdk/aws-lambda-event-sources/package.json b/packages/@aws-cdk/aws-lambda-event-sources/package.json index 6d5a36395f693..20112e1029cbf 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/package.json +++ b/packages/@aws-cdk/aws-lambda-event-sources/package.json @@ -126,5 +126,8 @@ "env": { "AWSLINT_BASE_CONSTRUCT": true } + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesiswithdlq.expected.json b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesiswithdlq.expected.json index 0e57bd7dc85d1..4d0a6c1a54707 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesiswithdlq.expected.json +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesiswithdlq.expected.json @@ -93,13 +93,13 @@ "Code": { "ZipFile": "exports.handler = async function handler(event) {\n // eslint-disable-next-line no-console\n console.log('event:', JSON.stringify(event, undefined, 2));\n throw new Error();\n}" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "FServiceRole3AC82EE1", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs10.x" }, "DependsOn": [ @@ -110,12 +110,6 @@ "FKinesisEventSourcelambdaeventsourcekinesiswithdlqSD357FCB87EEA8CB4": { "Type": "AWS::Lambda::EventSourceMapping", "Properties": { - "EventSourceArn": { - "Fn::GetAtt": [ - "S509448A1", - "Arn" - ] - }, "FunctionName": { "Ref": "FC4345940" }, @@ -130,6 +124,12 @@ } } }, + "EventSourceArn": { + "Fn::GetAtt": [ + "S509448A1", + "Arn" + ] + }, "MaximumRetryAttempts": 0, "StartingPosition": "TRIM_HORIZON" } @@ -154,7 +154,9 @@ } }, "Q63C6E3AB": { - "Type": "AWS::SQS::Queue" + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.sqs.expected.json b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.sqs.expected.json index e0bc8e07fece0..9f5565aff21d6 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.sqs.expected.json +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.sqs.expected.json @@ -69,13 +69,13 @@ "Code": { "ZipFile": "exports.handler = async function handler(event) {\n console.log('event:', JSON.stringify(event, undefined, 2));\n return { event };\n}" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "FServiceRole3AC82EE1", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs10.x" }, "DependsOn": [ @@ -86,20 +86,22 @@ "FSqsEventSourcelambdaeventsourcesqsQ67DE9201754EC819": { "Type": "AWS::Lambda::EventSourceMapping", "Properties": { + "FunctionName": { + "Ref": "FC4345940" + }, + "BatchSize": 5, "EventSourceArn": { "Fn::GetAtt": [ "Q63C6E3AB", "Arn" ] - }, - "FunctionName": { - "Ref": "FC4345940" - }, - "BatchSize": 5 + } } }, "Q63C6E3AB": { - "Type": "AWS::SQS::Queue" + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda-nodejs/README.md b/packages/@aws-cdk/aws-lambda-nodejs/README.md index bfaa99eb0b243..f35062120fb9d 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/README.md +++ b/packages/@aws-cdk/aws-lambda-nodejs/README.md @@ -162,13 +162,17 @@ It is possible to run additional commands by specifying the `commandHooks` prop: ```ts new lambda.NodejsFunction(this, 'my-handler-with-commands', { - commandHooks: { - // Copy a file so that it will be included in the bundled asset - afterBundling(inputDir: string, outputDir: string): string[] { - return [`cp ${inputDir}/my-binary.node ${outputDir}`]; + bundling: { + commandHooks: { + // Copy a file so that it will be included in the bundled asset + afterBundling(inputDir: string, outputDir: string): string[] { + return [`cp ${inputDir}/my-binary.node ${outputDir}`]; + } + // ... } // ... } + }); ``` diff --git a/packages/@aws-cdk/aws-lambda-nodejs/package.json b/packages/@aws-cdk/aws-lambda-nodejs/package.json index 16cb07a7c83c9..c2e2f658febac 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/package.json +++ b/packages/@aws-cdk/aws-lambda-nodejs/package.json @@ -66,8 +66,8 @@ "@aws-cdk/aws-ec2": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", - "delay": "4.4.1", - "esbuild": "^0.8.42", + "delay": "5.0.0", + "esbuild": "^0.8.50", "pkglint": "0.0.0" }, "dependencies": { @@ -91,5 +91,8 @@ }, "cdk-build": { "jest": true + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-lambda-python/package.json b/packages/@aws-cdk/aws-lambda-python/package.json index 33b6f04fa903a..f22b2076ee43f 100644 --- a/packages/@aws-cdk/aws-lambda-python/package.json +++ b/packages/@aws-cdk/aws-lambda-python/package.json @@ -90,5 +90,8 @@ }, "cdk-build": { "jest": true + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-lambda/README.md b/packages/@aws-cdk/aws-lambda/README.md index de6940cd249e8..98994962ec129 100644 --- a/packages/@aws-cdk/aws-lambda/README.md +++ b/packages/@aws-cdk/aws-lambda/README.md @@ -450,10 +450,8 @@ new lambda.Function(this, 'Function', { bundling: { image: lambda.Runtime.PYTHON_3_6.bundlingDockerImage, command: [ - 'bash', '-c', ` - pip install -r requirements.txt -t /asset-output && - cp -au . /asset-output - `, + 'bash', '-c', + 'pip install -r requirements.txt -t /asset-output && cp -au . /asset-output' ], }, }), diff --git a/packages/@aws-cdk/aws-lambda/package.json b/packages/@aws-cdk/aws-lambda/package.json index 619dde4ff50fa..de51f290aa4f5 100644 --- a/packages/@aws-cdk/aws-lambda/package.json +++ b/packages/@aws-cdk/aws-lambda/package.json @@ -76,13 +76,13 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/aws-lambda": "^8.10.71", + "@types/aws-lambda": "^8.10.72", "@types/lodash": "^4.14.168", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "jest": "^26.6.3", - "lodash": "^4.17.20", + "lodash": "^4.17.21", "pkglint": "0.0.0" }, "dependencies": { @@ -176,5 +176,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-lambda/test/integ.autoscaling.lit.expected.json b/packages/@aws-cdk/aws-lambda/test/integ.autoscaling.lit.expected.json index 39ff5f8f0e0fb..dc1f0b431db23 100644 --- a/packages/@aws-cdk/aws-lambda/test/integ.autoscaling.lit.expected.json +++ b/packages/@aws-cdk/aws-lambda/test/integ.autoscaling.lit.expected.json @@ -35,7 +35,7 @@ "Type": "AWS::Lambda::Function", "Properties": { "Code": { - "ZipFile": "exports.handler = async () => {\nconsole.log('hello world');\n};" + "ZipFile": "exports.handler = async () => { console.log('hello world'); };" }, "Handler": "index.handler", "Role": { @@ -161,4 +161,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-lambda/test/integ.autoscaling.lit.ts b/packages/@aws-cdk/aws-lambda/test/integ.autoscaling.lit.ts index 2bd3a195682e2..949670ec636b6 100644 --- a/packages/@aws-cdk/aws-lambda/test/integ.autoscaling.lit.ts +++ b/packages/@aws-cdk/aws-lambda/test/integ.autoscaling.lit.ts @@ -12,7 +12,7 @@ class TestStack extends cdk.Stack { super(scope, id); const fn = new lambda.Function(this, 'MyLambda', { - code: new lambda.InlineCode('exports.handler = async () => {\nconsole.log(\'hello world\');\n};'), + code: new lambda.InlineCode('exports.handler = async () => { console.log(\'hello world\'); };'), handler: 'index.handler', runtime: lambda.Runtime.NODEJS_10_X, }); @@ -50,4 +50,4 @@ const app = new cdk.App(); new TestStack(app, 'aws-lambda-autoscaling'); -app.synth(); \ No newline at end of file +app.synth(); diff --git a/packages/@aws-cdk/aws-licensemanager/package.json b/packages/@aws-cdk/aws-licensemanager/package.json index a84c776b55897..951f8982392ab 100644 --- a/packages/@aws-cdk/aws-licensemanager/package.json +++ b/packages/@aws-cdk/aws-licensemanager/package.json @@ -91,5 +91,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-logs-destinations/package.json b/packages/@aws-cdk/aws-logs-destinations/package.json index 644ca59bf6c39..a4edf4ce3473b 100644 --- a/packages/@aws-cdk/aws-logs-destinations/package.json +++ b/packages/@aws-cdk/aws-logs-destinations/package.json @@ -99,5 +99,8 @@ "env": { "AWSLINT_BASE_CONSTRUCT": true } + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-logs/package.json b/packages/@aws-cdk/aws-logs/package.json index 8d604e7562237..f5a004e27bb1f 100644 --- a/packages/@aws-cdk/aws-logs/package.json +++ b/packages/@aws-cdk/aws-logs/package.json @@ -72,7 +72,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", - "aws-sdk": "^2.830.0", + "aws-sdk": "^2.848.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", @@ -123,5 +123,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-lookoutvision/package.json b/packages/@aws-cdk/aws-lookoutvision/package.json index 9f7d59fd4c321..0a812168e8241 100644 --- a/packages/@aws-cdk/aws-lookoutvision/package.json +++ b/packages/@aws-cdk/aws-lookoutvision/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-macie/package.json b/packages/@aws-cdk/aws-macie/package.json index 9dc3906117ef3..7e2851d383765 100644 --- a/packages/@aws-cdk/aws-macie/package.json +++ b/packages/@aws-cdk/aws-macie/package.json @@ -91,5 +91,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-managedblockchain/package.json b/packages/@aws-cdk/aws-managedblockchain/package.json index 06f73c3d71b60..c94f2391242fb 100644 --- a/packages/@aws-cdk/aws-managedblockchain/package.json +++ b/packages/@aws-cdk/aws-managedblockchain/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-mediaconnect/package.json b/packages/@aws-cdk/aws-mediaconnect/package.json index e859f9c908c75..dbfd544d52dd2 100644 --- a/packages/@aws-cdk/aws-mediaconnect/package.json +++ b/packages/@aws-cdk/aws-mediaconnect/package.json @@ -91,5 +91,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-mediaconvert/package.json b/packages/@aws-cdk/aws-mediaconvert/package.json index df3d541f95ac8..938a726f92183 100644 --- a/packages/@aws-cdk/aws-mediaconvert/package.json +++ b/packages/@aws-cdk/aws-mediaconvert/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-medialive/package.json b/packages/@aws-cdk/aws-medialive/package.json index 43dd5b58cf04f..16ecfadc7c1bb 100644 --- a/packages/@aws-cdk/aws-medialive/package.json +++ b/packages/@aws-cdk/aws-medialive/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-mediapackage/package.json b/packages/@aws-cdk/aws-mediapackage/package.json index 22cf558399e53..40913de5b816e 100644 --- a/packages/@aws-cdk/aws-mediapackage/package.json +++ b/packages/@aws-cdk/aws-mediapackage/package.json @@ -91,5 +91,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-mediastore/package.json b/packages/@aws-cdk/aws-mediastore/package.json index 5e53e2568b020..46878264355f9 100644 --- a/packages/@aws-cdk/aws-mediastore/package.json +++ b/packages/@aws-cdk/aws-mediastore/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-msk/package.json b/packages/@aws-cdk/aws-msk/package.json index 7f1d3b8cf4076..939b66619cda7 100644 --- a/packages/@aws-cdk/aws-msk/package.json +++ b/packages/@aws-cdk/aws-msk/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-mwaa/package.json b/packages/@aws-cdk/aws-mwaa/package.json index 306739c25c7f9..17a5ba80b55f1 100644 --- a/packages/@aws-cdk/aws-mwaa/package.json +++ b/packages/@aws-cdk/aws-mwaa/package.json @@ -91,5 +91,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-neptune/package.json b/packages/@aws-cdk/aws-neptune/package.json index b0ff4727beb8a..f4ae26436389b 100644 --- a/packages/@aws-cdk/aws-neptune/package.json +++ b/packages/@aws-cdk/aws-neptune/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-networkfirewall/package.json b/packages/@aws-cdk/aws-networkfirewall/package.json index 318ecf359f489..8c218072fe92b 100644 --- a/packages/@aws-cdk/aws-networkfirewall/package.json +++ b/packages/@aws-cdk/aws-networkfirewall/package.json @@ -91,5 +91,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-networkmanager/package.json b/packages/@aws-cdk/aws-networkmanager/package.json index b90a276b6145c..9c38f74d32916 100644 --- a/packages/@aws-cdk/aws-networkmanager/package.json +++ b/packages/@aws-cdk/aws-networkmanager/package.json @@ -91,5 +91,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-opsworks/package.json b/packages/@aws-cdk/aws-opsworks/package.json index de850b75cff6f..b00cff3b7056e 100644 --- a/packages/@aws-cdk/aws-opsworks/package.json +++ b/packages/@aws-cdk/aws-opsworks/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-opsworkscm/package.json b/packages/@aws-cdk/aws-opsworkscm/package.json index 996ccc36dc81c..3c102533e89dc 100644 --- a/packages/@aws-cdk/aws-opsworkscm/package.json +++ b/packages/@aws-cdk/aws-opsworkscm/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-pinpoint/package.json b/packages/@aws-cdk/aws-pinpoint/package.json index 3afb1b9429da4..ed7fe94c40090 100644 --- a/packages/@aws-cdk/aws-pinpoint/package.json +++ b/packages/@aws-cdk/aws-pinpoint/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-pinpointemail/package.json b/packages/@aws-cdk/aws-pinpointemail/package.json index bf69610b3548a..5f98fa3d04e24 100644 --- a/packages/@aws-cdk/aws-pinpointemail/package.json +++ b/packages/@aws-cdk/aws-pinpointemail/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-qldb/package.json b/packages/@aws-cdk/aws-qldb/package.json index 433bb0a1c24d9..257716f07faea 100644 --- a/packages/@aws-cdk/aws-qldb/package.json +++ b/packages/@aws-cdk/aws-qldb/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-quicksight/package.json b/packages/@aws-cdk/aws-quicksight/package.json index f0bccf72e3de3..14526eb10a35a 100644 --- a/packages/@aws-cdk/aws-quicksight/package.json +++ b/packages/@aws-cdk/aws-quicksight/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-ram/package.json b/packages/@aws-cdk/aws-ram/package.json index 6dd1956dce5a7..2ca7d27497147 100644 --- a/packages/@aws-cdk/aws-ram/package.json +++ b/packages/@aws-cdk/aws-ram/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-rds/.gitignore b/packages/@aws-cdk/aws-rds/.gitignore index dcc1dc41e477f..17a41566f0002 100644 --- a/packages/@aws-cdk/aws-rds/.gitignore +++ b/packages/@aws-cdk/aws-rds/.gitignore @@ -15,4 +15,5 @@ nyc.config.js *.snk !.eslintrc.js -junit.xml \ No newline at end of file +junit.xml +!jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/.npmignore b/packages/@aws-cdk/aws-rds/.npmignore index a94c531529866..9e88226921c33 100644 --- a/packages/@aws-cdk/aws-rds/.npmignore +++ b/packages/@aws-cdk/aws-rds/.npmignore @@ -23,4 +23,5 @@ tsconfig.json # exclude cdk artifacts **/cdk.out junit.xml -test/ \ No newline at end of file +test/ +jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/README.md b/packages/@aws-cdk/aws-rds/README.md index 67bb8328696bc..b00e3c64187f0 100644 --- a/packages/@aws-cdk/aws-rds/README.md +++ b/packages/@aws-cdk/aws-rds/README.md @@ -283,7 +283,7 @@ instance.grantConnect(role); // Grant the role connection access to the DB. The following example shows granting connection access for RDS Proxy to an IAM role. ```ts -const cluster = new rds.DatabaseCluster(stack, 'Database'{ +const cluster = new rds.DatabaseCluster(stack, 'Database', { engine: rds.DatabaseClusterEngine.AURORA, instanceProps: { vpc }, }); @@ -295,7 +295,7 @@ const proxy = new rds.DatabaseProxy(stack, 'Proxy', { }); const role = new Role(stack, 'DBProxyRole', { assumedBy: new AccountPrincipal(stack.account) }); -proxy.grantConnect(role); // Grant the role connection access to the DB Proxy. +proxy.grantConnect(role, 'admin'); // Grant the role connection access to the DB Proxy for database user 'admin'. ``` **Note**: In addition to the setup above, a database user will need to be created to support IAM auth. diff --git a/packages/@aws-cdk/aws-rds/jest.config.js b/packages/@aws-cdk/aws-rds/jest.config.js new file mode 100644 index 0000000000000..54e28beb9798b --- /dev/null +++ b/packages/@aws-cdk/aws-rds/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-rds/lib/cluster.ts b/packages/@aws-cdk/aws-rds/lib/cluster.ts index e0f2618a2fdf2..a3f06555afdb9 100644 --- a/packages/@aws-cdk/aws-rds/lib/cluster.ts +++ b/packages/@aws-cdk/aws-rds/lib/cluster.ts @@ -10,7 +10,7 @@ import { IClusterEngine } from './cluster-engine'; import { DatabaseClusterAttributes, IDatabaseCluster } from './cluster-ref'; import { Endpoint } from './endpoint'; import { IParameterGroup } from './parameter-group'; -import { applyRemovalPolicy, DEFAULT_PASSWORD_EXCLUDE_CHARS, defaultDeletionProtection, renderCredentials, setupS3ImportExport } from './private/util'; +import { DEFAULT_PASSWORD_EXCLUDE_CHARS, defaultDeletionProtection, renderCredentials, setupS3ImportExport, helperRemovalPolicy, renderUnless } from './private/util'; import { BackupProps, Credentials, InstanceProps, PerformanceInsightRetention, RotationSingleUserOptions, RotationMultiUserOptions } from './props'; import { DatabaseProxy, DatabaseProxyOptions, ProxyTarget } from './proxy'; import { CfnDBCluster, CfnDBClusterProps, CfnDBInstance } from './rds.generated'; @@ -310,7 +310,7 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { description: `Subnets for ${id} database`, vpc: props.instanceProps.vpc, vpcSubnets: props.instanceProps.vpcSubnets, - removalPolicy: props.removalPolicy === RemovalPolicy.RETAIN ? props.removalPolicy : undefined, + removalPolicy: renderUnless(helperRemovalPolicy(props.removalPolicy), RemovalPolicy.DESTROY), }); this.securityGroups = props.instanceProps.securityGroups ?? [ @@ -512,7 +512,7 @@ export class DatabaseCluster extends DatabaseClusterNew { defaultPort: ec2.Port.tcp(this.clusterEndpoint.port), }); - applyRemovalPolicy(cluster, props.removalPolicy); + cluster.applyRemovalPolicy(props.removalPolicy ?? RemovalPolicy.SNAPSHOT); if (secret) { this.secret = secret.attach(this); @@ -608,7 +608,7 @@ export class DatabaseClusterFromSnapshot extends DatabaseClusterNew { defaultPort: ec2.Port.tcp(this.clusterEndpoint.port), }); - applyRemovalPolicy(cluster, props.removalPolicy); + cluster.applyRemovalPolicy(props.removalPolicy ?? RemovalPolicy.SNAPSHOT); setLogRetention(this, props); createInstances(this, props, this.subnetGroup); @@ -712,13 +712,11 @@ function createInstances(cluster: DatabaseClusterNew, props: DatabaseClusterBase deleteAutomatedBackups: props.instanceProps.deleteAutomatedBackups, }); - // If removalPolicy isn't explicitly set, - // it's Snapshot for Cluster. - // Because of that, in this case, - // we can safely use the CFN default of Delete for DbInstances with dbClusterIdentifier set. - if (props.removalPolicy) { - applyRemovalPolicy(instance, props.removalPolicy); - } + // For instances that are part of a cluster: + // + // Cluster DESTROY or SNAPSHOT -> DESTROY (snapshot is good enough to recreate) + // Cluster RETAIN -> RETAIN (otherwise cluster state will disappear) + instance.applyRemovalPolicy(helperRemovalPolicy(props.removalPolicy)); // We must have a dependency on the NAT gateway provider here to create // things in the right order. diff --git a/packages/@aws-cdk/aws-rds/lib/instance-engine.ts b/packages/@aws-cdk/aws-rds/lib/instance-engine.ts index e2e425eb71736..95d462c23f5fc 100644 --- a/packages/@aws-cdk/aws-rds/lib/instance-engine.ts +++ b/packages/@aws-cdk/aws-rds/lib/instance-engine.ts @@ -425,76 +425,181 @@ export interface PostgresEngineFeatures { * (those returned by {@link DatabaseInstanceEngine.postgres}). */ export class PostgresEngineVersion { - /** Version "9.5" (only a major version, without a specific minor version). */ + /** + * Version "9.5" (only a major version, without a specific minor version). + * @deprecated PostgreSQL 9.5 will reach end of life on February 16, 2021 + */ public static readonly VER_9_5 = PostgresEngineVersion.of('9.5', '9.5'); - /** Version "9.5.2". */ + /** + * Version "9.5.2". + * @deprecated PostgreSQL 9.5 will reach end of life on February 16, 2021 + */ public static readonly VER_9_5_2 = PostgresEngineVersion.of('9.5.2', '9.5'); - /** Version "9.5.4". */ + /** + * Version "9.5.4". + * @deprecated PostgreSQL 9.5 will reach end of life on February 16, 2021 + */ public static readonly VER_9_5_4 = PostgresEngineVersion.of('9.5.4', '9.5'); - /** Version "9.5.6". */ + /** + * Version "9.5.6". + * @deprecated PostgreSQL 9.5 will reach end of life on February 16, 2021 + */ public static readonly VER_9_5_6 = PostgresEngineVersion.of('9.5.6', '9.5'); - /** Version "9.5.7". */ + /** + * Version "9.5.7". + * @deprecated PostgreSQL 9.5 will reach end of life on February 16, 2021 + */ public static readonly VER_9_5_7 = PostgresEngineVersion.of('9.5.7', '9.5'); - /** Version "9.5.9". */ + /** + * Version "9.5.9". + * @deprecated PostgreSQL 9.5 will reach end of life on February 16, 2021 + */ public static readonly VER_9_5_9 = PostgresEngineVersion.of('9.5.9', '9.5'); - /** Version "9.5.10". */ + /** + * Version "9.5.10". + * @deprecated PostgreSQL 9.5 will reach end of life on February 16, 2021 + */ public static readonly VER_9_5_10 = PostgresEngineVersion.of('9.5.10', '9.5'); - /** Version "9.5.12". */ + /** + * Version "9.5.12". + * @deprecated PostgreSQL 9.5 will reach end of life on February 16, 2021 + */ public static readonly VER_9_5_12 = PostgresEngineVersion.of('9.5.12', '9.5'); - /** Version "9.5.13". */ + /** + * Version "9.5.13". + * @deprecated PostgreSQL 9.5 will reach end of life on February 16, 2021 + */ public static readonly VER_9_5_13 = PostgresEngineVersion.of('9.5.13', '9.5'); - /** Version "9.5.14". */ + /** + * Version "9.5.14". + * @deprecated PostgreSQL 9.5 will reach end of life on February 16, 2021 + */ public static readonly VER_9_5_14 = PostgresEngineVersion.of('9.5.14', '9.5'); - /** Version "9.5.15". */ + /** + * Version "9.5.15". + * @deprecated PostgreSQL 9.5 will reach end of life on February 16, 2021 + */ public static readonly VER_9_5_15 = PostgresEngineVersion.of('9.5.15', '9.5'); - /** Version "9.5.16". */ + /** + * Version "9.5.16". + * @deprecated PostgreSQL 9.5 will reach end of life on February 16, 2021 + */ public static readonly VER_9_5_16 = PostgresEngineVersion.of('9.5.16', '9.5'); - /** Version "9.5.18". */ + /** + * Version "9.5.18". + * @deprecated PostgreSQL 9.5 will reach end of life on February 16, 2021 + */ public static readonly VER_9_5_18 = PostgresEngineVersion.of('9.5.18', '9.5'); - /** Version "9.5.19". */ + /** + * Version "9.5.19". + * @deprecated PostgreSQL 9.5 will reach end of life on February 16, 2021 + */ public static readonly VER_9_5_19 = PostgresEngineVersion.of('9.5.19', '9.5'); - /** Version "9.5.20". */ + /** + * Version "9.5.20". + * @deprecated PostgreSQL 9.5 will reach end of life on February 16, 2021 + */ public static readonly VER_9_5_20 = PostgresEngineVersion.of('9.5.20', '9.5'); - /** Version "9.5.21". */ + /** + * Version "9.5.21". + * @deprecated PostgreSQL 9.5 will reach end of life on February 16, 2021 + */ public static readonly VER_9_5_21 = PostgresEngineVersion.of('9.5.21', '9.5'); - /** Version "9.5.22". */ + /** + * Version "9.5.22". + * @deprecated PostgreSQL 9.5 will reach end of life on February 16, 2021 + */ public static readonly VER_9_5_22 = PostgresEngineVersion.of('9.5.22', '9.5'); - /** Version "9.5.23". */ + /** + * Version "9.5.23". + * @deprecated PostgreSQL 9.5 will reach end of life on February 16, 2021 + */ public static readonly VER_9_5_23 = PostgresEngineVersion.of('9.5.23', '9.5'); - /** Version "9.6" (only a major version, without a specific minor version). */ + /** + * Version "9.6" (only a major version, without a specific minor version). + * @deprecated PostgreSQL 9.6 will reach end of life in November 2021 + */ public static readonly VER_9_6 = PostgresEngineVersion.of('9.6', '9.6'); - /** Version "9.6.1". */ + /** + * Version "9.6.1". + * @deprecated PostgreSQL 9.6 will reach end of life in November 2021 + */ public static readonly VER_9_6_1 = PostgresEngineVersion.of('9.6.1', '9.6'); - /** Version "9.6.2". */ + /** + * Version "9.6.2". + * @deprecated PostgreSQL 9.6 will reach end of life in November 2021 + */ public static readonly VER_9_6_2 = PostgresEngineVersion.of('9.6.2', '9.6'); - /** Version "9.6.3". */ + /** + * Version "9.6.3". + * @deprecated PostgreSQL 9.6 will reach end of life in November 2021 + */ public static readonly VER_9_6_3 = PostgresEngineVersion.of('9.6.3', '9.6'); - /** Version "9.6.5". */ + /** + * Version "9.6.5". + * @deprecated PostgreSQL 9.6 will reach end of life in November 2021 + */ public static readonly VER_9_6_5 = PostgresEngineVersion.of('9.6.5', '9.6'); - /** Version "9.6.6". */ + /** + * Version "9.6.6". + * @deprecated PostgreSQL 9.6 will reach end of life in November 2021 + */ public static readonly VER_9_6_6 = PostgresEngineVersion.of('9.6.6', '9.6'); - /** Version "9.6.8". */ + /** + * Version "9.6.8". + * @deprecated PostgreSQL 9.6 will reach end of life in November 2021 + */ public static readonly VER_9_6_8 = PostgresEngineVersion.of('9.6.8', '9.6'); - /** Version "9.6.9". */ + /** + * Version "9.6.9". + * @deprecated PostgreSQL 9.6 will reach end of life in November 2021 + */ public static readonly VER_9_6_9 = PostgresEngineVersion.of('9.6.9', '9.6'); - /** Version "9.6.10". */ + /** + * Version "9.6.10". + * @deprecated PostgreSQL 9.6 will reach end of life in November 2021 + */ public static readonly VER_9_6_10 = PostgresEngineVersion.of('9.6.10', '9.6'); - /** Version "9.6.11". */ + /** + * Version "9.6.11". + * @deprecated PostgreSQL 9.6 will reach end of life in November 2021 + */ public static readonly VER_9_6_11 = PostgresEngineVersion.of('9.6.11', '9.6'); - /** Version "9.6.12". */ + /** + * Version "9.6.12". + * @deprecated PostgreSQL 9.6 will reach end of life in November 2021 + */ public static readonly VER_9_6_12 = PostgresEngineVersion.of('9.6.12', '9.6'); - /** Version "9.6.14". */ + /** + * Version "9.6.14". + * @deprecated PostgreSQL 9.6 will reach end of life in November 2021 + */ public static readonly VER_9_6_14 = PostgresEngineVersion.of('9.6.14', '9.6'); - /** Version "9.6.15". */ + /** + * Version "9.6.15". + * @deprecated PostgreSQL 9.6 will reach end of life in November 2021 + */ public static readonly VER_9_6_15 = PostgresEngineVersion.of('9.6.15', '9.6'); - /** Version "9.6.16". */ + /** + * Version "9.6.16". + * @deprecated PostgreSQL 9.6 will reach end of life in November 2021 + */ public static readonly VER_9_6_16 = PostgresEngineVersion.of('9.6.16', '9.6'); - /** Version "9.6.17". */ + /** + * Version "9.6.17". + * @deprecated PostgreSQL 9.6 will reach end of life in November 2021 + */ public static readonly VER_9_6_17 = PostgresEngineVersion.of('9.6.17', '9.6'); - /** Version "9.6.18". */ + /** + * Version "9.6.18". + * @deprecated PostgreSQL 9.6 will reach end of life in November 2021 + */ public static readonly VER_9_6_18 = PostgresEngineVersion.of('9.6.18', '9.6'); - /** Version "9.6.19". */ + /** + * Version "9.6.19". + * @deprecated PostgreSQL 9.6 will reach end of life in November 2021 + */ public static readonly VER_9_6_19 = PostgresEngineVersion.of('9.6.19', '9.6'); /** Version "10" (only a major version, without a specific minor version). */ @@ -551,6 +656,8 @@ export class PostgresEngineVersion { public static readonly VER_12_3 = PostgresEngineVersion.of('12.3', '12', { s3Import: true }); /** Version "12.4". */ public static readonly VER_12_4 = PostgresEngineVersion.of('12.4', '12', { s3Import: true }); + /** Version "12.5". */ + public static readonly VER_12_5 = PostgresEngineVersion.of('12.5', '12', { s3Import: true }); /** * Create a new PostgresEngineVersion with an arbitrary version. diff --git a/packages/@aws-cdk/aws-rds/lib/instance.ts b/packages/@aws-cdk/aws-rds/lib/instance.ts index cb4c3d3487a8c..f6bbe5481a112 100644 --- a/packages/@aws-cdk/aws-rds/lib/instance.ts +++ b/packages/@aws-cdk/aws-rds/lib/instance.ts @@ -12,7 +12,7 @@ import { Endpoint } from './endpoint'; import { IInstanceEngine } from './instance-engine'; import { IOptionGroup } from './option-group'; import { IParameterGroup } from './parameter-group'; -import { applyRemovalPolicy, DEFAULT_PASSWORD_EXCLUDE_CHARS, defaultDeletionProtection, engineDescription, renderCredentials, setupS3ImportExport } from './private/util'; +import { DEFAULT_PASSWORD_EXCLUDE_CHARS, defaultDeletionProtection, engineDescription, renderCredentials, setupS3ImportExport, helperRemovalPolicy, renderUnless } from './private/util'; import { Credentials, PerformanceInsightRetention, RotationMultiUserOptions, RotationSingleUserOptions, SnapshotCredentials } from './props'; import { DatabaseProxy, DatabaseProxyOptions, ProxyTarget } from './proxy'; import { CfnDBInstance, CfnDBInstanceProps } from './rds.generated'; @@ -642,7 +642,7 @@ abstract class DatabaseInstanceNew extends DatabaseInstanceBase implements IData description: `Subnet group for ${this.node.id} database`, vpc: this.vpc, vpcSubnets: this.vpcPlacement, - removalPolicy: props.removalPolicy === RemovalPolicy.RETAIN ? props.removalPolicy : undefined, + removalPolicy: renderUnless(helperRemovalPolicy(props.removalPolicy), RemovalPolicy.DESTROY), }); const securityGroups = props.securityGroups || [new ec2.SecurityGroup(this, 'SecurityGroup', { @@ -976,7 +976,7 @@ export class DatabaseInstance extends DatabaseInstanceSource implements IDatabas const portAttribute = Token.asNumber(instance.attrEndpointPort); this.instanceEndpoint = new Endpoint(instance.attrEndpointAddress, portAttribute); - applyRemovalPolicy(instance, props.removalPolicy); + instance.applyRemovalPolicy(props.removalPolicy ?? RemovalPolicy.SNAPSHOT); if (secret) { this.secret = secret.attach(this); @@ -1052,7 +1052,7 @@ export class DatabaseInstanceFromSnapshot extends DatabaseInstanceSource impleme const portAttribute = Token.asNumber(instance.attrEndpointPort); this.instanceEndpoint = new Endpoint(instance.attrEndpointAddress, portAttribute); - applyRemovalPolicy(instance, props.removalPolicy); + instance.applyRemovalPolicy(props.removalPolicy ?? RemovalPolicy.SNAPSHOT); if (secret) { this.secret = secret.attach(this); @@ -1128,7 +1128,7 @@ export class DatabaseInstanceReadReplica extends DatabaseInstanceNew implements const portAttribute = Token.asNumber(instance.attrEndpointPort); this.instanceEndpoint = new Endpoint(instance.attrEndpointAddress, portAttribute); - applyRemovalPolicy(instance, props.removalPolicy); + instance.applyRemovalPolicy(props.removalPolicy ?? RemovalPolicy.SNAPSHOT); this.setLogRetention(); } diff --git a/packages/@aws-cdk/aws-rds/lib/private/util.ts b/packages/@aws-cdk/aws-rds/lib/private/util.ts index f97486b5daddf..0b6e2b72ff0be 100644 --- a/packages/@aws-cdk/aws-rds/lib/private/util.ts +++ b/packages/@aws-cdk/aws-rds/lib/private/util.ts @@ -1,6 +1,6 @@ import * as iam from '@aws-cdk/aws-iam'; import * as s3 from '@aws-cdk/aws-s3'; -import { CfnDeletionPolicy, CfnResource, RemovalPolicy } from '@aws-cdk/core'; +import { RemovalPolicy } from '@aws-cdk/core'; import { DatabaseSecret } from '../database-secret'; import { IEngine } from '../engine'; import { Credentials } from '../props'; @@ -76,17 +76,6 @@ export function engineDescription(engine: IEngine) { return engine.engineType + (engine.engineVersion?.fullVersion ? `-${engine.engineVersion.fullVersion}` : ''); } -export function applyRemovalPolicy(cfnDatabase: CfnResource, removalPolicy?: RemovalPolicy): void { - if (!removalPolicy) { - // the default DeletionPolicy is 'Snapshot', which is fine, - // but we should also make it 'Snapshot' for UpdateReplace policy - cfnDatabase.cfnOptions.updateReplacePolicy = CfnDeletionPolicy.SNAPSHOT; - } else { - // just apply whatever removal policy the customer explicitly provided - cfnDatabase.applyRemovalPolicy(removalPolicy); - } -} - /** * By default, deletion protection is disabled. * Enable if explicitly provided or if the RemovalPolicy has been set to RETAIN @@ -118,3 +107,28 @@ export function renderCredentials(scope: Construct, engine: IEngine, credentials return renderedCredentials; } + +/** + * The RemovalPolicy that should be applied to a "helper" resource, if the base resource has the given removal policy + * + * - For Clusters, this determines the RemovalPolicy for Instances/SubnetGroups. + * - For Instances, this determines the RemovalPolicy for SubnetGroups. + * + * If the basePolicy is: + * + * DESTROY or SNAPSHOT -> DESTROY (snapshot is good enough to recreate) + * RETAIN -> RETAIN (anything else will lose data or fail to deploy) + * (undefined) -> DESTROY (base policy is assumed to be SNAPSHOT) + */ +export function helperRemovalPolicy(basePolicy?: RemovalPolicy): RemovalPolicy { + return basePolicy === RemovalPolicy.RETAIN + ? RemovalPolicy.RETAIN + : RemovalPolicy.DESTROY; +} + +/** + * Return a given value unless it's the same as another value + */ +export function renderUnless(value: A, suppressValue: A): A | undefined { + return value === suppressValue ? undefined : value; +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/lib/proxy.ts b/packages/@aws-cdk/aws-rds/lib/proxy.ts index e0105702523c8..fa50b891fca80 100644 --- a/packages/@aws-cdk/aws-rds/lib/proxy.ts +++ b/packages/@aws-cdk/aws-rds/lib/proxy.ts @@ -70,7 +70,7 @@ export class ProxyTarget { /** * Bind this target to the specified database proxy. */ - public bind(_: DatabaseProxy): ProxyTargetConfig { + public bind(proxy: DatabaseProxy): ProxyTargetConfig { const engine: IEngine | undefined = this.dbInstance?.engine ?? this.dbCluster?.engine; if (!engine) { @@ -84,6 +84,10 @@ export class ProxyTarget { throw new Error(`Engine '${engineDescription(engine)}' does not support proxies`); } + // allow connecting to the Cluster/Instance from the Proxy + this.dbCluster?.connections.allowDefaultPortFrom(proxy, 'Allow connections to the database Cluster from the Proxy'); + this.dbInstance?.connections.allowDefaultPortFrom(proxy, 'Allow connections to the database Instance from the Proxy'); + return { engineFamily, dbClusters: this.dbCluster ? [this.dbCluster] : undefined, @@ -318,8 +322,14 @@ export interface IDatabaseProxy extends cdk.IResource { /** * Grant the given identity connection access to the proxy. + * + * @param grantee the Principal to grant the permissions to + * @param dbUser the name of the database user to allow connecting as to the proxy + * + * @default - if the Proxy had been provided a single Secret value, + * the user will be taken from that Secret */ - grantConnect(grantee: iam.IGrantable): iam.Grant; + grantConnect(grantee: iam.IGrantable, dbUser?: string): iam.Grant; } /** @@ -331,11 +341,22 @@ abstract class DatabaseProxyBase extends cdk.Resource implements IDatabaseProxy public abstract readonly dbProxyArn: string; public abstract readonly endpoint: string; - public grantConnect(grantee: iam.IGrantable): iam.Grant { + public grantConnect(grantee: iam.IGrantable, dbUser?: string): iam.Grant { + if (!dbUser) { + throw new Error('For imported Database Proxies, the dbUser is required in grantConnect()'); + } + const scopeStack = cdk.Stack.of(this); + const proxyGeneratedId = scopeStack.parseArn(this.dbProxyArn, ':').resourceName; + const userArn = scopeStack.formatArn({ + service: 'rds-db', + resource: 'dbuser', + resourceName: `${proxyGeneratedId}/${dbUser}`, + sep: ':', + }); return iam.Grant.addToPrincipal({ grantee, actions: ['rds-db:connect'], - resourceArns: [this.dbProxyArn], + resourceArns: [userArn], }); } } @@ -389,6 +410,7 @@ export class DatabaseProxy extends DatabaseProxyBase */ public readonly connections: ec2.Connections; + private readonly secrets: secretsmanager.ISecret[]; private readonly resource: CfnDBProxy; constructor(scope: Construct, id: string, props: DatabaseProxyProps) { @@ -402,13 +424,20 @@ export class DatabaseProxy extends DatabaseProxyBase secret.grantRead(role); } - this.connections = new ec2.Connections({ securityGroups: props.securityGroups }); + const securityGroups = props.securityGroups ?? [ + new ec2.SecurityGroup(this, 'ProxySecurityGroup', { + description: 'SecurityGroup for Database Proxy', + vpc: props.vpc, + }), + ]; + this.connections = new ec2.Connections({ securityGroups }); const bindResult = props.proxyTarget.bind(this); if (props.secrets.length < 1) { throw new Error('One or more secrets are required.'); } + this.secrets = props.secrets; this.resource = new CfnDBProxy(this, 'Resource', { auth: props.secrets.map(_ => { @@ -424,7 +453,7 @@ export class DatabaseProxy extends DatabaseProxyBase idleClientTimeout: props.idleClientTimeout?.toSeconds(), requireTls: props.requireTLS ?? true, roleArn: role.roleArn, - vpcSecurityGroupIds: props.securityGroups?.map(_ => _.securityGroupId), + vpcSecurityGroupIds: cdk.Lazy.list({ produce: () => this.connections.securityGroups.map(_ => _.securityGroupId) }), vpcSubnetIds: props.vpc.selectSubnets(props.vpcSubnets).subnetIds, }); @@ -467,6 +496,18 @@ export class DatabaseProxy extends DatabaseProxyBase targetType: secretsmanager.AttachmentTargetType.RDS_DB_PROXY, }; } + + public grantConnect(grantee: iam.IGrantable, dbUser?: string): iam.Grant { + if (!dbUser) { + if (this.secrets.length > 1) { + throw new Error('When the Proxy contains multiple Secrets, you must pass a dbUser explicitly to grantConnect()'); + } + // 'username' is the field RDS uses here, + // see https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/rds-proxy.html#rds-proxy-secrets-arns + dbUser = this.secrets[0].secretValueFromJson('username').toString(); + } + return super.grantConnect(grantee, dbUser); + } } /** diff --git a/packages/@aws-cdk/aws-rds/lib/serverless-cluster.ts b/packages/@aws-cdk/aws-rds/lib/serverless-cluster.ts index 39258de8c7748..90438cbaa1c79 100644 --- a/packages/@aws-cdk/aws-rds/lib/serverless-cluster.ts +++ b/packages/@aws-cdk/aws-rds/lib/serverless-cluster.ts @@ -8,7 +8,7 @@ import { IClusterEngine } from './cluster-engine'; import { Endpoint } from './endpoint'; import { IParameterGroup } from './parameter-group'; import { DATA_API_ACTIONS } from './perms'; -import { applyRemovalPolicy, defaultDeletionProtection, DEFAULT_PASSWORD_EXCLUDE_CHARS, renderCredentials } from './private/util'; +import { defaultDeletionProtection, DEFAULT_PASSWORD_EXCLUDE_CHARS, renderCredentials } from './private/util'; import { Credentials, RotationMultiUserOptions, RotationSingleUserOptions } from './props'; import { CfnDBCluster } from './rds.generated'; import { ISubnetGroup, SubnetGroup } from './subnet-group'; @@ -468,7 +468,7 @@ export class ServerlessCluster extends ServerlessClusterBase { defaultPort: ec2.Port.tcp(this.clusterEndpoint.port), }); - applyRemovalPolicy(cluster, props.removalPolicy); + cluster.applyRemovalPolicy(props.removalPolicy ?? RemovalPolicy.SNAPSHOT); if (secret) { this.secret = secret.attach(this); diff --git a/packages/@aws-cdk/aws-rds/package.json b/packages/@aws-cdk/aws-rds/package.json index bf1ce83d40d00..01ce0a8ca4a12 100644 --- a/packages/@aws-cdk/aws-rds/package.json +++ b/packages/@aws-cdk/aws-rds/package.json @@ -53,6 +53,7 @@ }, "cdk-build": { "cloudformation": "AWS::RDS", + "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,12 +74,11 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-events-targets": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", - "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "nodeunit": "^0.11.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "nodeunit-shim": "0.0.0" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", @@ -140,5 +140,8 @@ "maturity": "stable", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-rds/test/test.cluster-engine.ts b/packages/@aws-cdk/aws-rds/test/cluster-engine.test.ts similarity index 98% rename from packages/@aws-cdk/aws-rds/test/test.cluster-engine.ts rename to packages/@aws-cdk/aws-rds/test/cluster-engine.test.ts index d5af56f1d10da..54a02441fb9c7 100644 --- a/packages/@aws-cdk/aws-rds/test/test.cluster-engine.ts +++ b/packages/@aws-cdk/aws-rds/test/cluster-engine.test.ts @@ -1,7 +1,7 @@ -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import { AuroraEngineVersion, AuroraMysqlEngineVersion, AuroraPostgresEngineVersion, DatabaseClusterEngine } from '../lib'; -export = { +nodeunitShim({ "default parameterGroupFamily for versionless Aurora cluster engine is 'aurora5.6'"(test: Test) { // GIVEN const engine = DatabaseClusterEngine.AURORA; @@ -115,4 +115,4 @@ export = { test.deepEqual(DatabaseClusterEngine.auroraPostgres({ version: AuroraPostgresEngineVersion.VER_9_6_9 }).supportedLogTypes, ['postgresql']); test.done(); }, -} +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/test/test.cluster.ts b/packages/@aws-cdk/aws-rds/test/cluster.test.ts similarity index 97% rename from packages/@aws-cdk/aws-rds/test/test.cluster.ts rename to packages/@aws-cdk/aws-rds/test/cluster.test.ts index fc877641dcc42..6bfda0f1cfa50 100644 --- a/packages/@aws-cdk/aws-rds/test/test.cluster.ts +++ b/packages/@aws-cdk/aws-rds/test/cluster.test.ts @@ -5,13 +5,13 @@ import * as kms from '@aws-cdk/aws-kms'; import * as logs from '@aws-cdk/aws-logs'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import { AuroraEngineVersion, AuroraMysqlEngineVersion, AuroraPostgresEngineVersion, CfnDBCluster, Credentials, DatabaseCluster, DatabaseClusterEngine, DatabaseClusterFromSnapshot, ParameterGroup, PerformanceInsightRetention, SubnetGroup, } from '../lib'; -export = { +nodeunitShim({ 'creating a Cluster also creates 2 DB Instances'(test: Test) { // GIVEN const stack = testStack(); @@ -39,14 +39,14 @@ export = { MasterUserPassword: 'tooshort', VpcSecurityGroupIds: [{ 'Fn::GetAtt': ['DatabaseSecurityGroup5C91FDCB', 'GroupId'] }], }, - DeletionPolicy: ABSENT, + DeletionPolicy: 'Snapshot', UpdateReplacePolicy: 'Snapshot', }, ResourcePart.CompleteDefinition)); expect(stack).to(countResources('AWS::RDS::DBInstance', 2)); expect(stack).to(haveResource('AWS::RDS::DBInstance', { - DeletionPolicy: ABSENT, - UpdateReplacePolicy: ABSENT, + DeletionPolicy: 'Delete', + UpdateReplacePolicy: 'Delete', }, ResourcePart.CompleteDefinition)); test.done(); @@ -1674,7 +1674,7 @@ export = { VpcSecurityGroupIds: [{ 'Fn::GetAtt': ['DatabaseSecurityGroup5C91FDCB', 'GroupId'] }], SnapshotIdentifier: 'mySnapshot', }, - DeletionPolicy: ABSENT, + DeletionPolicy: 'Snapshot', UpdateReplacePolicy: 'Snapshot', }, ResourcePart.CompleteDefinition)); @@ -1838,7 +1838,43 @@ export = { test.done(); }, -}; +}); + +test.each([ + [cdk.RemovalPolicy.RETAIN, 'Retain', 'Retain', 'Retain'], + [cdk.RemovalPolicy.SNAPSHOT, 'Snapshot', 'Delete', ABSENT], + [cdk.RemovalPolicy.DESTROY, 'Delete', 'Delete', ABSENT], +])('if Cluster RemovalPolicy is \'%s\', the DBCluster has DeletionPolicy \'%s\', the DBInstance has \'%s\' and the DBSubnetGroup has \'%s\'', (clusterRemovalPolicy, clusterValue, instanceValue, subnetValue) => { + const stack = new cdk.Stack(); + + // WHEN + new DatabaseCluster(stack, 'Cluster', { + credentials: { username: 'admin' }, + engine: DatabaseClusterEngine.AURORA, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.LARGE), + vpc: new ec2.Vpc(stack, 'Vpc'), + }, + removalPolicy: clusterRemovalPolicy, + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::RDS::DBCluster', { + DeletionPolicy: clusterValue, + UpdateReplacePolicy: clusterValue, + }, ResourcePart.CompleteDefinition)); + + expect(stack).to(haveResourceLike('AWS::RDS::DBInstance', { + DeletionPolicy: instanceValue, + UpdateReplacePolicy: instanceValue, + }, ResourcePart.CompleteDefinition)); + + expect(stack).to(haveResourceLike('AWS::RDS::DBSubnetGroup', { + DeletionPolicy: subnetValue, + UpdateReplacePolicy: subnetValue, + }, ResourcePart.CompleteDefinition)); +}); + function testStack() { const stack = new cdk.Stack(undefined, undefined, { env: { account: '12345', region: 'us-test-1' } }); diff --git a/packages/@aws-cdk/aws-rds/test/test.database-secret.ts b/packages/@aws-cdk/aws-rds/test/database-secret.test.ts similarity index 97% rename from packages/@aws-cdk/aws-rds/test/test.database-secret.ts rename to packages/@aws-cdk/aws-rds/test/database-secret.test.ts index 6e4edb551d764..97de0085806e0 100644 --- a/packages/@aws-cdk/aws-rds/test/test.database-secret.ts +++ b/packages/@aws-cdk/aws-rds/test/database-secret.test.ts @@ -1,10 +1,10 @@ import { expect, haveResource } from '@aws-cdk/assert'; import { CfnResource, Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import { DatabaseSecret } from '../lib'; import { DEFAULT_PASSWORD_EXCLUDE_CHARS } from '../lib/private/util'; -export = { +nodeunitShim({ 'create a database secret'(test: Test) { // GIVEN const stack = new Stack(); @@ -110,7 +110,7 @@ export = { test.done(); }, -}; +}); function getSecretLogicalId(dbSecret: DatabaseSecret, stack: Stack): string { const cfnSecret = dbSecret.node.defaultChild as CfnResource; diff --git a/packages/@aws-cdk/aws-rds/test/test.database-secretmanager.ts b/packages/@aws-cdk/aws-rds/test/database-secretmanager.test.ts similarity index 91% rename from packages/@aws-cdk/aws-rds/test/test.database-secretmanager.ts rename to packages/@aws-cdk/aws-rds/test/database-secretmanager.test.ts index 8d6310d21ce42..d307c0f05cec6 100644 --- a/packages/@aws-cdk/aws-rds/test/test.database-secretmanager.ts +++ b/packages/@aws-cdk/aws-rds/test/database-secretmanager.test.ts @@ -1,11 +1,11 @@ -import { ABSENT, expect, haveResource, ResourcePart } from '@aws-cdk/assert'; +import { expect, haveResource, ResourcePart } from '@aws-cdk/assert'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import { ServerlessCluster, DatabaseClusterEngine, ParameterGroup, Credentials } from '../lib'; -export = { +nodeunitShim({ 'can create a Serverless Cluster using an existing secret from secretmanager'(test: Test) { // GIVEN const stack = testStack(); @@ -41,13 +41,13 @@ export = { }, ], }, - DeletionPolicy: ABSENT, + DeletionPolicy: 'Snapshot', UpdateReplacePolicy: 'Snapshot', }, ResourcePart.CompleteDefinition)); test.done(); }, -}; +}); function testStack() { const stack = new cdk.Stack(undefined, undefined, { env: { account: '12345', region: 'us-test-1' } }); diff --git a/packages/@aws-cdk/aws-rds/test/test.instance-engine.ts b/packages/@aws-cdk/aws-rds/test/instance-engine.test.ts similarity index 99% rename from packages/@aws-cdk/aws-rds/test/test.instance-engine.ts rename to packages/@aws-cdk/aws-rds/test/instance-engine.test.ts index 90d5a7a204eae..2c9f1fddf8076 100644 --- a/packages/@aws-cdk/aws-rds/test/test.instance-engine.ts +++ b/packages/@aws-cdk/aws-rds/test/instance-engine.test.ts @@ -1,10 +1,10 @@ import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as rds from '../lib'; -export = { +nodeunitShim({ 'default parameterGroupFamily for versionless MariaDB instance engine is not defined'(test: Test) { const engine = rds.DatabaseInstanceEngine.MARIADB; @@ -284,4 +284,4 @@ export = { test.done(); }, }, -}; +}); diff --git a/packages/@aws-cdk/aws-rds/test/test.instance.ts b/packages/@aws-cdk/aws-rds/test/instance.test.ts similarity index 97% rename from packages/@aws-cdk/aws-rds/test/test.instance.ts rename to packages/@aws-cdk/aws-rds/test/instance.test.ts index 7591a576946cb..625dfa7074ae3 100644 --- a/packages/@aws-cdk/aws-rds/test/test.instance.ts +++ b/packages/@aws-cdk/aws-rds/test/instance.test.ts @@ -7,13 +7,13 @@ import * as lambda from '@aws-cdk/aws-lambda'; import * as logs from '@aws-cdk/aws-logs'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as rds from '../lib'; let stack: cdk.Stack; let vpc: ec2.Vpc; -export = { +nodeunitShim({ 'setUp'(cb: () => void) { stack = new cdk.Stack(); vpc = new ec2.Vpc(stack, 'VPC'); @@ -114,7 +114,7 @@ export = { }, ], }, - DeletionPolicy: ABSENT, + DeletionPolicy: 'Snapshot', UpdateReplacePolicy: 'Snapshot', }, ResourcePart.CompleteDefinition)); @@ -1023,7 +1023,7 @@ export = { new rds.DatabaseInstance(stack, 'Instance', { vpc, engine: rds.DatabaseInstanceEngine.postgres({ - version: rds.PostgresEngineVersion.VER_9_5_7, + version: rds.PostgresEngineVersion.VER_12_4, }), }); @@ -1242,4 +1242,31 @@ export = { test.done(); }, -}; +}); + +test.each([ + [cdk.RemovalPolicy.RETAIN, 'Retain', 'Retain'], + [cdk.RemovalPolicy.SNAPSHOT, 'Snapshot', ABSENT], + [cdk.RemovalPolicy.DESTROY, 'Delete', ABSENT], +])('if Instance RemovalPolicy is \'%s\', the instance has DeletionPolicy \'%s\' and the DBSubnetGroup has \'%s\'', (instanceRemovalPolicy, instanceValue, subnetValue) => { + // WHEN + new rds.DatabaseInstance(stack, 'Instance', { + engine: rds.DatabaseInstanceEngine.mysql({ + version: rds.MysqlEngineVersion.VER_8_0_19, + }), + vpc, + vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC }, + removalPolicy: instanceRemovalPolicy, + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::RDS::DBInstance', { + DeletionPolicy: instanceValue, + UpdateReplacePolicy: instanceValue, + }, ResourcePart.CompleteDefinition)); + + expect(stack).to(haveResourceLike('AWS::RDS::DBSubnetGroup', { + DeletionPolicy: subnetValue, + UpdateReplacePolicy: subnetValue, + }, ResourcePart.CompleteDefinition)); +}); diff --git a/packages/@aws-cdk/aws-rds/test/integ.cluster-rotation.lit.expected.json b/packages/@aws-cdk/aws-rds/test/integ.cluster-rotation.lit.expected.json index 05293187edb33..74a0642b875c8 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.cluster-rotation.lit.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.cluster-rotation.lit.expected.json @@ -706,7 +706,8 @@ } ] }, - "UpdateReplacePolicy": "Snapshot" + "UpdateReplacePolicy": "Snapshot", + "DeletionPolicy": "Snapshot" }, "DatabaseInstance1844F58FD": { "Type": "AWS::RDS::DBInstance", @@ -724,7 +725,9 @@ "VPCPrivateSubnet1DefaultRouteAE1D6490", "VPCPrivateSubnet2DefaultRouteF4F5CFD2", "VPCPrivateSubnet3DefaultRoute27F311AE" - ] + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "DatabaseInstance2AA380DEE": { "Type": "AWS::RDS::DBInstance", @@ -742,7 +745,9 @@ "VPCPrivateSubnet1DefaultRouteAE1D6490", "VPCPrivateSubnet2DefaultRouteF4F5CFD2", "VPCPrivateSubnet3DefaultRoute27F311AE" - ] + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "DatabaseRotationSingleUserSecurityGroupAC6E0E73": { "Type": "AWS::EC2::SecurityGroup", diff --git a/packages/@aws-cdk/aws-rds/test/integ.cluster-s3.expected.json b/packages/@aws-cdk/aws-rds/test/integ.cluster-s3.expected.json index 710884195806a..3ee9358bebc33 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.cluster-s3.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.cluster-s3.expected.json @@ -361,23 +361,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { @@ -563,7 +547,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -668,7 +652,8 @@ } ] }, - "UpdateReplacePolicy": "Snapshot" + "UpdateReplacePolicy": "Snapshot", + "DeletionPolicy": "Snapshot" }, "DatabaseInstance1844F58FD": { "Type": "AWS::RDS::DBInstance", @@ -686,7 +671,9 @@ "DependsOn": [ "VPCPublicSubnet1DefaultRoute91CEF279", "VPCPublicSubnet2DefaultRouteB7481BBA" - ] + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "DatabaseInstance2AA380DEE": { "Type": "AWS::RDS::DBInstance", @@ -704,7 +691,9 @@ "DependsOn": [ "VPCPublicSubnet1DefaultRoute91CEF279", "VPCPublicSubnet2DefaultRouteB7481BBA" - ] + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/test/integ.cluster.expected.json b/packages/@aws-cdk/aws-rds/test/integ.cluster.expected.json index 37f63d001843e..04a2157aba0a8 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.cluster.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.cluster.expected.json @@ -371,23 +371,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { @@ -500,7 +484,8 @@ } ] }, - "UpdateReplacePolicy": "Snapshot" + "UpdateReplacePolicy": "Snapshot", + "DeletionPolicy": "Snapshot" }, "DatabaseInstance1844F58FD": { "Type": "AWS::RDS::DBInstance", @@ -518,7 +503,9 @@ "DependsOn": [ "VPCPublicSubnet1DefaultRoute91CEF279", "VPCPublicSubnet2DefaultRouteB7481BBA" - ] + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "DatabaseInstance2AA380DEE": { "Type": "AWS::RDS::DBInstance", @@ -536,7 +523,9 @@ "DependsOn": [ "VPCPublicSubnet1DefaultRoute91CEF279", "VPCPublicSubnet2DefaultRouteB7481BBA" - ] + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/test/integ.instance-from-generated-password.expected.json b/packages/@aws-cdk/aws-rds/test/integ.instance-from-generated-password.expected.json index a01587728dac5..ca2ee08c781ad 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.instance-from-generated-password.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.instance-from-generated-password.expected.json @@ -619,7 +619,8 @@ } ] }, - "UpdateReplacePolicy": "Snapshot" + "UpdateReplacePolicy": "Snapshot", + "DeletionPolicy": "Snapshot" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/test/integ.instance-s3.expected.json b/packages/@aws-cdk/aws-rds/test/integ.instance-s3.expected.json index cd2478b15b818..2b144dedcc3aa 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.instance-s3.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.instance-s3.expected.json @@ -453,7 +453,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -613,4 +613,4 @@ "DeletionPolicy": "Delete" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/test/integ.instance.lit.expected.json b/packages/@aws-cdk/aws-rds/test/integ.instance.lit.expected.json index ca91f92e62644..8a05969830f29 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.instance.lit.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.instance.lit.expected.json @@ -694,7 +694,8 @@ } ] }, - "UpdateReplacePolicy": "Snapshot" + "UpdateReplacePolicy": "Snapshot", + "DeletionPolicy": "Snapshot" }, "InstanceLogRetentiontrace487771C8": { "Type": "Custom::LogRetention", @@ -832,7 +833,6 @@ ] }, "functionName": "awscdkrdsinstanceInstanceRotationSingleUserAFE3C214", - "excludeCharacters": " %+~`#$&*()|[]{}:;<>?!'/@\"\\", "vpcSubnetIds": { "Fn::Join": [ "", @@ -852,7 +852,8 @@ "InstanceRotationSingleUserSecurityGroupF3FB5C25", "GroupId" ] - } + }, + "excludeCharacters": " %+~`#$&*()|[]{}:;<>?!'/@\"\\" } } }, @@ -1094,13 +1095,13 @@ "Code": { "ZipFile": "exports.handler = (event) => console.log(event);" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "FunctionServiceRole675BB04A", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs10.x" }, "DependsOn": [ @@ -1122,4 +1123,4 @@ "Description": "Artifact hash for asset \"884431e2bc651d2b61bd699a29dc9684b0f66911f06bd3ed0635f854bf18e147\"" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/test/integ.proxy.expected.json b/packages/@aws-cdk/aws-rds/test/integ.proxy.expected.json index 3a77314058702..a18c5f5843512 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.proxy.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.proxy.expected.json @@ -385,6 +385,37 @@ } } }, + "dbInstanceSecurityGroupfromawscdkrdsproxydbProxyProxySecurityGroupA345AFE5IndirectPortE3621D4F": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "Description": "Allow connections to the database Instance from the Proxy", + "FromPort": { + "Fn::GetAtt": [ + "dbInstance4076B1EC", + "Endpoint.Port" + ] + }, + "GroupId": { + "Fn::GetAtt": [ + "dbInstanceSecurityGroupA58A00A3", + "GroupId" + ] + }, + "SourceSecurityGroupId": { + "Fn::GetAtt": [ + "dbProxyProxySecurityGroup16E727A7", + "GroupId" + ] + }, + "ToPort": { + "Fn::GetAtt": [ + "dbInstance4076B1EC", + "Endpoint.Port" + ] + } + } + }, "dbInstanceSecret032D3661": { "Type": "AWS::SecretsManager::Secret", "Properties": { @@ -429,6 +460,7 @@ "Ref": "dbInstanceSubnetGroupD062EC9E" }, "Engine": "postgres", + "EngineVersion": "11.5", "MasterUsername": { "Fn::Join": [ "", @@ -463,7 +495,8 @@ } ] }, - "UpdateReplacePolicy": "Snapshot" + "UpdateReplacePolicy": "Snapshot", + "DeletionPolicy": "Snapshot" }, "dbProxyIAMRole662F3AB8": { "Type": "AWS::IAM::Role", @@ -508,6 +541,22 @@ ] } }, + "dbProxyProxySecurityGroup16E727A7": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "SecurityGroup for Database Proxy", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "vpcA2121C38" + } + } + }, "dbProxy3B89EAF2": { "Type": "AWS::RDS::DBProxy", "Properties": { @@ -522,7 +571,6 @@ ], "DBProxyName": "dbProxy", "EngineFamily": "POSTGRESQL", - "RequireTLS": true, "RoleArn": { "Fn::GetAtt": [ "dbProxyIAMRole662F3AB8", @@ -536,6 +584,15 @@ { "Ref": "vpcPrivateSubnet2Subnet7031C2BA" } + ], + "RequireTLS": true, + "VpcSecurityGroupIds": [ + { + "Fn::GetAtt": [ + "dbProxyProxySecurityGroup16E727A7", + "GroupId" + ] + } ] } }, @@ -545,6 +602,7 @@ "DBProxyName": { "Ref": "dbProxy3B89EAF2" }, + "TargetGroupName": "default", "ConnectionPoolConfigurationInfo": { "ConnectionBorrowTimeout": 30, "MaxConnectionsPercent": 50 @@ -553,9 +611,8 @@ { "Ref": "dbInstance4076B1EC" } - ], - "TargetGroupName": "default" + ] } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/test/integ.proxy.ts b/packages/@aws-cdk/aws-rds/test/integ.proxy.ts index d3945cf4a5b99..e59ead63f3590 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.proxy.ts +++ b/packages/@aws-cdk/aws-rds/test/integ.proxy.ts @@ -8,7 +8,9 @@ const stack = new cdk.Stack(app, 'aws-cdk-rds-proxy'); const vpc = new ec2.Vpc(stack, 'vpc', { maxAzs: 2 }); const dbInstance = new rds.DatabaseInstance(stack, 'dbInstance', { - engine: rds.DatabaseInstanceEngine.POSTGRES, + engine: rds.DatabaseInstanceEngine.postgres({ + version: rds.PostgresEngineVersion.VER_11_5, + }), instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE3, ec2.InstanceSize.MEDIUM), credentials: rds.Credentials.fromUsername('master', { excludeCharacters: '"@/\\', diff --git a/packages/@aws-cdk/aws-rds/test/integ.serverless-cluster.expected.json b/packages/@aws-cdk/aws-rds/test/integ.serverless-cluster.expected.json index 3d392f574621e..752eae1b22894 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.serverless-cluster.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.serverless-cluster.expected.json @@ -432,7 +432,8 @@ } ] }, - "UpdateReplacePolicy": "Snapshot" + "UpdateReplacePolicy": "Snapshot", + "DeletionPolicy": "Snapshot" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/test/test.option-group.ts b/packages/@aws-cdk/aws-rds/test/option-group.test.ts similarity index 98% rename from packages/@aws-cdk/aws-rds/test/test.option-group.ts rename to packages/@aws-cdk/aws-rds/test/option-group.test.ts index d4129b6aebd5a..b7c6cc851874c 100644 --- a/packages/@aws-cdk/aws-rds/test/test.option-group.ts +++ b/packages/@aws-cdk/aws-rds/test/option-group.test.ts @@ -1,10 +1,10 @@ import { expect, haveResource } from '@aws-cdk/assert'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import { DatabaseInstanceEngine, OptionGroup, OracleEngineVersion, OracleLegacyEngineVersion } from '../lib'; -export = { +nodeunitShim({ 'create an option group'(test: Test) { // GIVEN const stack = new cdk.Stack(); @@ -160,4 +160,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-rds/test/test.parameter-group.ts b/packages/@aws-cdk/aws-rds/test/parameter-group.test.ts similarity index 97% rename from packages/@aws-cdk/aws-rds/test/test.parameter-group.ts rename to packages/@aws-cdk/aws-rds/test/parameter-group.test.ts index f4a21db1fdec0..0f9fd73f44e8c 100644 --- a/packages/@aws-cdk/aws-rds/test/test.parameter-group.ts +++ b/packages/@aws-cdk/aws-rds/test/parameter-group.test.ts @@ -1,9 +1,9 @@ import { countResources, expect, haveResource } from '@aws-cdk/assert'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import { DatabaseClusterEngine, ParameterGroup } from '../lib'; -export = { +nodeunitShim({ "does not create a parameter group if it wasn't bound to a cluster or instance"(test: Test) { // GIVEN const stack = new cdk.Stack(); @@ -126,4 +126,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-rds/test/test.proxy.ts b/packages/@aws-cdk/aws-rds/test/proxy.test.ts similarity index 64% rename from packages/@aws-cdk/aws-rds/test/test.proxy.ts rename to packages/@aws-cdk/aws-rds/test/proxy.test.ts index 83d79146cebf7..a0835879b5d79 100644 --- a/packages/@aws-cdk/aws-rds/test/test.proxy.ts +++ b/packages/@aws-cdk/aws-rds/test/proxy.test.ts @@ -3,13 +3,15 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import { AccountPrincipal, Role } from '@aws-cdk/aws-iam'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as rds from '../lib'; let stack: cdk.Stack; let vpc: ec2.IVpc; -export = { +let importedDbProxy: rds.IDatabaseProxy; + +nodeunitShim({ 'setUp'(cb: () => void) { stack = new cdk.Stack(); vpc = new ec2.Vpc(stack, 'VPC'); @@ -123,8 +125,6 @@ export = { }, ], })); - - // THEN expect(stack).to(haveResourceLike('AWS::RDS::DBProxyTargetGroup', { DBProxyName: { Ref: 'ProxyCB0DFB71', @@ -138,6 +138,22 @@ export = { DBInstanceIdentifiers: ABSENT, TargetGroupName: 'default', })); + expect(stack).to(haveResourceLike('AWS::EC2::SecurityGroupIngress', { + IpProtocol: 'tcp', + Description: 'Allow connections to the database Cluster from the Proxy', + FromPort: { + 'Fn::GetAtt': ['DatabaseB269D8BB', 'Endpoint.Port'], + }, + GroupId: { + 'Fn::GetAtt': ['DatabaseSecurityGroup5C91FDCB', 'GroupId'], + }, + SourceSecurityGroupId: { + 'Fn::GetAtt': ['ProxyProxySecurityGroupC42FC3CE', 'GroupId'], + }, + ToPort: { + 'Fn::GetAtt': ['DatabaseB269D8BB', 'Endpoint.Port'], + }, + })); test.done(); }, @@ -205,6 +221,7 @@ export = { engine: rds.DatabaseClusterEngine.auroraPostgres({ version: rds.AuroraPostgresEngineVersion.VER_9_6_11, }), + port: 5432, }); new rds.DatabaseProxy(stack, 'Proxy', { @@ -221,11 +238,75 @@ export = { 'my-cluster', ], })); + expect(stack).to(haveResourceLike('AWS::EC2::SecurityGroup', { + GroupDescription: 'SecurityGroup for Database Proxy', + VpcId: { Ref: 'VPCB9E5F0B4' }, + })); test.done(); }, - 'grantConnect should add IAM Policy with action rds-db:connect'(test: Test) { + 'imported Proxies': { + 'setUp'(cb: () => void) { + importedDbProxy = rds.DatabaseProxy.fromDatabaseProxyAttributes(stack, 'Proxy', { + dbProxyName: 'my-proxy', + dbProxyArn: 'arn:aws:rds:us-east-1:123456789012:db-proxy:prx-1234abcd', + endpoint: 'my-endpoint', + securityGroups: [], + }); + + cb(); + }, + + 'grant rds-db:connect in grantConnect() with a dbUser explicitly passed'(test: Test) { + // WHEN + const role = new Role(stack, 'DBProxyRole', { + assumedBy: new AccountPrincipal(stack.account), + }); + const databaseUser = 'test'; + importedDbProxy.grantConnect(role, databaseUser); + + // THEN + expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [{ + Effect: 'Allow', + Action: 'rds-db:connect', + Resource: { + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':rds-db:', + { Ref: 'AWS::Region' }, + ':', + { Ref: 'AWS::AccountId' }, + ':dbuser:prx-1234abcd/test', + ]], + }, + }], + Version: '2012-10-17', + }, + })); + + test.done(); + }, + + 'throws when grantConnect() is used without a dbUser'(test: Test) { + // WHEN + const role = new Role(stack, 'DBProxyRole', { + assumedBy: new AccountPrincipal(stack.account), + }); + + // THEN + test.throws(() => { + importedDbProxy.grantConnect(role); + }, /For imported Database Proxies, the dbUser is required in grantConnect/); + + test.done(); + }, + }, + + 'new Proxy with a single Secret can use grantConnect() without a dbUser passed'(test: Test) { // GIVEN const cluster = new rds.DatabaseCluster(stack, 'Database', { engine: rds.DatabaseClusterEngine.AURORA, @@ -251,10 +332,29 @@ export = { Effect: 'Allow', Action: 'rds-db:connect', Resource: { - 'Fn::GetAtt': [ - 'ProxyCB0DFB71', - 'DBProxyArn', - ], + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':rds-db:', + { Ref: 'AWS::Region' }, + ':', + { Ref: 'AWS::AccountId' }, + ':dbuser:', + { + 'Fn::Select': [ + 6, + { + 'Fn::Split': [ + ':', + { 'Fn::GetAtt': ['ProxyCB0DFB71', 'DBProxyArn'] }, + ], + }, + ], + }, + '/{{resolve:secretsmanager:', + { Ref: 'DatabaseSecretAttachmentE5D1B020' }, + ':SecretString:username::}}', + ]], }, }], Version: '2012-10-17', @@ -264,6 +364,35 @@ export = { test.done(); }, + 'new Proxy with multiple Secrets cannot use grantConnect() without a dbUser passed'(test: Test) { + // GIVEN + const cluster = new rds.DatabaseCluster(stack, 'Database', { + engine: rds.DatabaseClusterEngine.AURORA, + instanceProps: { vpc }, + }); + + const proxy = new rds.DatabaseProxy(stack, 'Proxy', { + proxyTarget: rds.ProxyTarget.fromCluster(cluster), + secrets: [ + cluster.secret!, + new secretsmanager.Secret(stack, 'ProxySecret'), + ], + vpc, + }); + + // WHEN + const role = new Role(stack, 'DBProxyRole', { + assumedBy: new AccountPrincipal(stack.account), + }); + + // THEN + test.throws(() => { + proxy.grantConnect(role); + }, /When the Proxy contains multiple Secrets, you must pass a dbUser explicitly to grantConnect/); + + test.done(); + }, + 'DBProxyTargetGroup should have dependency on the proxy targets'(test: Test) { // GIVEN const cluster = new rds.DatabaseCluster(stack, 'cluster', { @@ -294,6 +423,7 @@ export = { 'cluster611F8AFF', 'clusterSecretAttachment69BFCEC4', 'clusterSecretE349B730', + 'clusterSecurityGroupfromproxyProxySecurityGroupA80F0525IndirectPortA13E5F3D', 'clusterSecurityGroupF441DCEA', 'clusterSubnets81E3593F', ], @@ -301,4 +431,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-rds/test/test.serverless-cluster.ts b/packages/@aws-cdk/aws-rds/test/serverless-cluster.test.ts similarity index 98% rename from packages/@aws-cdk/aws-rds/test/test.serverless-cluster.ts rename to packages/@aws-cdk/aws-rds/test/serverless-cluster.test.ts index de3c8a0018beb..e370ff915cb6c 100644 --- a/packages/@aws-cdk/aws-rds/test/test.serverless-cluster.ts +++ b/packages/@aws-cdk/aws-rds/test/serverless-cluster.test.ts @@ -1,12 +1,12 @@ -import { ABSENT, expect, haveResource, haveResourceLike, ResourcePart, SynthUtils } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike, ResourcePart, SynthUtils } from '@aws-cdk/assert'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import { AuroraPostgresEngineVersion, ServerlessCluster, DatabaseClusterEngine, ParameterGroup, AuroraCapacityUnit, DatabaseSecret } from '../lib'; -export = { +nodeunitShim({ 'can create a Serverless Cluster with Aurora Postgres database engine'(test: Test) { // GIVEN const stack = testStack(); @@ -44,7 +44,7 @@ export = { }, ], }, - DeletionPolicy: ABSENT, + DeletionPolicy: 'Snapshot', UpdateReplacePolicy: 'Snapshot', }, ResourcePart.CompleteDefinition)); @@ -105,7 +105,7 @@ export = { }, ], }, - DeletionPolicy: ABSENT, + DeletionPolicy: 'Snapshot', UpdateReplacePolicy: 'Snapshot', }, ResourcePart.CompleteDefinition)); test.done(); @@ -818,7 +818,7 @@ export = { test.done(); }, -}; +}); function testStack() { diff --git a/packages/@aws-cdk/aws-rds/test/sql-server/test.sql-server.instance-engine.ts b/packages/@aws-cdk/aws-rds/test/sql-server/sql-server.instance-engine.test.ts similarity index 94% rename from packages/@aws-cdk/aws-rds/test/sql-server/test.sql-server.instance-engine.ts rename to packages/@aws-cdk/aws-rds/test/sql-server/sql-server.instance-engine.test.ts index 7f9ecf0311faa..4255298f87d10 100644 --- a/packages/@aws-cdk/aws-rds/test/sql-server/test.sql-server.instance-engine.ts +++ b/packages/@aws-cdk/aws-rds/test/sql-server/sql-server.instance-engine.test.ts @@ -1,9 +1,9 @@ import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as core from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as rds from '../../lib'; -export = { +nodeunitShim({ 'SQL Server instance engine': { "has ParameterGroup family ending in '11.0' for major version 11"(test: Test) { const stack = new core.Stack(); @@ -43,4 +43,4 @@ export = { test.done(); }, }, -}; +}); diff --git a/packages/@aws-cdk/aws-rds/test/test.subnet-group.ts b/packages/@aws-cdk/aws-rds/test/subnet-group.test.ts similarity index 97% rename from packages/@aws-cdk/aws-rds/test/test.subnet-group.ts rename to packages/@aws-cdk/aws-rds/test/subnet-group.test.ts index 6d2a71e84bad7..c6c16add591ce 100644 --- a/packages/@aws-cdk/aws-rds/test/test.subnet-group.ts +++ b/packages/@aws-cdk/aws-rds/test/subnet-group.test.ts @@ -1,13 +1,13 @@ import { expect, haveResource } from '@aws-cdk/assert'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as rds from '../lib'; let stack: cdk.Stack; let vpc: ec2.IVpc; -export = { +nodeunitShim({ 'setUp'(cb: () => void) { stack = new cdk.Stack(); vpc = new ec2.Vpc(stack, 'VPC'); @@ -95,4 +95,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-redshift/package.json b/packages/@aws-cdk/aws-redshift/package.json index cac9210cac25b..cede50f836f54 100644 --- a/packages/@aws-cdk/aws-redshift/package.json +++ b/packages/@aws-cdk/aws-redshift/package.json @@ -114,5 +114,8 @@ "maturity": "experimental", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-resourcegroups/package.json b/packages/@aws-cdk/aws-resourcegroups/package.json index 2616f1f58fe7e..bd1848d6681e9 100644 --- a/packages/@aws-cdk/aws-resourcegroups/package.json +++ b/packages/@aws-cdk/aws-resourcegroups/package.json @@ -91,5 +91,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-robomaker/package.json b/packages/@aws-cdk/aws-robomaker/package.json index 2727122c5e1df..be52d60f6a739 100644 --- a/packages/@aws-cdk/aws-robomaker/package.json +++ b/packages/@aws-cdk/aws-robomaker/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-route53-patterns/package.json b/packages/@aws-cdk/aws-route53-patterns/package.json index d71489948d599..b10d3e4ceb714 100644 --- a/packages/@aws-cdk/aws-route53-patterns/package.json +++ b/packages/@aws-cdk/aws-route53-patterns/package.json @@ -106,5 +106,8 @@ "env": { "AWSLINT_BASE_CONSTRUCT": true } + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-route53-targets/package.json b/packages/@aws-cdk/aws-route53-targets/package.json index e8e2d73947f21..08ea2cb9e91f4 100644 --- a/packages/@aws-cdk/aws-route53-targets/package.json +++ b/packages/@aws-cdk/aws-route53-targets/package.json @@ -115,5 +115,8 @@ "env": { "AWSLINT_BASE_CONSTRUCT": true } + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-route53/README.md b/packages/@aws-cdk/aws-route53/README.md index b9f75fb1b9d4e..aa5bf109b7473 100644 --- a/packages/@aws-cdk/aws-route53/README.md +++ b/packages/@aws-cdk/aws-route53/README.md @@ -117,7 +117,7 @@ import * as route53 from '@aws-cdk/aws-route53'; // In the account containing the HostedZone const parentZone = new route53.PublicHostedZone(this, 'HostedZone', { zoneName: 'someexample.com', - crossAccountZoneDelegationPrinciple: new iam.AccountPrincipal('12345678901') + crossAccountZoneDelegationPrincipal: new iam.AccountPrincipal('12345678901') }); // In this account diff --git a/packages/@aws-cdk/aws-route53/package.json b/packages/@aws-cdk/aws-route53/package.json index 719f8bb3866ae..9a22737d55347 100644 --- a/packages/@aws-cdk/aws-route53/package.json +++ b/packages/@aws-cdk/aws-route53/package.json @@ -73,7 +73,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", - "aws-sdk": "^2.830.0", + "aws-sdk": "^2.848.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -129,5 +129,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-route53/test/hosted-zone.test.ts b/packages/@aws-cdk/aws-route53/test/hosted-zone.test.ts index 6e7810824c2bf..824e97cc93278 100644 --- a/packages/@aws-cdk/aws-route53/test/hosted-zone.test.ts +++ b/packages/@aws-cdk/aws-route53/test/hosted-zone.test.ts @@ -63,7 +63,7 @@ nodeunitShim({ test.done(); }, - 'with crossAccountZoneDelegationPrinciple'(test: Test) { + 'with crossAccountZoneDelegationPrincipal'(test: Test) { // GIVEN const stack = new cdk.Stack(undefined, 'TestStack', { env: { account: '123456789012', region: 'us-east-1' }, diff --git a/packages/@aws-cdk/aws-route53resolver/package.json b/packages/@aws-cdk/aws-route53resolver/package.json index 2d7c49574f4a7..79142ad18b7ef 100644 --- a/packages/@aws-cdk/aws-route53resolver/package.json +++ b/packages/@aws-cdk/aws-route53resolver/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-s3-assets/package.json b/packages/@aws-cdk/aws-s3-assets/package.json index 9f9d1e968fcbc..6d03905f64f85 100644 --- a/packages/@aws-cdk/aws-s3-assets/package.json +++ b/packages/@aws-cdk/aws-s3-assets/package.json @@ -107,5 +107,8 @@ }, "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-s3-deployment/README.md b/packages/@aws-cdk/aws-s3-deployment/README.md index f8da930bf947e..b0bb1e2d9ebd5 100644 --- a/packages/@aws-cdk/aws-s3-deployment/README.md +++ b/packages/@aws-cdk/aws-s3-deployment/README.md @@ -156,39 +156,15 @@ import * as origins from '@aws-cdk/aws-cloudfront-origins'; const bucket = new s3.Bucket(this, 'Destination'); -// Option 1 (Experimental): Handles buckets whether or not they are configured for website hosting. +// Handles buckets whether or not they are configured for website hosting. const distribution = new cloudfront.Distribution(this, 'Distribution', { defaultBehavior: { origin: new origins.S3Origin(bucket) }, }); -// Option 2 (Stable): Use this if the bucket has website hosting enabled. -const distribution_for_website_bucket = new cloudfront.CloudFrontWebDistribution(this, 'DistributionForWebBucket', { - originConfigs: [ - { - customOriginSource: { - domainName: bucket.bucketWebsiteDomainName, - }, - behaviors : [ {isDefaultBehavior: true}] - } - ] -}); - -// Option 3 (Stable): Use this version if the bucket does not have website hosting enabled. -const distribution_for_bucket = new cloudfront.CloudFrontWebDistribution(this, 'DistributionForBucket', { - originConfigs: [ - { - s3OriginSource: { - s3BucketSource: bucket - }, - behaviors : [ {isDefaultBehavior: true}] - } - ] -}); - new s3deploy.BucketDeployment(this, 'DeployWithInvalidation', { sources: [s3deploy.Source.asset('./website-dist')], destinationBucket: bucket, - distribution, // or distribution_for_website_bucket or distribution_for_bucket + distribution, distributionPaths: ['/images/*.png'], }); ``` @@ -229,5 +205,4 @@ might be tricky to build on Windows. ## Roadmap - - [ ] Support "progressive" mode (no `--delete`) ([#953](https://github.com/aws/aws-cdk/issues/953)) - [ ] Support "blue/green" deployments ([#954](https://github.com/aws/aws-cdk/issues/954)) diff --git a/packages/@aws-cdk/aws-s3-deployment/package.json b/packages/@aws-cdk/aws-s3-deployment/package.json index cf9089e39d715..fadd40d30149a 100644 --- a/packages/@aws-cdk/aws-s3-deployment/package.json +++ b/packages/@aws-cdk/aws-s3-deployment/package.json @@ -143,5 +143,8 @@ }, "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-cloudfront.expected.json b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-cloudfront.expected.json index fa5e26b9d57e9..76f906941f2bd 100644 --- a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-cloudfront.expected.json +++ b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-cloudfront.expected.json @@ -244,7 +244,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -390,4 +390,4 @@ "Description": "Artifact hash for asset \"fc4481abf279255619ff7418faa5d24456fef3432ea0da59c95542578ff0222e\"" } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment.expected.json b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment.expected.json index 92d6c5bb8514b..877298773816b 100644 --- a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment.expected.json +++ b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment.expected.json @@ -195,7 +195,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -228,7 +228,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -261,7 +261,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -725,4 +725,4 @@ "Description": "Artifact hash for asset \"fc4481abf279255619ff7418faa5d24456fef3432ea0da59c95542578ff0222e\"" } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-s3-notifications/package.json b/packages/@aws-cdk/aws-s3-notifications/package.json index afa1b27a1c80c..00d38a536ca6a 100644 --- a/packages/@aws-cdk/aws-s3-notifications/package.json +++ b/packages/@aws-cdk/aws-s3-notifications/package.json @@ -100,5 +100,8 @@ "env": { "AWSLINT_BASE_CONSTRUCT": true } + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-s3-notifications/test/queue.test.ts b/packages/@aws-cdk/aws-s3-notifications/test/queue.test.ts index 5e384d2377318..9cc4dad9712c7 100644 --- a/packages/@aws-cdk/aws-s3-notifications/test/queue.test.ts +++ b/packages/@aws-cdk/aws-s3-notifications/test/queue.test.ts @@ -1,4 +1,4 @@ -import { SynthUtils } from '@aws-cdk/assert'; +import { arrayWith, SynthUtils } from '@aws-cdk/assert'; import '@aws-cdk/assert/jest'; import * as s3 from '@aws-cdk/aws-s3'; import * as sqs from '@aws-cdk/aws-sqs'; @@ -77,65 +77,19 @@ test('if the queue is encrypted with a custom kms key, the key resource policy i bucket.addObjectCreatedNotification(new notif.SqsDestination(queue)); - expect(stack).toHaveResource('AWS::KMS::Key', { + expect(stack).toHaveResourceLike('AWS::KMS::Key', { 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:Encrypt', - 'kms:ReEncrypt*', - 'kms:GenerateDataKey*', - ], - Condition: { - ArnLike: { - 'aws:SourceArn': { 'Fn::GetAtt': ['Bucket83908E77', 'Arn'] }, - }, - }, - Effect: 'Allow', - Principal: { - Service: 's3.amazonaws.com', - }, - Resource: '*', + Statement: arrayWith({ + Action: [ + 'kms:GenerateDataKey*', + 'kms:Decrypt', + ], + Effect: 'Allow', + Principal: { + Service: 's3.amazonaws.com', }, - { - Action: [ - 'kms:GenerateDataKey*', - 'kms:Decrypt', - ], - Effect: 'Allow', - Principal: { - Service: 's3.amazonaws.com', - }, - Resource: '*', - }, - ], - Version: '2012-10-17', + Resource: '*', + }), }, - Description: 'Created by Default/Queue', }); }); diff --git a/packages/@aws-cdk/aws-s3-notifications/test/sqs/integ.bucket-notifications.expected.json b/packages/@aws-cdk/aws-s3-notifications/test/sqs/integ.bucket-notifications.expected.json index afcc652c50f99..0da38cd2026c5 100644 --- a/packages/@aws-cdk/aws-s3-notifications/test/sqs/integ.bucket-notifications.expected.json +++ b/packages/@aws-cdk/aws-s3-notifications/test/sqs/integ.bucket-notifications.expected.json @@ -53,7 +53,9 @@ ] }, "MyQueueE6CA6235": { - "Type": "AWS::SQS::Queue" + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "MyQueuePolicy6BBEDDAC": { "Type": "AWS::SQS::QueuePolicy", @@ -252,23 +254,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { @@ -341,7 +327,9 @@ "Arn" ] } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "EncryptedQueuePolicy8AEB1708": { "Type": "AWS::SQS::QueuePolicy", diff --git a/packages/@aws-cdk/aws-s3/lib/bucket.ts b/packages/@aws-cdk/aws-s3/lib/bucket.ts index 859f774565a93..4323f47daf575 100644 --- a/packages/@aws-cdk/aws-s3/lib/bucket.ts +++ b/packages/@aws-cdk/aws-s3/lib/bucket.ts @@ -1161,8 +1161,8 @@ export interface BucketProps { * * @see https://docs.aws.amazon.com/AmazonS3/latest/dev/access-control-block-public-access.html * - * @default false New buckets and objects don't allow public access, but users can modify bucket - * policies or object permissions to allow public access. + * + * @default - CloudFormation defaults will apply. New buckets and objects don't allow public access, but users can modify bucket policies or object permissions to allow public access */ readonly blockPublicAccess?: BlockPublicAccess; diff --git a/packages/@aws-cdk/aws-s3/package.json b/packages/@aws-cdk/aws-s3/package.json index b91cd909efb56..23d3345e1bfd5 100644 --- a/packages/@aws-cdk/aws-s3/package.json +++ b/packages/@aws-cdk/aws-s3/package.json @@ -151,5 +151,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-s3/test/bucket.test.ts b/packages/@aws-cdk/aws-s3/test/bucket.test.ts index 51b2874311af8..0fb1bffa3726f 100644 --- a/packages/@aws-cdk/aws-s3/test/bucket.test.ts +++ b/packages/@aws-cdk/aws-s3/test/bucket.test.ts @@ -2405,7 +2405,5 @@ describe('bucket', () => { expect(() => new s3.Bucket(stack, 'MyBucket', { autoDeleteObjects: true, })).toThrow(/Cannot use \'autoDeleteObjects\' property on a bucket without setting removal policy to \'DESTROY\'/); - - }); -}); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-s3/test/integ.bucket-grantdelete-kms.expected.json b/packages/@aws-cdk/aws-s3/test/integ.bucket-grantdelete-kms.expected.json index 08c82035e2188..bf2f24e021308 100644 --- a/packages/@aws-cdk/aws-s3/test/integ.bucket-grantdelete-kms.expected.json +++ b/packages/@aws-cdk/aws-s3/test/integ.bucket-grantdelete-kms.expected.json @@ -6,23 +6,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { diff --git a/packages/@aws-cdk/aws-s3/test/integ.bucket-sharing.lit.expected.json b/packages/@aws-cdk/aws-s3/test/integ.bucket-sharing.lit.expected.json index 04e17f51774e9..4197e9179b4ff 100644 --- a/packages/@aws-cdk/aws-s3/test/integ.bucket-sharing.lit.expected.json +++ b/packages/@aws-cdk/aws-s3/test/integ.bucket-sharing.lit.expected.json @@ -37,7 +37,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -71,4 +71,4 @@ } } } -] \ No newline at end of file +] diff --git a/packages/@aws-cdk/aws-s3/test/integ.bucket.expected.json b/packages/@aws-cdk/aws-s3/test/integ.bucket.expected.json index 1919b71360c2d..58cd3c5760961 100644 --- a/packages/@aws-cdk/aws-s3/test/integ.bucket.expected.json +++ b/packages/@aws-cdk/aws-s3/test/integ.bucket.expected.json @@ -6,23 +6,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { @@ -43,25 +27,6 @@ } }, "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" @@ -123,7 +88,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -208,4 +173,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-sagemaker/package.json b/packages/@aws-cdk/aws-sagemaker/package.json index 60c95684c3e51..532be18efa37d 100644 --- a/packages/@aws-cdk/aws-sagemaker/package.json +++ b/packages/@aws-cdk/aws-sagemaker/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-sam/package.json b/packages/@aws-cdk/aws-sam/package.json index 0faab61b0e3eb..6e76bd0098faf 100644 --- a/packages/@aws-cdk/aws-sam/package.json +++ b/packages/@aws-cdk/aws-sam/package.json @@ -78,7 +78,7 @@ "cfn2ts": "0.0.0", "jest": "^26.6.3", "pkglint": "0.0.0", - "ts-jest": "^26.5.0" + "ts-jest": "^26.5.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", @@ -95,5 +95,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-sam/test/sam.test.ts b/packages/@aws-cdk/aws-sam/test/application.test.ts similarity index 100% rename from packages/@aws-cdk/aws-sam/test/sam.test.ts rename to packages/@aws-cdk/aws-sam/test/application.test.ts diff --git a/packages/@aws-cdk/aws-sam/test/function.test.ts b/packages/@aws-cdk/aws-sam/test/function.test.ts new file mode 100644 index 0000000000000..d8dade625be0e --- /dev/null +++ b/packages/@aws-cdk/aws-sam/test/function.test.ts @@ -0,0 +1,27 @@ +import '@aws-cdk/assert/jest'; +import * as cdk from '@aws-cdk/core'; +import * as sam from '../lib'; + +test("correctly chooses a string array from the type unions of the 'policies' property", () => { + const stack = new cdk.Stack(); + + new sam.CfnFunction(stack, 'MyFunction', { + codeUri: { + bucket: 'my-bucket', + key: 'my-key', + }, + runtime: 'nodejs-12.x', + handler: 'index.handler', + policies: ['AWSLambdaExecute'], + }); + + expect(stack).toHaveResourceLike('AWS::Serverless::Function', { + CodeUri: { + Bucket: 'my-bucket', + Key: 'my-key', + }, + Handler: 'index.handler', + Runtime: 'nodejs-12.x', + Policies: ['AWSLambdaExecute'], + }); +}); diff --git a/packages/@aws-cdk/aws-sdb/package.json b/packages/@aws-cdk/aws-sdb/package.json index 7d7f6d78a4bd6..9c1660f111f4b 100644 --- a/packages/@aws-cdk/aws-sdb/package.json +++ b/packages/@aws-cdk/aws-sdb/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-secretsmanager/package.json b/packages/@aws-cdk/aws-secretsmanager/package.json index 2906dd1c3ad99..fbd131bf94e89 100644 --- a/packages/@aws-cdk/aws-secretsmanager/package.json +++ b/packages/@aws-cdk/aws-secretsmanager/package.json @@ -127,5 +127,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-secretsmanager/test/integ.secret-name-parsed.ts b/packages/@aws-cdk/aws-secretsmanager/test/integ.secret-name-parsed.ts index 49dde40e8b9f4..2d245cc6e3e01 100644 --- a/packages/@aws-cdk/aws-secretsmanager/test/integ.secret-name-parsed.ts +++ b/packages/@aws-cdk/aws-secretsmanager/test/integ.secret-name-parsed.ts @@ -39,9 +39,6 @@ class SecretsManagerStack extends cdk.Stack { } const app = new cdk.App({ - context: { - '@aws-cdk/aws-secretsmanager:parseOwnedSecretName': 'true', - }, }); new SecretsManagerStack(app, 'Integ-SecretsManager-ParsedSecretName'); app.synth(); diff --git a/packages/@aws-cdk/aws-securityhub/package.json b/packages/@aws-cdk/aws-securityhub/package.json index a434471266f9b..32dc742b38c9c 100644 --- a/packages/@aws-cdk/aws-securityhub/package.json +++ b/packages/@aws-cdk/aws-securityhub/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-servicecatalog/package.json b/packages/@aws-cdk/aws-servicecatalog/package.json index 93012365276b5..546f615a66693 100644 --- a/packages/@aws-cdk/aws-servicecatalog/package.json +++ b/packages/@aws-cdk/aws-servicecatalog/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-servicecatalogappregistry/package.json b/packages/@aws-cdk/aws-servicecatalogappregistry/package.json index 5e889cf4373ea..8887c8c0682d6 100644 --- a/packages/@aws-cdk/aws-servicecatalogappregistry/package.json +++ b/packages/@aws-cdk/aws-servicecatalogappregistry/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-servicediscovery/package.json b/packages/@aws-cdk/aws-servicediscovery/package.json index b76e7009fd3b0..4af44ea9879e1 100644 --- a/packages/@aws-cdk/aws-servicediscovery/package.json +++ b/packages/@aws-cdk/aws-servicediscovery/package.json @@ -161,5 +161,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-ses-actions/package.json b/packages/@aws-cdk/aws-ses-actions/package.json index 00a789c607b3f..ea141e0c8d37f 100644 --- a/packages/@aws-cdk/aws-ses-actions/package.json +++ b/packages/@aws-cdk/aws-ses-actions/package.json @@ -116,5 +116,8 @@ "env": { "AWSLINT_BASE_CONSTRUCT": true } + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-ses-actions/test/actions.test.ts b/packages/@aws-cdk/aws-ses-actions/test/actions.test.ts index 3a963fcf3f24b..d3268e949b7dc 100644 --- a/packages/@aws-cdk/aws-ses-actions/test/actions.test.ts +++ b/packages/@aws-cdk/aws-ses-actions/test/actions.test.ts @@ -1,4 +1,4 @@ -import { ResourcePart } from '@aws-cdk/assert'; +import { arrayWith, ResourcePart } from '@aws-cdk/assert'; import '@aws-cdk/assert/jest'; import * as kms from '@aws-cdk/aws-kms'; import * as lambda from '@aws-cdk/aws-lambda'; @@ -223,72 +223,30 @@ test('add s3 action', () => { }, }); - expect(stack).toHaveResource('AWS::KMS::Key', { + expect(stack).toHaveResourceLike('AWS::KMS::Key', { 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', - ], - ], - }, + Statement: arrayWith({ + Action: [ + 'kms:Encrypt', + 'kms:GenerateDataKey', + ], + Condition: { + Null: { + 'kms:EncryptionContext:aws:ses:rule-name': 'false', + 'kms:EncryptionContext:aws:ses:message-id': 'false', }, - Resource: '*', - }, - { - Action: [ - 'kms:Encrypt', - 'kms:GenerateDataKey', - ], - Condition: { - Null: { - 'kms:EncryptionContext:aws:ses:rule-name': 'false', - 'kms:EncryptionContext:aws:ses:message-id': 'false', - }, - StringEquals: { - 'kms:EncryptionContext:aws:ses:source-account': { - Ref: 'AWS::AccountId', - }, + StringEquals: { + 'kms:EncryptionContext:aws:ses:source-account': { + Ref: 'AWS::AccountId', }, }, - Effect: 'Allow', - Principal: { - Service: 'ses.amazonaws.com', - }, - Resource: '*', }, - ], - Version: '2012-10-17', + Effect: 'Allow', + Principal: { + Service: 'ses.amazonaws.com', + }, + Resource: '*', + }), }, }); }); diff --git a/packages/@aws-cdk/aws-ses-actions/test/integ.actions.expected.json b/packages/@aws-cdk/aws-ses-actions/test/integ.actions.expected.json index 2bde038826803..b58b770bcd426 100644 --- a/packages/@aws-cdk/aws-ses-actions/test/integ.actions.expected.json +++ b/packages/@aws-cdk/aws-ses-actions/test/integ.actions.expected.json @@ -121,23 +121,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { diff --git a/packages/@aws-cdk/aws-ses/package.json b/packages/@aws-cdk/aws-ses/package.json index 5a28111cbaaf8..c4fac8762a988 100644 --- a/packages/@aws-cdk/aws-ses/package.json +++ b/packages/@aws-cdk/aws-ses/package.json @@ -112,5 +112,8 @@ }, "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-signer/package.json b/packages/@aws-cdk/aws-signer/package.json index 4d9d5cef26a04..40a8f5872b5b1 100644 --- a/packages/@aws-cdk/aws-signer/package.json +++ b/packages/@aws-cdk/aws-signer/package.json @@ -91,5 +91,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-sns-subscriptions/package.json b/packages/@aws-cdk/aws-sns-subscriptions/package.json index f89258c018931..354b1c386b44e 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/package.json +++ b/packages/@aws-cdk/aws-sns-subscriptions/package.json @@ -99,5 +99,8 @@ "env": { "AWSLINT_BASE_CONSTRUCT": true } + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-sns-subscriptions/test/integ.sns-lambda.expected.json b/packages/@aws-cdk/aws-sns-subscriptions/test/integ.sns-lambda.expected.json index 38367e9204de2..d20fe9bf9a8db 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/test/integ.sns-lambda.expected.json +++ b/packages/@aws-cdk/aws-sns-subscriptions/test/integ.sns-lambda.expected.json @@ -40,13 +40,13 @@ "Code": { "ZipFile": "exports.handler = function handler(event, _context, callback) {\n /* eslint-disable no-console */\n console.log('====================================================');\n console.log(JSON.stringify(event, undefined, 2));\n console.log('====================================================');\n return callback(undefined, event);\n}" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "EchoServiceRoleBE28060B", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs10.x" }, "DependsOn": [ @@ -93,7 +93,9 @@ } }, "DeadLetterQueue9F481546": { - "Type": "AWS::SQS::Queue" + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "DeadLetterQueuePolicyB1FB890C": { "Type": "AWS::SQS::QueuePolicy", @@ -167,13 +169,13 @@ "Code": { "ZipFile": "exports.handler = function handler(event, _context, callback) {\n /* eslint-disable no-console */\n console.log('====================================================');\n console.log(JSON.stringify(event, undefined, 2));\n console.log('====================================================');\n return callback(undefined, event);\n}" }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "FilteredServiceRole16D9DDC1", "Arn" ] }, + "Handler": "index.handler", "Runtime": "nodejs10.x" }, "DependsOn": [ diff --git a/packages/@aws-cdk/aws-sns-subscriptions/test/integ.sns-sqs.lit.expected.json b/packages/@aws-cdk/aws-sns-subscriptions/test/integ.sns-sqs.lit.expected.json index ea6b8345f0469..f9b68ad7da9ca 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/test/integ.sns-sqs.lit.expected.json +++ b/packages/@aws-cdk/aws-sns-subscriptions/test/integ.sns-sqs.lit.expected.json @@ -4,7 +4,9 @@ "Type": "AWS::SNS::Topic" }, "MyQueueE6CA6235": { - "Type": "AWS::SQS::Queue" + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "MyQueuePolicy6BBEDDAC": { "Type": "AWS::SQS::QueuePolicy", @@ -66,8 +68,8 @@ }, "DeadLetterQueue9F481546": { "Type": "AWS::SQS::Queue", - "Properties": { - } + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "DeadLetterQueuePolicyB1FB890C": { "Type": "AWS::SQS::QueuePolicy", diff --git a/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts b/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts index b2da0de8099b3..4bd8646176d08 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts +++ b/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts @@ -82,6 +82,8 @@ test('url subscription with user provided dlq', () => { }, 'DeadLetterQueue9F481546': { 'Type': 'AWS::SQS::Queue', + 'DeletionPolicy': 'Delete', + 'UpdateReplacePolicy': 'Delete', 'Properties': { 'MessageRetentionPeriod': 1209600, 'QueueName': 'MySubscription_DLQ', @@ -248,6 +250,8 @@ test('queue subscription', () => { }, 'MyQueueE6CA6235': { 'Type': 'AWS::SQS::Queue', + 'DeletionPolicy': 'Delete', + 'UpdateReplacePolicy': 'Delete', }, 'MyQueuePolicy6BBEDDAC': { 'Type': 'AWS::SQS::QueuePolicy', @@ -325,6 +329,8 @@ test('queue subscription with user provided dlq', () => { }, 'MyQueueE6CA6235': { 'Type': 'AWS::SQS::Queue', + 'DeletionPolicy': 'Delete', + 'UpdateReplacePolicy': 'Delete', }, 'MyQueuePolicy6BBEDDAC': { 'Type': 'AWS::SQS::QueuePolicy', @@ -386,6 +392,8 @@ test('queue subscription with user provided dlq', () => { }, 'DeadLetterQueue9F481546': { 'Type': 'AWS::SQS::Queue', + 'DeletionPolicy': 'Delete', + 'UpdateReplacePolicy': 'Delete', 'Properties': { 'MessageRetentionPeriod': 1209600, 'QueueName': 'MySubscription_DLQ', @@ -745,6 +753,8 @@ test('multiple subscriptions', () => { }, 'MyQueueE6CA6235': { 'Type': 'AWS::SQS::Queue', + 'DeletionPolicy': 'Delete', + 'UpdateReplacePolicy': 'Delete', }, 'MyQueuePolicy6BBEDDAC': { 'Type': 'AWS::SQS::QueuePolicy', diff --git a/packages/@aws-cdk/aws-sns/package.json b/packages/@aws-cdk/aws-sns/package.json index dd9486fc85b0e..4b60a53f24c35 100644 --- a/packages/@aws-cdk/aws-sns/package.json +++ b/packages/@aws-cdk/aws-sns/package.json @@ -114,5 +114,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-sns/test/integ.sns.expected.json b/packages/@aws-cdk/aws-sns/test/integ.sns.expected.json index 8ef28440f5185..86cfd60faf932 100644 --- a/packages/@aws-cdk/aws-sns/test/integ.sns.expected.json +++ b/packages/@aws-cdk/aws-sns/test/integ.sns.expected.json @@ -6,23 +6,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { @@ -65,4 +49,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-sqs/lib/queue.ts b/packages/@aws-cdk/aws-sqs/lib/queue.ts index 63b466de84421..1c3067c7a70d6 100644 --- a/packages/@aws-cdk/aws-sqs/lib/queue.ts +++ b/packages/@aws-cdk/aws-sqs/lib/queue.ts @@ -1,5 +1,5 @@ import * as kms from '@aws-cdk/aws-kms'; -import { Duration, Stack, Token } from '@aws-cdk/core'; +import { Duration, RemovalPolicy, Stack, Token } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { IQueue, QueueAttributes, QueueBase } from './queue-base'; import { CfnQueue } from './sqs.generated'; @@ -137,6 +137,18 @@ export interface QueueProps { * @default false */ readonly contentBasedDeduplication?: boolean; + + /** + * Policy to apply when the user pool is removed from the stack + * + * Even though queues are technically stateful, their contents are transient and it + * is common to add and remove Queues while rearchitecting your application. The + * default is therefore `DESTROY`. Change it to `RETAIN` if the messages are so + * valuable that accidentally losing them would be unacceptable. + * + * @default RemovalPolicy.DESTROY + */ + readonly removalPolicy?: RemovalPolicy; } /** @@ -273,6 +285,7 @@ export class Queue extends QueueBase { receiveMessageWaitTimeSeconds: props.receiveMessageWaitTime && props.receiveMessageWaitTime.toSeconds(), visibilityTimeout: props.visibilityTimeout && props.visibilityTimeout.toSeconds(), }); + queue.applyRemovalPolicy(props.removalPolicy ?? RemovalPolicy.DESTROY); this.queueArn = this.getResourceArnAttribute(queue.attrArn, { service: 'sqs', diff --git a/packages/@aws-cdk/aws-sqs/package.json b/packages/@aws-cdk/aws-sqs/package.json index 87c9aa9ffebff..7b610c64bb71c 100644 --- a/packages/@aws-cdk/aws-sqs/package.json +++ b/packages/@aws-cdk/aws-sqs/package.json @@ -73,7 +73,7 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@types/nodeunit": "^0.0.31", - "aws-sdk": "^2.830.0", + "aws-sdk": "^2.848.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -107,5 +107,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-sqs/test/integ.sqs.expected.json b/packages/@aws-cdk/aws-sqs/test/integ.sqs.expected.json index 4ad0f8e0c8b34..c310198cfcae6 100644 --- a/packages/@aws-cdk/aws-sqs/test/integ.sqs.expected.json +++ b/packages/@aws-cdk/aws-sqs/test/integ.sqs.expected.json @@ -1,7 +1,9 @@ { "Resources": { "DeadLetterQueue9F481546": { - "Type": "AWS::SQS::Queue" + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "Queue4A7E3555": { "Type": "AWS::SQS::Queue", @@ -16,7 +18,9 @@ }, "maxReceiveCount": 5 } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "EncryptionKey1B843E66": { "Type": "AWS::KMS::Key", @@ -24,23 +28,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { @@ -61,19 +49,6 @@ } }, "Resource": "*" - }, - { - "Action": "kms:Decrypt", - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "Role1ABCC5F0", - "Arn" - ] - } - }, - "Resource": "*" } ], "Version": "2012-10-17" @@ -92,7 +67,9 @@ "Arn" ] } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "Role1ABCC5F0": { "Type": "AWS::IAM::Role", @@ -208,4 +185,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-sqs/test/test.sqs.ts b/packages/@aws-cdk/aws-sqs/test/test.sqs.ts index 87e38c2dcf2ca..ea0233578c5a6 100644 --- a/packages/@aws-cdk/aws-sqs/test/test.sqs.ts +++ b/packages/@aws-cdk/aws-sqs/test/test.sqs.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource, ResourcePart } from '@aws-cdk/assert'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import { CfnParameter, Duration, Stack, App } from '@aws-cdk/core'; @@ -18,10 +18,16 @@ export = { 'Resources': { 'Queue4A7E3555': { 'Type': 'AWS::SQS::Queue', + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', }, }, }); + expect(stack).to(haveResource('AWS::SQS::Queue', { + DeletionPolicy: 'Delete', + }, ResourcePart.CompleteDefinition)); + test.done(); }, 'with a dead letter queue'(test: Test) { @@ -33,6 +39,8 @@ export = { 'Resources': { 'DLQ581697C4': { 'Type': 'AWS::SQS::Queue', + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', }, 'Queue4A7E3555': { 'Type': 'AWS::SQS::Queue', @@ -47,6 +55,8 @@ export = { 'maxReceiveCount': 3, }, }, + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', }, }, }); @@ -99,6 +109,8 @@ export = { 'Ref': 'myretentionperiod', }, }, + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', }, }, }); @@ -119,6 +131,8 @@ export = { 'Resources': { 'MyQueueE6CA6235': { 'Type': 'AWS::SQS::Queue', + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', }, 'MyQueuePolicy6BBEDDAC': { 'Type': 'AWS::SQS::QueuePolicy', @@ -311,6 +325,8 @@ export = { 'Properties': { 'KmsMasterKeyId': 'alias/aws/sqs', }, + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', }, }, }); @@ -378,6 +394,8 @@ export = { 'QueueName': 'MyQueue.fifo', 'FifoQueue': true, }, + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', }, }, }); @@ -400,6 +418,8 @@ export = { 'Properties': { 'FifoQueue': true, }, + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', }, }, }); diff --git a/packages/@aws-cdk/aws-ssm/package.json b/packages/@aws-cdk/aws-ssm/package.json index 3345c0368b78d..234d166c9152f 100644 --- a/packages/@aws-cdk/aws-ssm/package.json +++ b/packages/@aws-cdk/aws-ssm/package.json @@ -100,5 +100,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/aws-sso/package.json b/packages/@aws-cdk/aws-sso/package.json index ec332f75b3477..af088e448aff9 100644 --- a/packages/@aws-cdk/aws-sso/package.json +++ b/packages/@aws-cdk/aws-sso/package.json @@ -91,5 +91,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/README.md b/packages/@aws-cdk/aws-stepfunctions-tasks/README.md index 80e1dab5ef73f..e7616028054fd 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/README.md +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/README.md @@ -54,6 +54,8 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aw - [Cancel Step](#cancel-step) - [Modify Instance Fleet](#modify-instance-fleet) - [Modify Instance Group](#modify-instance-group) +- [EKS](#eks) + - [Call](#call) - [Glue](#glue) - [Glue DataBrew](#glue-databrew) - [Lambda](#lambda) @@ -664,6 +666,37 @@ new tasks.EmrModifyInstanceGroupByName(stack, 'Task', { }); ``` +## EKS + +Step Functions supports Amazon EKS through the service integration pattern. +The service integration APIs correspond to Amazon EKS APIs. + +[Read more](https://docs.aws.amazon.com/step-functions/latest/dg/connect-eks.html) about the differences when using these service integrations. + +### Call + +Read and write Kubernetes resource objects via a Kubernetes API endpoint. +Corresponds to the [`call`](https://docs.aws.amazon.com/step-functions/latest/dg/connect-eks.html) API in Step Functions Connector. + +The following code snippet includes a Task state that uses eks:call to list the pods. + +```ts +import * as eks from '@aws-cdk/aws-eks'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import * as tasks from '@aws-cdk/aws-stepfunctions-tasks'; + +const myEksCluster = new eks.Cluster(this, 'my sample cluster', { + version: eks.KubernetesVersion.V1_18, + clusterName: 'myEksCluster', + }); + +new tasks.EksCall(stack, 'Call a EKS Endpoint', { + cluster: myEksCluster, + httpMethod: MethodType.GET, + httpPath: '/api/v1/namespaces/default/pods', +}); +``` + ## Glue Step Functions supports [AWS Glue](https://docs.aws.amazon.com/step-functions/latest/dg/connect-glue.html) through the service integration pattern. @@ -811,7 +844,7 @@ Step Functions supports [AWS SageMaker](https://docs.aws.amazon.com/step-functio You can call the [`CreateTrainingJob`](https://docs.aws.amazon.com/sagemaker/latest/dg/API_CreateTrainingJob.html) API from a `Task` state. ```ts -new sfn.SagemakerTrainTask(this, 'TrainSagemaker', { +new sfn.SageMakerCreateTrainingJob(this, 'TrainSagemaker', { trainingJobName: sfn.JsonPath.stringAt('$.JobName'), role, algorithmSpecification: { @@ -846,7 +879,7 @@ new sfn.SagemakerTrainTask(this, 'TrainSagemaker', { You can call the [`CreateTransformJob`](https://docs.aws.amazon.com/sagemaker/latest/dg/API_CreateTransformJob.html) API from a `Task` state. ```ts -new sfn.SagemakerTransformTask(this, 'Batch Inference', { +new sfn.SageMakerCreateTransformJob(this, 'Batch Inference', { transformJobName: 'MyTransformJob', modelName: 'MyModelName', modelClientOptions: { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/eks/call.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/eks/call.ts new file mode 100644 index 0000000000000..8cbf3fcca5886 --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/eks/call.ts @@ -0,0 +1,137 @@ +import * as eks from '@aws-cdk/aws-eks'; +import * as iam from '@aws-cdk/aws-iam'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import { Construct } from 'constructs'; +import { integrationResourceArn, validatePatternSupported } from '../private/task-utils'; + +/** + * Properties for calling a EKS endpoint with EksCall + * @experimental + */ +export interface EksCallProps extends sfn.TaskStateBaseProps { + + /** + * The EKS cluster + */ + readonly cluster: eks.ICluster; + + /** + * HTTP method ("GET", "POST", "PUT", ...) part of HTTP request + */ + readonly httpMethod: HttpMethods; + + /** + * HTTP path of the Kubernetes REST API operation + * For example: /api/v1/namespaces/default/pods + */ + readonly httpPath: string; + + /** + * Query Parameters part of HTTP request + * @default - no query parameters + */ + readonly queryParameters?: { [key: string]: string[] }; + + /** + * Request body part of HTTP request + * @default - No request body + */ + readonly requestBody?: sfn.TaskInput; +} + +/** + * Call a EKS endpoint as a Task + * + * @see https://docs.aws.amazon.com/step-functions/latest/dg/connect-eks.html + * @experimental + */ +export class EksCall extends sfn.TaskStateBase { + + private static readonly SUPPORTED_INTEGRATION_PATTERNS: sfn.IntegrationPattern[] = [ + sfn.IntegrationPattern.REQUEST_RESPONSE, + ]; + + /** No policies are required due to eks:call is an Http service integration and does not call and EKS API directly + * @see https://docs.aws.amazon.com/step-functions/latest/dg/connect-eks.html#connect-eks-permissions + */ + protected readonly taskMetrics?: sfn.TaskMetricsConfig; + protected readonly taskPolicies?: iam.PolicyStatement[]; + + private readonly integrationPattern: sfn.IntegrationPattern; + + private readonly clusterEndpoint: string; + private readonly clusterCertificateAuthorityData: string; + + constructor(scope: Construct, id: string, private readonly props: EksCallProps) { + super(scope, id, props); + this.integrationPattern = props.integrationPattern ?? sfn.IntegrationPattern.REQUEST_RESPONSE; + + validatePatternSupported(this.integrationPattern, EksCall.SUPPORTED_INTEGRATION_PATTERNS); + + try { + this.clusterEndpoint = this.props.cluster.clusterEndpoint; + } catch (e) { + throw new Error('The "clusterEndpoint" property must be specified when using an imported Cluster.'); + } + + try { + this.clusterCertificateAuthorityData = this.props.cluster.clusterCertificateAuthorityData; + } catch (e) { + throw new Error('The "clusterCertificateAuthorityData" property must be specified when using an imported Cluster.'); + } + } + + /** + * Provides the EKS Call service integration task configuration + * @internal + */ + protected _renderTask(): any { + return { + Resource: integrationResourceArn('eks', 'call', this.integrationPattern), + Parameters: sfn.FieldUtils.renderObject({ + ClusterName: this.props.cluster.clusterName, + CertificateAuthority: this.clusterCertificateAuthorityData, + Endpoint: this.clusterEndpoint, + Method: this.props.httpMethod, + Path: this.props.httpPath, + QueryParameters: this.props.queryParameters, + RequestBody: this.props.requestBody?.value, + }), + }; + } +} + +/** + * Method type of a EKS call + */ +export enum HttpMethods { + /** + * Retrieve data from a server at the specified resource + */ + GET = 'GET', + + /** + * Send data to the API endpoint to create or update a resource + */ + POST = 'POST', + + /** + * Send data to the API endpoint to update or create a resource + */ + PUT = 'PUT', + + /** + * Delete the resource at the specified endpoint + */ + DELETE = 'DELETE', + + /** + * Apply partial modifications to the resource + */ + PATCH = 'PATCH', + + /** + * Retrieve data from a server at the specified resource without the response body + */ + HEAD = 'HEAD' +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/index.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/index.ts index 84b790beff216..32e684f6d1adf 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/index.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/index.ts @@ -44,3 +44,4 @@ export * from './athena/stop-query-execution'; export * from './athena/get-query-execution'; export * from './athena/get-query-results'; export * from './databrew/start-job-run'; +export * from './eks/call'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json index 3031ab05dc9a3..a6137f570b1a3 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json @@ -81,6 +81,7 @@ "@aws-cdk/aws-ecr": "0.0.0", "@aws-cdk/aws-ecr-assets": "0.0.0", "@aws-cdk/aws-ecs": "0.0.0", + "@aws-cdk/aws-eks": "0.0.0", "@aws-cdk/aws-glue": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", @@ -103,6 +104,7 @@ "@aws-cdk/aws-ecr": "0.0.0", "@aws-cdk/aws-ecr-assets": "0.0.0", "@aws-cdk/aws-ecs": "0.0.0", + "@aws-cdk/aws-eks": "0.0.0", "@aws-cdk/aws-glue": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", @@ -127,5 +129,8 @@ "env": { "AWSLINT_BASE_CONSTRUCT": true } + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/call.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/call.test.ts new file mode 100644 index 0000000000000..fd7c9f7cb0dd7 --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/call.test.ts @@ -0,0 +1,234 @@ +import * as eks from '@aws-cdk/aws-eks'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import { Stack } from '@aws-cdk/core'; +import { EksCall, HttpMethods } from '../../lib/eks/call'; + +let stack: Stack; +let cluster: eks.Cluster; + +beforeEach(() => { + //GIVEN + stack = new Stack(); + cluster = new eks.Cluster(stack, 'Cluster', { + version: eks.KubernetesVersion.V1_18, + clusterName: 'eksCluster', + }); +}); + +test('Call an EKS endpoint', () => { + // WHEN + const task = new EksCall(stack, 'Call', { + cluster: cluster, + httpMethod: HttpMethods.GET, + httpPath: 'path', + requestBody: sfn.TaskInput.fromObject({ + Body: 'requestBody', + }), + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toEqual({ + Type: 'Task', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:::eks:call', + ], + ], + }, + End: true, + Parameters: { + ClusterName: { + Ref: 'Cluster9EE0221C', + }, + CertificateAuthority: { + 'Fn::GetAtt': [ + 'Cluster9EE0221C', + 'CertificateAuthorityData', + ], + }, + Endpoint: { + 'Fn::GetAtt': [ + 'Cluster9EE0221C', + 'Endpoint', + ], + }, + Method: 'GET', + Path: 'path', + RequestBody: { + Body: 'requestBody', + }, + }, + }); +}); + +test('Call an EKS endpoint with requestBody as a string', () => { + // WHEN + const task = new EksCall(stack, 'Call', { + cluster: cluster, + httpMethod: HttpMethods.GET, + httpPath: 'path', + requestBody: sfn.TaskInput.fromText('requestBody'), + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toEqual({ + Type: 'Task', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:::eks:call', + ], + ], + }, + End: true, + Parameters: { + ClusterName: { + Ref: 'Cluster9EE0221C', + }, + CertificateAuthority: { + 'Fn::GetAtt': [ + 'Cluster9EE0221C', + 'CertificateAuthorityData', + ], + }, + Endpoint: { + 'Fn::GetAtt': [ + 'Cluster9EE0221C', + 'Endpoint', + ], + }, + Method: 'GET', + Path: 'path', + RequestBody: 'requestBody', + }, + }); +}); + +test('Call an EKS endpoint with requestBody supply through path', () => { + // WHEN + const task = new EksCall(stack, 'Call', { + cluster: cluster, + httpMethod: HttpMethods.GET, + httpPath: 'path', + requestBody: sfn.TaskInput.fromJsonPathAt('$.Request.Body'), + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toEqual({ + Type: 'Task', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:::eks:call', + ], + ], + }, + End: true, + Parameters: { + 'ClusterName': { + Ref: 'Cluster9EE0221C', + }, + 'CertificateAuthority': { + 'Fn::GetAtt': [ + 'Cluster9EE0221C', + 'CertificateAuthorityData', + ], + }, + 'Endpoint': { + 'Fn::GetAtt': [ + 'Cluster9EE0221C', + 'Endpoint', + ], + }, + 'Method': 'GET', + 'Path': 'path', + 'RequestBody.$': '$.Request.Body', + }, + }); +}); + +test('Task throws if RUN_JOB is supplied as service integration pattern', () => { + expect(() => { + new EksCall(stack, 'Call', { + cluster: cluster, + httpMethod: HttpMethods.GET, + httpPath: 'path', + requestBody: sfn.TaskInput.fromObject({ + RequestBody: 'requestBody', + }), + integrationPattern: sfn.IntegrationPattern.RUN_JOB, + }); + }).toThrow( + /Unsupported service integration pattern. Supported Patterns: REQUEST_RESPONSE. Received: RUN_JOB/, + ); +}); + +test('Task throws if WAIT_FOR_TASK_TOKEN is supplied as service integration pattern', () => { + expect(() => { + new EksCall(stack, 'Call', { + cluster: cluster, + httpMethod: HttpMethods.GET, + httpPath: 'path', + requestBody: sfn.TaskInput.fromObject({ + RequestBody: 'requestBody', + }), + integrationPattern: sfn.IntegrationPattern.WAIT_FOR_TASK_TOKEN, + }); + }).toThrow( + /Unsupported service integration pattern. Supported Patterns: REQUEST_RESPONSE. Received: WAIT_FOR_TASK_TOKEN/, + ); +}); + +test('Task throws if cluster supplied does not have clusterEndpoint configured', () => { + const importedCluster = eks.Cluster.fromClusterAttributes(stack, 'InvalidCluster', { + clusterName: 'importedCluster', + clusterCertificateAuthorityData: 'clusterCertificateAuthorityData', + }); + expect(() => { + new EksCall(stack, 'Call', { + cluster: importedCluster, + httpMethod: HttpMethods.GET, + httpPath: 'path', + requestBody: sfn.TaskInput.fromObject({ + RequestBody: 'requestBody', + }), + }); + }).toThrow( + /The "clusterEndpoint" property must be specified when using an imported Cluster./, + ); +}); + +test('Task throws if cluster supplied does not have clusterCertificateAuthorityData configured', () => { + const importedCluster = eks.Cluster.fromClusterAttributes(stack, 'InvalidCluster', { + clusterName: 'importedCluster', + clusterEndpoint: 'clusterEndpoint', + }); + expect(() => { + new EksCall(stack, 'Call', { + cluster: importedCluster, + httpMethod: HttpMethods.GET, + httpPath: 'path', + requestBody: sfn.TaskInput.fromObject({ + RequestBody: 'requestBody', + }), + }); + }).toThrow( + /The "clusterCertificateAuthorityData" property must be specified when using an imported Cluster./, + ); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.expected.json new file mode 100644 index 0000000000000..23ad4160b9f7b --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.expected.json @@ -0,0 +1,1580 @@ +{ + "Resources": { + "EksClusterDefaultVpcB24550B2": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc" + } + ] + } + }, + "EksClusterDefaultVpcPublicSubnet1SubnetCB1D1047": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/19", + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PublicSubnet1" + } + ] + } + }, + "EksClusterDefaultVpcPublicSubnet1RouteTable163DE10A": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PublicSubnet1" + } + ] + } + }, + "EksClusterDefaultVpcPublicSubnet1RouteTableAssociation36D085C2": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "EksClusterDefaultVpcPublicSubnet1RouteTable163DE10A" + }, + "SubnetId": { + "Ref": "EksClusterDefaultVpcPublicSubnet1SubnetCB1D1047" + } + } + }, + "EksClusterDefaultVpcPublicSubnet1DefaultRouteCE5F6EF3": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "EksClusterDefaultVpcPublicSubnet1RouteTable163DE10A" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "EksClusterDefaultVpcIGWCA6A3220" + } + }, + "DependsOn": [ + "EksClusterDefaultVpcVPCGW0E4A5673" + ] + }, + "EksClusterDefaultVpcPublicSubnet1EIPF53713C9": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PublicSubnet1" + } + ] + } + }, + "EksClusterDefaultVpcPublicSubnet1NATGateway548C2CDF": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "EksClusterDefaultVpcPublicSubnet1EIPF53713C9", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "EksClusterDefaultVpcPublicSubnet1SubnetCB1D1047" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PublicSubnet1" + } + ] + } + }, + "EksClusterDefaultVpcPublicSubnet2SubnetA8FE675D": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.32.0/19", + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PublicSubnet2" + } + ] + } + }, + "EksClusterDefaultVpcPublicSubnet2RouteTable1027E4DE": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PublicSubnet2" + } + ] + } + }, + "EksClusterDefaultVpcPublicSubnet2RouteTableAssociation39E2ABB3": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "EksClusterDefaultVpcPublicSubnet2RouteTable1027E4DE" + }, + "SubnetId": { + "Ref": "EksClusterDefaultVpcPublicSubnet2SubnetA8FE675D" + } + } + }, + "EksClusterDefaultVpcPublicSubnet2DefaultRoute8B910E5C": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "EksClusterDefaultVpcPublicSubnet2RouteTable1027E4DE" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "EksClusterDefaultVpcIGWCA6A3220" + } + }, + "DependsOn": [ + "EksClusterDefaultVpcVPCGW0E4A5673" + ] + }, + "EksClusterDefaultVpcPublicSubnet2EIP16D41D80": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PublicSubnet2" + } + ] + } + }, + "EksClusterDefaultVpcPublicSubnet2NATGateway869DDCBF": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "EksClusterDefaultVpcPublicSubnet2EIP16D41D80", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "EksClusterDefaultVpcPublicSubnet2SubnetA8FE675D" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PublicSubnet2" + } + ] + } + }, + "EksClusterDefaultVpcPublicSubnet3SubnetA04EFFC1": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/19", + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + }, + "AvailabilityZone": "test-region-1c", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PublicSubnet3" + } + ] + } + }, + "EksClusterDefaultVpcPublicSubnet3RouteTableEBB51B8A": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PublicSubnet3" + } + ] + } + }, + "EksClusterDefaultVpcPublicSubnet3RouteTableAssociationFE466321": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "EksClusterDefaultVpcPublicSubnet3RouteTableEBB51B8A" + }, + "SubnetId": { + "Ref": "EksClusterDefaultVpcPublicSubnet3SubnetA04EFFC1" + } + } + }, + "EksClusterDefaultVpcPublicSubnet3DefaultRoute1F5BE861": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "EksClusterDefaultVpcPublicSubnet3RouteTableEBB51B8A" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "EksClusterDefaultVpcIGWCA6A3220" + } + }, + "DependsOn": [ + "EksClusterDefaultVpcVPCGW0E4A5673" + ] + }, + "EksClusterDefaultVpcPublicSubnet3EIPF8D34EDE": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PublicSubnet3" + } + ] + } + }, + "EksClusterDefaultVpcPublicSubnet3NATGatewayC35C74D3": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "EksClusterDefaultVpcPublicSubnet3EIPF8D34EDE", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "EksClusterDefaultVpcPublicSubnet3SubnetA04EFFC1" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PublicSubnet3" + } + ] + } + }, + "EksClusterDefaultVpcPrivateSubnet1Subnet4D665A2F": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.96.0/19", + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PrivateSubnet1" + } + ] + } + }, + "EksClusterDefaultVpcPrivateSubnet1RouteTable9104CFAB": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PrivateSubnet1" + } + ] + } + }, + "EksClusterDefaultVpcPrivateSubnet1RouteTableAssociationCC31B65B": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "EksClusterDefaultVpcPrivateSubnet1RouteTable9104CFAB" + }, + "SubnetId": { + "Ref": "EksClusterDefaultVpcPrivateSubnet1Subnet4D665A2F" + } + } + }, + "EksClusterDefaultVpcPrivateSubnet1DefaultRoute790DE5CF": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "EksClusterDefaultVpcPrivateSubnet1RouteTable9104CFAB" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "EksClusterDefaultVpcPublicSubnet1NATGateway548C2CDF" + } + } + }, + "EksClusterDefaultVpcPrivateSubnet2Subnet180B8A71": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/19", + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PrivateSubnet2" + } + ] + } + }, + "EksClusterDefaultVpcPrivateSubnet2RouteTable04B34031": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PrivateSubnet2" + } + ] + } + }, + "EksClusterDefaultVpcPrivateSubnet2RouteTableAssociation86243837": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "EksClusterDefaultVpcPrivateSubnet2RouteTable04B34031" + }, + "SubnetId": { + "Ref": "EksClusterDefaultVpcPrivateSubnet2Subnet180B8A71" + } + } + }, + "EksClusterDefaultVpcPrivateSubnet2DefaultRoute99A19B21": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "EksClusterDefaultVpcPrivateSubnet2RouteTable04B34031" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "EksClusterDefaultVpcPublicSubnet2NATGateway869DDCBF" + } + } + }, + "EksClusterDefaultVpcPrivateSubnet3Subnet6C4BFC07": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.160.0/19", + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + }, + "AvailabilityZone": "test-region-1c", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PrivateSubnet3" + } + ] + } + }, + "EksClusterDefaultVpcPrivateSubnet3RouteTableA8F449F1": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc/PrivateSubnet3" + } + ] + } + }, + "EksClusterDefaultVpcPrivateSubnet3RouteTableAssociationCE2741BE": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "EksClusterDefaultVpcPrivateSubnet3RouteTableA8F449F1" + }, + "SubnetId": { + "Ref": "EksClusterDefaultVpcPrivateSubnet3Subnet6C4BFC07" + } + } + }, + "EksClusterDefaultVpcPrivateSubnet3DefaultRouteDC2E9DE0": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "EksClusterDefaultVpcPrivateSubnet3RouteTableA8F449F1" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "EksClusterDefaultVpcPublicSubnet3NATGatewayC35C74D3" + } + } + }, + "EksClusterDefaultVpcIGWCA6A3220": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-eks-call-integ/EksCluster/DefaultVpc" + } + ] + } + }, + "EksClusterDefaultVpcVPCGW0E4A5673": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + }, + "InternetGatewayId": { + "Ref": "EksClusterDefaultVpcIGWCA6A3220" + } + } + }, + "EksClusterRoleC84B376F": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "eks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/AmazonEKSClusterPolicy" + ] + ] + } + ] + } + }, + "EksClusterControlPlaneSecurityGroup9257A6D0": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "EKS Control Plane Security Group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "EksClusterDefaultVpcB24550B2" + } + } + }, + "EksClusterCreationRole75AABE42": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + }, + "DependsOn": [ + "EksClusterDefaultVpcIGWCA6A3220", + "EksClusterDefaultVpcPrivateSubnet1DefaultRoute790DE5CF", + "EksClusterDefaultVpcPrivateSubnet1RouteTable9104CFAB", + "EksClusterDefaultVpcPrivateSubnet1RouteTableAssociationCC31B65B", + "EksClusterDefaultVpcPrivateSubnet1Subnet4D665A2F", + "EksClusterDefaultVpcPrivateSubnet2DefaultRoute99A19B21", + "EksClusterDefaultVpcPrivateSubnet2RouteTable04B34031", + "EksClusterDefaultVpcPrivateSubnet2RouteTableAssociation86243837", + "EksClusterDefaultVpcPrivateSubnet2Subnet180B8A71", + "EksClusterDefaultVpcPrivateSubnet3DefaultRouteDC2E9DE0", + "EksClusterDefaultVpcPrivateSubnet3RouteTableA8F449F1", + "EksClusterDefaultVpcPrivateSubnet3RouteTableAssociationCE2741BE", + "EksClusterDefaultVpcPrivateSubnet3Subnet6C4BFC07", + "EksClusterDefaultVpcPublicSubnet1DefaultRouteCE5F6EF3", + "EksClusterDefaultVpcPublicSubnet1EIPF53713C9", + "EksClusterDefaultVpcPublicSubnet1NATGateway548C2CDF", + "EksClusterDefaultVpcPublicSubnet1RouteTable163DE10A", + "EksClusterDefaultVpcPublicSubnet1RouteTableAssociation36D085C2", + "EksClusterDefaultVpcPublicSubnet1SubnetCB1D1047", + "EksClusterDefaultVpcPublicSubnet2DefaultRoute8B910E5C", + "EksClusterDefaultVpcPublicSubnet2EIP16D41D80", + "EksClusterDefaultVpcPublicSubnet2NATGateway869DDCBF", + "EksClusterDefaultVpcPublicSubnet2RouteTable1027E4DE", + "EksClusterDefaultVpcPublicSubnet2RouteTableAssociation39E2ABB3", + "EksClusterDefaultVpcPublicSubnet2SubnetA8FE675D", + "EksClusterDefaultVpcPublicSubnet3DefaultRoute1F5BE861", + "EksClusterDefaultVpcPublicSubnet3EIPF8D34EDE", + "EksClusterDefaultVpcPublicSubnet3NATGatewayC35C74D3", + "EksClusterDefaultVpcPublicSubnet3RouteTableEBB51B8A", + "EksClusterDefaultVpcPublicSubnet3RouteTableAssociationFE466321", + "EksClusterDefaultVpcPublicSubnet3SubnetA04EFFC1", + "EksClusterDefaultVpcB24550B2", + "EksClusterDefaultVpcVPCGW0E4A5673" + ] + }, + "EksClusterCreationRoleDefaultPolicy2DFE4D73": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "iam:PassRole", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "EksClusterRoleC84B376F", + "Arn" + ] + } + }, + { + "Action": [ + "eks:CreateCluster", + "eks:DescribeCluster", + "eks:DescribeUpdate", + "eks:DeleteCluster", + "eks:UpdateClusterVersion", + "eks:UpdateClusterConfig", + "eks:CreateFargateProfile", + "eks:TagResource", + "eks:UntagResource" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":eks:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":cluster/eksCluster" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":eks:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":cluster/eksCluster/*" + ] + ] + } + ] + }, + { + "Action": [ + "eks:DescribeFargateProfile", + "eks:DeleteFargateProfile" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":eks:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":fargateprofile/eksCluster/*" + ] + ] + } + }, + { + "Action": [ + "iam:GetRole", + "iam:listAttachedRolePolicies" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "iam:CreateServiceLinkedRole", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ec2:DescribeInstances", + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", + "ec2:DescribeRouteTables", + "ec2:DescribeDhcpOptions", + "ec2:DescribeVpcs" + ], + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "EksClusterCreationRoleDefaultPolicy2DFE4D73", + "Roles": [ + { + "Ref": "EksClusterCreationRole75AABE42" + } + ] + }, + "DependsOn": [ + "EksClusterDefaultVpcIGWCA6A3220", + "EksClusterDefaultVpcPrivateSubnet1DefaultRoute790DE5CF", + "EksClusterDefaultVpcPrivateSubnet1RouteTable9104CFAB", + "EksClusterDefaultVpcPrivateSubnet1RouteTableAssociationCC31B65B", + "EksClusterDefaultVpcPrivateSubnet1Subnet4D665A2F", + "EksClusterDefaultVpcPrivateSubnet2DefaultRoute99A19B21", + "EksClusterDefaultVpcPrivateSubnet2RouteTable04B34031", + "EksClusterDefaultVpcPrivateSubnet2RouteTableAssociation86243837", + "EksClusterDefaultVpcPrivateSubnet2Subnet180B8A71", + "EksClusterDefaultVpcPrivateSubnet3DefaultRouteDC2E9DE0", + "EksClusterDefaultVpcPrivateSubnet3RouteTableA8F449F1", + "EksClusterDefaultVpcPrivateSubnet3RouteTableAssociationCE2741BE", + "EksClusterDefaultVpcPrivateSubnet3Subnet6C4BFC07", + "EksClusterDefaultVpcPublicSubnet1DefaultRouteCE5F6EF3", + "EksClusterDefaultVpcPublicSubnet1EIPF53713C9", + "EksClusterDefaultVpcPublicSubnet1NATGateway548C2CDF", + "EksClusterDefaultVpcPublicSubnet1RouteTable163DE10A", + "EksClusterDefaultVpcPublicSubnet1RouteTableAssociation36D085C2", + "EksClusterDefaultVpcPublicSubnet1SubnetCB1D1047", + "EksClusterDefaultVpcPublicSubnet2DefaultRoute8B910E5C", + "EksClusterDefaultVpcPublicSubnet2EIP16D41D80", + "EksClusterDefaultVpcPublicSubnet2NATGateway869DDCBF", + "EksClusterDefaultVpcPublicSubnet2RouteTable1027E4DE", + "EksClusterDefaultVpcPublicSubnet2RouteTableAssociation39E2ABB3", + "EksClusterDefaultVpcPublicSubnet2SubnetA8FE675D", + "EksClusterDefaultVpcPublicSubnet3DefaultRoute1F5BE861", + "EksClusterDefaultVpcPublicSubnet3EIPF8D34EDE", + "EksClusterDefaultVpcPublicSubnet3NATGatewayC35C74D3", + "EksClusterDefaultVpcPublicSubnet3RouteTableEBB51B8A", + "EksClusterDefaultVpcPublicSubnet3RouteTableAssociationFE466321", + "EksClusterDefaultVpcPublicSubnet3SubnetA04EFFC1", + "EksClusterDefaultVpcB24550B2", + "EksClusterDefaultVpcVPCGW0E4A5673" + ] + }, + "EksClusterFAB68BDB": { + "Type": "Custom::AWSCDK-EKS-Cluster", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "awscdkawseksClusterResourceProviderNestedStackawscdkawseksClusterResourceProviderNestedStackResource9827C454", + "Outputs.awsstepfunctionstasksekscallintegawscdkawseksClusterResourceProviderframeworkonEvent5722A6A8Arn" + ] + }, + "Config": { + "name": "eksCluster", + "version": "1.18", + "roleArn": { + "Fn::GetAtt": [ + "EksClusterRoleC84B376F", + "Arn" + ] + }, + "resourcesVpcConfig": { + "subnetIds": [ + { + "Ref": "EksClusterDefaultVpcPublicSubnet1SubnetCB1D1047" + }, + { + "Ref": "EksClusterDefaultVpcPublicSubnet2SubnetA8FE675D" + }, + { + "Ref": "EksClusterDefaultVpcPublicSubnet3SubnetA04EFFC1" + }, + { + "Ref": "EksClusterDefaultVpcPrivateSubnet1Subnet4D665A2F" + }, + { + "Ref": "EksClusterDefaultVpcPrivateSubnet2Subnet180B8A71" + }, + { + "Ref": "EksClusterDefaultVpcPrivateSubnet3Subnet6C4BFC07" + } + ], + "securityGroupIds": [ + { + "Fn::GetAtt": [ + "EksClusterControlPlaneSecurityGroup9257A6D0", + "GroupId" + ] + } + ], + "endpointPublicAccess": true, + "endpointPrivateAccess": true + } + }, + "AssumeRoleArn": { + "Fn::GetAtt": [ + "EksClusterCreationRole75AABE42", + "Arn" + ] + }, + "AttributesRevision": 2 + }, + "DependsOn": [ + "EksClusterDefaultVpcIGWCA6A3220", + "EksClusterDefaultVpcPrivateSubnet1DefaultRoute790DE5CF", + "EksClusterDefaultVpcPrivateSubnet1RouteTable9104CFAB", + "EksClusterDefaultVpcPrivateSubnet1RouteTableAssociationCC31B65B", + "EksClusterDefaultVpcPrivateSubnet1Subnet4D665A2F", + "EksClusterDefaultVpcPrivateSubnet2DefaultRoute99A19B21", + "EksClusterDefaultVpcPrivateSubnet2RouteTable04B34031", + "EksClusterDefaultVpcPrivateSubnet2RouteTableAssociation86243837", + "EksClusterDefaultVpcPrivateSubnet2Subnet180B8A71", + "EksClusterDefaultVpcPrivateSubnet3DefaultRouteDC2E9DE0", + "EksClusterDefaultVpcPrivateSubnet3RouteTableA8F449F1", + "EksClusterDefaultVpcPrivateSubnet3RouteTableAssociationCE2741BE", + "EksClusterDefaultVpcPrivateSubnet3Subnet6C4BFC07", + "EksClusterDefaultVpcPublicSubnet1DefaultRouteCE5F6EF3", + "EksClusterDefaultVpcPublicSubnet1EIPF53713C9", + "EksClusterDefaultVpcPublicSubnet1NATGateway548C2CDF", + "EksClusterDefaultVpcPublicSubnet1RouteTable163DE10A", + "EksClusterDefaultVpcPublicSubnet1RouteTableAssociation36D085C2", + "EksClusterDefaultVpcPublicSubnet1SubnetCB1D1047", + "EksClusterDefaultVpcPublicSubnet2DefaultRoute8B910E5C", + "EksClusterDefaultVpcPublicSubnet2EIP16D41D80", + "EksClusterDefaultVpcPublicSubnet2NATGateway869DDCBF", + "EksClusterDefaultVpcPublicSubnet2RouteTable1027E4DE", + "EksClusterDefaultVpcPublicSubnet2RouteTableAssociation39E2ABB3", + "EksClusterDefaultVpcPublicSubnet2SubnetA8FE675D", + "EksClusterDefaultVpcPublicSubnet3DefaultRoute1F5BE861", + "EksClusterDefaultVpcPublicSubnet3EIPF8D34EDE", + "EksClusterDefaultVpcPublicSubnet3NATGatewayC35C74D3", + "EksClusterDefaultVpcPublicSubnet3RouteTableEBB51B8A", + "EksClusterDefaultVpcPublicSubnet3RouteTableAssociationFE466321", + "EksClusterDefaultVpcPublicSubnet3SubnetA04EFFC1", + "EksClusterDefaultVpcB24550B2", + "EksClusterDefaultVpcVPCGW0E4A5673", + "EksClusterCreationRoleDefaultPolicy2DFE4D73", + "EksClusterCreationRole75AABE42" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "EksClusterKubectlReadyBarrier502B0E83": { + "Type": "AWS::SSM::Parameter", + "Properties": { + "Type": "String", + "Value": "aws:cdk:eks:kubectl-ready" + }, + "DependsOn": [ + "EksClusterCreationRoleDefaultPolicy2DFE4D73", + "EksClusterCreationRole75AABE42", + "EksClusterFAB68BDB" + ] + }, + "EksClusterMastersRole3F49FAC3": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "EksClusterAwsAuthmanifest4F460A9B": { + "Type": "Custom::AWSCDK-EKS-KubernetesResource", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "awscdkawseksKubectlProviderNestedStackawscdkawseksKubectlProviderNestedStackResourceA7AEBA6B", + "Outputs.awsstepfunctionstasksekscallintegawscdkawseksKubectlProviderframeworkonEventAF076895Arn" + ] + }, + "Manifest": { + "Fn::Join": [ + "", + [ + "[{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"aws-auth\",\"namespace\":\"kube-system\",\"labels\":{\"aws.cdk.eks/prune-c8f58087a1a3e6c10f65d847befda9c1aa2145a8fc\":\"\"}},\"data\":{\"mapRoles\":\"[{\\\"rolearn\\\":\\\"", + { + "Fn::GetAtt": [ + "EksClusterMastersRole3F49FAC3", + "Arn" + ] + }, + "\\\",\\\"username\\\":\\\"", + { + "Fn::GetAtt": [ + "EksClusterMastersRole3F49FAC3", + "Arn" + ] + }, + "\\\",\\\"groups\\\":[\\\"system:masters\\\"]},{\\\"rolearn\\\":\\\"", + { + "Fn::GetAtt": [ + "EksClusterNodegroupDefaultCapacityNodeGroupRole70D09CEC", + "Arn" + ] + }, + "\\\",\\\"username\\\":\\\"system:node:{{EC2PrivateDNSName}}\\\",\\\"groups\\\":[\\\"system:bootstrappers\\\",\\\"system:nodes\\\"]},{\\\"rolearn\\\":\\\"", + { + "Fn::GetAtt": [ + "Role1ABCC5F0", + "Arn" + ] + }, + "\\\",\\\"username\\\":\\\"", + { + "Fn::GetAtt": [ + "Role1ABCC5F0", + "Arn" + ] + }, + "\\\",\\\"groups\\\":[\\\"system:masters\\\"]}]\",\"mapUsers\":\"[]\",\"mapAccounts\":\"[]\"}}]" + ] + ] + }, + "ClusterName": { + "Ref": "EksClusterFAB68BDB" + }, + "RoleArn": { + "Fn::GetAtt": [ + "EksClusterCreationRole75AABE42", + "Arn" + ] + }, + "PruneLabel": "aws.cdk.eks/prune-c8f58087a1a3e6c10f65d847befda9c1aa2145a8fc", + "Overwrite": true + }, + "DependsOn": [ + "EksClusterKubectlReadyBarrier502B0E83" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "EksClusterNodegroupDefaultCapacityNodeGroupRole70D09CEC": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ec2.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/AmazonEKSWorkerNodePolicy" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/AmazonEKS_CNI_Policy" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" + ] + ] + } + ] + } + }, + "EksClusterNodegroupDefaultCapacityA81E70F9": { + "Type": "AWS::EKS::Nodegroup", + "Properties": { + "ClusterName": { + "Ref": "EksClusterFAB68BDB" + }, + "NodeRole": { + "Fn::GetAtt": [ + "EksClusterNodegroupDefaultCapacityNodeGroupRole70D09CEC", + "Arn" + ] + }, + "Subnets": [ + { + "Ref": "EksClusterDefaultVpcPrivateSubnet1Subnet4D665A2F" + }, + { + "Ref": "EksClusterDefaultVpcPrivateSubnet2Subnet180B8A71" + }, + { + "Ref": "EksClusterDefaultVpcPrivateSubnet3Subnet6C4BFC07" + } + ], + "AmiType": "AL2_x86_64", + "ForceUpdateEnabled": true, + "InstanceTypes": [ + "m5.large" + ], + "ScalingConfig": { + "DesiredSize": 2, + "MaxSize": 2, + "MinSize": 2 + } + } + }, + "awscdkawseksClusterResourceProviderNestedStackawscdkawseksClusterResourceProviderNestedStackResource9827C454": { + "Type": "AWS::CloudFormation::Stack", + "Properties": { + "TemplateURL": { + "Fn::Join": [ + "", + [ + "https://s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "AssetParameters3aee2b76026cd725af3b14456bf03061e83d56cce0e0354c7c8e88ee1150e527S3Bucket7ED14FA7" + }, + "/", + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters3aee2b76026cd725af3b14456bf03061e83d56cce0e0354c7c8e88ee1150e527S3VersionKeyF4EF0775" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters3aee2b76026cd725af3b14456bf03061e83d56cce0e0354c7c8e88ee1150e527S3VersionKeyF4EF0775" + } + ] + } + ] + } + ] + ] + }, + "Parameters": { + "referencetoawsstepfunctionstasksekscallintegEksClusterCreationRole00B486C4Arn": { + "Fn::GetAtt": [ + "EksClusterCreationRole75AABE42", + "Arn" + ] + }, + "referencetoawsstepfunctionstasksekscallintegAssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket61AA45E5Ref": { + "Ref": "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket14D204F9" + }, + "referencetoawsstepfunctionstasksekscallintegAssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKey48ACDBCFRef": { + "Ref": "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyDE8A2F1F" + }, + "referencetoawsstepfunctionstasksekscallintegAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketCF9FB24DRef": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + }, + "referencetoawsstepfunctionstasksekscallintegAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey4B465A75Ref": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + } + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "awscdkawseksKubectlProviderNestedStackawscdkawseksKubectlProviderNestedStackResourceA7AEBA6B": { + "Type": "AWS::CloudFormation::Stack", + "Properties": { + "TemplateURL": { + "Fn::Join": [ + "", + [ + "https://s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "AssetParameterscad1ae036643e3cd17cd3b2b30a2f9e07c1aacaf5284314f41437e4c20447aeaS3BucketED16A657" + }, + "/", + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameterscad1ae036643e3cd17cd3b2b30a2f9e07c1aacaf5284314f41437e4c20447aeaS3VersionKey37A80BBF" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameterscad1ae036643e3cd17cd3b2b30a2f9e07c1aacaf5284314f41437e4c20447aeaS3VersionKey37A80BBF" + } + ] + } + ] + } + ] + ] + }, + "Parameters": { + "referencetoawsstepfunctionstasksekscallintegEksClusterCA674174Arn": { + "Fn::GetAtt": [ + "EksClusterFAB68BDB", + "Arn" + ] + }, + "referencetoawsstepfunctionstasksekscallintegEksClusterCreationRole00B486C4Arn": { + "Fn::GetAtt": [ + "EksClusterCreationRole75AABE42", + "Arn" + ] + }, + "referencetoawsstepfunctionstasksekscallintegAssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3BucketB45933E2Ref": { + "Ref": "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket008DBB35" + }, + "referencetoawsstepfunctionstasksekscallintegAssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey897E2F88Ref": { + "Ref": "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey97C3E1A0" + }, + "referencetoawsstepfunctionstasksekscallintegEksClusterDefaultVpcPrivateSubnet1Subnet3A6964EARef": { + "Ref": "EksClusterDefaultVpcPrivateSubnet1Subnet4D665A2F" + }, + "referencetoawsstepfunctionstasksekscallintegEksClusterDefaultVpcPrivateSubnet2Subnet08905A58Ref": { + "Ref": "EksClusterDefaultVpcPrivateSubnet2Subnet180B8A71" + }, + "referencetoawsstepfunctionstasksekscallintegEksClusterDefaultVpcPrivateSubnet3SubnetF3A2081ERef": { + "Ref": "EksClusterDefaultVpcPrivateSubnet3Subnet6C4BFC07" + }, + "referencetoawsstepfunctionstasksekscallintegEksClusterCA674174ClusterSecurityGroupId": { + "Fn::GetAtt": [ + "EksClusterFAB68BDB", + "ClusterSecurityGroupId" + ] + }, + "referencetoawsstepfunctionstasksekscallintegAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3Bucket3F56B6C0Ref": { + "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" + }, + "referencetoawsstepfunctionstasksekscallintegAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKey14F73D88Ref": { + "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" + }, + "referencetoawsstepfunctionstasksekscallintegAssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket82DB0998Ref": { + "Ref": "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket6ABE1927" + }, + "referencetoawsstepfunctionstasksekscallintegAssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKey5CB2DA63Ref": { + "Ref": "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyF55A2EA9" + }, + "referencetoawsstepfunctionstasksekscallintegAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketCF9FB24DRef": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + }, + "referencetoawsstepfunctionstasksekscallintegAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey4B465A75Ref": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + } + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "Role1ABCC5F0": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "states.", + { + "Ref": "AWS::Region" + }, + ".amazonaws.com" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + }, + "RoleName": "stateMachineExecutionRole" + } + }, + "StateMachine2E01A3A5": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "Role1ABCC5F0", + "Arn" + ] + }, + "DefinitionString": { + "Fn::Join": [ + "", + [ + "{\"StartAt\":\"Call a EKS Endpoint\",\"States\":{\"Call a EKS Endpoint\":{\"End\":true,\"Type\":\"Task\",\"Resource\":\"arn:", + { + "Ref": "AWS::Partition" + }, + ":states:::eks:call\",\"Parameters\":{\"ClusterName\":\"", + { + "Ref": "EksClusterFAB68BDB" + }, + "\",\"CertificateAuthority\":\"", + { + "Fn::GetAtt": [ + "EksClusterFAB68BDB", + "CertificateAuthorityData" + ] + }, + "\",\"Endpoint\":\"", + { + "Fn::GetAtt": [ + "EksClusterFAB68BDB", + "Endpoint" + ] + }, + "\",\"Method\":\"GET\",\"Path\":\"/api/v1/namespaces/default/pods\"}}},\"TimeoutSeconds\":30}" + ] + ] + } + }, + "DependsOn": [ + "Role1ABCC5F0" + ] + } + }, + "Outputs": { + "EksClusterConfigCommand2AE6ED67": { + "Value": { + "Fn::Join": [ + "", + [ + "aws eks update-kubeconfig --name ", + { + "Ref": "EksClusterFAB68BDB" + }, + " --region ", + { + "Ref": "AWS::Region" + }, + " --role-arn ", + { + "Fn::GetAtt": [ + "EksClusterMastersRole3F49FAC3", + "Arn" + ] + } + ] + ] + } + }, + "EksClusterGetTokenCommandDF0BEDB9": { + "Value": { + "Fn::Join": [ + "", + [ + "aws eks get-token --cluster-name ", + { + "Ref": "EksClusterFAB68BDB" + }, + " --region ", + { + "Ref": "AWS::Region" + }, + " --role-arn ", + { + "Fn::GetAtt": [ + "EksClusterMastersRole3F49FAC3", + "Arn" + ] + } + ] + ] + } + }, + "stateMachineArn": { + "Value": { + "Ref": "StateMachine2E01A3A5" + } + } + }, + "Parameters": { + "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket14D204F9": { + "Type": "String", + "Description": "S3 bucket for asset \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + }, + "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyDE8A2F1F": { + "Type": "String", + "Description": "S3 key for asset version \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + }, + "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaArtifactHash54822A43": { + "Type": "String", + "Description": "Artifact hash for asset \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + }, + "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { + "Type": "String", + "Description": "S3 bucket for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + }, + "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F": { + "Type": "String", + "Description": "S3 key for asset version \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + }, + "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1ArtifactHashA521A16F": { + "Type": "String", + "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + }, + "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket008DBB35": { + "Type": "String", + "Description": "S3 bucket for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + }, + "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey97C3E1A0": { + "Type": "String", + "Description": "S3 key for asset version \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + }, + "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757ArtifactHashF584A7D8": { + "Type": "String", + "Description": "Artifact hash for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + }, + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { + "Type": "String", + "Description": "S3 bucket for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + }, + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F": { + "Type": "String", + "Description": "S3 key for asset version \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + }, + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68ArtifactHashD9A515C3": { + "Type": "String", + "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + }, + "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket6ABE1927": { + "Type": "String", + "Description": "S3 bucket for asset \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" + }, + "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyF55A2EA9": { + "Type": "String", + "Description": "S3 key for asset version \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" + }, + "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0ArtifactHash1D7A2D6E": { + "Type": "String", + "Description": "Artifact hash for asset \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" + }, + "AssetParameters3aee2b76026cd725af3b14456bf03061e83d56cce0e0354c7c8e88ee1150e527S3Bucket7ED14FA7": { + "Type": "String", + "Description": "S3 bucket for asset \"3aee2b76026cd725af3b14456bf03061e83d56cce0e0354c7c8e88ee1150e527\"" + }, + "AssetParameters3aee2b76026cd725af3b14456bf03061e83d56cce0e0354c7c8e88ee1150e527S3VersionKeyF4EF0775": { + "Type": "String", + "Description": "S3 key for asset version \"3aee2b76026cd725af3b14456bf03061e83d56cce0e0354c7c8e88ee1150e527\"" + }, + "AssetParameters3aee2b76026cd725af3b14456bf03061e83d56cce0e0354c7c8e88ee1150e527ArtifactHash94EFED5E": { + "Type": "String", + "Description": "Artifact hash for asset \"3aee2b76026cd725af3b14456bf03061e83d56cce0e0354c7c8e88ee1150e527\"" + }, + "AssetParameterscad1ae036643e3cd17cd3b2b30a2f9e07c1aacaf5284314f41437e4c20447aeaS3BucketED16A657": { + "Type": "String", + "Description": "S3 bucket for asset \"cad1ae036643e3cd17cd3b2b30a2f9e07c1aacaf5284314f41437e4c20447aea\"" + }, + "AssetParameterscad1ae036643e3cd17cd3b2b30a2f9e07c1aacaf5284314f41437e4c20447aeaS3VersionKey37A80BBF": { + "Type": "String", + "Description": "S3 key for asset version \"cad1ae036643e3cd17cd3b2b30a2f9e07c1aacaf5284314f41437e4c20447aea\"" + }, + "AssetParameterscad1ae036643e3cd17cd3b2b30a2f9e07c1aacaf5284314f41437e4c20447aeaArtifactHash11CEC9E5": { + "Type": "String", + "Description": "Artifact hash for asset \"cad1ae036643e3cd17cd3b2b30a2f9e07c1aacaf5284314f41437e4c20447aea\"" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.ts new file mode 100644 index 0000000000000..7a3f0b70c8e9d --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.ts @@ -0,0 +1,52 @@ +import * as eks from '@aws-cdk/aws-eks'; +import * as iam from '@aws-cdk/aws-iam'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import * as cdk from '@aws-cdk/core'; +import { EksCall, HttpMethods } from '../../lib'; + +/* + * Create a state machine with a task state to use the Kubernetes API to read Kubernetes resource objects + * via a Kubernetes API endpoint. + * + * Stack verification steps: + * The generated State Machine can be executed from the CLI (or Step Functions console) + * and runs with an execution status of `Succeeded`. + * + * -- aws stepfunctions start-execution --state-machine-arn provides execution arn + * -- aws stepfunctions describe-execution --execution-arn returns a status of `Succeeded` + */ + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-stepfunctions-tasks-eks-call-integ'); + +const cluster = new eks.Cluster(stack, 'EksCluster', { + version: eks.KubernetesVersion.V1_18, + clusterName: 'eksCluster', +}); + +const executionRole = new iam.Role(stack, 'Role', { + roleName: 'stateMachineExecutionRole', + assumedBy: new iam.ServicePrincipal('states.amazonaws.com'), +}); + +cluster.awsAuth.addMastersRole(executionRole); + +const callJob = new EksCall(stack, 'Call a EKS Endpoint', { + cluster: cluster, + httpMethod: HttpMethods.GET, + httpPath: '/api/v1/namespaces/default/pods', +}); + +const chain = sfn.Chain.start(callJob); + +const sm = new sfn.StateMachine(stack, 'StateMachine', { + definition: chain, + role: executionRole, + timeout: cdk.Duration.seconds(30), +}); + +new cdk.CfnOutput(stack, 'stateMachineArn', { + value: sm.stateMachineArn, +}); + +app.synth(); diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/integ.call-sagemaker.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/integ.call-sagemaker.expected.json index 06de00eb99d3f..1e8f55ca57056 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/integ.call-sagemaker.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/integ.call-sagemaker.expected.json @@ -6,23 +6,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { @@ -43,40 +27,6 @@ } }, "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "TrainTaskSagemakerRoleD5A6F967", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*", - "kms:Decrypt" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "TrainTaskSagemakerRoleD5A6F967", - "Arn" - ] - } - }, - "Resource": "*" } ], "Version": "2012-10-17" @@ -197,7 +147,7 @@ { "Action": [ "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -636,4 +586,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/integ.create-training-job.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/integ.create-training-job.expected.json index fe1ebdecd9509..209c5520c1c64 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/integ.create-training-job.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/integ.create-training-job.expected.json @@ -6,23 +6,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { @@ -43,40 +27,6 @@ } }, "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "TrainTaskSagemakerRole0A9B1CDD", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*", - "kms:Decrypt" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "TrainTaskSagemakerRole0A9B1CDD", - "Arn" - ] - } - }, - "Resource": "*" } ], "Version": "2012-10-17" @@ -197,7 +147,7 @@ { "Action": [ "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -408,4 +358,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sns/integ.publish.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sns/integ.publish.expected.json index bf407af2694d8..e5ac1d8ff84a7 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sns/integ.publish.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sns/integ.publish.expected.json @@ -4,7 +4,9 @@ "Type": "AWS::SNS::Topic" }, "showmethemessages8D16BBDB": { - "Type": "AWS::SQS::Queue" + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "showmethemessagesPolicyB08B04B0": { "Type": "AWS::SQS::QueuePolicy", @@ -110,6 +112,12 @@ "StateMachine2E01A3A5": { "Type": "AWS::StepFunctions::StateMachine", "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRoleB840431D", + "Arn" + ] + }, "DefinitionString": { "Fn::Join": [ "", @@ -125,12 +133,6 @@ "\",\"Message\":\"sending message over\"}},\"Final step\":{\"Type\":\"Pass\",\"End\":true}},\"TimeoutSeconds\":30}" ] ] - }, - "RoleArn": { - "Fn::GetAtt": [ - "StateMachineRoleB840431D", - "Arn" - ] } }, "DependsOn": [ diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sqs/integ.send-message.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sqs/integ.send-message.expected.json index 7465187d65c20..5d13c58fc0a5b 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sqs/integ.send-message.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sqs/integ.send-message.expected.json @@ -1,7 +1,9 @@ { "Resources": { "showmethemessages8D16BBDB": { - "Type": "AWS::SQS::Queue" + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "StateMachineRoleB840431D": { "Type": "AWS::IAM::Role", @@ -60,6 +62,12 @@ "StateMachine2E01A3A5": { "Type": "AWS::StepFunctions::StateMachine", "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRoleB840431D", + "Arn" + ] + }, "DefinitionString": { "Fn::Join": [ "", @@ -75,12 +83,6 @@ "\",\"MessageBody\":\"sending message over\"}},\"Final step\":{\"Type\":\"Pass\",\"End\":true}},\"TimeoutSeconds\":30}" ] ] - }, - "RoleArn": { - "Fn::GetAtt": [ - "StateMachineRoleB840431D", - "Arn" - ] } }, "DependsOn": [ diff --git a/packages/@aws-cdk/aws-stepfunctions/package.json b/packages/@aws-cdk/aws-stepfunctions/package.json index 8d149e097da10..80035201f8b36 100644 --- a/packages/@aws-cdk/aws-stepfunctions/package.json +++ b/packages/@aws-cdk/aws-stepfunctions/package.json @@ -109,5 +109,8 @@ "maturity": "stable", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-synthetics/README.md b/packages/@aws-cdk/aws-synthetics/README.md index fd2310ecaacf3..80a6defd34848 100644 --- a/packages/@aws-cdk/aws-synthetics/README.md +++ b/packages/@aws-cdk/aws-synthetics/README.md @@ -44,7 +44,7 @@ const canary = new synthetics.Canary(this, 'MyCanary', { code: synthetics.Code.fromAsset(path.join(__dirname, 'canary')), handler: 'index.handler', }), - runtime: synthetics.Runtime.SYNTHETICS_NODEJS_2_2, + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_0, }); ``` @@ -107,7 +107,7 @@ const canary = new Canary(this, 'MyCanary', { code: synthetics.Code.fromInline('/* Synthetics handler code */'), handler: 'index.handler', // must be 'index.handler' }), - runtime: synthetics.Runtime.SYNTHETICS_NODEJS_2_2, + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_0, }); // To supply the code from your local filesystem: @@ -116,7 +116,7 @@ const canary = new Canary(this, 'MyCanary', { code: synthetics.Code.fromAsset(path.join(__dirname, 'canary')), handler: 'index.handler', // must end with '.handler' }), - runtime: synthetics.Runtime.SYNTHETICS_NODEJS_2_2, + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_0, }); // To supply the code from a S3 bucket: @@ -125,7 +125,7 @@ const canary = new Canary(this, 'MyCanary', { code: synthetics.Code.fromBucket(bucket, 'canary.zip'), handler: 'index.handler', // must end with '.handler' }), - runtime: synthetics.Runtime.SYNTHETICS_NODEJS_2_2, + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_0, }); ``` diff --git a/packages/@aws-cdk/aws-synthetics/lib/canary.ts b/packages/@aws-cdk/aws-synthetics/lib/canary.ts index 7e6d6c8b53b0f..72d4b311ce6e3 100644 --- a/packages/@aws-cdk/aws-synthetics/lib/canary.ts +++ b/packages/@aws-cdk/aws-synthetics/lib/canary.ts @@ -112,6 +112,16 @@ export class Runtime { */ public static readonly SYNTHETICS_NODEJS_2_2 = new Runtime('syn-nodejs-2.2'); + /** + * `syn-nodejs-puppeteer-3.0` includes the following: + * - Lambda runtime Node.js 12.x + * - Puppeteer-core version 5.5.0 + * - Chromium version 88.0.4298.0 + * + * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Library_nodejs_puppeteer.html#CloudWatch_Synthetics_runtimeversion-nodejs-puppeteer-3.0 + */ + public static readonly SYNTHETICS_NODEJS_PUPPETEER_3_0 = new Runtime('syn-nodejs-puppeteer-3.0'); + /** * @param name The name of the runtime version */ diff --git a/packages/@aws-cdk/aws-synthetics/package.json b/packages/@aws-cdk/aws-synthetics/package.json index 8cb33be39e399..3b15e2a0b8ffb 100644 --- a/packages/@aws-cdk/aws-synthetics/package.json +++ b/packages/@aws-cdk/aws-synthetics/package.json @@ -102,5 +102,8 @@ "maturity": "developer-preview", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-synthetics/test/canary.test.ts b/packages/@aws-cdk/aws-synthetics/test/canary.test.ts index d4a505e3a492b..bb5e479e7f7e9 100644 --- a/packages/@aws-cdk/aws-synthetics/test/canary.test.ts +++ b/packages/@aws-cdk/aws-synthetics/test/canary.test.ts @@ -44,7 +44,7 @@ test('Canary can have generated name', () => { handler: 'index.handler', code: synthetics.Code.fromInline('/* Synthetics handler code */'), }), - runtime: synthetics.Runtime.SYNTHETICS_NODEJS_2_0, + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_0, }); // THEN @@ -355,4 +355,4 @@ test('can specify custom test', () => { };`, }, }); -}); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-timestream/package.json b/packages/@aws-cdk/aws-timestream/package.json index 5baa3f1625ad6..c432583d5cbdb 100644 --- a/packages/@aws-cdk/aws-timestream/package.json +++ b/packages/@aws-cdk/aws-timestream/package.json @@ -91,5 +91,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-transfer/package.json b/packages/@aws-cdk/aws-transfer/package.json index e9a884bb6c2d5..b70fc5929c4c0 100644 --- a/packages/@aws-cdk/aws-transfer/package.json +++ b/packages/@aws-cdk/aws-transfer/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-waf/package.json b/packages/@aws-cdk/aws-waf/package.json index f8ef1f1343d4d..ced3ca7dc741b 100644 --- a/packages/@aws-cdk/aws-waf/package.json +++ b/packages/@aws-cdk/aws-waf/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-wafregional/package.json b/packages/@aws-cdk/aws-wafregional/package.json index fe819f3890521..8e165fd4169f8 100644 --- a/packages/@aws-cdk/aws-wafregional/package.json +++ b/packages/@aws-cdk/aws-wafregional/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-wafv2/package.json b/packages/@aws-cdk/aws-wafv2/package.json index 9fe9d0c90d02e..7bae0807f8209 100644 --- a/packages/@aws-cdk/aws-wafv2/package.json +++ b/packages/@aws-cdk/aws-wafv2/package.json @@ -93,5 +93,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/aws-workspaces/package.json b/packages/@aws-cdk/aws-workspaces/package.json index e0272248924c4..d2a3313f491dd 100644 --- a/packages/@aws-cdk/aws-workspaces/package.json +++ b/packages/@aws-cdk/aws-workspaces/package.json @@ -92,5 +92,8 @@ "maturity": "cfn-only", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/cdk-assets-schema/package.json b/packages/@aws-cdk/cdk-assets-schema/package.json index 08b52ca9c331d..272b962c836ad 100644 --- a/packages/@aws-cdk/cdk-assets-schema/package.json +++ b/packages/@aws-cdk/cdk-assets-schema/package.json @@ -76,5 +76,8 @@ "maturity": "deprecated", "cdk-build": { "jest": true + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/cfnspec/CHANGELOG.md b/packages/@aws-cdk/cfnspec/CHANGELOG.md index 2d117eebb4978..abcd6fa61a9c9 100644 --- a/packages/@aws-cdk/cfnspec/CHANGELOG.md +++ b/packages/@aws-cdk/cfnspec/CHANGELOG.md @@ -1,3 +1,197 @@ +# CloudFormation Resource Specification v28.0.0 + +## New Resource Types + +* AWS::CloudFormation::ResourceDefaultVersion +* AWS::CloudFormation::ResourceVersion +* AWS::EC2::TransitGatewayMulticastDomain +* AWS::EC2::TransitGatewayMulticastDomainAssociation +* AWS::EC2::TransitGatewayMulticastGroupMember +* AWS::EC2::TransitGatewayMulticastGroupSource +* AWS::SageMaker::App +* AWS::SageMaker::AppImageConfig +* AWS::SageMaker::Domain +* AWS::SageMaker::UserProfile +* AWS::ServiceCatalog::ServiceAction +* AWS::ServiceCatalog::ServiceActionAssociation + +## Attribute Changes + +* AWS::ApiGateway::ApiKey APIKeyId (__added__) + +## Property Changes + +* AWS::DMS::Endpoint DocDbSettings (__added__) +* AWS::DMS::Endpoint IbmDb2Settings (__added__) +* AWS::DMS::Endpoint MicrosoftSqlServerSettings (__added__) +* AWS::DMS::Endpoint MySqlSettings (__added__) +* AWS::DMS::Endpoint OracleSettings (__added__) +* AWS::DMS::Endpoint PostgreSqlSettings (__added__) +* AWS::DMS::Endpoint RedshiftSettings (__added__) +* AWS::DMS::Endpoint SybaseSettings (__added__) +* AWS::ECS::Cluster Configuration (__deleted__) +* AWS::ECS::Service EnableExecuteCommand (__deleted__) +* AWS::ManagedBlockchain::Node MemberId.Required (__changed__) + * Old: true + * New: false +* AWS::MediaLive::Channel Vpc (__added__) + +## Property Type Changes + +* AWS::ECS::Cluster.ClusterConfiguration (__removed__) +* AWS::ECS::Cluster.ExecuteCommandConfiguration (__removed__) +* AWS::ECS::Cluster.ExecuteCommandLogConfiguration (__removed__) +* AWS::AppMesh::VirtualGateway.SubjectAlternativeNameMatchers (__added__) +* AWS::AppMesh::VirtualGateway.SubjectAlternativeNames (__added__) +* AWS::AppMesh::VirtualGateway.VirtualGatewayClientTlsCertificate (__added__) +* AWS::AppMesh::VirtualGateway.VirtualGatewayListenerTlsSdsCertificate (__added__) +* AWS::AppMesh::VirtualGateway.VirtualGatewayListenerTlsValidationContext (__added__) +* AWS::AppMesh::VirtualGateway.VirtualGatewayListenerTlsValidationContextTrust (__added__) +* AWS::AppMesh::VirtualGateway.VirtualGatewayTlsValidationContextSdsTrust (__added__) +* AWS::AppMesh::VirtualNode.ClientTlsCertificate (__added__) +* AWS::AppMesh::VirtualNode.ListenerTlsSdsCertificate (__added__) +* AWS::AppMesh::VirtualNode.ListenerTlsValidationContext (__added__) +* AWS::AppMesh::VirtualNode.ListenerTlsValidationContextTrust (__added__) +* AWS::AppMesh::VirtualNode.SubjectAlternativeNameMatchers (__added__) +* AWS::AppMesh::VirtualNode.SubjectAlternativeNames (__added__) +* AWS::AppMesh::VirtualNode.TlsValidationContextSdsTrust (__added__) +* AWS::DMS::Endpoint.DocDbSettings (__added__) +* AWS::DMS::Endpoint.IbmDb2Settings (__added__) +* AWS::DMS::Endpoint.MicrosoftSqlServerSettings (__added__) +* AWS::DMS::Endpoint.MySqlSettings (__added__) +* AWS::DMS::Endpoint.OracleSettings (__added__) +* AWS::DMS::Endpoint.PostgreSqlSettings (__added__) +* AWS::DMS::Endpoint.RedshiftSettings (__added__) +* AWS::DMS::Endpoint.SybaseSettings (__added__) +* AWS::MediaLive::Channel.VpcOutputSettings (__added__) +* AWS::AppMesh::VirtualGateway.VirtualGatewayClientPolicyTls Certificate (__added__) +* AWS::AppMesh::VirtualGateway.VirtualGatewayListenerTls Validation (__added__) +* AWS::AppMesh::VirtualGateway.VirtualGatewayListenerTlsCertificate SDS (__added__) +* AWS::AppMesh::VirtualGateway.VirtualGatewayTlsValidationContext SubjectAlternativeNames (__added__) +* AWS::AppMesh::VirtualGateway.VirtualGatewayTlsValidationContextTrust SDS (__added__) +* AWS::AppMesh::VirtualNode.ClientPolicyTls Certificate (__added__) +* AWS::AppMesh::VirtualNode.ListenerTls Validation (__added__) +* AWS::AppMesh::VirtualNode.ListenerTlsCertificate SDS (__added__) +* AWS::AppMesh::VirtualNode.TlsValidationContext SubjectAlternativeNames (__added__) +* AWS::AppMesh::VirtualNode.TlsValidationContextTrust SDS (__added__) +* AWS::DMS::Endpoint.MongoDbSettings SecretsManagerAccessRoleArn (__added__) +* AWS::DMS::Endpoint.MongoDbSettings SecretsManagerSecretId (__added__) + + +# CloudFormation Resource Specification v27.0.0 + +## New Resource Types + +* AWS::ECR::RegistryPolicy +* AWS::ECR::ReplicationConfiguration +* AWS::ElastiCache::GlobalReplicationGroup +* AWS::ImageBuilder::ContainerRecipe + +## Attribute Changes + +* AWS::IoTWireless::ServiceProfile LoRaWANResponse (__added__) +* AWS::MWAA::Environment CreatedAt (__deleted__) +* AWS::MWAA::Environment LastUpdate (__deleted__) +* AWS::MWAA::Environment Name (__deleted__) +* AWS::MWAA::Environment ServiceRoleArn (__deleted__) +* AWS::MWAA::Environment Status (__deleted__) +* AWS::MWAA::Environment WebserverUrl (__added__) + +## Property Changes + +* AWS::AppMesh::GatewayRoute GatewayRouteName.Required (__changed__) + * Old: true + * New: false +* AWS::AppMesh::Mesh MeshName.Required (__changed__) + * Old: true + * New: false +* AWS::AppMesh::Route RouteName.Required (__changed__) + * Old: true + * New: false +* AWS::AppMesh::VirtualGateway VirtualGatewayName.Required (__changed__) + * Old: true + * New: false +* AWS::AppMesh::VirtualNode VirtualNodeName.Required (__changed__) + * Old: true + * New: false +* AWS::AppMesh::VirtualRouter VirtualRouterName.Required (__changed__) + * Old: true + * New: false +* AWS::Cassandra::Keyspace Tags (__added__) +* AWS::Cassandra::Table PointInTimeRecoveryEnabled (__added__) +* AWS::Cassandra::Table Tags (__added__) +* AWS::CloudWatch::MetricStream OutputFormat (__added__) +* AWS::ECS::Service EnableExecuteCommand (__added__) +* AWS::ECS::Service PlatformVersion.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::IoTWireless::Destination NextToken (__deleted__) +* AWS::IoTWireless::Destination Name.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::IoTWireless::DeviceProfile LoRaWANDeviceProfile (__deleted__) +* AWS::IoTWireless::DeviceProfile NextToken (__deleted__) +* AWS::IoTWireless::DeviceProfile LoRaWAN (__added__) +* AWS::IoTWireless::ServiceProfile LoRaWANGetServiceProfileInfo (__deleted__) +* AWS::IoTWireless::ServiceProfile LoRaWANServiceProfile (__deleted__) +* AWS::IoTWireless::ServiceProfile NextToken (__deleted__) +* AWS::IoTWireless::ServiceProfile LoRaWAN (__added__) +* AWS::IoTWireless::WirelessDevice LoRaWANDevice (__deleted__) +* AWS::IoTWireless::WirelessDevice NextToken (__deleted__) +* AWS::IoTWireless::WirelessDevice LastUplinkReceivedAt (__added__) +* AWS::IoTWireless::WirelessDevice LoRaWAN (__added__) +* AWS::IoTWireless::WirelessGateway LoRaWANGateway (__deleted__) +* AWS::IoTWireless::WirelessGateway NextToken (__deleted__) +* AWS::IoTWireless::WirelessGateway LastUplinkReceivedAt (__added__) +* AWS::IoTWireless::WirelessGateway LoRaWAN (__added__) +* AWS::MWAA::Environment WebserverUrl (__deleted__) +* AWS::MWAA::Environment Name (__added__) +* AWS::MWAA::Environment KmsKey.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::MWAA::Environment NetworkConfiguration.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::SageMaker::Model InferenceExecutionConfig (__deleted__) + +## Property Type Changes + +* AWS::IoTWireless::WirelessDevice.AbpV10X (__removed__) +* AWS::IoTWireless::WirelessDevice.OtaaV10X (__removed__) +* AWS::IoTWireless::WirelessDevice.SessionKeysAbpV10X (__removed__) +* AWS::MWAA::Environment.LastUpdate (__removed__) +* AWS::MWAA::Environment.SecurityGroupList (__removed__) +* AWS::MWAA::Environment.SubnetList (__removed__) +* AWS::MWAA::Environment.UpdateError (__removed__) +* AWS::SageMaker::Model.InferenceExecutionConfig (__removed__) +* AWS::DataBrew::Job.CsvOutputOptions (__added__) +* AWS::DataBrew::Job.OutputFormatOptions (__added__) +* AWS::IoTWireless::WirelessDevice.AbpV10x (__added__) +* AWS::IoTWireless::WirelessDevice.OtaaV10x (__added__) +* AWS::IoTWireless::WirelessDevice.SessionKeysAbpV10x (__added__) +* AWS::Cognito::UserPoolClient.AnalyticsConfiguration ApplicationArn (__added__) +* AWS::DataBrew::Job.Output FormatOptions (__added__) +* AWS::IoTWireless::WirelessDevice.LoRaWANDevice AbpV10X (__deleted__) +* AWS::IoTWireless::WirelessDevice.LoRaWANDevice OtaaV10X (__deleted__) +* AWS::IoTWireless::WirelessDevice.LoRaWANDevice AbpV10x (__added__) +* AWS::IoTWireless::WirelessDevice.LoRaWANDevice OtaaV10x (__added__) +* AWS::MWAA::Environment.NetworkConfiguration SecurityGroupIds.PrimitiveItemType (__added__) +* AWS::MWAA::Environment.NetworkConfiguration SecurityGroupIds.Type (__changed__) + * Old: SecurityGroupList + * New: List +* AWS::MWAA::Environment.NetworkConfiguration SecurityGroupIds.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::MWAA::Environment.NetworkConfiguration SubnetIds.PrimitiveItemType (__added__) +* AWS::MWAA::Environment.NetworkConfiguration SubnetIds.Type (__changed__) + * Old: SubnetList + * New: List +* AWS::MediaPackage::PackagingConfiguration.CmafEncryption SpekeKeyProvider.Type (__added__) +* AWS::MediaPackage::PackagingConfiguration.DashEncryption SpekeKeyProvider.Type (__added__) +* AWS::MediaPackage::PackagingConfiguration.HlsEncryption SpekeKeyProvider.Type (__added__) +* AWS::MediaPackage::PackagingConfiguration.MssEncryption SpekeKeyProvider.Type (__added__) + + # CloudFormation Resource Specification v26.0.0 ## New Resource Types diff --git a/packages/@aws-cdk/cfnspec/build-tools/build.ts b/packages/@aws-cdk/cfnspec/build-tools/build.ts index 913605461e224..a96688ecc36f1 100644 --- a/packages/@aws-cdk/cfnspec/build-tools/build.ts +++ b/packages/@aws-cdk/cfnspec/build-tools/build.ts @@ -13,8 +13,19 @@ import { decorateResourceTypes, forEachSection, massageSpec, merge, normalize, p async function main() { const inputDir = path.join(process.cwd(), 'spec-source'); - const files = await fs.readdir(inputDir); + const outDir = path.join(process.cwd(), 'spec'); + + await generateResourceSpecification(inputDir, path.join(outDir, 'specification.json')); + await mergeSpecificationFromDirs(path.join(inputDir, 'cfn-lint'), path.join(outDir, 'cfn-lint.json')); +} + +/** + * Generate CloudFormation resource specification from sources and patches + */ +async function generateResourceSpecification(inputDir: string, outFile: string) { const spec: schema.Specification = { PropertyTypes: {}, ResourceTypes: {}, Fingerprint: '' }; + + const files = await fs.readdir(inputDir); for (const file of files.filter(n => n.endsWith('.json')).sort()) { const data = await fs.readJson(path.join(inputDir, file)); if (file.indexOf('patch') === -1) { @@ -29,9 +40,49 @@ async function main() { spec.Fingerprint = md5(JSON.stringify(normalize(spec))); - const outDir = path.join(process.cwd(), 'spec'); - await fs.mkdirp(outDir); - await fs.writeJson(path.join(outDir, 'specification.json'), spec, { spaces: 2 }); + await fs.mkdirp(path.dirname(outFile)); + await fs.writeJson(outFile, spec, { spaces: 2 }); +} + +/** + * Generate Cfnlint spec annotations from sources and patches + */ +async function mergeSpecificationFromDirs(inputDir: string, outFile: string) { + const spec: any = {}; + + for (const child of await fs.readdir(inputDir)) { + const fullPath = path.join(inputDir, child); + if (!(await fs.stat(fullPath)).isDirectory()) { continue; } + + const subspec = await loadMergedSpec(fullPath); + spec[child] = subspec; + } + + await fs.mkdirp(path.dirname(outFile)); + await fs.writeJson(outFile, spec, { spaces: 2 }); +} + +/** + * Load all files in the given directory, merge them and apply patches in the order found + * + * The base structure is always an empty object + */ +async function loadMergedSpec(inputDir: string) { + const structure: any = {}; + + const files = await fs.readdir(inputDir); + for (const file of files.filter(n => n.endsWith('.json')).sort()) { + const data = await fs.readJson(path.join(inputDir, file)); + if (file.indexOf('patch') === -1) { + // Copy properties from current object into structure, adding/overwriting whatever is found + Object.assign(structure, data); + } else { + // Apply the loaded file as a patch onto the current structure + patch(structure, data); + } + } + + return structure; } main() diff --git a/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts b/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts index 6ddfb76a4f782..93d20a169a12a 100644 --- a/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts +++ b/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts @@ -195,6 +195,9 @@ async function main() { awscdkio: { announce: false, }, + publishConfig: { + tag: 'latest', + }, }); await write('.gitignore', [ diff --git a/packages/@aws-cdk/cfnspec/build-tools/update-cfnlint.sh b/packages/@aws-cdk/cfnspec/build-tools/update-cfnlint.sh new file mode 100755 index 0000000000000..594e7dd165b87 --- /dev/null +++ b/packages/@aws-cdk/cfnspec/build-tools/update-cfnlint.sh @@ -0,0 +1,18 @@ +#!/bin/bash +set -euo pipefail +scriptdir=$(cd $(dirname $0) && pwd) + +# Download (parts of) the cfn-lint repo that we use to enhance our model +intermediate="$(mktemp -d)/tmp.zip" + +url="https://github.com/aws-cloudformation/cfn-python-lint/archive/master.zip" +echo >&2 "Downloading from ${url}..." +curl -sSfL "${url}" -o ${intermediate} + +for file in StatefulResources; do + echo >&2 "${file}.json" + mkdir -p "spec-source/cfn-lint/${file}" + unzip -p "${intermediate}" cfn-python-lint-master/src/cfnlint/data/AdditionalSpecs/${file}.json > spec-source/cfn-lint/${file}/000.json +done + +echo >&2 "Done." diff --git a/packages/@aws-cdk/cfnspec/cfn.version b/packages/@aws-cdk/cfnspec/cfn.version index 1e212a919f492..0b4dfcf095f29 100644 --- a/packages/@aws-cdk/cfnspec/cfn.version +++ b/packages/@aws-cdk/cfnspec/cfn.version @@ -1 +1 @@ -26.0.0 +28.0.0 diff --git a/packages/@aws-cdk/cfnspec/lib/_private_schema/cfn-lint.ts b/packages/@aws-cdk/cfnspec/lib/_private_schema/cfn-lint.ts new file mode 100644 index 0000000000000..4c11394888ec4 --- /dev/null +++ b/packages/@aws-cdk/cfnspec/lib/_private_schema/cfn-lint.ts @@ -0,0 +1,23 @@ +/** + * All annotations imported from cfn-lint + */ +export interface CfnLintFileSchema { + /** + * Resource types that are in this map are stateful + * + * There is more information in the structure this maps to. + */ + readonly StatefulResources: { readonly ResourceTypes: Record }; +} + +/** + * Extra information on stateful resource types + */ +export interface CfnLintStatefulSchema { + /** + * Whether or not a Delete operation requires the resource to be empty + * + * @default false + */ + readonly DeleteRequiresEmptyResource?: boolean; +} diff --git a/packages/@aws-cdk/cfnspec/lib/index.ts b/packages/@aws-cdk/cfnspec/lib/index.ts index 8584e6877ed62..6ab020d9580cc 100644 --- a/packages/@aws-cdk/cfnspec/lib/index.ts +++ b/packages/@aws-cdk/cfnspec/lib/index.ts @@ -1,4 +1,5 @@ import * as crypto from 'crypto'; +import { CfnLintFileSchema } from './_private_schema/cfn-lint'; import * as schema from './schema'; export { schema }; export * from './canned-metrics'; @@ -38,6 +39,19 @@ export function resourceAugmentation(typeName: string): schema.ResourceAugmentat } } +/** + * Get the resource augmentations for a given type + */ +export function cfnLintAnnotations(typeName: string): schema.CfnLintResourceAnnotations { + // eslint-disable-next-line @typescript-eslint/no-require-imports + const allAnnotations: CfnLintFileSchema = require('../spec/cfn-lint.json'); + + return { + stateful: !!allAnnotations.StatefulResources.ResourceTypes[typeName], + mustBeEmptyToDelete: allAnnotations.StatefulResources.ResourceTypes[typeName]?.DeleteRequiresEmptyResource ?? false, + }; +} + /** * Return the property specification for the given resource's property */ diff --git a/packages/@aws-cdk/cfnspec/lib/schema/cfn-lint.ts b/packages/@aws-cdk/cfnspec/lib/schema/cfn-lint.ts new file mode 100644 index 0000000000000..204892f173a95 --- /dev/null +++ b/packages/@aws-cdk/cfnspec/lib/schema/cfn-lint.ts @@ -0,0 +1,14 @@ +/** + * Additional resource information obtained from cfn-lint + */ +export interface CfnLintResourceAnnotations { + /** + * Whether or not the given resource is stateful + */ + readonly stateful: boolean; + + /** + * Whether or not a Delete operation requires the resource to be empty + */ + readonly mustBeEmptyToDelete: boolean; +} \ No newline at end of file diff --git a/packages/@aws-cdk/cfnspec/lib/schema/index.ts b/packages/@aws-cdk/cfnspec/lib/schema/index.ts index 250e5cc1edd96..e4f8720f79e82 100644 --- a/packages/@aws-cdk/cfnspec/lib/schema/index.ts +++ b/packages/@aws-cdk/cfnspec/lib/schema/index.ts @@ -3,3 +3,4 @@ export * from './property'; export * from './resource-type'; export * from './specification'; export * from './augmentation'; +export * from './cfn-lint'; diff --git a/packages/@aws-cdk/cfnspec/package.json b/packages/@aws-cdk/cfnspec/package.json index a9cca1eb3107a..06c46cf79b839 100644 --- a/packages/@aws-cdk/cfnspec/package.json +++ b/packages/@aws-cdk/cfnspec/package.json @@ -3,7 +3,7 @@ "description": "The CloudFormation resource specification used by @aws-cdk packages", "version": "0.0.0", "scripts": { - "update": "cdk-build && /bin/bash build-tools/update.sh", + "update": "cdk-build && /bin/bash build-tools/update.sh && /bin/bash build-tools/update-cfnlint.sh", "update-metrics": "/bin/bash build-tools/update-metrics.sh", "build": "cdk-build && node build-tools/build", "watch": "cdk-watch", @@ -25,7 +25,7 @@ "types": "lib/index.d.ts", "devDependencies": { "@types/fs-extra": "^8.1.1", - "@types/md5": "^2.2.1", + "@types/md5": "^2.3.0", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "fast-json-patch": "^2.2.1", diff --git a/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json b/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json index 9391cf7efc80d..eca5e7601bdb5 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json +++ b/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json @@ -4621,6 +4621,29 @@ } } }, + "AWS::AppMesh::VirtualGateway.SubjectAlternativeNameMatchers": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-subjectalternativenamematchers.html", + "Properties": { + "Exact": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-subjectalternativenamematchers.html#cfn-appmesh-virtualgateway-subjectalternativenamematchers-exact", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::AppMesh::VirtualGateway.SubjectAlternativeNames": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-subjectalternativenames.html", + "Properties": { + "Match": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-subjectalternativenames.html#cfn-appmesh-virtualgateway-subjectalternativenames-match", + "Required": true, + "Type": "SubjectAlternativeNameMatchers", + "UpdateType": "Mutable" + } + } + }, "AWS::AppMesh::VirtualGateway.VirtualGatewayAccessLog": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-virtualgatewayaccesslog.html", "Properties": { @@ -4657,6 +4680,12 @@ "AWS::AppMesh::VirtualGateway.VirtualGatewayClientPolicyTls": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-virtualgatewayclientpolicytls.html", "Properties": { + "Certificate": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-virtualgatewayclientpolicytls.html#cfn-appmesh-virtualgateway-virtualgatewayclientpolicytls-certificate", + "Required": false, + "Type": "VirtualGatewayClientTlsCertificate", + "UpdateType": "Mutable" + }, "Enforce": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-virtualgatewayclientpolicytls.html#cfn-appmesh-virtualgateway-virtualgatewayclientpolicytls-enforce", "PrimitiveType": "Boolean", @@ -4678,6 +4707,23 @@ } } }, + "AWS::AppMesh::VirtualGateway.VirtualGatewayClientTlsCertificate": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-virtualgatewayclienttlscertificate.html", + "Properties": { + "File": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-virtualgatewayclienttlscertificate.html#cfn-appmesh-virtualgateway-virtualgatewayclienttlscertificate-file", + "Required": false, + "Type": "VirtualGatewayListenerTlsFileCertificate", + "UpdateType": "Mutable" + }, + "SDS": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-virtualgatewayclienttlscertificate.html#cfn-appmesh-virtualgateway-virtualgatewayclienttlscertificate-sds", + "Required": false, + "Type": "VirtualGatewayListenerTlsSdsCertificate", + "UpdateType": "Mutable" + } + } + }, "AWS::AppMesh::VirtualGateway.VirtualGatewayConnectionPool": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-virtualgatewayconnectionpool.html", "Properties": { @@ -4841,6 +4887,12 @@ "PrimitiveType": "String", "Required": true, "UpdateType": "Mutable" + }, + "Validation": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-virtualgatewaylistenertls.html#cfn-appmesh-virtualgateway-virtualgatewaylistenertls-validation", + "Required": false, + "Type": "VirtualGatewayListenerTlsValidationContext", + "UpdateType": "Mutable" } } }, @@ -4869,6 +4921,12 @@ "Required": false, "Type": "VirtualGatewayListenerTlsFileCertificate", "UpdateType": "Mutable" + }, + "SDS": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-virtualgatewaylistenertlscertificate.html#cfn-appmesh-virtualgateway-virtualgatewaylistenertlscertificate-sds", + "Required": false, + "Type": "VirtualGatewayListenerTlsSdsCertificate", + "UpdateType": "Mutable" } } }, @@ -4889,6 +4947,51 @@ } } }, + "AWS::AppMesh::VirtualGateway.VirtualGatewayListenerTlsSdsCertificate": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-virtualgatewaylistenertlssdscertificate.html", + "Properties": { + "SecretName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-virtualgatewaylistenertlssdscertificate.html#cfn-appmesh-virtualgateway-virtualgatewaylistenertlssdscertificate-secretname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::AppMesh::VirtualGateway.VirtualGatewayListenerTlsValidationContext": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-virtualgatewaylistenertlsvalidationcontext.html", + "Properties": { + "SubjectAlternativeNames": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-virtualgatewaylistenertlsvalidationcontext.html#cfn-appmesh-virtualgateway-virtualgatewaylistenertlsvalidationcontext-subjectalternativenames", + "Required": false, + "Type": "SubjectAlternativeNames", + "UpdateType": "Mutable" + }, + "Trust": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-virtualgatewaylistenertlsvalidationcontext.html#cfn-appmesh-virtualgateway-virtualgatewaylistenertlsvalidationcontext-trust", + "Required": true, + "Type": "VirtualGatewayListenerTlsValidationContextTrust", + "UpdateType": "Mutable" + } + } + }, + "AWS::AppMesh::VirtualGateway.VirtualGatewayListenerTlsValidationContextTrust": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-virtualgatewaylistenertlsvalidationcontexttrust.html", + "Properties": { + "File": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-virtualgatewaylistenertlsvalidationcontexttrust.html#cfn-appmesh-virtualgateway-virtualgatewaylistenertlsvalidationcontexttrust-file", + "Required": false, + "Type": "VirtualGatewayTlsValidationContextFileTrust", + "UpdateType": "Mutable" + }, + "SDS": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-virtualgatewaylistenertlsvalidationcontexttrust.html#cfn-appmesh-virtualgateway-virtualgatewaylistenertlsvalidationcontexttrust-sds", + "Required": false, + "Type": "VirtualGatewayTlsValidationContextSdsTrust", + "UpdateType": "Mutable" + } + } + }, "AWS::AppMesh::VirtualGateway.VirtualGatewayLogging": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-virtualgatewaylogging.html", "Properties": { @@ -4944,6 +5047,12 @@ "AWS::AppMesh::VirtualGateway.VirtualGatewayTlsValidationContext": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-virtualgatewaytlsvalidationcontext.html", "Properties": { + "SubjectAlternativeNames": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-virtualgatewaytlsvalidationcontext.html#cfn-appmesh-virtualgateway-virtualgatewaytlsvalidationcontext-subjectalternativenames", + "Required": false, + "Type": "SubjectAlternativeNames", + "UpdateType": "Mutable" + }, "Trust": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-virtualgatewaytlsvalidationcontext.html#cfn-appmesh-virtualgateway-virtualgatewaytlsvalidationcontext-trust", "Required": true, @@ -4975,6 +5084,17 @@ } } }, + "AWS::AppMesh::VirtualGateway.VirtualGatewayTlsValidationContextSdsTrust": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-virtualgatewaytlsvalidationcontextsdstrust.html", + "Properties": { + "SecretName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-virtualgatewaytlsvalidationcontextsdstrust.html#cfn-appmesh-virtualgateway-virtualgatewaytlsvalidationcontextsdstrust-secretname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::AppMesh::VirtualGateway.VirtualGatewayTlsValidationContextTrust": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-virtualgatewaytlsvalidationcontexttrust.html", "Properties": { @@ -4989,6 +5109,12 @@ "Required": false, "Type": "VirtualGatewayTlsValidationContextFileTrust", "UpdateType": "Mutable" + }, + "SDS": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualgateway-virtualgatewaytlsvalidationcontexttrust.html#cfn-appmesh-virtualgateway-virtualgatewaytlsvalidationcontexttrust-sds", + "Required": false, + "Type": "VirtualGatewayTlsValidationContextSdsTrust", + "UpdateType": "Mutable" } } }, @@ -5080,6 +5206,12 @@ "AWS::AppMesh::VirtualNode.ClientPolicyTls": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-clientpolicytls.html", "Properties": { + "Certificate": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-clientpolicytls.html#cfn-appmesh-virtualnode-clientpolicytls-certificate", + "Required": false, + "Type": "ClientTlsCertificate", + "UpdateType": "Mutable" + }, "Enforce": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-clientpolicytls.html#cfn-appmesh-virtualnode-clientpolicytls-enforce", "PrimitiveType": "Boolean", @@ -5101,6 +5233,23 @@ } } }, + "AWS::AppMesh::VirtualNode.ClientTlsCertificate": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-clienttlscertificate.html", + "Properties": { + "File": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-clienttlscertificate.html#cfn-appmesh-virtualnode-clienttlscertificate-file", + "Required": false, + "Type": "ListenerTlsFileCertificate", + "UpdateType": "Mutable" + }, + "SDS": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-clienttlscertificate.html#cfn-appmesh-virtualnode-clienttlscertificate-sds", + "Required": false, + "Type": "ListenerTlsSdsCertificate", + "UpdateType": "Mutable" + } + } + }, "AWS::AppMesh::VirtualNode.DnsServiceDiscovery": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-dnsservicediscovery.html", "Properties": { @@ -5305,6 +5454,12 @@ "PrimitiveType": "String", "Required": true, "UpdateType": "Mutable" + }, + "Validation": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-listenertls.html#cfn-appmesh-virtualnode-listenertls-validation", + "Required": false, + "Type": "ListenerTlsValidationContext", + "UpdateType": "Mutable" } } }, @@ -5333,6 +5488,12 @@ "Required": false, "Type": "ListenerTlsFileCertificate", "UpdateType": "Mutable" + }, + "SDS": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-listenertlscertificate.html#cfn-appmesh-virtualnode-listenertlscertificate-sds", + "Required": false, + "Type": "ListenerTlsSdsCertificate", + "UpdateType": "Mutable" } } }, @@ -5353,6 +5514,51 @@ } } }, + "AWS::AppMesh::VirtualNode.ListenerTlsSdsCertificate": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-listenertlssdscertificate.html", + "Properties": { + "SecretName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-listenertlssdscertificate.html#cfn-appmesh-virtualnode-listenertlssdscertificate-secretname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::AppMesh::VirtualNode.ListenerTlsValidationContext": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-listenertlsvalidationcontext.html", + "Properties": { + "SubjectAlternativeNames": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-listenertlsvalidationcontext.html#cfn-appmesh-virtualnode-listenertlsvalidationcontext-subjectalternativenames", + "Required": false, + "Type": "SubjectAlternativeNames", + "UpdateType": "Mutable" + }, + "Trust": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-listenertlsvalidationcontext.html#cfn-appmesh-virtualnode-listenertlsvalidationcontext-trust", + "Required": true, + "Type": "ListenerTlsValidationContextTrust", + "UpdateType": "Mutable" + } + } + }, + "AWS::AppMesh::VirtualNode.ListenerTlsValidationContextTrust": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-listenertlsvalidationcontexttrust.html", + "Properties": { + "File": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-listenertlsvalidationcontexttrust.html#cfn-appmesh-virtualnode-listenertlsvalidationcontexttrust-file", + "Required": false, + "Type": "TlsValidationContextFileTrust", + "UpdateType": "Mutable" + }, + "SDS": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-listenertlsvalidationcontexttrust.html#cfn-appmesh-virtualnode-listenertlsvalidationcontexttrust-sds", + "Required": false, + "Type": "TlsValidationContextSdsTrust", + "UpdateType": "Mutable" + } + } + }, "AWS::AppMesh::VirtualNode.Logging": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-logging.html", "Properties": { @@ -5427,6 +5633,29 @@ } } }, + "AWS::AppMesh::VirtualNode.SubjectAlternativeNameMatchers": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-subjectalternativenamematchers.html", + "Properties": { + "Exact": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-subjectalternativenamematchers.html#cfn-appmesh-virtualnode-subjectalternativenamematchers-exact", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::AppMesh::VirtualNode.SubjectAlternativeNames": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-subjectalternativenames.html", + "Properties": { + "Match": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-subjectalternativenames.html#cfn-appmesh-virtualnode-subjectalternativenames-match", + "Required": true, + "Type": "SubjectAlternativeNameMatchers", + "UpdateType": "Mutable" + } + } + }, "AWS::AppMesh::VirtualNode.TcpTimeout": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-tcptimeout.html", "Properties": { @@ -5441,6 +5670,12 @@ "AWS::AppMesh::VirtualNode.TlsValidationContext": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-tlsvalidationcontext.html", "Properties": { + "SubjectAlternativeNames": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-tlsvalidationcontext.html#cfn-appmesh-virtualnode-tlsvalidationcontext-subjectalternativenames", + "Required": false, + "Type": "SubjectAlternativeNames", + "UpdateType": "Mutable" + }, "Trust": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-tlsvalidationcontext.html#cfn-appmesh-virtualnode-tlsvalidationcontext-trust", "Required": true, @@ -5472,6 +5707,17 @@ } } }, + "AWS::AppMesh::VirtualNode.TlsValidationContextSdsTrust": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-tlsvalidationcontextsdstrust.html", + "Properties": { + "SecretName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-tlsvalidationcontextsdstrust.html#cfn-appmesh-virtualnode-tlsvalidationcontextsdstrust-secretname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::AppMesh::VirtualNode.TlsValidationContextTrust": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-tlsvalidationcontexttrust.html", "Properties": { @@ -5486,6 +5732,12 @@ "Required": false, "Type": "TlsValidationContextFileTrust", "UpdateType": "Mutable" + }, + "SDS": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-virtualnode-tlsvalidationcontexttrust.html#cfn-appmesh-virtualnode-tlsvalidationcontexttrust-sds", + "Required": false, + "Type": "TlsValidationContextSdsTrust", + "UpdateType": "Mutable" } } }, @@ -9128,6 +9380,23 @@ } } }, + "AWS::CloudFormation::ResourceVersion.LoggingConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudformation-resourceversion-loggingconfig.html", + "Properties": { + "LogGroupName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudformation-resourceversion-loggingconfig.html#cfn-cloudformation-resourceversion-loggingconfig-loggroupname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "LogRoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudformation-resourceversion-loggingconfig.html#cfn-cloudformation-resourceversion-loggingconfig-logrolearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::CloudFormation::StackSet.AutoDeployment": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudformation-stackset-autodeployment.html", "Properties": { @@ -12702,6 +12971,12 @@ "AWS::Cognito::UserPoolClient.AnalyticsConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cognito-userpoolclient-analyticsconfiguration.html", "Properties": { + "ApplicationArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cognito-userpoolclient-analyticsconfiguration.html#cfn-cognito-userpoolclient-analyticsconfiguration-applicationarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "ApplicationId": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cognito-userpoolclient-analyticsconfiguration.html#cfn-cognito-userpoolclient-analyticsconfiguration-applicationid", "PrimitiveType": "String", @@ -13765,6 +14040,23 @@ } } }, + "AWS::DMS::Endpoint.DocDbSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-docdbsettings.html", + "Properties": { + "SecretsManagerAccessRoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-docdbsettings.html#cfn-dms-endpoint-docdbsettings-secretsmanageraccessrolearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SecretsManagerSecretId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-docdbsettings.html#cfn-dms-endpoint-docdbsettings-secretsmanagersecretid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::DMS::Endpoint.DynamoDbSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-dynamodbsettings.html", "Properties": { @@ -13805,6 +14097,23 @@ } } }, + "AWS::DMS::Endpoint.IbmDb2Settings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-ibmdb2settings.html", + "Properties": { + "SecretsManagerAccessRoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-ibmdb2settings.html#cfn-dms-endpoint-ibmdb2settings-secretsmanageraccessrolearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SecretsManagerSecretId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-ibmdb2settings.html#cfn-dms-endpoint-ibmdb2settings-secretsmanagersecretid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::DMS::Endpoint.KafkaSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kafkasettings.html", "Properties": { @@ -13845,6 +14154,23 @@ } } }, + "AWS::DMS::Endpoint.MicrosoftSqlServerSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-microsoftsqlserversettings.html", + "Properties": { + "SecretsManagerAccessRoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-microsoftsqlserversettings.html#cfn-dms-endpoint-microsoftsqlserversettings-secretsmanageraccessrolearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SecretsManagerSecretId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-microsoftsqlserversettings.html#cfn-dms-endpoint-microsoftsqlserversettings-secretsmanagersecretid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::DMS::Endpoint.MongoDbSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-mongodbsettings.html", "Properties": { @@ -13902,6 +14228,18 @@ "Required": false, "UpdateType": "Mutable" }, + "SecretsManagerAccessRoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-mongodbsettings.html#cfn-dms-endpoint-mongodbsettings-secretsmanageraccessrolearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SecretsManagerSecretId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-mongodbsettings.html#cfn-dms-endpoint-mongodbsettings-secretsmanagersecretid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "ServerName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-mongodbsettings.html#cfn-dms-endpoint-mongodbsettings-servername", "PrimitiveType": "String", @@ -13916,6 +14254,23 @@ } } }, + "AWS::DMS::Endpoint.MySqlSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-mysqlsettings.html", + "Properties": { + "SecretsManagerAccessRoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-mysqlsettings.html#cfn-dms-endpoint-mysqlsettings-secretsmanageraccessrolearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SecretsManagerSecretId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-mysqlsettings.html#cfn-dms-endpoint-mysqlsettings-secretsmanagersecretid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::DMS::Endpoint.NeptuneSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-neptunesettings.html", "Properties": { @@ -13963,6 +14318,69 @@ } } }, + "AWS::DMS::Endpoint.OracleSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-oraclesettings.html", + "Properties": { + "SecretsManagerAccessRoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-oraclesettings.html#cfn-dms-endpoint-oraclesettings-secretsmanageraccessrolearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SecretsManagerOracleAsmAccessRoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-oraclesettings.html#cfn-dms-endpoint-oraclesettings-secretsmanageroracleasmaccessrolearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SecretsManagerOracleAsmSecretId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-oraclesettings.html#cfn-dms-endpoint-oraclesettings-secretsmanageroracleasmsecretid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SecretsManagerSecretId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-oraclesettings.html#cfn-dms-endpoint-oraclesettings-secretsmanagersecretid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::DMS::Endpoint.PostgreSqlSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-postgresqlsettings.html", + "Properties": { + "SecretsManagerAccessRoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-postgresqlsettings.html#cfn-dms-endpoint-postgresqlsettings-secretsmanageraccessrolearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SecretsManagerSecretId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-postgresqlsettings.html#cfn-dms-endpoint-postgresqlsettings-secretsmanagersecretid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::DMS::Endpoint.RedshiftSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-redshiftsettings.html", + "Properties": { + "SecretsManagerAccessRoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-redshiftsettings.html#cfn-dms-endpoint-redshiftsettings-secretsmanageraccessrolearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SecretsManagerSecretId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-redshiftsettings.html#cfn-dms-endpoint-redshiftsettings-secretsmanagersecretid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::DMS::Endpoint.S3Settings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-s3settings.html", "Properties": { @@ -14010,6 +14428,34 @@ } } }, + "AWS::DMS::Endpoint.SybaseSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-sybasesettings.html", + "Properties": { + "SecretsManagerAccessRoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-sybasesettings.html#cfn-dms-endpoint-sybasesettings-secretsmanageraccessrolearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SecretsManagerSecretId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-sybasesettings.html#cfn-dms-endpoint-sybasesettings-secretsmanagersecretid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::DataBrew::Job.CsvOutputOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-job-csvoutputoptions.html", + "Properties": { + "Delimiter": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-job-csvoutputoptions.html#cfn-databrew-job-csvoutputoptions-delimiter", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::DataBrew::Job.Output": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-job-output.html", "Properties": { @@ -14025,6 +14471,12 @@ "Required": false, "UpdateType": "Mutable" }, + "FormatOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-job-output.html#cfn-databrew-job-output-formatoptions", + "Required": false, + "Type": "OutputFormatOptions", + "UpdateType": "Mutable" + }, "Location": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-job-output.html#cfn-databrew-job-output-location", "Required": true, @@ -14047,6 +14499,17 @@ } } }, + "AWS::DataBrew::Job.OutputFormatOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-job-outputformatoptions.html", + "Properties": { + "Csv": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-job-outputformatoptions.html#cfn-databrew-job-outputformatoptions-csv", + "Required": false, + "Type": "CsvOutputOptions", + "UpdateType": "Mutable" + } + } + }, "AWS::DataBrew::Job.S3Location": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-job-s3location.html", "Properties": { @@ -18362,6 +18825,47 @@ } } }, + "AWS::ECR::ReplicationConfiguration.ReplicationConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecr-replicationconfiguration-replicationconfiguration.html", + "Properties": { + "Rules": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecr-replicationconfiguration-replicationconfiguration.html#cfn-ecr-replicationconfiguration-replicationconfiguration-rules", + "ItemType": "ReplicationRule", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::ECR::ReplicationConfiguration.ReplicationDestination": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecr-replicationconfiguration-replicationdestination.html", + "Properties": { + "Region": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecr-replicationconfiguration-replicationdestination.html#cfn-ecr-replicationconfiguration-replicationdestination-region", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "RegistryId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecr-replicationconfiguration-replicationdestination.html#cfn-ecr-replicationconfiguration-replicationdestination-registryid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::ECR::ReplicationConfiguration.ReplicationRule": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecr-replicationconfiguration-replicationrule.html", + "Properties": { + "Destinations": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecr-replicationconfiguration-replicationrule.html#cfn-ecr-replicationconfiguration-replicationrule-destinations", + "ItemType": "ReplicationDestination", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::ECR::Repository.LifecyclePolicy": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecr-repository-lifecyclepolicy.html", "Properties": { @@ -18454,17 +18958,6 @@ } } }, - "AWS::ECS::Cluster.ClusterConfiguration": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-cluster-clusterconfiguration.html", - "Properties": { - "ExecuteCommandConfiguration": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-cluster-clusterconfiguration.html#cfn-ecs-cluster-clusterconfiguration-executecommandconfiguration", - "Required": false, - "Type": "ExecuteCommandConfiguration", - "UpdateType": "Mutable" - } - } - }, "AWS::ECS::Cluster.ClusterSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-cluster-clustersettings.html", "Properties": { @@ -18482,64 +18975,6 @@ } } }, - "AWS::ECS::Cluster.ExecuteCommandConfiguration": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-cluster-executecommandconfiguration.html", - "Properties": { - "KmsKeyId": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-cluster-executecommandconfiguration.html#cfn-ecs-cluster-executecommandconfiguration-kmskeyid", - "PrimitiveType": "String", - "Required": false, - "UpdateType": "Mutable" - }, - "LogConfiguration": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-cluster-executecommandconfiguration.html#cfn-ecs-cluster-executecommandconfiguration-logconfiguration", - "Required": false, - "Type": "ExecuteCommandLogConfiguration", - "UpdateType": "Mutable" - }, - "Logging": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-cluster-executecommandconfiguration.html#cfn-ecs-cluster-executecommandconfiguration-logging", - "PrimitiveType": "String", - "Required": false, - "UpdateType": "Mutable" - } - } - }, - "AWS::ECS::Cluster.ExecuteCommandLogConfiguration": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-cluster-executecommandlogconfiguration.html", - "Properties": { - "CloudWatchEncryptionEnabled": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-cluster-executecommandlogconfiguration.html#cfn-ecs-cluster-executecommandlogconfiguration-cloudwatchencryptionenabled", - "PrimitiveType": "Boolean", - "Required": false, - "UpdateType": "Mutable" - }, - "CloudWatchLogGroupName": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-cluster-executecommandlogconfiguration.html#cfn-ecs-cluster-executecommandlogconfiguration-cloudwatchloggroupname", - "PrimitiveType": "String", - "Required": false, - "UpdateType": "Mutable" - }, - "S3BucketName": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-cluster-executecommandlogconfiguration.html#cfn-ecs-cluster-executecommandlogconfiguration-s3bucketname", - "PrimitiveType": "String", - "Required": false, - "UpdateType": "Mutable" - }, - "S3EncryptionEnabled": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-cluster-executecommandlogconfiguration.html#cfn-ecs-cluster-executecommandlogconfiguration-s3encryptionenabled", - "PrimitiveType": "Boolean", - "Required": false, - "UpdateType": "Mutable" - }, - "S3KeyPrefix": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-cluster-executecommandlogconfiguration.html#cfn-ecs-cluster-executecommandlogconfiguration-s3keyprefix", - "PrimitiveType": "String", - "Required": false, - "UpdateType": "Mutable" - } - } - }, "AWS::ECS::Service.AwsVpcConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-awsvpcconfiguration.html", "Properties": { @@ -21368,6 +21803,73 @@ } } }, + "AWS::ElastiCache::GlobalReplicationGroup.GlobalReplicationGroupMember": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-globalreplicationgroup-globalreplicationgroupmember.html", + "Properties": { + "ReplicationGroupId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-globalreplicationgroup-globalreplicationgroupmember.html#cfn-elasticache-globalreplicationgroup-globalreplicationgroupmember-replicationgroupid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ReplicationGroupRegion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-globalreplicationgroup-globalreplicationgroupmember.html#cfn-elasticache-globalreplicationgroup-globalreplicationgroupmember-replicationgroupregion", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Role": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-globalreplicationgroup-globalreplicationgroupmember.html#cfn-elasticache-globalreplicationgroup-globalreplicationgroupmember-role", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::ElastiCache::GlobalReplicationGroup.RegionalConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-globalreplicationgroup-regionalconfiguration.html", + "Properties": { + "ReplicationGroupId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-globalreplicationgroup-regionalconfiguration.html#cfn-elasticache-globalreplicationgroup-regionalconfiguration-replicationgroupid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ReplicationGroupRegion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-globalreplicationgroup-regionalconfiguration.html#cfn-elasticache-globalreplicationgroup-regionalconfiguration-replicationgroupregion", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ReshardingConfigurations": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-globalreplicationgroup-regionalconfiguration.html#cfn-elasticache-globalreplicationgroup-regionalconfiguration-reshardingconfigurations", + "DuplicatesAllowed": false, + "ItemType": "ReshardingConfiguration", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::ElastiCache::GlobalReplicationGroup.ReshardingConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-globalreplicationgroup-reshardingconfiguration.html", + "Properties": { + "NodeGroupId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-globalreplicationgroup-reshardingconfiguration.html#cfn-elasticache-globalreplicationgroup-reshardingconfiguration-nodegroupid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "PreferredAvailabilityZones": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-globalreplicationgroup-reshardingconfiguration.html#cfn-elasticache-globalreplicationgroup-reshardingconfiguration-preferredavailabilityzones", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::ElastiCache::ReplicationGroup.NodeGroupConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-replicationgroup-nodegroupconfiguration.html", "Properties": { @@ -26986,6 +27488,34 @@ } } }, + "AWS::ImageBuilder::ContainerRecipe.ComponentConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-containerrecipe-componentconfiguration.html", + "Properties": { + "ComponentArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-containerrecipe-componentconfiguration.html#cfn-imagebuilder-containerrecipe-componentconfiguration-componentarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::ImageBuilder::ContainerRecipe.TargetContainerRepository": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-containerrecipe-targetcontainerrepository.html", + "Properties": { + "RepositoryName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-containerrecipe-targetcontainerrepository.html#cfn-imagebuilder-containerrecipe-targetcontainerrepository-repositoryname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Service": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-containerrecipe-targetcontainerrepository.html#cfn-imagebuilder-containerrecipe-targetcontainerrepository-service", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, "AWS::ImageBuilder::DistributionConfiguration.Distribution": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-distributionconfiguration-distribution.html", "Properties": { @@ -30179,7 +30709,7 @@ } } }, - "AWS::IoTWireless::WirelessDevice.AbpV10X": { + "AWS::IoTWireless::WirelessDevice.AbpV10x": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-wirelessdevice-abpv10x.html", "Properties": { "DevAddr": { @@ -30191,7 +30721,7 @@ "SessionKeys": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-wirelessdevice-abpv10x.html#cfn-iotwireless-wirelessdevice-abpv10x-sessionkeys", "Required": true, - "Type": "SessionKeysAbpV10X", + "Type": "SessionKeysAbpV10x", "UpdateType": "Mutable" } } @@ -30216,10 +30746,10 @@ "AWS::IoTWireless::WirelessDevice.LoRaWANDevice": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-wirelessdevice-lorawandevice.html", "Properties": { - "AbpV10X": { + "AbpV10x": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-wirelessdevice-lorawandevice.html#cfn-iotwireless-wirelessdevice-lorawandevice-abpv10x", "Required": false, - "Type": "AbpV10X", + "Type": "AbpV10x", "UpdateType": "Mutable" }, "AbpV11": { @@ -30240,10 +30770,10 @@ "Required": false, "UpdateType": "Mutable" }, - "OtaaV10X": { + "OtaaV10x": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-wirelessdevice-lorawandevice.html#cfn-iotwireless-wirelessdevice-lorawandevice-otaav10x", "Required": false, - "Type": "OtaaV10X", + "Type": "OtaaV10x", "UpdateType": "Mutable" }, "OtaaV11": { @@ -30260,7 +30790,7 @@ } } }, - "AWS::IoTWireless::WirelessDevice.OtaaV10X": { + "AWS::IoTWireless::WirelessDevice.OtaaV10x": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-wirelessdevice-otaav10x.html", "Properties": { "AppEui": { @@ -30300,7 +30830,7 @@ } } }, - "AWS::IoTWireless::WirelessDevice.SessionKeysAbpV10X": { + "AWS::IoTWireless::WirelessDevice.SessionKeysAbpV10x": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-wirelessdevice-sessionkeysabpv10x.html", "Properties": { "AppSKey": { @@ -35037,29 +35567,6 @@ "AWS::MWAA::Environment.AirflowConfigurationOptions": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mwaa-environment-airflowconfigurationoptions.html" }, - "AWS::MWAA::Environment.LastUpdate": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mwaa-environment-lastupdate.html", - "Properties": { - "CreatedAt": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mwaa-environment-lastupdate.html#cfn-mwaa-environment-lastupdate-createdat", - "PrimitiveType": "String", - "Required": false, - "UpdateType": "Mutable" - }, - "Error": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mwaa-environment-lastupdate.html#cfn-mwaa-environment-lastupdate-error", - "Required": false, - "Type": "UpdateError", - "UpdateType": "Mutable" - }, - "Status": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mwaa-environment-lastupdate.html#cfn-mwaa-environment-lastupdate-status", - "PrimitiveType": "String", - "Required": false, - "UpdateType": "Mutable" - } - } - }, "AWS::MWAA::Environment.LoggingConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mwaa-environment-loggingconfiguration.html", "Properties": { @@ -35123,35 +35630,13 @@ "Properties": { "SecurityGroupIds": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mwaa-environment-networkconfiguration.html#cfn-mwaa-environment-networkconfiguration-securitygroupids", + "PrimitiveItemType": "String", "Required": false, - "Type": "SecurityGroupList", - "UpdateType": "Immutable" + "Type": "List", + "UpdateType": "Mutable" }, "SubnetIds": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mwaa-environment-networkconfiguration.html#cfn-mwaa-environment-networkconfiguration-subnetids", - "Required": false, - "Type": "SubnetList", - "UpdateType": "Immutable" - } - } - }, - "AWS::MWAA::Environment.SecurityGroupList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mwaa-environment-securitygrouplist.html", - "Properties": { - "SecurityGroupList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mwaa-environment-securitygrouplist.html#cfn-mwaa-environment-securitygrouplist-securitygrouplist", - "PrimitiveItemType": "String", - "Required": false, - "Type": "List", - "UpdateType": "Immutable" - } - } - }, - "AWS::MWAA::Environment.SubnetList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mwaa-environment-subnetlist.html", - "Properties": { - "SubnetList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mwaa-environment-subnetlist.html#cfn-mwaa-environment-subnetlist-subnetlist", "PrimitiveItemType": "String", "Required": false, "Type": "List", @@ -35162,23 +35647,6 @@ "AWS::MWAA::Environment.TagMap": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mwaa-environment-tagmap.html" }, - "AWS::MWAA::Environment.UpdateError": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mwaa-environment-updateerror.html", - "Properties": { - "ErrorCode": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mwaa-environment-updateerror.html#cfn-mwaa-environment-updateerror-errorcode", - "PrimitiveType": "String", - "Required": false, - "UpdateType": "Mutable" - }, - "ErrorMessage": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mwaa-environment-updateerror.html#cfn-mwaa-environment-updateerror-errormessage", - "PrimitiveType": "String", - "Required": false, - "UpdateType": "Mutable" - } - } - }, "AWS::Macie::FindingsFilter.Criterion": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-macie-findingsfilter-criterion.html" }, @@ -40013,6 +40481,32 @@ } } }, + "AWS::MediaLive::Channel.VpcOutputSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-vpcoutputsettings.html", + "Properties": { + "PublicAddressAllocationIds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-vpcoutputsettings.html#cfn-medialive-channel-vpcoutputsettings-publicaddressallocationids", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "SecurityGroupIds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-vpcoutputsettings.html#cfn-medialive-channel-vpcoutputsettings-securitygroupids", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "SubnetIds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-vpcoutputsettings.html#cfn-medialive-channel-vpcoutputsettings-subnetids", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::MediaLive::Channel.WavSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-wavsettings.html", "Properties": { @@ -40645,6 +41139,7 @@ "SpekeKeyProvider": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mediapackage-packagingconfiguration-cmafencryption.html#cfn-mediapackage-packagingconfiguration-cmafencryption-spekekeyprovider", "Required": true, + "Type": "SpekeKeyProvider", "UpdateType": "Mutable" } } @@ -40679,6 +41174,7 @@ "SpekeKeyProvider": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mediapackage-packagingconfiguration-dashencryption.html#cfn-mediapackage-packagingconfiguration-dashencryption-spekekeyprovider", "Required": true, + "Type": "SpekeKeyProvider", "UpdateType": "Mutable" } } @@ -40773,6 +41269,7 @@ "SpekeKeyProvider": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mediapackage-packagingconfiguration-hlsencryption.html#cfn-mediapackage-packagingconfiguration-hlsencryption-spekekeyprovider", "Required": true, + "Type": "SpekeKeyProvider", "UpdateType": "Mutable" } } @@ -40854,6 +41351,7 @@ "SpekeKeyProvider": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mediapackage-packagingconfiguration-mssencryption.html#cfn-mediapackage-packagingconfiguration-mssencryption-spekekeyprovider", "Required": true, + "Type": "SpekeKeyProvider", "UpdateType": "Mutable" } } @@ -47663,6 +48161,87 @@ } } }, + "AWS::SageMaker::App.ResourceSpec": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-app-resourcespec.html", + "Properties": { + "InstanceType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-app-resourcespec.html#cfn-sagemaker-app-resourcespec-instancetype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SageMakerImageArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-app-resourcespec.html#cfn-sagemaker-app-resourcespec-sagemakerimagearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SageMakerImageVersionArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-app-resourcespec.html#cfn-sagemaker-app-resourcespec-sagemakerimageversionarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::AppImageConfig.FileSystemConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-appimageconfig-filesystemconfig.html", + "Properties": { + "DefaultGid": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-appimageconfig-filesystemconfig.html#cfn-sagemaker-appimageconfig-filesystemconfig-defaultgid", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "DefaultUid": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-appimageconfig-filesystemconfig.html#cfn-sagemaker-appimageconfig-filesystemconfig-defaultuid", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "MountPath": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-appimageconfig-filesystemconfig.html#cfn-sagemaker-appimageconfig-filesystemconfig-mountpath", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::AppImageConfig.KernelGatewayImageConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-appimageconfig-kernelgatewayimageconfig.html", + "Properties": { + "FileSystemConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-appimageconfig-kernelgatewayimageconfig.html#cfn-sagemaker-appimageconfig-kernelgatewayimageconfig-filesystemconfig", + "Required": false, + "Type": "FileSystemConfig", + "UpdateType": "Mutable" + }, + "KernelSpecs": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-appimageconfig-kernelgatewayimageconfig.html#cfn-sagemaker-appimageconfig-kernelgatewayimageconfig-kernelspecs", + "ItemType": "KernelSpec", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::AppImageConfig.KernelSpec": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-appimageconfig-kernelspec.html", + "Properties": { + "DisplayName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-appimageconfig-kernelspec.html#cfn-sagemaker-appimageconfig-kernelspec-displayname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-appimageconfig-kernelspec.html#cfn-sagemaker-appimageconfig-kernelspec-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::SageMaker::CodeRepository.GitConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-coderepository-gitconfig.html", "Properties": { @@ -48002,6 +48581,142 @@ } } }, + "AWS::SageMaker::Domain.CustomImage": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-domain-customimage.html", + "Properties": { + "AppImageConfigName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-domain-customimage.html#cfn-sagemaker-domain-customimage-appimageconfigname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ImageName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-domain-customimage.html#cfn-sagemaker-domain-customimage-imagename", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ImageVersionNumber": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-domain-customimage.html#cfn-sagemaker-domain-customimage-imageversionnumber", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::Domain.JupyterServerAppSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-domain-jupyterserverappsettings.html", + "Properties": { + "DefaultResourceSpec": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-domain-jupyterserverappsettings.html#cfn-sagemaker-domain-jupyterserverappsettings-defaultresourcespec", + "Required": false, + "Type": "ResourceSpec", + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::Domain.KernelGatewayAppSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-domain-kernelgatewayappsettings.html", + "Properties": { + "CustomImages": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-domain-kernelgatewayappsettings.html#cfn-sagemaker-domain-kernelgatewayappsettings-customimages", + "DuplicatesAllowed": true, + "ItemType": "CustomImage", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "DefaultResourceSpec": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-domain-kernelgatewayappsettings.html#cfn-sagemaker-domain-kernelgatewayappsettings-defaultresourcespec", + "Required": false, + "Type": "ResourceSpec", + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::Domain.ResourceSpec": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-domain-resourcespec.html", + "Properties": { + "InstanceType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-domain-resourcespec.html#cfn-sagemaker-domain-resourcespec-instancetype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SageMakerImageArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-domain-resourcespec.html#cfn-sagemaker-domain-resourcespec-sagemakerimagearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SageMakerImageVersionArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-domain-resourcespec.html#cfn-sagemaker-domain-resourcespec-sagemakerimageversionarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::Domain.SharingSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-domain-sharingsettings.html", + "Properties": { + "NotebookOutputOption": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-domain-sharingsettings.html#cfn-sagemaker-domain-sharingsettings-notebookoutputoption", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "S3KmsKeyId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-domain-sharingsettings.html#cfn-sagemaker-domain-sharingsettings-s3kmskeyid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "S3OutputPath": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-domain-sharingsettings.html#cfn-sagemaker-domain-sharingsettings-s3outputpath", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::Domain.UserSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-domain-usersettings.html", + "Properties": { + "ExecutionRole": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-domain-usersettings.html#cfn-sagemaker-domain-usersettings-executionrole", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "JupyterServerAppSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-domain-usersettings.html#cfn-sagemaker-domain-usersettings-jupyterserverappsettings", + "Required": false, + "Type": "JupyterServerAppSettings", + "UpdateType": "Mutable" + }, + "KernelGatewayAppSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-domain-usersettings.html#cfn-sagemaker-domain-usersettings-kernelgatewayappsettings", + "Required": false, + "Type": "KernelGatewayAppSettings", + "UpdateType": "Mutable" + }, + "SecurityGroups": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-domain-usersettings.html#cfn-sagemaker-domain-usersettings-securitygroups", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "SharingSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-domain-usersettings.html#cfn-sagemaker-domain-usersettings-sharingsettings", + "Required": false, + "Type": "SharingSettings", + "UpdateType": "Mutable" + } + } + }, "AWS::SageMaker::Endpoint.Alarm": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-endpoint-alarm.html", "Properties": { @@ -48310,17 +49025,6 @@ } } }, - "AWS::SageMaker::Model.InferenceExecutionConfig": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-model-inferenceexecutionconfig.html", - "Properties": { - "Mode": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-model-inferenceexecutionconfig.html#cfn-sagemaker-model-inferenceexecutionconfig-mode", - "PrimitiveType": "String", - "Required": true, - "UpdateType": "Immutable" - } - } - }, "AWS::SageMaker::Model.MultiModelConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-model-containerdefinition-multimodelconfig.html", "Properties": { @@ -49651,6 +50355,142 @@ } } }, + "AWS::SageMaker::UserProfile.CustomImage": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-userprofile-customimage.html", + "Properties": { + "AppImageConfigName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-userprofile-customimage.html#cfn-sagemaker-userprofile-customimage-appimageconfigname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ImageName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-userprofile-customimage.html#cfn-sagemaker-userprofile-customimage-imagename", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ImageVersionNumber": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-userprofile-customimage.html#cfn-sagemaker-userprofile-customimage-imageversionnumber", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::UserProfile.JupyterServerAppSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-userprofile-jupyterserverappsettings.html", + "Properties": { + "DefaultResourceSpec": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-userprofile-jupyterserverappsettings.html#cfn-sagemaker-userprofile-jupyterserverappsettings-defaultresourcespec", + "Required": false, + "Type": "ResourceSpec", + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::UserProfile.KernelGatewayAppSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-userprofile-kernelgatewayappsettings.html", + "Properties": { + "CustomImages": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-userprofile-kernelgatewayappsettings.html#cfn-sagemaker-userprofile-kernelgatewayappsettings-customimages", + "DuplicatesAllowed": true, + "ItemType": "CustomImage", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "DefaultResourceSpec": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-userprofile-kernelgatewayappsettings.html#cfn-sagemaker-userprofile-kernelgatewayappsettings-defaultresourcespec", + "Required": false, + "Type": "ResourceSpec", + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::UserProfile.ResourceSpec": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-userprofile-resourcespec.html", + "Properties": { + "InstanceType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-userprofile-resourcespec.html#cfn-sagemaker-userprofile-resourcespec-instancetype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SageMakerImageArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-userprofile-resourcespec.html#cfn-sagemaker-userprofile-resourcespec-sagemakerimagearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SageMakerImageVersionArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-userprofile-resourcespec.html#cfn-sagemaker-userprofile-resourcespec-sagemakerimageversionarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::UserProfile.SharingSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-userprofile-sharingsettings.html", + "Properties": { + "NotebookOutputOption": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-userprofile-sharingsettings.html#cfn-sagemaker-userprofile-sharingsettings-notebookoutputoption", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "S3KmsKeyId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-userprofile-sharingsettings.html#cfn-sagemaker-userprofile-sharingsettings-s3kmskeyid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "S3OutputPath": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-userprofile-sharingsettings.html#cfn-sagemaker-userprofile-sharingsettings-s3outputpath", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::UserProfile.UserSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-userprofile-usersettings.html", + "Properties": { + "ExecutionRole": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-userprofile-usersettings.html#cfn-sagemaker-userprofile-usersettings-executionrole", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "JupyterServerAppSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-userprofile-usersettings.html#cfn-sagemaker-userprofile-usersettings-jupyterserverappsettings", + "Required": false, + "Type": "JupyterServerAppSettings", + "UpdateType": "Mutable" + }, + "KernelGatewayAppSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-userprofile-usersettings.html#cfn-sagemaker-userprofile-usersettings-kernelgatewayappsettings", + "Required": false, + "Type": "KernelGatewayAppSettings", + "UpdateType": "Mutable" + }, + "SecurityGroups": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-userprofile-usersettings.html#cfn-sagemaker-userprofile-usersettings-securitygroups", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "SharingSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-userprofile-usersettings.html#cfn-sagemaker-userprofile-usersettings-sharingsettings", + "Required": false, + "Type": "SharingSettings", + "UpdateType": "Mutable" + } + } + }, "AWS::SageMaker::Workteam.CognitoMemberDefinition": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-workteam-cognitomemberdefinition.html", "Properties": { @@ -49916,6 +50756,23 @@ } } }, + "AWS::ServiceCatalog::ServiceAction.DefinitionParameter": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-servicecatalog-serviceaction-definitionparameter.html", + "Properties": { + "Key": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-servicecatalog-serviceaction-definitionparameter.html#cfn-servicecatalog-serviceaction-definitionparameter-key", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-servicecatalog-serviceaction-definitionparameter.html#cfn-servicecatalog-serviceaction-definitionparameter-value", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::ServiceCatalogAppRegistry::AttributeGroup.Attributes": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-servicecatalogappregistry-attributegroup-attributes.html" }, @@ -52460,7 +53317,7 @@ } } }, - "ResourceSpecificationVersion": "26.0.0", + "ResourceSpecificationVersion": "28.0.0", "ResourceTypes": { "AWS::ACMPCA::Certificate": { "Attributes": { @@ -53147,6 +54004,11 @@ } }, "AWS::ApiGateway::ApiKey": { + "Attributes": { + "APIKeyId": { + "PrimitiveType": "String" + } + }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-apikey.html", "Properties": { "CustomerId": { @@ -55075,7 +55937,7 @@ "GatewayRouteName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appmesh-gatewayroute.html#cfn-appmesh-gatewayroute-gatewayroutename", "PrimitiveType": "String", - "Required": true, + "Required": false, "UpdateType": "Immutable" }, "MeshName": { @@ -55134,7 +55996,7 @@ "MeshName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appmesh-mesh.html#cfn-appmesh-mesh-meshname", "PrimitiveType": "String", - "Required": true, + "Required": false, "UpdateType": "Immutable" }, "Spec": { @@ -55193,7 +56055,7 @@ "RouteName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appmesh-route.html#cfn-appmesh-route-routename", "PrimitiveType": "String", - "Required": true, + "Required": false, "UpdateType": "Immutable" }, "Spec": { @@ -55268,7 +56130,7 @@ "VirtualGatewayName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appmesh-virtualgateway.html#cfn-appmesh-virtualgateway-virtualgatewayname", "PrimitiveType": "String", - "Required": true, + "Required": false, "UpdateType": "Immutable" } } @@ -55324,7 +56186,7 @@ "VirtualNodeName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appmesh-virtualnode.html#cfn-appmesh-virtualnode-virtualnodename", "PrimitiveType": "String", - "Required": true, + "Required": false, "UpdateType": "Immutable" } } @@ -55380,7 +56242,7 @@ "VirtualRouterName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appmesh-virtualrouter.html#cfn-appmesh-virtualrouter-virtualroutername", "PrimitiveType": "String", - "Required": true, + "Required": false, "UpdateType": "Immutable" } } @@ -57427,6 +58289,14 @@ "PrimitiveType": "String", "Required": false, "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cassandra-keyspace.html#cfn-cassandra-keyspace-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" } } }, @@ -57461,6 +58331,12 @@ "Type": "List", "UpdateType": "Immutable" }, + "PointInTimeRecoveryEnabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cassandra-table.html#cfn-cassandra-table-pointintimerecoveryenabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, "RegularColumns": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cassandra-table.html#cfn-cassandra-table-regularcolumns", "DuplicatesAllowed": false, @@ -57474,6 +58350,14 @@ "PrimitiveType": "String", "Required": false, "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cassandra-table.html#cfn-cassandra-table-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" } } }, @@ -57759,6 +58643,83 @@ } } }, + "AWS::CloudFormation::ResourceDefaultVersion": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-resourcedefaultversion.html", + "Properties": { + "TypeName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-resourcedefaultversion.html#cfn-cloudformation-resourcedefaultversion-typename", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "TypeVersionArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-resourcedefaultversion.html#cfn-cloudformation-resourcedefaultversion-typeversionarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "VersionId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-resourcedefaultversion.html#cfn-cloudformation-resourcedefaultversion-versionid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFormation::ResourceVersion": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "IsDefaultVersion": { + "PrimitiveType": "Boolean" + }, + "ProvisioningType": { + "PrimitiveType": "String" + }, + "TypeArn": { + "PrimitiveType": "String" + }, + "VersionId": { + "PrimitiveType": "String" + }, + "Visibility": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-resourceversion.html", + "Properties": { + "ExecutionRoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-resourceversion.html#cfn-cloudformation-resourceversion-executionrolearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "LoggingConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-resourceversion.html#cfn-cloudformation-resourceversion-loggingconfig", + "Required": false, + "Type": "LoggingConfig", + "UpdateType": "Mutable" + }, + "SchemaHandlerPackage": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-resourceversion.html#cfn-cloudformation-resourceversion-schemahandlerpackage", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "TypeName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-resourceversion.html#cfn-cloudformation-resourceversion-typename", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::CloudFormation::Stack": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-stack.html", "Properties": { @@ -58535,6 +59496,12 @@ "Required": false, "UpdateType": "Immutable" }, + "OutputFormat": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudwatch-metricstream.html#cfn-cloudwatch-metricstream-outputformat", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "RoleArn": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudwatch-metricstream.html#cfn-cloudwatch-metricstream-rolearn", "PrimitiveType": "String", @@ -60745,6 +61712,12 @@ "Required": false, "UpdateType": "Mutable" }, + "DocDbSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-docdbsettings", + "Required": false, + "Type": "DocDbSettings", + "UpdateType": "Mutable" + }, "DynamoDbSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-dynamodbsettings", "Required": false, @@ -60781,6 +61754,12 @@ "Required": false, "UpdateType": "Mutable" }, + "IbmDb2Settings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-ibmdb2settings", + "Required": false, + "Type": "IbmDb2Settings", + "UpdateType": "Mutable" + }, "KafkaSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-kafkasettings", "Required": false, @@ -60799,18 +61778,36 @@ "Required": false, "UpdateType": "Immutable" }, + "MicrosoftSqlServerSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-microsoftsqlserversettings", + "Required": false, + "Type": "MicrosoftSqlServerSettings", + "UpdateType": "Mutable" + }, "MongoDbSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-mongodbsettings", "Required": false, "Type": "MongoDbSettings", "UpdateType": "Mutable" }, + "MySqlSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-mysqlsettings", + "Required": false, + "Type": "MySqlSettings", + "UpdateType": "Mutable" + }, "NeptuneSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-neptunesettings", "Required": false, "Type": "NeptuneSettings", "UpdateType": "Mutable" }, + "OracleSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-oraclesettings", + "Required": false, + "Type": "OracleSettings", + "UpdateType": "Mutable" + }, "Password": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-password", "PrimitiveType": "String", @@ -60823,6 +61820,18 @@ "Required": false, "UpdateType": "Mutable" }, + "PostgreSqlSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-postgresqlsettings", + "Required": false, + "Type": "PostgreSqlSettings", + "UpdateType": "Mutable" + }, + "RedshiftSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-redshiftsettings", + "Required": false, + "Type": "RedshiftSettings", + "UpdateType": "Mutable" + }, "S3Settings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-s3settings", "Required": false, @@ -60841,6 +61850,12 @@ "Required": false, "UpdateType": "Mutable" }, + "SybaseSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-sybasesettings", + "Required": false, + "Type": "SybaseSettings", + "UpdateType": "Mutable" + }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-tags", "ItemType": "Tag", @@ -64548,6 +65563,185 @@ } } }, + "AWS::EC2::TransitGatewayMulticastDomain": { + "Attributes": { + "CreationTime": { + "PrimitiveType": "String" + }, + "State": { + "PrimitiveType": "String" + }, + "TransitGatewayMulticastDomainArn": { + "PrimitiveType": "String" + }, + "TransitGatewayMulticastDomainId": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewaymulticastdomain.html", + "Properties": { + "Options": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewaymulticastdomain.html#cfn-ec2-transitgatewaymulticastdomain-options", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewaymulticastdomain.html#cfn-ec2-transitgatewaymulticastdomain-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "TransitGatewayId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewaymulticastdomain.html#cfn-ec2-transitgatewaymulticastdomain-transitgatewayid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::EC2::TransitGatewayMulticastDomainAssociation": { + "Attributes": { + "ResourceId": { + "PrimitiveType": "String" + }, + "ResourceType": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewaymulticastdomainassociation.html", + "Properties": { + "State": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewaymulticastdomainassociation.html#cfn-ec2-transitgatewaymulticastdomainassociation-state", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SubnetId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewaymulticastdomainassociation.html#cfn-ec2-transitgatewaymulticastdomainassociation-subnetid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "TransitGatewayAttachmentId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewaymulticastdomainassociation.html#cfn-ec2-transitgatewaymulticastdomainassociation-transitgatewayattachmentid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "TransitGatewayMulticastDomainId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewaymulticastdomainassociation.html#cfn-ec2-transitgatewaymulticastdomainassociation-transitgatewaymulticastdomainid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::EC2::TransitGatewayMulticastGroupMember": { + "Attributes": { + "GroupMember": { + "PrimitiveType": "Boolean" + }, + "GroupSource": { + "PrimitiveType": "Boolean" + }, + "MemberType": { + "PrimitiveType": "String" + }, + "ResourceId": { + "PrimitiveType": "String" + }, + "ResourceType": { + "PrimitiveType": "String" + }, + "SourceType": { + "PrimitiveType": "String" + }, + "SubnetId": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewaymulticastgroupmember.html", + "Properties": { + "GroupIpAddress": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewaymulticastgroupmember.html#cfn-ec2-transitgatewaymulticastgroupmember-groupipaddress", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "NetworkInterfaceId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewaymulticastgroupmember.html#cfn-ec2-transitgatewaymulticastgroupmember-networkinterfaceid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "TransitGatewayAttachmentId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewaymulticastgroupmember.html#cfn-ec2-transitgatewaymulticastgroupmember-transitgatewayattachmentid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "TransitGatewayMulticastDomainId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewaymulticastgroupmember.html#cfn-ec2-transitgatewaymulticastgroupmember-transitgatewaymulticastdomainid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::EC2::TransitGatewayMulticastGroupSource": { + "Attributes": { + "GroupMember": { + "PrimitiveType": "Boolean" + }, + "GroupSource": { + "PrimitiveType": "Boolean" + }, + "MemberType": { + "PrimitiveType": "String" + }, + "ResourceId": { + "PrimitiveType": "String" + }, + "ResourceType": { + "PrimitiveType": "String" + }, + "SourceType": { + "PrimitiveType": "String" + }, + "SubnetId": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewaymulticastgroupsource.html", + "Properties": { + "GroupIpAddress": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewaymulticastgroupsource.html#cfn-ec2-transitgatewaymulticastgroupsource-groupipaddress", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "NetworkInterfaceId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewaymulticastgroupsource.html#cfn-ec2-transitgatewaymulticastgroupsource-networkinterfaceid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "TransitGatewayAttachmentId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewaymulticastgroupsource.html#cfn-ec2-transitgatewaymulticastgroupsource-transitgatewayattachmentid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "TransitGatewayMulticastDomainId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewaymulticastgroupsource.html#cfn-ec2-transitgatewaymulticastgroupsource-transitgatewaymulticastdomainid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, "AWS::EC2::TransitGatewayRoute": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewayroute.html", "Properties": { @@ -65178,6 +66372,38 @@ } } }, + "AWS::ECR::RegistryPolicy": { + "Attributes": { + "RegistryId": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecr-registrypolicy.html", + "Properties": { + "PolicyText": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecr-registrypolicy.html#cfn-ecr-registrypolicy-policytext", + "PrimitiveType": "Json", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::ECR::ReplicationConfiguration": { + "Attributes": { + "RegistryId": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecr-replicationconfiguration.html", + "Properties": { + "ReplicationConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecr-replicationconfiguration.html#cfn-ecr-replicationconfiguration-replicationconfiguration", + "Required": true, + "Type": "ReplicationConfiguration", + "UpdateType": "Mutable" + } + } + }, "AWS::ECR::Repository": { "Attributes": { "Arn": { @@ -65278,12 +66504,6 @@ "Type": "List", "UpdateType": "Mutable" }, - "Configuration": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-cluster.html#cfn-ecs-cluster-configuration", - "Required": false, - "Type": "ClusterConfiguration", - "UpdateType": "Mutable" - }, "DefaultCapacityProviderStrategy": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-cluster.html#cfn-ecs-cluster-defaultcapacityproviderstrategy", "ItemType": "CapacityProviderStrategyItem", @@ -65411,7 +66631,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-service.html#cfn-ecs-service-platformversion", "PrimitiveType": "String", "Required": false, - "UpdateType": "Immutable" + "UpdateType": "Mutable" }, "PropagateTags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-service.html#cfn-ecs-service-propagatetags", @@ -66525,6 +67745,71 @@ } } }, + "AWS::ElastiCache::GlobalReplicationGroup": { + "Attributes": { + "GlobalReplicationGroupId": { + "PrimitiveType": "String" + }, + "Status": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticache-globalreplicationgroup.html", + "Properties": { + "AutomaticFailoverEnabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticache-globalreplicationgroup.html#cfn-elasticache-globalreplicationgroup-automaticfailoverenabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "CacheNodeType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticache-globalreplicationgroup.html#cfn-elasticache-globalreplicationgroup-cachenodetype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "EngineVersion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticache-globalreplicationgroup.html#cfn-elasticache-globalreplicationgroup-engineversion", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "GlobalNodeGroupCount": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticache-globalreplicationgroup.html#cfn-elasticache-globalreplicationgroup-globalnodegroupcount", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "GlobalReplicationGroupDescription": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticache-globalreplicationgroup.html#cfn-elasticache-globalreplicationgroup-globalreplicationgroupdescription", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "GlobalReplicationGroupIdSuffix": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticache-globalreplicationgroup.html#cfn-elasticache-globalreplicationgroup-globalreplicationgroupidsuffix", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Members": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticache-globalreplicationgroup.html#cfn-elasticache-globalreplicationgroup-members", + "DuplicatesAllowed": false, + "ItemType": "GlobalReplicationGroupMember", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "RegionalConfigurations": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticache-globalreplicationgroup.html#cfn-elasticache-globalreplicationgroup-regionalconfigurations", + "DuplicatesAllowed": false, + "ItemType": "RegionalConfiguration", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::ElastiCache::ParameterGroup": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-parameter-group.html", "Properties": { @@ -70841,6 +72126,102 @@ } } }, + "AWS::ImageBuilder::ContainerRecipe": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-containerrecipe.html", + "Properties": { + "Components": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-containerrecipe.html#cfn-imagebuilder-containerrecipe-components", + "ItemType": "ComponentConfiguration", + "Required": true, + "Type": "List", + "UpdateType": "Immutable" + }, + "ContainerType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-containerrecipe.html#cfn-imagebuilder-containerrecipe-containertype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-containerrecipe.html#cfn-imagebuilder-containerrecipe-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "DockerfileTemplateData": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-containerrecipe.html#cfn-imagebuilder-containerrecipe-dockerfiletemplatedata", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "DockerfileTemplateUri": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-containerrecipe.html#cfn-imagebuilder-containerrecipe-dockerfiletemplateuri", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ImageOsVersionOverride": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-containerrecipe.html#cfn-imagebuilder-containerrecipe-imageosversionoverride", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "KmsKeyId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-containerrecipe.html#cfn-imagebuilder-containerrecipe-kmskeyid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-containerrecipe.html#cfn-imagebuilder-containerrecipe-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "ParentImage": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-containerrecipe.html#cfn-imagebuilder-containerrecipe-parentimage", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "PlatformOverride": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-containerrecipe.html#cfn-imagebuilder-containerrecipe-platformoverride", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-containerrecipe.html#cfn-imagebuilder-containerrecipe-tags", + "PrimitiveItemType": "String", + "Required": false, + "Type": "Map", + "UpdateType": "Immutable" + }, + "TargetRepository": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-containerrecipe.html#cfn-imagebuilder-containerrecipe-targetrepository", + "Required": true, + "Type": "TargetContainerRepository", + "UpdateType": "Immutable" + }, + "Version": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-containerrecipe.html#cfn-imagebuilder-containerrecipe-version", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "WorkingDirectory": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-containerrecipe.html#cfn-imagebuilder-containerrecipe-workingdirectory", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, "AWS::ImageBuilder::DistributionConfiguration": { "Attributes": { "Arn": { @@ -72236,13 +73617,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-destination.html#cfn-iotwireless-destination-name", "PrimitiveType": "String", "Required": true, - "UpdateType": "Mutable" - }, - "NextToken": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-destination.html#cfn-iotwireless-destination-nexttoken", - "PrimitiveType": "String", - "Required": false, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "RoleArn": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-destination.html#cfn-iotwireless-destination-rolearn", @@ -72271,8 +73646,8 @@ }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-deviceprofile.html", "Properties": { - "LoRaWANDeviceProfile": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-deviceprofile.html#cfn-iotwireless-deviceprofile-lorawandeviceprofile", + "LoRaWAN": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-deviceprofile.html#cfn-iotwireless-deviceprofile-lorawan", "Required": false, "Type": "LoRaWANDeviceProfile", "UpdateType": "Mutable" @@ -72283,12 +73658,6 @@ "Required": false, "UpdateType": "Mutable" }, - "NextToken": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-deviceprofile.html#cfn-iotwireless-deviceprofile-nexttoken", - "PrimitiveType": "String", - "Required": false, - "UpdateType": "Mutable" - }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-deviceprofile.html#cfn-iotwireless-deviceprofile-tags", "DuplicatesAllowed": false, @@ -72306,18 +73675,15 @@ }, "Id": { "PrimitiveType": "String" + }, + "LoRaWANResponse": { + "Type": "LoRaWANGetServiceProfileInfo" } }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-serviceprofile.html", "Properties": { - "LoRaWANGetServiceProfileInfo": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-serviceprofile.html#cfn-iotwireless-serviceprofile-lorawangetserviceprofileinfo", - "Required": false, - "Type": "LoRaWANGetServiceProfileInfo", - "UpdateType": "Mutable" - }, - "LoRaWANServiceProfile": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-serviceprofile.html#cfn-iotwireless-serviceprofile-lorawanserviceprofile", + "LoRaWAN": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-serviceprofile.html#cfn-iotwireless-serviceprofile-lorawan", "Required": false, "Type": "LoRaWANServiceProfile", "UpdateType": "Mutable" @@ -72328,12 +73694,6 @@ "Required": false, "UpdateType": "Mutable" }, - "NextToken": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-serviceprofile.html#cfn-iotwireless-serviceprofile-nexttoken", - "PrimitiveType": "String", - "Required": false, - "UpdateType": "Mutable" - }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-serviceprofile.html#cfn-iotwireless-serviceprofile-tags", "DuplicatesAllowed": false, @@ -72373,20 +73733,20 @@ "Required": true, "UpdateType": "Mutable" }, - "LoRaWANDevice": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-wirelessdevice.html#cfn-iotwireless-wirelessdevice-lorawandevice", + "LastUplinkReceivedAt": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-wirelessdevice.html#cfn-iotwireless-wirelessdevice-lastuplinkreceivedat", + "PrimitiveType": "String", "Required": false, - "Type": "LoRaWANDevice", "UpdateType": "Mutable" }, - "Name": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-wirelessdevice.html#cfn-iotwireless-wirelessdevice-name", - "PrimitiveType": "String", + "LoRaWAN": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-wirelessdevice.html#cfn-iotwireless-wirelessdevice-lorawan", "Required": false, + "Type": "LoRaWANDevice", "UpdateType": "Mutable" }, - "NextToken": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-wirelessdevice.html#cfn-iotwireless-wirelessdevice-nexttoken", + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-wirelessdevice.html#cfn-iotwireless-wirelessdevice-name", "PrimitiveType": "String", "Required": false, "UpdateType": "Mutable" @@ -72427,8 +73787,14 @@ "Required": false, "UpdateType": "Mutable" }, - "LoRaWANGateway": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-wirelessgateway.html#cfn-iotwireless-wirelessgateway-lorawangateway", + "LastUplinkReceivedAt": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-wirelessgateway.html#cfn-iotwireless-wirelessgateway-lastuplinkreceivedat", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "LoRaWAN": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-wirelessgateway.html#cfn-iotwireless-wirelessgateway-lorawan", "Required": true, "Type": "LoRaWANGateway", "UpdateType": "Mutable" @@ -72439,12 +73805,6 @@ "Required": false, "UpdateType": "Mutable" }, - "NextToken": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-wirelessgateway.html#cfn-iotwireless-wirelessgateway-nexttoken", - "PrimitiveType": "String", - "Required": false, - "UpdateType": "Mutable" - }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-wirelessgateway.html#cfn-iotwireless-wirelessgateway-tags", "DuplicatesAllowed": false, @@ -73987,19 +75347,7 @@ "Arn": { "PrimitiveType": "String" }, - "CreatedAt": { - "PrimitiveType": "String" - }, - "LastUpdate": { - "Type": "LastUpdate" - }, - "Name": { - "PrimitiveType": "String" - }, - "ServiceRoleArn": { - "PrimitiveType": "String" - }, - "Status": { + "WebserverUrl": { "PrimitiveType": "String" } }, @@ -74039,7 +75387,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-mwaa-environment.html#cfn-mwaa-environment-kmskey", "PrimitiveType": "String", "Required": false, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "LoggingConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-mwaa-environment.html#cfn-mwaa-environment-loggingconfiguration", @@ -74053,11 +75401,17 @@ "Required": false, "UpdateType": "Mutable" }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-mwaa-environment.html#cfn-mwaa-environment-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, "NetworkConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-mwaa-environment.html#cfn-mwaa-environment-networkconfiguration", "Required": false, "Type": "NetworkConfiguration", - "UpdateType": "Immutable" + "UpdateType": "Mutable" }, "PluginsS3ObjectVersion": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-mwaa-environment.html#cfn-mwaa-environment-pluginss3objectversion", @@ -74101,12 +75455,6 @@ "Required": false, "UpdateType": "Mutable" }, - "WebserverUrl": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-mwaa-environment.html#cfn-mwaa-environment-webserverurl", - "PrimitiveType": "String", - "Required": false, - "UpdateType": "Mutable" - }, "WeeklyMaintenanceWindowStart": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-mwaa-environment.html#cfn-mwaa-environment-weeklymaintenancewindowstart", "PrimitiveType": "String", @@ -74301,7 +75649,7 @@ "MemberId": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-managedblockchain-node.html#cfn-managedblockchain-node-memberid", "PrimitiveType": "String", - "Required": true, + "Required": false, "UpdateType": "Mutable" }, "NetworkId": { @@ -74863,6 +76211,12 @@ "PrimitiveType": "Json", "Required": false, "UpdateType": "Mutable" + }, + "Vpc": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-medialive-channel.html#cfn-medialive-channel-vpc", + "Required": false, + "Type": "VpcOutputSettings", + "UpdateType": "Immutable" } } }, @@ -81432,6 +82786,84 @@ } } }, + "AWS::SageMaker::App": { + "Attributes": { + "AppArn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-app.html", + "Properties": { + "AppName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-app.html#cfn-sagemaker-app-appname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "AppType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-app.html#cfn-sagemaker-app-apptype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "DomainId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-app.html#cfn-sagemaker-app-domainid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "ResourceSpec": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-app.html#cfn-sagemaker-app-resourcespec", + "Required": false, + "Type": "ResourceSpec", + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-app.html#cfn-sagemaker-app-tags", + "DuplicatesAllowed": true, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "UserProfileName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-app.html#cfn-sagemaker-app-userprofilename", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, + "AWS::SageMaker::AppImageConfig": { + "Attributes": { + "AppImageConfigArn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-appimageconfig.html", + "Properties": { + "AppImageConfigName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-appimageconfig.html#cfn-sagemaker-appimageconfig-appimageconfigname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "KernelGatewayImageConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-appimageconfig.html#cfn-sagemaker-appimageconfig-kernelgatewayimageconfig", + "Required": false, + "Type": "KernelGatewayImageConfig", + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-appimageconfig.html#cfn-sagemaker-appimageconfig-tags", + "DuplicatesAllowed": true, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + } + } + }, "AWS::SageMaker::CodeRepository": { "Attributes": { "CodeRepositoryName": { @@ -81589,6 +83021,80 @@ } } }, + "AWS::SageMaker::Domain": { + "Attributes": { + "DomainArn": { + "PrimitiveType": "String" + }, + "DomainId": { + "PrimitiveType": "String" + }, + "HomeEfsFileSystemId": { + "PrimitiveType": "String" + }, + "SingleSignOnManagedApplicationInstanceId": { + "PrimitiveType": "String" + }, + "Url": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-domain.html", + "Properties": { + "AppNetworkAccessType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-domain.html#cfn-sagemaker-domain-appnetworkaccesstype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "AuthMode": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-domain.html#cfn-sagemaker-domain-authmode", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "DefaultUserSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-domain.html#cfn-sagemaker-domain-defaultusersettings", + "Required": true, + "Type": "UserSettings", + "UpdateType": "Mutable" + }, + "DomainName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-domain.html#cfn-sagemaker-domain-domainname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "KmsKeyId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-domain.html#cfn-sagemaker-domain-kmskeyid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "SubnetIds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-domain.html#cfn-sagemaker-domain-subnetids", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-domain.html#cfn-sagemaker-domain-tags", + "DuplicatesAllowed": true, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "VpcId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-domain.html#cfn-sagemaker-domain-vpcid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, "AWS::SageMaker::Endpoint": { "Attributes": { "EndpointName": { @@ -81769,12 +83275,6 @@ "Required": true, "UpdateType": "Immutable" }, - "InferenceExecutionConfig": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-model.html#cfn-sagemaker-model-inferenceexecutionconfig", - "Required": false, - "Type": "InferenceExecutionConfig", - "UpdateType": "Immutable" - }, "ModelName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-model.html#cfn-sagemaker-model-modelname", "PrimitiveType": "String", @@ -82342,6 +83842,54 @@ } } }, + "AWS::SageMaker::UserProfile": { + "Attributes": { + "UserProfileArn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-userprofile.html", + "Properties": { + "DomainId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-userprofile.html#cfn-sagemaker-userprofile-domainid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "SingleSignOnUserIdentifier": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-userprofile.html#cfn-sagemaker-userprofile-singlesignonuseridentifier", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "SingleSignOnUserValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-userprofile.html#cfn-sagemaker-userprofile-singlesignonuservalue", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-userprofile.html#cfn-sagemaker-userprofile-tags", + "DuplicatesAllowed": true, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "UserProfileName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-userprofile.html#cfn-sagemaker-userprofile-userprofilename", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "UserSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-userprofile.html#cfn-sagemaker-userprofile-usersettings", + "Required": false, + "Type": "UserSettings", + "UpdateType": "Mutable" + } + } + }, "AWS::SageMaker::Workteam": { "Attributes": { "WorkteamName": { @@ -82984,6 +84532,70 @@ } } }, + "AWS::ServiceCatalog::ServiceAction": { + "Attributes": { + "Id": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-servicecatalog-serviceaction.html", + "Properties": { + "AcceptLanguage": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-servicecatalog-serviceaction.html#cfn-servicecatalog-serviceaction-acceptlanguage", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Definition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-servicecatalog-serviceaction.html#cfn-servicecatalog-serviceaction-definition", + "ItemType": "DefinitionParameter", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "DefinitionType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-servicecatalog-serviceaction.html#cfn-servicecatalog-serviceaction-definitiontype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-servicecatalog-serviceaction.html#cfn-servicecatalog-serviceaction-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-servicecatalog-serviceaction.html#cfn-servicecatalog-serviceaction-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::ServiceCatalog::ServiceActionAssociation": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-servicecatalog-serviceactionassociation.html", + "Properties": { + "ProductId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-servicecatalog-serviceactionassociation.html#cfn-servicecatalog-serviceactionassociation-productid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "ProvisioningArtifactId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-servicecatalog-serviceactionassociation.html#cfn-servicecatalog-serviceactionassociation-provisioningartifactid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "ServiceActionId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-servicecatalog-serviceactionassociation.html#cfn-servicecatalog-serviceactionassociation-serviceactionid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, "AWS::ServiceCatalog::StackSetConstraint": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-servicecatalog-stacksetconstraint.html", "Properties": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/800_IoTWireless_ServicProfile_patch.json b/packages/@aws-cdk/cfnspec/spec-source/800_IoTWireless_ServicProfile_patch.json new file mode 100644 index 0000000000000..8fbd5d77b4619 --- /dev/null +++ b/packages/@aws-cdk/cfnspec/spec-source/800_IoTWireless_ServicProfile_patch.json @@ -0,0 +1,17 @@ +{ + "ResourceTypes": { + "patch": { + "description": "Invalid attribute type for LoRaWANResponse", + "operations": [ + { + "op": "add", + "path": "/AWS::IoTWireless::ServiceProfile/Attributes/LoRaWANResponse", + "value": { + "Type": "Map", + "PrimitiveItemType": "String" + } + } + ] + } + } +} diff --git a/packages/@aws-cdk/cfnspec/spec-source/cfn-lint/StatefulResources/000.json b/packages/@aws-cdk/cfnspec/spec-source/cfn-lint/StatefulResources/000.json new file mode 100644 index 0000000000000..25c5e11c890ff --- /dev/null +++ b/packages/@aws-cdk/cfnspec/spec-source/cfn-lint/StatefulResources/000.json @@ -0,0 +1,30 @@ +{ + "ResourceTypes": { + "AWS::CloudFormation::Stack" : {}, + "AWS::Backup::BackupVault" : {}, + "AWS::Cognito::UserPool" : {}, + "AWS::DocDB::DBCluster" : {}, + "AWS::DocDB::DBInstance" : {}, + "AWS::DynamoDB::Table" : {}, + "AWS::EC2::Volume" : {}, + "AWS::EFS::FileSystem" : {}, + "AWS::EMR::Cluster" : {}, + "AWS::ElastiCache::CacheCluster" : {}, + "AWS::ElastiCache::ReplicationGroup" : {}, + "AWS::Elasticsearch::Domain" : {}, + "AWS::FSx::FileSystem" : {}, + "AWS::Logs::LogGroup" : {}, + "AWS::Neptune::DBCluster" : {}, + "AWS::Neptune::DBInstance" : {}, + "AWS::QLDB::Ledger" : {}, + "AWS::RDS::DBCluster" : {}, + "AWS::RDS::DBInstance" : {}, + "AWS::Redshift::Cluster" : {}, + "AWS::SDB::Domain" : {}, + "AWS::SQS::Queue" : {}, + "AWS::S3::Bucket" : { + "DeleteRequiresEmptyResource": true + } + } +} + diff --git a/packages/@aws-cdk/cfnspec/test/test.cfnlint-annotations.ts b/packages/@aws-cdk/cfnspec/test/test.cfnlint-annotations.ts new file mode 100644 index 0000000000000..04e0972893d12 --- /dev/null +++ b/packages/@aws-cdk/cfnspec/test/test.cfnlint-annotations.ts @@ -0,0 +1,28 @@ +import { Test } from 'nodeunit'; +import * as cfnspec from '../lib'; + +module.exports = { + 'spot-check Bucket statefulness'(test: Test) { + const anno = cfnspec.cfnLintAnnotations('AWS::S3::Bucket'); + test.equal(anno.stateful, true); + test.equal(anno.mustBeEmptyToDelete, true); + + test.done(); + }, + + 'spot-check Table statefulness'(test: Test) { + const anno = cfnspec.cfnLintAnnotations('AWS::DynamoDB::Table'); + test.equal(anno.stateful, true); + test.equal(anno.mustBeEmptyToDelete, false); + + test.done(); + }, + + 'spot-check MediaStore metrics'(test: Test) { + const anno = cfnspec.cfnLintAnnotations('AWS::MediaStore::Thingy'); + test.equal(anno.stateful, false); + + test.done(); + }, +}; + diff --git a/packages/@aws-cdk/cloud-assembly-schema/package.json b/packages/@aws-cdk/cloud-assembly-schema/package.json index c931954efcf0b..724512a094826 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/package.json +++ b/packages/@aws-cdk/cloud-assembly-schema/package.json @@ -64,7 +64,7 @@ "jest": "^26.6.3", "mock-fs": "^4.13.0", "pkglint": "0.0.0", - "typescript-json-schema": "^0.48.0" + "typescript-json-schema": "^0.49.0" }, "repository": { "url": "https://github.com/aws/aws-cdk.git", @@ -97,5 +97,8 @@ "maturity": "stable", "cdk-build": { "jest": true + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/cloudformation-diff/lib/diff/util.ts b/packages/@aws-cdk/cloudformation-diff/lib/diff/util.ts index 763afbecaf79e..f4c452499ee09 100644 --- a/packages/@aws-cdk/cloudformation-diff/lib/diff/util.ts +++ b/packages/@aws-cdk/cloudformation-diff/lib/diff/util.ts @@ -23,7 +23,8 @@ export function deepEqual(lvalue: any, rvalue: any): boolean { } // allows a numeric 10 and a literal "10" to be equivalent; // this is consistent with CloudFormation. - if (((typeof lvalue === 'string') || (typeof rvalue === 'string')) && (parseFloat(lvalue) === parseFloat(rvalue))) { + if ((typeof lvalue === 'string' || typeof rvalue === 'string') && + safeParseFloat(lvalue) === safeParseFloat(rvalue)) { return true; } if (typeof lvalue !== typeof rvalue) { return false; } @@ -132,3 +133,20 @@ export function unionOf(lv: string[] | Set, rv: string[] | Set): } return new Array(...result); } + +/** + * A parseFloat implementation that does the right thing for + * strings like '0.0.0' + * (for which JavaScript's parseFloat() returns 0). + */ +function safeParseFloat(str: string): number { + const ret = parseFloat(str); + if (ret === 0) { + // if the str is exactly '0', that's OK; + // but parseFloat() also returns 0 for things like '0.0'; + // in this case, return NaN, so we'll fall back to string comparison + return str === '0' ? ret : NaN; + } else { + return ret; + } +} diff --git a/packages/@aws-cdk/cloudformation-diff/lib/diffable.ts b/packages/@aws-cdk/cloudformation-diff/lib/diffable.ts index 7bc87b51144ef..445f6adcef7c3 100644 --- a/packages/@aws-cdk/cloudformation-diff/lib/diffable.ts +++ b/packages/@aws-cdk/cloudformation-diff/lib/diffable.ts @@ -44,13 +44,13 @@ interface Eq { /** * Whether a collection contains some element (by value) */ -function contains>(element: T, xs: T[]) { +function contains>(element: T, xs: T[]): boolean { return xs.some(x => x.equal(element)); } /** * Return collection except for elements */ -function difference>(collection: T[], elements: T[]) { +function difference>(collection: T[], elements: T[]): T[] { return collection.filter(x => !contains(x, elements)); } diff --git a/packages/@aws-cdk/cloudformation-diff/lib/iam/iam-changes.ts b/packages/@aws-cdk/cloudformation-diff/lib/iam/iam-changes.ts index 824e9403c95d4..291ab9803f4c9 100644 --- a/packages/@aws-cdk/cloudformation-diff/lib/iam/iam-changes.ts +++ b/packages/@aws-cdk/cloudformation-diff/lib/iam/iam-changes.ts @@ -4,8 +4,8 @@ import { PropertyChange, PropertyMap, ResourceChange } from '../diff/types'; import { DiffableCollection } from '../diffable'; import { renderIntrinsics } from '../render-intrinsics'; import { deepRemoveUndefined, dropIfEmpty, flatMap, makeComparator } from '../util'; -import { ManagedPolicyAttachment, ManagedPolicyJson, parseManagedPolicies } from './managed-policy'; -import { parseLambdaPermission, parseStatements, renderCondition, Statement, StatementJson, Targets } from './statement'; +import { ManagedPolicyAttachment, ManagedPolicyJson } from './managed-policy'; +import { parseLambdaPermission, parseStatements, Statement, StatementJson } from './statement'; export interface IamChangesProps { propertyChanges: PropertyChange[]; @@ -69,23 +69,25 @@ export class IamChanges { // First generate all lines, then sort on Resource so that similar resources are together for (const statement of this.statements.additions) { + const renderedStatement = statement.render(); ret.push([ '+', - renderTargets(statement.resources), - statement.effect, - renderTargets(statement.actions), - renderTargets(statement.principals), - renderCondition(statement.condition), + renderedStatement.resource, + renderedStatement.effect, + renderedStatement.action, + renderedStatement.principal, + renderedStatement.condition, ].map(s => colors.green(s))); } for (const statement of this.statements.removals) { + const renderedStatement = statement.render(); ret.push([ colors.red('-'), - renderTargets(statement.resources), - statement.effect, - renderTargets(statement.actions), - renderTargets(statement.principals), - renderCondition(statement.condition), + renderedStatement.resource, + renderedStatement.effect, + renderedStatement.action, + renderedStatement.principal, + renderedStatement.condition, ].map(s => colors.red(s))); } @@ -125,14 +127,17 @@ export class IamChanges { } /** - * Return a machine-readable version of the changes + * Return a machine-readable version of the changes. + * This is only used in tests. + * + * @internal */ - public toJson(): IamChangesJson { + public _toJson(): IamChangesJson { return deepRemoveUndefined({ - statementAdditions: dropIfEmpty(this.statements.additions.map(s => s.toJson())), - statementRemovals: dropIfEmpty(this.statements.removals.map(s => s.toJson())), - managedPolicyAdditions: dropIfEmpty(this.managedPolicies.additions.map(s => s.toJson())), - managedPolicyRemovals: dropIfEmpty(this.managedPolicies.removals.map(s => s.toJson())), + statementAdditions: dropIfEmpty(this.statements.additions.map(s => s._toJson())), + statementRemovals: dropIfEmpty(this.statements.removals.map(s => s._toJson())), + managedPolicyAdditions: dropIfEmpty(this.managedPolicies.additions.map(s => s._toJson())), + managedPolicyRemovals: dropIfEmpty(this.managedPolicies.removals.map(s => s._toJson())), }); } @@ -184,7 +189,11 @@ export class IamChanges { const appliesToPrincipal = 'AWS:${' + logicalId + '}'; return flatMap(policies, (policy: any) => { - return defaultPrincipal(appliesToPrincipal, parseStatements(renderIntrinsics(policy.PolicyDocument.Statement))); + // check if the Policy itself is not an intrinsic, like an Fn::If + const unparsedStatement = policy.PolicyDocument?.Statement + ? policy.PolicyDocument.Statement + : policy; + return defaultPrincipal(appliesToPrincipal, parseStatements(renderIntrinsics(unparsedStatement))); }); } @@ -234,11 +243,11 @@ export class IamChanges { }); } - private readManagedPolicies(policyArns: string[] | undefined, logicalId: string): ManagedPolicyAttachment[] { + private readManagedPolicies(policyArns: any, logicalId: string): ManagedPolicyAttachment[] { if (!policyArns) { return []; } const rep = '${' + logicalId + '}'; - return parseManagedPolicies(rep, renderIntrinsics(policyArns)); + return ManagedPolicyAttachment.parseManagedPolicies(rep, renderIntrinsics(policyArns)); } private readLambdaStatements(properties?: PropertyMap): Statement[] { @@ -266,16 +275,6 @@ function defaultResource(resource: string, statements: Statement[]) { return statements; } -/** - * Render into a summary table cell - */ -function renderTargets(targets: Targets): string { - if (targets.not) { - return targets.values.map(s => `NOT ${s}`).join('\n'); - } - return targets.values.join('\n'); -} - export interface IamChangesJson { statementAdditions?: StatementJson[]; statementRemovals?: StatementJson[]; diff --git a/packages/@aws-cdk/cloudformation-diff/lib/iam/managed-policy.ts b/packages/@aws-cdk/cloudformation-diff/lib/iam/managed-policy.ts index 121b2eae1efd3..f0d54140398bc 100644 --- a/packages/@aws-cdk/cloudformation-diff/lib/iam/managed-policy.ts +++ b/packages/@aws-cdk/cloudformation-diff/lib/iam/managed-policy.ts @@ -1,13 +1,25 @@ export class ManagedPolicyAttachment { + public static parseManagedPolicies(identityArn: string, arns: string | string[]): ManagedPolicyAttachment[] { + return typeof arns === 'string' + ? [new ManagedPolicyAttachment(identityArn, arns)] + : arns.map((arn: string) => new ManagedPolicyAttachment(identityArn, arn)); + } + constructor(public readonly identityArn: string, public readonly managedPolicyArn: string) { } - public equal(other: ManagedPolicyAttachment) { + public equal(other: ManagedPolicyAttachment): boolean { return this.identityArn === other.identityArn && this.managedPolicyArn === other.managedPolicyArn; } - public toJson() { + /** + * Return a machine-readable version of the changes. + * This is only used in tests. + * + * @internal + */ + public _toJson(): ManagedPolicyJson { return { identityArn: this.identityArn, managedPolicyArn: this.managedPolicyArn }; } } @@ -16,7 +28,3 @@ export interface ManagedPolicyJson { identityArn: string; managedPolicyArn: string; } - -export function parseManagedPolicies(identityArn: string, arns: string[]): ManagedPolicyAttachment[] { - return arns.map((arn: string) => new ManagedPolicyAttachment(identityArn, arn)); -} \ No newline at end of file diff --git a/packages/@aws-cdk/cloudformation-diff/lib/iam/statement.ts b/packages/@aws-cdk/cloudformation-diff/lib/iam/statement.ts index c9c950875e8bc..ea89ad4e597ee 100644 --- a/packages/@aws-cdk/cloudformation-diff/lib/iam/statement.ts +++ b/packages/@aws-cdk/cloudformation-diff/lib/iam/statement.ts @@ -32,36 +32,76 @@ export class Statement { */ public readonly condition?: any; - constructor(statement: UnknownMap) { - this.sid = expectString(statement.Sid); - this.effect = expectEffect(statement.Effect); - this.resources = new Targets(statement, 'Resource', 'NotResource'); - this.actions = new Targets(statement, 'Action', 'NotAction'); - this.principals = new Targets(statement, 'Principal', 'NotPrincipal'); - this.condition = statement.Condition; + private readonly serializedIntrinsic: string | undefined; + + constructor(statement: UnknownMap | string) { + if (typeof statement === 'string') { + this.sid = undefined; + this.effect = Effect.Unknown; + this.resources = new Targets({}, '', ''); + this.actions = new Targets({}, '', ''); + this.principals = new Targets({}, '', ''); + this.condition = undefined; + this.serializedIntrinsic = statement; + } else { + this.sid = expectString(statement.Sid); + this.effect = expectEffect(statement.Effect); + this.resources = new Targets(statement, 'Resource', 'NotResource'); + this.actions = new Targets(statement, 'Action', 'NotAction'); + this.principals = new Targets(statement, 'Principal', 'NotPrincipal'); + this.condition = statement.Condition; + this.serializedIntrinsic = undefined; + } } /** * Whether this statement is equal to the other statement */ - public equal(other: Statement) { + public equal(other: Statement): boolean { return (this.sid === other.sid && this.effect === other.effect + && this.serializedIntrinsic === other.serializedIntrinsic && this.resources.equal(other.resources) && this.actions.equal(other.actions) && this.principals.equal(other.principals) && deepEqual(this.condition, other.condition)); } - public toJson(): StatementJson { - return deepRemoveUndefined({ - sid: this.sid, - effect: this.effect, - resources: this.resources.toJson(), - principals: this.principals.toJson(), - actions: this.actions.toJson(), - condition: this.condition, - }); + public render(): RenderedStatement { + return this.serializedIntrinsic + ? { + resource: this.serializedIntrinsic, + effect: '', + action: '', + principal: this.principals.render(), // these will be replaced by the call to replaceEmpty() from IamChanges + condition: '', + } + : { + resource: this.resources.render(), + effect: this.effect, + action: this.actions.render(), + principal: this.principals.render(), + condition: renderCondition(this.condition), + }; + } + + /** + * Return a machine-readable version of the changes. + * This is only used in tests. + * + * @internal + */ + public _toJson(): StatementJson { + return this.serializedIntrinsic + ? this.serializedIntrinsic + : deepRemoveUndefined({ + sid: this.sid, + effect: this.effect, + resources: this.resources._toJson(), + principals: this.principals._toJson(), + actions: this.actions._toJson(), + condition: this.condition, + }); } /** @@ -76,6 +116,14 @@ export class Statement { } } +export interface RenderedStatement { + readonly resource: string; + readonly effect: string; + readonly action: string; + readonly principal: string; + readonly condition: string; +} + export interface StatementJson { sid?: string; effect: string; @@ -199,7 +247,22 @@ export class Targets { this.values.sort(); } - public toJson(): TargetsJson { + /** + * Render into a summary table cell + */ + public render(): string { + return this.not + ? this.values.map(s => `NOT ${s}`).join('\n') + : this.values.join('\n'); + } + + /** + * Return a machine-readable version of the changes. + * This is only used in tests. + * + * @internal + */ + public _toJson(): TargetsJson { return { not: this.not, values: this.values }; } } @@ -243,7 +306,7 @@ function forceListOfStrings(x: unknown): string[] { /** * Render the Condition column */ -export function renderCondition(condition: any) { +export function renderCondition(condition: any): string { if (!condition || Object.keys(condition).length === 0) { return ''; } const jsonRepresentation = JSON.stringify(condition, undefined, 2); diff --git a/packages/@aws-cdk/cloudformation-diff/package.json b/packages/@aws-cdk/cloudformation-diff/package.json index cac65d5775eab..2a1705ab876fd 100644 --- a/packages/@aws-cdk/cloudformation-diff/package.json +++ b/packages/@aws-cdk/cloudformation-diff/package.json @@ -31,12 +31,12 @@ "devDependencies": { "@types/jest": "^26.0.20", "@types/string-width": "^4.0.1", - "@types/table": "^5.0.0", + "@types/table": "^6.0.0", "cdk-build-tools": "0.0.0", - "fast-check": "^2.12.1", + "fast-check": "^2.13.0", "jest": "^26.6.3", "pkglint": "0.0.0", - "ts-jest": "^26.5.0" + "ts-jest": "^26.5.1" }, "repository": { "url": "https://github.com/aws/aws-cdk.git", @@ -55,5 +55,8 @@ "maturity": "experimental", "cdk-build": { "jest": true + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/cloudformation-diff/test/diff-template.test.ts b/packages/@aws-cdk/cloudformation-diff/test/diff-template.test.ts index 8110922a41790..bde05ef09056e 100644 --- a/packages/@aws-cdk/cloudformation-diff/test/diff-template.test.ts +++ b/packages/@aws-cdk/cloudformation-diff/test/diff-template.test.ts @@ -375,6 +375,34 @@ test('adding and removing quotes from a numeric property causes no changes', () expect(differences.resources.differenceCount).toBe(0); }); +test('versions are correctly detected as not numbers', () => { + const currentTemplate = { + Resources: { + ImageBuilderComponent: { + Type: 'AWS::ImageBuilder::Component', + Properties: { + Platform: 'Linux', + Version: '0.0.1', + }, + }, + }, + }; + const newTemplate = { + Resources: { + ImageBuilderComponent: { + Type: 'AWS::ImageBuilder::Component', + Properties: { + Platform: 'Linux', + Version: '0.0.2', + }, + }, + }, + }; + + const differences = diffTemplate(currentTemplate, newTemplate); + expect(differences.resources.differenceCount).toBe(1); +}); + test('single element arrays are equivalent to the single element in DependsOn expressions', () => { // GIVEN const currentTemplate = { diff --git a/packages/@aws-cdk/cloudformation-diff/test/iam/detect-changes.test.ts b/packages/@aws-cdk/cloudformation-diff/test/iam/detect-changes.test.ts index 1cf62c8d5286b..fd457cd701b66 100644 --- a/packages/@aws-cdk/cloudformation-diff/test/iam/detect-changes.test.ts +++ b/packages/@aws-cdk/cloudformation-diff/test/iam/detect-changes.test.ts @@ -14,7 +14,7 @@ test('shows new AssumeRolePolicyDocument', () => { })); // THEN - expect(diff.iamChanges.toJson()).toEqual({ + expect(diff.iamChanges._toJson()).toEqual({ statementAdditions: [ { effect: 'Allow', @@ -41,7 +41,7 @@ test('implicitly knows principal of identity policy for all resource types', () })); // THEN - expect(diff.iamChanges.toJson()).toEqual({ + expect(diff.iamChanges._toJson()).toEqual({ statementAdditions: [ { effect: 'Allow', @@ -73,7 +73,7 @@ test('policies on an identity object', () => { })); // THEN - expect(diff.iamChanges.toJson()).toEqual({ + expect(diff.iamChanges._toJson()).toEqual({ statementAdditions: [ { effect: 'Allow', @@ -100,7 +100,7 @@ test('if policy is attached to multiple roles all are shown', () => { })); // THEN - expect(diff.iamChanges.toJson()).toEqual({ + expect(diff.iamChanges._toJson()).toEqual({ statementAdditions: [ { effect: 'Allow', @@ -131,7 +131,7 @@ test('correctly parses Lambda permissions', () => { })); // THEN - expect(diff.iamChanges.toJson()).toEqual({ + expect(diff.iamChanges._toJson()).toEqual({ statementAdditions: [ { effect: 'Allow', @@ -162,7 +162,7 @@ test('implicitly knows resource of (queue) resource policy even if * given', () })); // THEN - expect(diff.iamChanges.toJson()).toEqual({ + expect(diff.iamChanges._toJson()).toEqual({ statementAdditions: [ { effect: 'Allow', @@ -189,7 +189,7 @@ test('finds sole statement removals', () => { }), {}); // THEN - expect(diff.iamChanges.toJson()).toEqual({ + expect(diff.iamChanges._toJson()).toEqual({ statementRemovals: [ { effect: 'Allow', @@ -233,7 +233,7 @@ test('finds one of many statement removals', () => { })); // THEN - expect(diff.iamChanges.toJson()).toEqual({ + expect(diff.iamChanges._toJson()).toEqual({ statementRemovals: [ { effect: 'Allow', @@ -254,7 +254,7 @@ test('finds policy attachments', () => { })); // THEN - expect(diff.iamChanges.toJson()).toEqual({ + expect(diff.iamChanges._toJson()).toEqual({ managedPolicyAdditions: [ { identityArn: '${SomeRole}', @@ -279,7 +279,7 @@ test('finds policy removals', () => { })); // THEN - expect(diff.iamChanges.toJson()).toEqual({ + expect(diff.iamChanges._toJson()).toEqual({ managedPolicyRemovals: [ { identityArn: '${SomeRole}', @@ -314,7 +314,7 @@ test('queuepolicy queue change counts as removal+addition', () => { })); // THEN - expect(diff.iamChanges.toJson()).toEqual({ + expect(diff.iamChanges._toJson()).toEqual({ statementAdditions: [ { effect: 'Allow', @@ -333,3 +333,90 @@ test('queuepolicy queue change counts as removal+addition', () => { ], }); }); + +test('supports Fn::If in the top-level property value of Role', () => { + // WHEN + const diff = diffTemplate({}, template({ + MyRole: role({ + AssumeRolePolicyDocument: poldoc({ + Action: 'sts:AssumeRole', + Effect: 'Allow', + Principal: { Service: 'lambda.amazonaws.com' }, + }), + ManagedPolicyArns: { + 'Fn::If': [ + 'SomeCondition', + ['then-managed-policy-arn'], + ['else-managed-policy-arn'], + ], + }, + }), + })); + + // THEN + expect(diff.iamChanges._toJson()).toEqual({ + managedPolicyAdditions: [ + { + identityArn: '${MyRole}', + managedPolicyArn: '{"Fn::If":["SomeCondition",["then-managed-policy-arn"],["else-managed-policy-arn"]]}', + }, + ], + statementAdditions: [ + { + effect: 'Allow', + principals: { not: false, values: ['Service:lambda.amazonaws.com'] }, + actions: { not: false, values: ['sts:AssumeRole'] }, + resources: { + not: false, + values: ['${MyRole.Arn}'], + }, + }, + ], + }); +}); + +test('supports Fn::If in the elements of an array-typed property of Role', () => { + // WHEN + const diff = diffTemplate({}, template({ + MyRole: role({ + AssumeRolePolicyDocument: poldoc({ + Action: 'sts:AssumeRole', + Effect: 'Allow', + Principal: { Service: 'lambda.amazonaws.com' }, + }), + Policies: [ + { + 'Fn::If': [ + 'SomeCondition', + { + PolicyName: 'S3', + PolicyDocument: poldoc({ + Effect: 'Allow', + Action: 's3:GetObject', + Resource: '*', + }), + }, + { + Ref: 'AWS::NoValue', + }, + ], + }, + ], + }), + })); + + // THEN + const changedStatements = diff.iamChanges.summarizeStatements(); + + // there are 2 rows of changes + // (one for the AssumeRolePolicyDocument, + // one for the Policies), + // plus a row of headers + expect(changedStatements.length).toBe(3); + + const changedPolicies = changedStatements[2]; + const resourceColumn = 1, principalColumn = 4; + + expect(changedPolicies[resourceColumn]).toContain('{"Fn::If":["SomeCondition",{"PolicyName":"S3","PolicyDocument":{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"s3:GetObject","Resource":"*"}]}}]}'); + expect(changedPolicies[principalColumn]).toContain('AWS:${MyRole}'); +}); diff --git a/packages/@aws-cdk/cloudformation-include/package.json b/packages/@aws-cdk/cloudformation-include/package.json index a69f649f5b80e..457f11834e88a 100644 --- a/packages/@aws-cdk/cloudformation-include/package.json +++ b/packages/@aws-cdk/cloudformation-include/package.json @@ -367,7 +367,7 @@ "cdk-integ-tools": "0.0.0", "jest": "^26.6.3", "pkglint": "0.0.0", - "ts-jest": "^26.5.0" + "ts-jest": "^26.5.1" }, "keywords": [ "aws", @@ -393,5 +393,8 @@ "maturity": "stable", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/core/.vscode/tasks.json b/packages/@aws-cdk/core/.vscode/tasks.json new file mode 100644 index 0000000000000..3726d98503637 --- /dev/null +++ b/packages/@aws-cdk/core/.vscode/tasks.json @@ -0,0 +1,16 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "type": "npm", + "script": "watch", + "problemMatcher": [ + "$tsc-watch" + ], + "group": "build", + "label": "npm: watch", + "detail": "cdk-watch", + "isBackground": true + } + ] +} \ No newline at end of file diff --git a/packages/@aws-cdk/core/README.md b/packages/@aws-cdk/core/README.md index 880aea79a55fc..0e0b38943a803 100644 --- a/packages/@aws-cdk/core/README.md +++ b/packages/@aws-cdk/core/README.md @@ -141,7 +141,7 @@ DEPLOYMENT 1: break the relationship - Make sure `stack2` no longer references `bucket.bucketName` (maybe the consumer stack now uses its own bucket, or it writes to an AWS DynamoDB table, or maybe you just remove the Lambda Function altogether). -- In the `stack1` class, call `this.exportAttribute(this.bucket.bucketName)`. This +- In the `stack1` class, call `this.exportValue(this.bucket.bucketName)`. This will make sure the CloudFormation Export continues to exist while the relationship between the two stacks is being broken. - Deploy (this will effectively only change the `stack2`, but it's safe to deploy both). @@ -149,7 +149,7 @@ DEPLOYMENT 1: break the relationship DEPLOYMENT 2: remove the resource - You are now free to remove the `bucket` resource from `stack1`. -- Don't forget to remove the `exportAttribute()` call as well. +- Don't forget to remove the `exportValue()` call as well. - Deploy again (this time only the `stack1` will be changed -- the bucket will be deleted). ## Durations diff --git a/packages/@aws-cdk/core/lib/cfn-resource.ts b/packages/@aws-cdk/core/lib/cfn-resource.ts index c436e453cacac..9f9ee669374ed 100644 --- a/packages/@aws-cdk/core/lib/cfn-resource.ts +++ b/packages/@aws-cdk/core/lib/cfn-resource.ts @@ -320,13 +320,13 @@ export class CfnResource extends CfnRefElement { Description: this.cfnOptions.description, Metadata: ignoreEmpty(this.cfnOptions.metadata), Condition: this.cfnOptions.condition && this.cfnOptions.condition.logicalId, - }, props => { - const renderedProps = this.renderProperties(props.Properties || {}); + }, resourceDef => { + const renderedProps = this.renderProperties(resourceDef.Properties || {}); if (renderedProps) { const hasDefined = Object.values(renderedProps).find(v => v !== undefined); - props.Properties = hasDefined !== undefined ? renderedProps : undefined; + resourceDef.Properties = hasDefined !== undefined ? renderedProps : undefined; } - return deepMerge(props, this.rawOverrides); + return deepMerge(resourceDef, this.rawOverrides); }), }, }; diff --git a/packages/@aws-cdk/core/lib/construct-compat.ts b/packages/@aws-cdk/core/lib/construct-compat.ts index 76e95ad38071d..ac7873a837dde 100644 --- a/packages/@aws-cdk/core/lib/construct-compat.ts +++ b/packages/@aws-cdk/core/lib/construct-compat.ts @@ -472,6 +472,13 @@ export class ConstructNode { Aspects.of(this.host).add(aspect); } + /** + * Add a validator to this construct Node + */ + public addValidation(validation: constructs.IValidation) { + this._actualNode.addValidation(validation); + } + /** * All parent scopes of this construct. * diff --git a/packages/@aws-cdk/core/lib/nested-stack.ts b/packages/@aws-cdk/core/lib/nested-stack.ts index f130d00ded80b..648211aab22f0 100644 --- a/packages/@aws-cdk/core/lib/nested-stack.ts +++ b/packages/@aws-cdk/core/lib/nested-stack.ts @@ -8,6 +8,7 @@ import { CfnStack } from './cloudformation.generated'; import { Duration } from './duration'; import { Lazy } from './lazy'; import { Names } from './names'; +import { RemovalPolicy } from './removal-policy'; import { IResolveContext } from './resolvable'; import { Stack } from './stack'; import { NestedStackSynthesizer } from './stack-synthesizers'; @@ -60,6 +61,17 @@ export interface NestedStackProps { * @default - notifications are not sent for this stack. */ readonly notificationArns?: string[]; + + /** + * Policy to apply when the nested stack is removed + * + * The default is `Destroy`, because all Removal Policies of resources inside the + * Nested Stack should already have been set correctly. You normally should + * not need to set this value. + * + * @default RemovalPolicy.DESTROY + */ + readonly removalPolicy?: RemovalPolicy; } /** @@ -126,6 +138,7 @@ export class NestedStack extends Stack { notificationArns: props.notificationArns, timeoutInMinutes: props.timeout ? props.timeout.toMinutes() : undefined, }); + this.resource.applyRemovalPolicy(props.removalPolicy ?? RemovalPolicy.DESTROY); this.nestedStackResource = this.resource; diff --git a/packages/@aws-cdk/core/lib/private/runtime-info.ts b/packages/@aws-cdk/core/lib/private/runtime-info.ts index 34a4129abe491..b0cf266e8e11d 100644 --- a/packages/@aws-cdk/core/lib/private/runtime-info.ts +++ b/packages/@aws-cdk/core/lib/private/runtime-info.ts @@ -3,9 +3,9 @@ import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import { major as nodeMajorVersion } from './node-version'; // list of NPM scopes included in version reporting e.g. @aws-cdk and @aws-solutions-konstruk -const WHITELIST_SCOPES = ['@aws-cdk', '@aws-cdk-containers', '@aws-solutions-konstruk', '@aws-solutions-constructs', '@amzn']; +const ALLOWED_SCOPES = ['@aws-cdk', '@aws-cdk-containers', '@aws-solutions-konstruk', '@aws-solutions-constructs', '@amzn']; // list of NPM packages included in version reporting -const WHITELIST_PACKAGES = ['aws-rfdk', 'aws-cdk-lib']; +const ALLOWED_PACKAGES = ['aws-rfdk', 'aws-cdk-lib', 'monocdk']; /** * Returns a list of loaded modules and their versions. @@ -20,15 +20,15 @@ export function collectRuntimeInformation(): cxschema.RuntimeInfo { } } - // include only libraries that are in the whitelistLibraries list + // include only libraries that are in the allowlistLibraries list for (const name of Object.keys(libraries)) { let foundMatch = false; - for (const scope of WHITELIST_SCOPES) { + for (const scope of ALLOWED_SCOPES) { if (name.startsWith(`${scope}/`)) { foundMatch = true; } } - foundMatch = foundMatch || WHITELIST_PACKAGES.includes(name); + foundMatch = foundMatch || ALLOWED_PACKAGES.includes(name); if (!foundMatch) { delete libraries[name]; diff --git a/packages/@aws-cdk/core/lib/private/synthesis.ts b/packages/@aws-cdk/core/lib/private/synthesis.ts index bcc6ddc94dbc8..737f11367e13f 100644 --- a/packages/@aws-cdk/core/lib/private/synthesis.ts +++ b/packages/@aws-cdk/core/lib/private/synthesis.ts @@ -171,11 +171,12 @@ function synthesizeTree(root: IConstruct, builder: cxapi.CloudAssemblyBuilder) { function validateTree(root: IConstruct) { const errors = new Array(); - visit(root, 'pre', construct => { - for (const message of construct.onValidate()) { - errors.push({ message, source: construct as unknown as Construct }); - } - }); + // Validations added through `node.addValidation()` + // This automatically also includes Ye Olde Method of validating, using + // the `protected validate()` methods. + errors.push(...constructs.Node.of(root).validate().map(e => ({ + message: e.message, source: e.source as unknown as Construct, + }))); if (errors.length > 0) { const errorList = errors.map(e => `[${e.source.node.path}] ${e.message}`).join('\n '); diff --git a/packages/@aws-cdk/core/lib/private/tree-metadata.ts b/packages/@aws-cdk/core/lib/private/tree-metadata.ts index eb18252a0e8bd..caa5c37a5940d 100644 --- a/packages/@aws-cdk/core/lib/private/tree-metadata.ts +++ b/packages/@aws-cdk/core/lib/private/tree-metadata.ts @@ -9,6 +9,13 @@ import { IInspectable, TreeInspector } from '../tree'; const FILE_PATH = 'tree.json'; +/** + * Symbol for accessing jsii runtime information + * + * Introduced in jsii 1.19.0, cdk 1.90.0. + */ +const JSII_RUNTIME_SYMBOL = Symbol.for('jsii.rtti'); + /** * Construct that is automatically attached to the top-level `App`. * This generates, as part of synthesis, a file containing the construct tree and the metadata for each node in the tree. @@ -41,11 +48,14 @@ export class TreeMetadata extends Construct { .filter((child) => child !== undefined) .reduce((map, child) => Object.assign(map, { [child!.id]: child }), {}); + const jsiiRuntimeInfo = Object.getPrototypeOf(construct).constructor[JSII_RUNTIME_SYMBOL]; + const node: Node = { id: construct.node.id || 'App', path: construct.node.path, children: Object.keys(childrenMap).length === 0 ? undefined : childrenMap, attributes: this.synthAttributes(construct), + constructInfo: constructInfoFromRuntimeInfo(jsiiRuntimeInfo), }; lookup[node.path] = node; @@ -86,9 +96,32 @@ export class TreeMetadata extends Construct { } } +function constructInfoFromRuntimeInfo(jsiiRuntimeInfo: any): ConstructInfo | undefined { + if (typeof jsiiRuntimeInfo === 'object' + && jsiiRuntimeInfo !== null + && typeof jsiiRuntimeInfo.fqn === 'string' + && typeof jsiiRuntimeInfo.version === 'string') { + return { fqn: jsiiRuntimeInfo.fqn, version: jsiiRuntimeInfo.version }; + } + return undefined; +} + interface Node { - id: string; - path: string; - children?: { [key: string]: Node }; - attributes?: { [key: string]: any }; + readonly id: string; + readonly path: string; + readonly children?: { [key: string]: Node }; + readonly attributes?: { [key: string]: any }; + + /** + * Information on the construct class that led to this node, if available + */ + readonly constructInfo?: ConstructInfo; +} + +/** + * Source information on a construct (class fqn and version) + */ +interface ConstructInfo { + readonly fqn: string; + readonly version: string; } diff --git a/packages/@aws-cdk/core/lib/removal-policy.ts b/packages/@aws-cdk/core/lib/removal-policy.ts index 879a00f53b4f9..d815967fa2bf0 100644 --- a/packages/@aws-cdk/core/lib/removal-policy.ts +++ b/packages/@aws-cdk/core/lib/removal-policy.ts @@ -1,3 +1,28 @@ +/** + * Possible values for a resource's Removal Policy + * + * The removal policy controls what happens to the resource if it stops being + * managed by CloudFormation. This can happen in one of three situations: + * + * - The resource is removed from the template, so CloudFormation stops managing it; + * - A change to the resource is made that requires it to be replaced, so CloudFormation stops + * managing it; + * - The stack is deleted, so CloudFormation stops managing all resources in it. + * + * The Removal Policy applies to all above cases. + * + * Many stateful resources in the AWS Construct Library will accept a + * `removalPolicy` as a property, typically defaulting it to `RETAIN`. + * + * If the AWS Construct Library resource does not accept a `removalPolicy` + * argument, you can always configure it by using the escape hatch mechanism, + * as shown in the following example: + * + * ```ts + * const cfnBucket = bucket.node.findChild('Resource') as cdk.CfnResource; + * cfnBucket.applyRemovalPolicy(cdk.RemovalPolicy.DESTROY); + * ``` + */ export enum RemovalPolicy { /** * This is the default removal policy. It means that when the resource is diff --git a/packages/@aws-cdk/core/lib/resource.ts b/packages/@aws-cdk/core/lib/resource.ts index 917a2c442dcf1..a828f0d6cec98 100644 --- a/packages/@aws-cdk/core/lib/resource.ts +++ b/packages/@aws-cdk/core/lib/resource.ts @@ -1,14 +1,19 @@ -// v2 - leave this as a separate section so it reduces merge conflicts when compat is removed -// eslint-disable-next-line import/order -import { IConstruct, Construct as CoreConstruct } from './construct-compat'; - -import { Construct } from 'constructs'; import { ArnComponents } from './arn'; -import { Lazy } from './lazy'; +import { CfnResource } from './cfn-resource'; +import { IConstruct, Construct as CoreConstruct } from './construct-compat'; +import { IStringProducer, Lazy } from './lazy'; import { generatePhysicalName, isGeneratedWhenNeededMarker } from './private/physical-name-generator'; +import { Reference } from './reference'; +import { RemovalPolicy } from './removal-policy'; import { IResolveContext } from './resolvable'; import { Stack } from './stack'; -import { Token } from './token'; +import { Token, Tokenization } from './token'; + +// v2 - leave this as a separate section so it reduces merge conflicts when compat is removed +// eslint-disable-next-line import/order +import { Construct } from 'constructs'; + +const RESOURCE_SYMBOL = Symbol.for('@aws-cdk/core.Resource'); /** * Represents the environment a given resource lives in. @@ -91,6 +96,13 @@ export interface ResourceProps { * A construct which represents an AWS resource. */ export abstract class Resource extends CoreConstruct implements IResource { + /** + * Check whether the given construct is a Resource + */ + public static isResource(construct: IConstruct): construct is CfnResource { + return construct !== null && typeof(construct) === 'object' && RESOURCE_SYMBOL in construct; + } + public readonly stack: Stack; public readonly env: ResourceEnvironment; @@ -114,6 +126,8 @@ export abstract class Resource extends CoreConstruct implements IResource { constructor(scope: Construct, id: string, props: ResourceProps = {}) { super(scope, id); + Object.defineProperty(this, RESOURCE_SYMBOL, { value: true }); + this.stack = Stack.of(this); this.env = { account: props.account ?? this.stack.account, @@ -164,6 +178,25 @@ export abstract class Resource extends CoreConstruct implements IResource { } } + /** + * Apply the given removal policy to this resource + * + * The Removal Policy controls what happens to this resource when it stops + * being managed by CloudFormation, either because you've removed it from the + * CDK application or because you've made a change that requires the resource + * to be replaced. + * + * The resource can be deleted (`RemovalPolicy.DELETE`), or left in your AWS + * account for data recovery and cleanup later (`RemovalPolicy.RETAIN`). + */ + public applyRemovalPolicy(policy: RemovalPolicy) { + const child = this.node.defaultChild; + if (!child || !CfnResource.isCfnResource(child)) { + throw new Error('Cannot apply RemovalPolicy: no child or not a CfnResource. Apply the removal policy on the CfnResource directly.'); + } + child.applyRemovalPolicy(policy); + } + protected generatePhysicalName(): string { return generatePhysicalName(this); } @@ -181,7 +214,7 @@ export abstract class Resource extends CoreConstruct implements IResource { * @experimental */ protected getResourceNameAttribute(nameAttr: string) { - return Lazy.uncachedString({ + return mimicReference(nameAttr, { produce: (context: IResolveContext) => { const consumingStack = Stack.of(context.scope); @@ -214,8 +247,8 @@ export abstract class Resource extends CoreConstruct implements IResource { * @experimental */ protected getResourceArnAttribute(arnAttr: string, arnComponents: ArnComponents) { - return Token.asString({ - resolve: (context: IResolveContext) => { + return mimicReference(arnAttr, { + produce: (context: IResolveContext) => { const consumingStack = Stack.of(context.scope); if (this.stack.environment !== consumingStack.environment) { this._enableCrossEnvironment(); @@ -227,3 +260,28 @@ export abstract class Resource extends CoreConstruct implements IResource { }); } } + +/** + * Produce a Lazy that is also a Reference (if the base value is a Reference). + * + * If the given value is a Reference (or resolves to a Reference), return a new + * Reference that mimics the same target and display name, but resolves using + * the logic of the passed lazy. + * + * If the given value is NOT a Reference, just return a simple Lazy. + */ +function mimicReference(refSource: any, producer: IStringProducer): string { + const reference = Tokenization.reverse(refSource, { + // If this is an ARN concatenation, just fail to extract a reference. + failConcat: false, + }); + if (!Reference.isReference(reference)) { + return Lazy.uncachedString(producer); + } + + return Token.asString(new class extends Reference { + resolve(context: IResolveContext) { + return producer.produce(context); + } + }(reference, reference.target, reference.displayName)); +} \ No newline at end of file diff --git a/packages/@aws-cdk/core/lib/token.ts b/packages/@aws-cdk/core/lib/token.ts index f92a2560cac7c..e17227d0f8ef5 100644 --- a/packages/@aws-cdk/core/lib/token.ts +++ b/packages/@aws-cdk/core/lib/token.ts @@ -164,9 +164,16 @@ export class Tokenization { * * In case of a string, the string must not be a concatenation. */ - public static reverse(x: any): IResolvable | undefined { + public static reverse(x: any, options: ReverseOptions = {}): IResolvable | undefined { if (Tokenization.isResolvable(x)) { return x; } - if (typeof x === 'string') { return Tokenization.reverseCompleteString(x); } + if (typeof x === 'string') { + if (options.failConcat === false) { + // Handle this specially because reverseCompleteString might fail + const fragments = Tokenization.reverseString(x); + return fragments.length === 1 ? fragments.firstToken : undefined; + } + return Tokenization.reverseCompleteString(x); + } if (Array.isArray(x)) { return Tokenization.reverseList(x); } if (typeof x === 'number') { return Tokenization.reverseNumber(x); } return undefined; @@ -220,6 +227,20 @@ export class Tokenization { } } +/** + * Options for the 'reverse()' operation + */ +export interface ReverseOptions { + /** + * Fail if the given string is a concatenation + * + * If `false`, just return `undefined`. + * + * @default true + */ + readonly failConcat?: boolean; +} + /** * Options to the resolve() operation * diff --git a/packages/@aws-cdk/core/package.json b/packages/@aws-cdk/core/package.json index 26fef1278c798..643f809bca142 100644 --- a/packages/@aws-cdk/core/package.json +++ b/packages/@aws-cdk/core/package.json @@ -176,12 +176,12 @@ "devDependencies": { "@types/lodash": "^4.14.168", "@types/minimatch": "^3.0.3", - "@types/node": "^10.17.51", + "@types/node": "^10.17.54", "@types/sinon": "^9.0.10", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "fast-check": "^2.12.1", - "lodash": "^4.17.20", + "fast-check": "^2.13.0", + "lodash": "^4.17.21", "nodeunit-shim": "0.0.0", "pkglint": "0.0.0", "sinon": "^9.2.4", @@ -217,5 +217,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/core/test/cross-environment-token.test.ts b/packages/@aws-cdk/core/test/cross-environment-token.test.ts index 4ab55922369e4..a0d833996121c 100644 --- a/packages/@aws-cdk/core/test/cross-environment-token.test.ts +++ b/packages/@aws-cdk/core/test/cross-environment-token.test.ts @@ -244,6 +244,36 @@ nodeunitShim({ }, }); +test.each([undefined, 'SomeName'])('stack.exportValue() on name attributes with PhysicalName=%s', physicalName => { + // Check that automatic exports and manual exports look the same + // GIVEN - auto + const appA = new App(); + const producerA = new Stack(appA, 'Producer'); + const resourceA = new MyResource(producerA, 'Resource', physicalName); + + const consumerA = new Stack(appA, 'Consumer'); + new CfnOutput(consumerA, 'ConsumeName', { value: resourceA.name }); + new CfnOutput(consumerA, 'ConsumeArn', { value: resourceA.arn }); + + // WHEN - manual + const appM = new App(); + const producerM = new Stack(appM, 'Producer'); + const resourceM = new MyResource(producerM, 'Resource', physicalName); + producerM.exportValue(resourceM.name); + producerM.exportValue(resourceM.arn); + + // THEN - producers are the same + const templateA = appA.synth().getStackByName(producerA.stackName).template; + const templateM = appM.synth().getStackByName(producerM.stackName).template; + + expect(templateA).toEqual(templateM); +}); + +test('can instantiate resource with constructed physicalname ARN', () => { + const stack = new Stack(); + new MyResourceWithConstructedArnAttribute(stack, 'Resource'); +}); + class MyResource extends Resource { public readonly arn: string; public readonly name: string; @@ -251,20 +281,54 @@ class MyResource extends Resource { constructor(scope: Construct, id: string, physicalName?: string) { super(scope, id, { physicalName }); - this.arn = this.getResourceArnAttribute('simple-arn', { + const res = new CfnResource(this, 'Resource', { + type: 'My::Resource', + properties: { + resourceName: this.physicalName, + }, + }); + + this.name = this.getResourceNameAttribute(res.ref.toString()); + this.arn = this.getResourceArnAttribute(res.getAtt('Arn').toString(), { region: '', account: '', resource: 'my-resource', resourceName: this.physicalName, service: 'myservice', }); - this.name = this.getResourceNameAttribute('simple-name'); + } +} - new CfnResource(this, 'Resource', { +/** + * Some resources build their own Arn attribute by constructing strings + * + * This will be because the L1 doesn't expose a `{ Fn::GetAtt: ['Arn'] }`. + * + * They won't be able to `exportValue()` it, but it shouldn't crash. + */ +class MyResourceWithConstructedArnAttribute extends Resource { + public readonly arn: string; + public readonly name: string; + + constructor(scope: Construct, id: string, physicalName?: string) { + super(scope, id, { physicalName }); + + const res = new CfnResource(this, 'Resource', { type: 'My::Resource', properties: { resourceName: this.physicalName, }, }); + + this.name = this.getResourceNameAttribute(res.ref.toString()); + this.arn = this.getResourceArnAttribute(Stack.of(this).formatArn({ + resource: 'my-resource', + resourceName: res.ref.toString(), + service: 'myservice', + }), { + resource: 'my-resource', + resourceName: this.physicalName, + service: 'myservice', + }); } } diff --git a/packages/@aws-cdk/core/test/private/tree-metadata.test.ts b/packages/@aws-cdk/core/test/private/tree-metadata.test.ts index f62df683c422a..b7173aca585ec 100644 --- a/packages/@aws-cdk/core/test/private/tree-metadata.test.ts +++ b/packages/@aws-cdk/core/test/private/tree-metadata.test.ts @@ -2,10 +2,10 @@ import * as fs from 'fs'; import * as path from 'path'; import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import { nodeunitShim, Test } from 'nodeunit-shim'; -import { App, CfnParameter, CfnResource, Construct, Lazy, Stack, TreeInspector } from '../../lib/index'; +import { App, CfnParameter, CfnResource, Construct as CfnConstruct, Lazy, Stack, TreeInspector } from '../../lib/index'; abstract class AbstractCfnResource extends CfnResource { - constructor(scope: Construct, id: string) { + constructor(scope: CfnConstruct, id: string) { super(scope, id, { type: 'CDK::UnitTest::MyCfnResource', }); @@ -24,7 +24,7 @@ nodeunitShim({ const app = new App(); const stack = new Stack(app, 'mystack'); - new Construct(stack, 'myconstruct'); + new CfnConstruct(stack, 'myconstruct'); const assembly = app.synth(); const treeArtifact = assembly.tree(); @@ -32,26 +32,26 @@ nodeunitShim({ test.deepEqual(readJson(assembly.directory, treeArtifact!.file), { version: 'tree-0.1', - tree: { + tree: expect.objectContaining({ id: 'App', path: '', children: { - Tree: { + Tree: expect.objectContaining({ id: 'Tree', path: 'Tree', - }, - mystack: { + }), + mystack: expect.objectContaining({ id: 'mystack', path: 'mystack', children: { - myconstruct: { + myconstruct: expect.objectContaining({ id: 'myconstruct', path: 'mystack/myconstruct', - }, + }), }, - }, + }), }, - }, + }), }); test.done(); }, @@ -80,19 +80,19 @@ nodeunitShim({ test.deepEqual(readJson(assembly.directory, treeArtifact!.file), { version: 'tree-0.1', - tree: { + tree: expect.objectContaining({ id: 'App', path: '', children: { - Tree: { + Tree: expect.objectContaining({ id: 'Tree', path: 'Tree', - }, - mystack: { + }), + mystack: expect.objectContaining({ id: 'mystack', path: 'mystack', children: { - mycfnresource: { + mycfnresource: expect.objectContaining({ id: 'mycfnresource', path: 'mystack/mycfnresource', attributes: { @@ -106,15 +106,72 @@ nodeunitShim({ }, }, }, - }, + }), }, - }, + }), }, - }, + }), }); test.done(); }, + 'tree metadata has construct class & version in there'(test: Test) { + // The runtime metadata this test relies on is only available if the most + // recent compile has happened using 'jsii', as the jsii compiler injects + // this metadata. + // + // If the most recent compile was using 'tsc', the metadata will not have + // been injected, and the test will fail. + // + // People may choose to run `tsc` directly (instead of `yarn build` for + // example) to escape the additional TSC compilation time that is necessary + // to run 'eslint', or the additional time that 'jsii' needs to analyze the + // type system), this test is allowed to fail if we're not running on CI. + // + // If the compile of this library has been done using `tsc`, the runtime + // information will always find `constructs.Construct` as the construct + // identifier, since `constructs` will have had a release build done using `jsii`. + // + // If this test is running on CodeBuild, we will require that the more specific + // class names are found. If this test is NOT running on CodeBuild, we will + // allow the specific class name (for a 'jsii' build) or the generic + // 'constructs.Construct' class name (for a 'tsc' build). + const app = new App(); + + const stack = new Stack(app, 'mystack'); + new CfnResource(stack, 'myconstruct', { type: 'Aws::Some::Resource' }); + + const assembly = app.synth(); + const treeArtifact = assembly.tree(); + test.ok(treeArtifact); + + const codeBuild = !!process.env.CODEBUILD_BUILD_ID; + + test.deepEqual(readJson(assembly.directory, treeArtifact!.file), { + version: 'tree-0.1', + tree: expect.objectContaining({ + children: expect.objectContaining({ + mystack: expect.objectContaining({ + constructInfo: { + fqn: expect.stringMatching(codeBuild ? /\bStack$/ : /\bStack$|^constructs.Construct$/), + version: expect.any(String), + }, + children: { + myconstruct: expect.objectContaining({ + constructInfo: { + fqn: expect.stringMatching(codeBuild ? /\bCfnResource$/ : /\bCfnResource$|^constructs.Construct$/), + version: expect.any(String), + }, + }), + }, + }), + }), + }), + }); + + test.done(); + }, + 'token resolution & cfn parameter'(test: Test) { const app = new App(); const stack = new Stack(app, 'mystack'); @@ -137,23 +194,23 @@ nodeunitShim({ test.deepEqual(readJson(assembly.directory, treeArtifact!.file), { version: 'tree-0.1', - tree: { + tree: expect.objectContaining({ id: 'App', path: '', children: { - Tree: { + Tree: expect.objectContaining({ id: 'Tree', path: 'Tree', - }, - mystack: { + }), + mystack: expect.objectContaining({ id: 'mystack', path: 'mystack', children: { - mycfnparam: { + mycfnparam: expect.objectContaining({ id: 'mycfnparam', path: 'mystack/mycfnparam', - }, - mycfnresource: { + }), + mycfnresource: expect.objectContaining({ id: 'mycfnresource', path: 'mystack/mycfnresource', attributes: { @@ -163,11 +220,11 @@ nodeunitShim({ cfnparamkey: { Ref: 'mycfnparam' }, }, }, - }, + }), }, - }, + }), }, - }, + }), }); test.done(); }, @@ -176,7 +233,7 @@ nodeunitShim({ class MyFirstResource extends AbstractCfnResource { public readonly lazykey: string; - constructor(scope: Construct, id: string) { + constructor(scope: CfnConstruct, id: string) { super(scope, id); this.lazykey = Lazy.string({ produce: () => 'LazyResolved!' }); } @@ -191,7 +248,7 @@ nodeunitShim({ class MySecondResource extends AbstractCfnResource { public readonly myprop: string; - constructor(scope: Construct, id: string, myprop: string) { + constructor(scope: CfnConstruct, id: string, myprop: string) { super(scope, id); this.myprop = myprop; } @@ -215,19 +272,19 @@ nodeunitShim({ test.deepEqual(readJson(assembly.directory, treeArtifact!.file), { version: 'tree-0.1', - tree: { + tree: expect.objectContaining({ id: 'App', path: '', children: { - Tree: { + Tree: expect.objectContaining({ id: 'Tree', path: 'Tree', - }, - myfirststack: { + }), + myfirststack: expect.objectContaining({ id: 'myfirststack', path: 'myfirststack', children: { - myfirstresource: { + myfirstresource: expect.objectContaining({ id: 'myfirstresource', path: 'myfirststack/myfirstresource', attributes: { @@ -236,14 +293,14 @@ nodeunitShim({ lazykey: 'LazyResolved!', }, }, - }, + }), }, - }, - mysecondstack: { + }), + mysecondstack: expect.objectContaining({ id: 'mysecondstack', path: 'mysecondstack', children: { - mysecondresource: { + mysecondresource: expect.objectContaining({ id: 'mysecondresource', path: 'mysecondstack/mysecondresource', attributes: { @@ -252,11 +309,11 @@ nodeunitShim({ myprop: 'LazyResolved!', }, }, - }, + }), }, - }, + }), }, - }, + }), }); test.done(); @@ -291,20 +348,20 @@ nodeunitShim({ // assert that the rest of the construct tree is rendered test.deepEqual(readJson(assembly.directory, treeArtifact!.file), { version: 'tree-0.1', - tree: { + tree: expect.objectContaining({ id: 'App', path: '', children: { - Tree: { + Tree: expect.objectContaining({ id: 'Tree', path: 'Tree', - }, - mystack: { + }), + mystack: expect.objectContaining({ id: 'mystack', path: 'mystack', - }, + }), }, - }, + }), }); test.done(); diff --git a/packages/@aws-cdk/core/test/stack.test.ts b/packages/@aws-cdk/core/test/stack.test.ts index 8891dbaa138c6..849ad10369147 100644 --- a/packages/@aws-cdk/core/test/stack.test.ts +++ b/packages/@aws-cdk/core/test/stack.test.ts @@ -640,7 +640,25 @@ describe('stack', () => { const assembly = app.synth(); expect(assembly.getStackByName(parentStack.stackName).template).toEqual({ Resources: { MyParentResource: { Type: 'Resource::Parent' } } }); expect(assembly.getStackByName(childStack.stackName).template).toEqual({ Resources: { MyChildResource: { Type: 'Resource::Child' } } }); + }); + + test('Nested Stacks are synthesized with DESTROY policy', () => { + const app = new App(); + // WHEN + const parentStack = new Stack(app, 'parent'); + const childStack = new NestedStack(parentStack, 'child'); + new CfnResource(childStack, 'ChildResource', { type: 'Resource::Child' }); + + const assembly = app.synth(); + expect(assembly.getStackByName(parentStack.stackName).template).toEqual(expect.objectContaining({ + Resources: { + childNestedStackchildNestedStackResource7408D03F: expect.objectContaining({ + Type: 'AWS::CloudFormation::Stack', + DeletionPolicy: 'Delete', + }), + }, + })); }); test('cross-stack reference (substack references parent stack)', () => { diff --git a/packages/@aws-cdk/core/test/synthesis.test.ts b/packages/@aws-cdk/core/test/synthesis.test.ts index 464e544cc562a..8b5200c1dfb72 100644 --- a/packages/@aws-cdk/core/test/synthesis.test.ts +++ b/packages/@aws-cdk/core/test/synthesis.test.ts @@ -28,13 +28,13 @@ nodeunitShim({ }); test.deepEqual(readJson(session.directory, 'tree.json'), { version: 'tree-0.1', - tree: { + tree: expect.objectContaining({ id: 'App', path: '', children: { - Tree: { id: 'Tree', path: 'Tree' }, + Tree: expect.objectContaining({ id: 'Tree', path: 'Tree' }), }, - }, + }), }); test.done(); }, diff --git a/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts b/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts index 9da696f268b92..2139866ae3d06 100644 --- a/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts +++ b/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts @@ -93,6 +93,16 @@ export interface ProviderProps { */ readonly vpcSubnets?: ec2.SubnetSelection; + /** + * Security groups to attach to the provider functions. + * + * Only used if 'vpc' is supplied + * + * @default - If `vpc` is not supplied, no security groups are attached. Otherwise, a dedicated security + * group is created for each function. + */ + readonly securityGroups?: ec2.ISecurityGroup[]; + } /** @@ -122,6 +132,7 @@ export class Provider extends CoreConstruct implements cfn.ICustomResourceProvid private readonly logRetention?: logs.RetentionDays; private readonly vpc?: ec2.IVpc; private readonly vpcSubnets?: ec2.SubnetSelection; + private readonly securityGroups?: ec2.ISecurityGroup[]; constructor(scope: Construct, id: string, props: ProviderProps) { super(scope, id); @@ -137,6 +148,7 @@ export class Provider extends CoreConstruct implements cfn.ICustomResourceProvid this.logRetention = props.logRetention; this.vpc = props.vpc; this.vpcSubnets = props.vpcSubnets; + this.securityGroups = props.securityGroups; const onEventFunction = this.createFunction(consts.FRAMEWORK_ON_EVENT_HANDLER_NAME); @@ -182,6 +194,7 @@ export class Provider extends CoreConstruct implements cfn.ICustomResourceProvid logRetention: this.logRetention, vpc: this.vpc, vpcSubnets: this.vpcSubnets, + securityGroups: this.securityGroups, }); fn.addEnvironment(consts.USER_ON_EVENT_FUNCTION_ARN_ENV, this.onEventHandler.functionArn); diff --git a/packages/@aws-cdk/custom-resources/package.json b/packages/@aws-cdk/custom-resources/package.json index be4cbae5bc2c0..aed86e63bdb0f 100644 --- a/packages/@aws-cdk/custom-resources/package.json +++ b/packages/@aws-cdk/custom-resources/package.json @@ -75,10 +75,10 @@ "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", - "@types/aws-lambda": "^8.10.71", + "@types/aws-lambda": "^8.10.72", "@types/fs-extra": "^8.1.1", "@types/sinon": "^9.0.10", - "aws-sdk": "^2.830.0", + "aws-sdk": "^2.848.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", @@ -121,5 +121,8 @@ "awscdkio": { "announce": false }, - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/custom-resources/test/provider-framework/provider.test.ts b/packages/@aws-cdk/custom-resources/test/provider-framework/provider.test.ts index deed031d8909f..b60ef1a602431 100644 --- a/packages/@aws-cdk/custom-resources/test/provider-framework/provider.test.ts +++ b/packages/@aws-cdk/custom-resources/test/provider-framework/provider.test.ts @@ -8,6 +8,75 @@ import * as util from '../../lib/provider-framework/util'; import '@aws-cdk/assert/jest'; +test('security groups are applied to all framework functions', () => { + + // GIVEN + const stack = new Stack(); + + const vpc = new ec2.Vpc(stack, 'Vpc'); + const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup', { vpc }); + + // WHEN + new cr.Provider(stack, 'MyProvider', { + onEventHandler: new lambda.Function(stack, 'OnEvent', { + code: lambda.Code.fromInline('foo'), + handler: 'index.onEvent', + runtime: lambda.Runtime.NODEJS_10_X, + }), + isCompleteHandler: new lambda.Function(stack, 'IsComplete', { + code: lambda.Code.fromInline('foo'), + handler: 'index.isComplete', + runtime: lambda.Runtime.NODEJS_10_X, + }), + vpc: vpc, + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE }, + securityGroups: [securityGroup], + }); + + expect(stack).toHaveResourceLike('AWS::Lambda::Function', { + Handler: 'framework.onEvent', + VpcConfig: { + SecurityGroupIds: [ + { + 'Fn::GetAtt': [ + 'SecurityGroupDD263621', + 'GroupId', + ], + }, + ], + }, + }); + + expect(stack).toHaveResourceLike('AWS::Lambda::Function', { + Handler: 'framework.isComplete', + VpcConfig: { + SecurityGroupIds: [ + { + 'Fn::GetAtt': [ + 'SecurityGroupDD263621', + 'GroupId', + ], + }, + ], + }, + }); + + expect(stack).toHaveResourceLike('AWS::Lambda::Function', { + Handler: 'framework.onTimeout', + VpcConfig: { + SecurityGroupIds: [ + { + 'Fn::GetAtt': [ + 'SecurityGroupDD263621', + 'GroupId', + ], + }, + ], + }, + }); + +}); + test('vpc is applied to all framework functions', () => { // GIVEN diff --git a/packages/@aws-cdk/cx-api/lib/features.ts b/packages/@aws-cdk/cx-api/lib/features.ts index 57c9a5738ee96..24ba471882644 100644 --- a/packages/@aws-cdk/cx-api/lib/features.ts +++ b/packages/@aws-cdk/cx-api/lib/features.ts @@ -102,7 +102,7 @@ export const S3_GRANT_WRITE_WITHOUT_ACL = '@aws-cdk/aws-s3:grantWriteWithoutAcl' * * Tests must cover the default (disabled) case and the future (enabled) case. */ -export const FUTURE_FLAGS = { +export const FUTURE_FLAGS: { [key: string]: any } = { [ENABLE_STACK_NAME_DUPLICATES_CONTEXT]: 'true', [ENABLE_DIFF_NO_FAIL_CONTEXT]: 'true', [STACK_RELATIVE_EXPORTS_CONTEXT]: 'true', diff --git a/packages/@aws-cdk/cx-api/package.json b/packages/@aws-cdk/cx-api/package.json index dd015ee63986c..9b5c09a9a999d 100644 --- a/packages/@aws-cdk/cx-api/package.json +++ b/packages/@aws-cdk/cx-api/package.json @@ -156,5 +156,8 @@ }, "cdk-build": { "jest": true + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/cx-api/test/features.test.ts b/packages/@aws-cdk/cx-api/test/features.test.ts index fbff6c236b984..81b42773fd292 100644 --- a/packages/@aws-cdk/cx-api/test/features.test.ts +++ b/packages/@aws-cdk/cx-api/test/features.test.ts @@ -1,7 +1,12 @@ +import { testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; import * as feats from '../lib/features'; test('all future flags have defaults configured', () => { Object.keys(feats.FUTURE_FLAGS).forEach(flag => { expect(typeof(feats.futureFlagDefault(flag))).toEqual('boolean'); }); +}); + +testLegacyBehavior('FUTURE_FLAGS_EXPIRED must be empty in CDKv1', Object, () => { + expect(feats.FUTURE_FLAGS_EXPIRED.length).toEqual(0); }); \ No newline at end of file diff --git a/packages/@aws-cdk/lambda-layer-awscli/package.json b/packages/@aws-cdk/lambda-layer-awscli/package.json index 838d613b03ddf..115f686f9e414 100644 --- a/packages/@aws-cdk/lambda-layer-awscli/package.json +++ b/packages/@aws-cdk/lambda-layer-awscli/package.json @@ -100,5 +100,8 @@ }, "ubergen": { "exclude": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/lambda-layer-kubectl/package.json b/packages/@aws-cdk/lambda-layer-kubectl/package.json index 7f561b67712e5..9ba2b10e89d47 100644 --- a/packages/@aws-cdk/lambda-layer-kubectl/package.json +++ b/packages/@aws-cdk/lambda-layer-kubectl/package.json @@ -106,5 +106,8 @@ }, "ubergen": { "exclude": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/pipelines/package.json b/packages/@aws-cdk/pipelines/package.json index b13b5877cace7..8717570fc8f1d 100644 --- a/packages/@aws-cdk/pipelines/package.json +++ b/packages/@aws-cdk/pipelines/package.json @@ -124,5 +124,8 @@ "events-method-signature:@aws-cdk/pipelines.UpdatePipelineAction.onStateChange" ] }, - "homepage": "https://github.com/aws/aws-cdk" + "homepage": "https://github.com/aws/aws-cdk", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-assets.expected.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-assets.expected.json index 365e0fa9d06ee..248e3b79911c9 100644 --- a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-assets.expected.json +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-assets.expected.json @@ -38,23 +38,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { @@ -71,186 +55,6 @@ } }, "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineRoleB27FAA37", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineBuildSynthCdkBuildProjectRole231EEA2A", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineBuildSynthCdkBuildProjectRole231EEA2A", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineUpdatePipelineSelfMutationRole57E559E8", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineUpdatePipelineSelfMutationRole57E559E8", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineAssetsFileRole59943A77", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineAssetsFileRole59943A77", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelinePreProdUseSourceProjectRole69B20A71", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelinePreProdUseSourceProjectRole69B20A71", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::12345678:role/cdk-hnb659fds-deploy-role-12345678-test-region" - ] - ] - } - }, - "Resource": "*" } ], "Version": "2012-10-17" @@ -329,7 +133,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -884,7 +688,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline.expected.json b/packages/@aws-cdk/pipelines/test/integ.pipeline.expected.json index 9e0541be1e17d..5d1569fbadc84 100644 --- a/packages/@aws-cdk/pipelines/test/integ.pipeline.expected.json +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline.expected.json @@ -38,23 +38,7 @@ "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" - ], + "Action": "kms:*", "Effect": "Allow", "Principal": { "AWS": { @@ -71,152 +55,6 @@ } }, "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineRoleB27FAA37", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineBuildSynthCdkBuildProjectRole231EEA2A", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineBuildSynthCdkBuildProjectRole231EEA2A", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineUpdatePipelineSelfMutationRole57E559E8", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelineUpdatePipelineSelfMutationRole57E559E8", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelinePreProdUseSourceProjectRole69B20A71", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "PipelinePreProdUseSourceProjectRole69B20A71", - "Arn" - ] - } - }, - "Resource": "*" - }, - { - "Action": [ - "kms:Decrypt", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::12345678:role/cdk-hnb659fds-deploy-role-12345678-test-region" - ] - ] - } - }, - "Resource": "*" } ], "Version": "2012-10-17" @@ -295,7 +133,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", @@ -783,7 +621,7 @@ "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*" ], "Effect": "Allow", diff --git a/packages/@aws-cdk/region-info/package.json b/packages/@aws-cdk/region-info/package.json index 72ffe996d0060..fe5a7e1acf1ec 100644 --- a/packages/@aws-cdk/region-info/package.json +++ b/packages/@aws-cdk/region-info/package.json @@ -83,5 +83,8 @@ }, "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@aws-cdk/yaml-cfn/package.json b/packages/@aws-cdk/yaml-cfn/package.json index 7db67d8171bd4..45e121a4cb7f5 100644 --- a/packages/@aws-cdk/yaml-cfn/package.json +++ b/packages/@aws-cdk/yaml-cfn/package.json @@ -86,5 +86,8 @@ "maturity": "experimental", "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/@monocdk-experiment/assert/package.json b/packages/@monocdk-experiment/assert/package.json index fbc5314061789..86806f041880f 100644 --- a/packages/@monocdk-experiment/assert/package.json +++ b/packages/@monocdk-experiment/assert/package.json @@ -35,13 +35,13 @@ "devDependencies": { "@monocdk-experiment/rewrite-imports": "0.0.0", "@types/jest": "^26.0.20", - "@types/node": "^10.17.51", + "@types/node": "^10.17.54", "cdk-build-tools": "0.0.0", "constructs": "^3.2.0", "jest": "^26.6.3", "monocdk": "0.0.0", "pkglint": "0.0.0", - "ts-jest": "^26.5.0" + "ts-jest": "^26.5.1" }, "dependencies": { "@aws-cdk/cloudformation-diff": "0.0.0" @@ -65,5 +65,8 @@ "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", - "maturity": "developer-preview" + "maturity": "developer-preview", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/@monocdk-experiment/rewrite-imports/package.json b/packages/@monocdk-experiment/rewrite-imports/package.json index 87cc7afc0f0aa..b824068d0354f 100644 --- a/packages/@monocdk-experiment/rewrite-imports/package.json +++ b/packages/@monocdk-experiment/rewrite-imports/package.json @@ -33,12 +33,12 @@ "license": "Apache-2.0", "dependencies": { "glob": "^7.1.6", - "typescript": "~3.9.7" + "typescript": "~3.9.9" }, "devDependencies": { "@types/glob": "^7.1.3", "@types/jest": "^26.0.20", - "@types/node": "^10.17.51", + "@types/node": "^10.17.54", "cdk-build-tools": "0.0.0", "pkglint": "0.0.0" }, @@ -52,5 +52,8 @@ "maturity": "developer-preview", "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/aws-cdk-lib/package.json b/packages/aws-cdk-lib/package.json index cad68c582ab70..6eadd958185df 100644 --- a/packages/aws-cdk-lib/package.json +++ b/packages/aws-cdk-lib/package.json @@ -283,7 +283,7 @@ "@aws-cdk/region-info": "0.0.0", "@aws-cdk/yaml-cfn": "0.0.0", "@types/fs-extra": "^8.1.1", - "@types/node": "^10.17.51", + "@types/node": "^10.17.54", "cdk-build-tools": "0.0.0", "constructs": "^3.2.0", "fs-extra": "^9.1.0", diff --git a/packages/aws-cdk/lib/init.ts b/packages/aws-cdk/lib/init.ts index 6166736f3e8da..78c844b0a6550 100644 --- a/packages/aws-cdk/lib/init.ts +++ b/packages/aws-cdk/lib/init.ts @@ -179,10 +179,15 @@ export class InitTemplate { return; } + const futureFlags: {[key: string]: any} = {}; + Object.entries(cxapi.FUTURE_FLAGS) + .filter(([k, _]) => !cxapi.FUTURE_FLAGS_EXPIRED.includes(k)) + .forEach(([k, v]) => futureFlags[k] = v); + const config = await fs.readJson(cdkJson); config.context = { ...config.context, - ...cxapi.FUTURE_FLAGS, + ...futureFlags, }; await fs.writeJson(cdkJson, config, { spaces: 2 }); diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index 2131e1330b289..a3f34cdacf9d4 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -39,18 +39,18 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/core": "0.0.0", - "@octokit/rest": "^18.1.0", + "@octokit/rest": "^18.2.0", "@types/archiver": "^5.1.0", "@types/fs-extra": "^8.1.1", "@types/glob": "^7.1.3", "@types/jest": "^26.0.20", "@types/minimatch": "^3.0.3", "@types/mockery": "^1.4.29", - "@types/node": "^10.17.51", + "@types/node": "^10.17.54", "@types/promptly": "^3.0.1", "@types/semver": "^7.3.4", "@types/sinon": "^9.0.10", - "@types/table": "^5.0.0", + "@types/table": "^6.0.0", "@types/uuid": "^8.3.0", "@types/wrap-ansi": "^3.0.0", "@types/yargs": "^15.0.13", @@ -62,7 +62,7 @@ "nock": "^13.0.7", "pkglint": "0.0.0", "sinon": "^9.2.4", - "ts-jest": "^26.5.0", + "ts-jest": "^26.5.1", "ts-mock-imports": "^1.3.3", "xml-js": "^1.6.11" }, @@ -73,7 +73,7 @@ "@aws-cdk/region-info": "0.0.0", "@aws-cdk/yaml-cfn": "0.0.0", "archiver": "^5.2.0", - "aws-sdk": "^2.830.0", + "aws-sdk": "^2.848.0", "camelcase": "^6.2.0", "cdk-assets": "0.0.0", "colors": "^1.4.0", @@ -105,5 +105,8 @@ "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "stable", - "maturity": "stable" + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/aws-cdk/test/init.test.ts b/packages/aws-cdk/test/init.test.ts index db042d76fc25d..e659161fbb38a 100644 --- a/packages/aws-cdk/test/init.test.ts +++ b/packages/aws-cdk/test/init.test.ts @@ -83,10 +83,15 @@ describe.each(['1', '2'])('v%s tests', (majorVersion) => { const config = await fs.readJson(path.join(tmpDir, 'cdk.json')); const context = config.context || {}; - for (const [key, expected] of Object.entries(cxapi.FUTURE_FLAGS)) { - const actual = context[key]; + for (const [key, expected] of Object.entries(context)) { + const actual = cxapi.FUTURE_FLAGS[key]; expect(actual).toEqual(expected); } + + // assert that expired future flags are not part of the cdk.json + Object.keys(context).forEach(k => { + expect(cxapi.FUTURE_FLAGS_EXPIRED.includes(k)).toEqual(false); + }); }); } } diff --git a/packages/awslint/package.json b/packages/awslint/package.json index b2f60b1dc12dd..f0a74898f0148 100644 --- a/packages/awslint/package.json +++ b/packages/awslint/package.json @@ -16,18 +16,18 @@ "awslint": "bin/awslint" }, "dependencies": { - "@jsii/spec": "^1.20.1", + "@jsii/spec": "^1.21.0", "camelcase": "^6.2.0", "colors": "^1.4.0", "fs-extra": "^9.1.0", - "jsii-reflect": "^1.20.1", + "jsii-reflect": "^1.21.0", "yargs": "^16.2.0" }, "devDependencies": { "@types/fs-extra": "^8.1.1", "@types/yargs": "^15.0.13", "pkglint": "0.0.0", - "typescript": "~3.9.7" + "typescript": "~3.9.9" }, "repository": { "type": "git", @@ -49,5 +49,8 @@ "stability": "experimental", "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" + }, + "publishConfig": { + "tag": "latest" } } diff --git a/packages/cdk-assets/package.json b/packages/cdk-assets/package.json index 13448591960e5..16f767306dbdc 100644 --- a/packages/cdk-assets/package.json +++ b/packages/cdk-assets/package.json @@ -35,11 +35,11 @@ "@types/jest": "^26.0.20", "@types/jszip": "^3.4.1", "@types/mock-fs": "^4.13.0", - "@types/node": "^10.17.51", + "@types/node": "^10.17.54", "@types/yargs": "^15.0.13", "cdk-build-tools": "0.0.0", "jest": "^26.6.3", - "jszip": "^3.5.0", + "jszip": "^3.6.0", "mock-fs": "^4.13.0", "pkglint": "0.0.0" }, @@ -47,7 +47,7 @@ "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "archiver": "^5.2.0", - "aws-sdk": "^2.830.0", + "aws-sdk": "^2.848.0", "glob": "^7.1.6", "yargs": "^16.2.0" }, @@ -68,5 +68,8 @@ "shrinkWrap": true }, "stability": "experimental", - "maturity": "experimental" + "maturity": "experimental", + "publishConfig": { + "tag": "latest" + } } diff --git a/packages/cdk-dasm/package.json b/packages/cdk-dasm/package.json index f17d6c6adaa90..917a0b25715aa 100644 --- a/packages/cdk-dasm/package.json +++ b/packages/cdk-dasm/package.json @@ -26,7 +26,7 @@ }, "license": "Apache-2.0", "dependencies": { - "codemaker": "^1.20.1", + "codemaker": "^1.21.0", "yaml": "1.10.0" }, "devDependencies": { diff --git a/packages/decdk/package.json b/packages/decdk/package.json index a7ca2a1d2ba1a..ec918d8d77feb 100644 --- a/packages/decdk/package.json +++ b/packages/decdk/package.json @@ -210,7 +210,7 @@ "@aws-cdk/yaml-cfn": "0.0.0", "constructs": "^3.2.0", "fs-extra": "^9.1.0", - "jsii-reflect": "^1.20.1", + "jsii-reflect": "^1.21.0", "jsonschema": "^1.4.0", "yaml": "1.10.0", "yargs": "^16.2.0" @@ -221,7 +221,7 @@ "@types/yaml": "1.9.7", "@types/yargs": "^15.0.13", "jest": "^26.6.3", - "jsii": "^1.20.1" + "jsii": "^1.21.0" }, "keywords": [ "aws", diff --git a/packages/decdk/test/__snapshots__/synth.test.js.snap b/packages/decdk/test/__snapshots__/synth.test.js.snap index 0befd96765754..86a1fdd32f534 100644 --- a/packages/decdk/test/__snapshots__/synth.test.js.snap +++ b/packages/decdk/test/__snapshots__/synth.test.js.snap @@ -1786,7 +1786,7 @@ Object { "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*", ], "Effect": "Allow", @@ -1847,23 +1847,7 @@ Object { "KeyPolicy": Object { "Statement": Array [ Object { - "Action": Array [ - "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", - ], + "Action": "kms:*", "Effect": "Allow", "Principal": Object { "AWS": Object { @@ -1885,24 +1869,6 @@ Object { }, "Resource": "*", }, - Object { - "Action": Array [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*", - ], - "Effect": "Allow", - "Principal": Object { - "AWS": Object { - "Fn::GetAtt": Array [ - "BuildProjectRoleAA92C755", - "Arn", - ], - }, - }, - "Resource": "*", - }, ], "Version": "2012-10-17", }, @@ -1944,23 +1910,7 @@ Object { "KeyPolicy": Object { "Statement": Array [ Object { - "Action": Array [ - "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", - ], + "Action": "kms:*", "Effect": "Allow", "Principal": Object { "AWS": Object { @@ -1982,95 +1932,6 @@ Object { }, "Resource": "*", }, - Object { - "Action": Array [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*", - ], - "Effect": "Allow", - "Principal": Object { - "AWS": Object { - "Fn::GetAtt": Array [ - "PipelineRoleD68726F7", - "Arn", - ], - }, - }, - "Resource": "*", - }, - Object { - "Action": Array [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*", - ], - "Effect": "Allow", - "Principal": Object { - "AWS": Object { - "Fn::GetAtt": Array [ - "PipelineSourceCodePipelineActionRoleC6F9E7F5", - "Arn", - ], - }, - }, - "Resource": "*", - }, - Object { - "Action": Array [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*", - ], - "Effect": "Allow", - "Principal": Object { - "AWS": Object { - "Fn::GetAtt": Array [ - "BuildProjectRoleAA92C755", - "Arn", - ], - }, - }, - "Resource": "*", - }, - Object { - "Action": Array [ - "kms:Decrypt", - "kms:DescribeKey", - ], - "Effect": "Allow", - "Principal": Object { - "AWS": Object { - "Fn::GetAtt": Array [ - "PipelineDeployRole97597E3E", - "Arn", - ], - }, - }, - "Resource": "*", - }, - Object { - "Action": Array [ - "kms:Decrypt", - "kms:DescribeKey", - ], - "Effect": "Allow", - "Principal": Object { - "AWS": Object { - "Fn::GetAtt": Array [ - "PipelineDeployCodePipelineActionRole8B83082E", - "Arn", - ], - }, - }, - "Resource": "*", - }, ], "Version": "2012-10-17", }, @@ -2597,7 +2458,7 @@ Object { "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*", ], "Effect": "Allow", @@ -2724,7 +2585,7 @@ Object { "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", - "s3:PutObject*", + "s3:PutObject", "s3:Abort*", ], "Effect": "Allow", @@ -2874,7 +2735,9 @@ exports[`pure-cfn.json: pure-cfn 1`] = ` Object { "Resources": Object { "Hello4A628BD4": Object { + "DeletionPolicy": "Delete", "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", }, "MyLogGroup": Object { "Properties": Object { @@ -2892,6 +2755,7 @@ exports[`queue-kms.json: queue-kms 1`] = ` Object { "Resources": Object { "MyQueueE6CA6235": Object { + "DeletionPolicy": "Delete", "Properties": Object { "KmsMasterKeyId": Object { "Fn::GetAtt": Array [ @@ -2901,6 +2765,7 @@ Object { }, }, "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", }, "MyQueueKey6C31ABF3": Object { "DeletionPolicy": "Retain", @@ -2909,23 +2774,7 @@ Object { "KeyPolicy": Object { "Statement": Array [ Object { - "Action": Array [ - "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", - ], + "Action": "kms:*", "Effect": "Allow", "Principal": Object { "AWS": Object { diff --git a/packages/decdk/test/fixture/tsconfig.json b/packages/decdk/test/fixture/tsconfig.json index 44dbf4775b1a7..1b7d2bae0fab0 100644 --- a/packages/decdk/test/fixture/tsconfig.json +++ b/packages/decdk/test/fixture/tsconfig.json @@ -4,6 +4,7 @@ "charset": "utf8", "declaration": true, "experimentalDecorators": true, + "incremental": true, "inlineSourceMap": true, "inlineSources": true, "lib": [ @@ -22,8 +23,10 @@ "strict": true, "strictNullChecks": true, "strictPropertyInitialization": true, - "stripInternal": true, - "target": "ES2018" + "stripInternal": false, + "target": "ES2018", + "composite": false, + "tsBuildInfoFile": "tsconfig.tsbuildinfo" }, "include": [ "**/*.ts" diff --git a/packages/decdk/test/synth.test.ts b/packages/decdk/test/synth.test.ts index ab025ab1ddbdd..8952a9aa11fd8 100644 --- a/packages/decdk/test/synth.test.ts +++ b/packages/decdk/test/synth.test.ts @@ -2,6 +2,7 @@ import * as cdk from '@aws-cdk/core'; import * as fs from 'fs'; import * as reflect from 'jsii-reflect'; import * as path from 'path'; +import { FUTURE_FLAGS } from '@aws-cdk/cx-api'; import { DeclarativeStack, loadTypeSystem, readTemplate, stackNameFromFileName } from '../lib'; const VALIDATE_ASSEMBLIES = true; @@ -31,7 +32,11 @@ for (const templateFile of fs.readdirSync(dir)) { const template = await readTemplate(path.resolve(dir, templateFile)); const typeSystem = await obtainTypeSystem(); - const app = new cdk.App(); + const app = new cdk.App({ + context: { + ...FUTURE_FLAGS, + } + }); const stackName = stackNameFromFileName(templateFile); new DeclarativeStack(app, stackName, { diff --git a/packages/monocdk/package.json b/packages/monocdk/package.json index 33e824037bb3c..c71d755b3c2bb 100644 --- a/packages/monocdk/package.json +++ b/packages/monocdk/package.json @@ -288,7 +288,7 @@ "@aws-cdk/region-info": "0.0.0", "@aws-cdk/yaml-cfn": "0.0.0", "@types/fs-extra": "^8.1.1", - "@types/node": "^10.17.51", + "@types/node": "^10.17.54", "cdk-build-tools": "0.0.0", "constructs": "^3.2.0", "fs-extra": "^9.1.0", @@ -310,5 +310,8 @@ ], "awscdkio": { "announce": false + }, + "publishConfig": { + "tag": "latest" } } diff --git a/release.json b/release.json index bbd42d0c80ea6..318d5d9a12072 100644 --- a/release.json +++ b/release.json @@ -1,5 +1,4 @@ { "majorVersion": 1, - "releaseType": "stable", - "distTag": "latest" + "releaseType": "stable" } diff --git a/scripts/bump.js b/scripts/bump.js index a1d678c57ce18..5d8b4d63a62d0 100755 --- a/scripts/bump.js +++ b/scripts/bump.js @@ -1,8 +1,9 @@ #!/usr/bin/env node -const standardVersion = require('standard-version'); const fs = require('fs'); const path = require('path'); +const semver = require('semver'); const ver = require('./resolve-version'); +const { exec } = require('child_process'); const repoRoot = path.join(__dirname, '..'); const releaseAs = process.argv[2] || 'minor'; @@ -40,7 +41,19 @@ async function main() { console.error(`BUMP_CANDIDATE is set, so bumping version for testing (with the "${opts.prerelease}" prerelease tag)`); } - return standardVersion(opts); + // `standard-release` will -- among other things -- create the changelog. + // However, on the v2 branch, `conventional-changelog` (which `standard-release` uses) gets confused + // and creates really muddled changelogs with both v1 and v2 releases intermingled, and lots of missing data. + // A super HACK here is to locally remove all version tags that don't match this major version prior + // to doing the bump, and then later fetching to restore those tags. + const majorVersion = semver.major(ver.version); + await exec(`git tag -d $(git tag -l | grep -v '^v${majorVersion}.')`); + + // Delay loading standard-version until the git tags have been pruned. + const standardVersion = require('standard-version'); + await standardVersion(opts); + + await exec('git fetch -t'); } main().catch(err => { diff --git a/scripts/check-api-compatibility.sh b/scripts/check-api-compatibility.sh index ece902e7130f9..1b99f9e05f188 100755 --- a/scripts/check-api-compatibility.sh +++ b/scripts/check-api-compatibility.sh @@ -9,6 +9,10 @@ package_name() { node -pe "require('$1/package.json').name" } +package_name_and_dist_tag() { + node -pe "const pkg = require('$1/package.json'); pkg.name + '@' + pkg.publishConfig.tag" +} + # Determine whether an NPM package exists on NPM # # Doesn't use 'npm view' as that is slow. Direct curl'ing npmjs is better @@ -18,7 +22,6 @@ package_exists_on_npm() { curl -I 2>/dev/null https://registry.npmjs.org/$pkg/$ver | head -n 1 | grep 200 >/dev/null } - #---------------------------------------------------------------------- list_jsii_packages() { @@ -33,12 +36,11 @@ jsii_package_dirs=$(list_jsii_packages) #---------------------------------------------------------------------- -# Input a directory, output the package name IF it exists on GitHub -dirs_to_existing_names() { +# Input a directory, output the directory IF it exists on NPM +dirs_for_existing_pkgs() { local dir="$1" - local name=$(package_name "$dir") - if package_exists_on_npm $name; then - echo "$name" + if package_exists_on_npm $(package_name $dir); then + echo "$dir" echo -n "." >&2 else echo -n "x" >&2 @@ -46,28 +48,29 @@ dirs_to_existing_names() { } export -f package_name +export -f package_name_and_dist_tag export -f package_exists_on_npm -export -f dirs_to_existing_names +export -f dirs_for_existing_pkgs if ! ${SKIP_DOWNLOAD:-false}; then echo "Filtering on existing packages on NPM..." >&2 # In parallel - existing_names=$(echo "$jsii_package_dirs" | xargs -n1 -P4 -I {} bash -c 'dirs_to_existing_names "$@"' _ {}) + existing_pkg_dirs=$(echo "$jsii_package_dirs" | xargs -n1 -P4 -I {} bash -c 'dirs_for_existing_pkgs "$@"' _ {}) + existing_names=$(echo "$existing_pkg_dirs" | xargs -n1 -P4 -I {} bash -c 'package_name "$@"' _ {}) echo " Done." >&2 echo "Determining baseline version..." >&2 version=$(node -p 'require("./scripts/resolve-version.js").version') - disttag=$(node -p 'require("./scripts/resolve-version.js").npmDistTag') echo " Current version is $version." >&2 if ! package_exists_on_npm aws-cdk $version; then - echo " Version $version does not exist in npm. Falling back to resolved dist tag '$disttag'" >&2 - version=$disttag + echo " Version $version does not exist in npm. Falling back to package dist tags" >&2 + existing_names=$(echo "$existing_pkg_dirs" | xargs -n1 -P4 -I {} bash -c 'package_name_and_dist_tag "$@"' _ {}) + else + echo "Using version '$version' as the baseline..." + existing_names=$(echo "$existing_names" | sed -e "s/$/@$version/") fi - echo "Using version '$version' as the baseline..." - existing_names=$(echo "$existing_names" | sed -e "s/$/@$version/") - rm -rf $tmpdir mkdir -p $tmpdir diff --git a/scripts/resolve-version-lib.js b/scripts/resolve-version-lib.js index 63d54f33c4a70..2a7f0e4eecebc 100755 --- a/scripts/resolve-version-lib.js +++ b/scripts/resolve-version-lib.js @@ -3,13 +3,13 @@ const path = require('path'); const fs = require('fs'); //============================================================= -// UNIT TESTS: tools/script-tests/test/resolve-version.test.js +// UNIT TESTS: tools/script-tests/test/resolve-version.test.js //============================================================= function resolveVersion(rootdir) { const ALLOWED_RELEASE_TYPES = [ 'alpha', 'rc', 'stable' ]; const MIN_MAJOR = 1, MAX_MAJOR = 2; // extra safety: update to allow new major versions - + // // parse release.json // @@ -17,31 +17,30 @@ function resolveVersion(rootdir) { const releaseConfig = require(releaseFile); const majorVersion = releaseConfig.majorVersion; const releaseType = releaseConfig.releaseType; - const distTag = releaseConfig.distTag; if (!majorVersion) { throw new Error(`"majorVersion"" must be defined in ${releaseFile}`); } if (!releaseType) { throw new Error(`"releaseType" must be defined in ${releaseFile}`); } if (typeof(majorVersion) !== 'number') { throw new Error(`majorVersion=${majorVersion} must be a number`); } if (majorVersion < MIN_MAJOR || majorVersion > MAX_MAJOR) { throw new Error(`majorVersion=${majorVersion} is an unsupported major version (should be between ${MIN_MAJOR} and ${MAX_MAJOR})`); } if (!ALLOWED_RELEASE_TYPES.includes(releaseType)) { throw new Error(`releaseType=${releaseType} is not allowed. Allowed values: ${ALLOWED_RELEASE_TYPES.join(',')}`); } - + // // resolve and check that we have a version file // - + const versionFile = `version.v${majorVersion}.json`; const versionFilePath = path.join(rootdir, versionFile); if (!fs.existsSync(versionFilePath)) { throw new Error(`unable to find version file ${versionFile} for major version ${majorVersion}`); } - + // // validate that current version matches the requirements // - + const currentVersion = require(versionFilePath).version; console.error(`current version: ${currentVersion}`); - if (!currentVersion.startsWith(`${majorVersion}.`)) { - throw new Error(`current version "${currentVersion}" does not use the expected major version ${majorVersion}`); + if (!currentVersion.startsWith(`${majorVersion}.`)) { + throw new Error(`current version "${currentVersion}" does not use the expected major version ${majorVersion}`); } // if this is a pre-release, make sure current version includes the // pre-release tag (e.g. "1.0.0-alpha.0"). we allow stable branches to bump to @@ -51,27 +50,26 @@ function resolveVersion(rootdir) { throw new Error(`could not find pre-release tag "${releaseType}" in current version "${currentVersion}" defined in ${versionFile}`); } } - + // // determine changelog file name // - - const changelogFile = majorVersion === 1 - ? 'CHANGELOG.md' + + const changelogFile = majorVersion === 1 + ? 'CHANGELOG.md' : `CHANGELOG.v${majorVersion}.md`; - + // // export all of it // - + return { version: currentVersion, versionFile: versionFile, changelogFile: changelogFile, prerelease: releaseType !== 'stable' ? releaseType : undefined, marker: '0.0.0', - ...(distTag ? { npmDistTag: distTag } : {}), }; } -module.exports = resolveVersion; \ No newline at end of file +module.exports = resolveVersion; diff --git a/scripts/script-tests/resolve-version.test.js b/scripts/script-tests/resolve-version.test.js index 57e72019245d8..442e97e45b3cf 100644 --- a/scripts/script-tests/resolve-version.test.js +++ b/scripts/script-tests/resolve-version.test.js @@ -67,7 +67,7 @@ happy({ happy({ name: 'to support BUMP_CANDIDATE stable branches can be bumped towards a pre-release', - inputs: { + inputs: { 'release.json': { majorVersion: 2, releaseType: 'stable' }, 'version.v2.json': { version: '2.0.0-rc.0' } }, @@ -80,23 +80,6 @@ happy({ } }); -happy({ - name: 'dist tag is correctly shown', - inputs: { - 'release.json': { majorVersion: 2, releaseType: 'alpha', distTag: 'v2-preview' }, - 'version.v2.json': { version: '2.0.0-alpha.5' } - }, - expected: { - changelogFile: 'CHANGELOG.v2.md', - marker: '0.0.0', - prerelease: 'alpha', - version: '2.0.0-alpha.5', - versionFile: 'version.v2.json', - npmDistTag: 'v2-preview', - } -}); - - failure({ name: 'invalid release type', inputs: { 'release.json': { majorVersion: 2, releaseType: 'build' } }, @@ -129,7 +112,7 @@ failure({ failure({ name: 'actual version not the right major', - inputs: { + inputs: { 'release.json': { majorVersion: 1, releaseType: 'stable' }, 'version.v1.json': { version: '2.0.0' } }, @@ -138,7 +121,7 @@ failure({ failure({ name: 'actual version not the right pre-release', - inputs: { + inputs: { 'release.json': { majorVersion: 2, releaseType: 'alpha' }, 'version.v2.json': { version: '2.0.0-rc.0' } }, diff --git a/tools/cdk-build-tools/lib/feature-flag.ts b/tools/cdk-build-tools/lib/feature-flag.ts index eec1d28d6e9e4..36b22588288aa 100644 --- a/tools/cdk-build-tools/lib/feature-flag.ts +++ b/tools/cdk-build-tools/lib/feature-flag.ts @@ -30,9 +30,8 @@ export function testFutureBehavior( const major = cdkMajorVersion(repoRoot); if (major === 2) { - // Temporaily disable CDKv2 behaviour - // const app = new cdkApp(); - // return test(name, async () => fn(app)); + const app = new cdkApp(); + return test(name, async () => fn(app)); } const app = new cdkApp({ context: flags }); return test(name, () => fn(app)); @@ -59,8 +58,7 @@ export function testLegacyBehavior( const major = cdkMajorVersion(repoRoot); if (major === 2) { - // Temporarily disable CDKv2 behaviour - // return; + return; } const app = new cdkApp(); return test(name, () => fn(app)); @@ -78,4 +76,4 @@ function cdkMajorVersion(repoRoot: string) { throw new Error(`version ${ver} is not a semver`); } return sem.major; -} \ No newline at end of file +} diff --git a/tools/cdk-build-tools/package.json b/tools/cdk-build-tools/package.json index 9e90bcc164364..8b2a6236620e9 100644 --- a/tools/cdk-build-tools/package.json +++ b/tools/cdk-build-tools/package.json @@ -39,26 +39,26 @@ "pkglint": "0.0.0" }, "dependencies": { - "@typescript-eslint/eslint-plugin": "^4.15.0", - "@typescript-eslint/parser": "^4.14.2", + "@typescript-eslint/eslint-plugin": "^4.15.1", + "@typescript-eslint/parser": "^4.15.1", "awslint": "0.0.0", "colors": "^1.4.0", - "eslint": "^7.19.0", + "eslint": "^7.20.0", "eslint-import-resolver-node": "^0.3.4", - "eslint-import-resolver-typescript": "^2.3.0", + "eslint-import-resolver-typescript": "^2.4.0", "eslint-plugin-cdk": "0.0.0", "eslint-plugin-import": "^2.22.1", - "eslint-plugin-jest": "^24.1.3", + "eslint-plugin-jest": "^24.1.5", "fs-extra": "^9.1.0", "jest": "^26.6.3", - "jsii": "^1.20.1", - "jsii-pacmak": "^1.20.1", + "jsii": "^1.21.0", + "jsii-pacmak": "^1.21.0", "markdownlint-cli": "^0.26.0", "nodeunit": "^0.11.3", "nyc": "^15.1.0", "semver": "^7.3.4", - "ts-jest": "^26.5.0", - "typescript": "~3.9.7", + "ts-jest": "^26.5.1", + "typescript": "~3.9.9", "yargs": "^16.2.0", "yarn-cling": "0.0.0" }, diff --git a/tools/cdk-integ-tools/lib/integ-helpers.ts b/tools/cdk-integ-tools/lib/integ-helpers.ts index 3a81fe8466465..bf65e8cbb8b9a 100644 --- a/tools/cdk-integ-tools/lib/integ-helpers.ts +++ b/tools/cdk-integ-tools/lib/integ-helpers.ts @@ -1,6 +1,7 @@ // Helper functions for integration tests import { spawnSync } from 'child_process'; import * as path from 'path'; +import { FUTURE_FLAGS } from '@aws-cdk/cx-api'; import * as fs from 'fs-extra'; import { AVAILABILITY_ZONE_FALLBACK_CONTEXT_KEY } from '../../../packages/@aws-cdk/cx-api/lib'; @@ -337,7 +338,8 @@ export const DEFAULT_SYNTH_OPTIONS = { }, ], }, - '@aws-cdk/aws-ecr-assets:dockerIgnoreSupport': true, + // Enable feature flags for all integ tests + ...FUTURE_FLAGS, }, env: { CDK_INTEG_ACCOUNT: '12345678', diff --git a/tools/cfn2ts/lib/codegen.ts b/tools/cfn2ts/lib/codegen.ts index 8d85d05f7ee72..c06fce32e10ff 100644 --- a/tools/cfn2ts/lib/codegen.ts +++ b/tools/cfn2ts/lib/codegen.ts @@ -1,4 +1,4 @@ -import { schema } from '@aws-cdk/cfnspec'; +import { schema, cfnLintAnnotations } from '@aws-cdk/cfnspec'; import { CodeMaker } from 'codemaker'; import * as genspec from './genspec'; import { itemTypeNames, PropertyAttributeName, scalarTypeNames, SpecName } from './spec-utils'; @@ -125,7 +125,7 @@ export default class CodeGenerator { this.code.closeBlock(); this.code.line(); - this.emitValidator(resourceContext, name, spec.Properties, conversionTable); + this.emitPropertiesValidator(resourceContext, name, spec.Properties, conversionTable); this.code.line(); this.emitCloudFormationMapper(resourceContext, name, spec.Properties, conversionTable); this.emitFromCfnFactoryFunction(resourceContext, name, spec.Properties, conversionTable, false); @@ -343,6 +343,13 @@ export default class CodeGenerator { } } } + + // + // Validator + // + this.emitConstructValidator(resourceName); + + // End constructor this.code.closeBlock(); this.code.line(); @@ -385,6 +392,37 @@ export default class CodeGenerator { this.code.closeBlock(); } + /** + * Add validations for the given construct + * + * The generated code looks like this: + * + * ``` + * this.node.addValidation({ validate: () => /* validation code * / }); + * } + * ``` + */ + private emitConstructValidator(resourceType: genspec.CodeName) { + const cfnLint = cfnLintAnnotations(resourceType.specName?.fqn ?? ''); + + if (cfnLint.stateful) { + // Do a statefulness check. A deletionPolicy is required (and in normal operation an UpdateReplacePolicy + // would also be set if a user doesn't do complicated shenanigans, in which case they probably know what + // they're doing. + // + // Only do this for L1s embedded in L2s (to force L2 authors to add a way to set this policy). If we did it for all L1s: + // + // - users working at the L1 level would start getting synthesis failures when we add this feature + // - the `cloudformation-include` library that loads CFN templates to L1s would start failing when it loads + // templates that don't have DeletionPolicy set. + this.code.openBlock(`if (this.node.scope && ${CORE}.Resource.isResource(this.node.scope))`); + this.code.line('this.node.addValidation({ validate: () => this.cfnOptions.deletionPolicy === undefined'); + this.code.line(` ? [\'\\\'${resourceType.specName?.fqn}\\\' is a stateful resource type, and you must specify a Removal Policy for it. Call \\\'resource.applyRemovalPolicy()\\\'.\']`); + this.code.line(' : [] });'); + this.code.closeBlock(); + } + } + /** * Emit the function that is going to implement the IInspectable interface. * @@ -665,7 +703,7 @@ export default class CodeGenerator { * * Generated as a top-level function outside any namespace so we can hide it from library consumers. */ - private emitValidator( + private emitPropertiesValidator( resource: genspec.CodeName, typeName: genspec.CodeName, propSpecs: { [name: string]: schema.Property }, @@ -684,6 +722,15 @@ export default class CodeGenerator { this.code.line(`const errors = new ${CORE}.ValidationResults();`); + // check that the argument is an object + // normally, we would have to explicitly check for null here, + // as typeof null is 'object' in JavaScript, + // but validators are never called with null + // (as evidenced by the code below accessing properties of the argument without checking for null) + this.code.openBlock("if (typeof properties !== 'object')"); + this.code.line(`errors.collect(new ${CORE}.ValidationResult('Expected an object, but received: ' + JSON.stringify(properties)));`); + this.code.closeBlock(); + Object.keys(propSpecs).forEach(cfnPropName => { const propSpec = propSpecs[cfnPropName]; const propName = nameConversionTable[cfnPropName]; @@ -819,7 +866,7 @@ export default class CodeGenerator { this.endNamespace(typeName); this.code.line(); - this.emitValidator(resourceContext, typeName, propTypeSpec.Properties, conversionTable); + this.emitPropertiesValidator(resourceContext, typeName, propTypeSpec.Properties, conversionTable); this.code.line(); this.emitCloudFormationMapper(resourceContext, typeName, propTypeSpec.Properties, conversionTable); this.emitFromCfnFactoryFunction(resourceContext, typeName, propTypeSpec.Properties, conversionTable, true); diff --git a/tools/cfn2ts/package.json b/tools/cfn2ts/package.json index 0a4297e691b39..7a62104df3ea9 100644 --- a/tools/cfn2ts/package.json +++ b/tools/cfn2ts/package.json @@ -30,7 +30,7 @@ "license": "Apache-2.0", "dependencies": { "@aws-cdk/cfnspec": "0.0.0", - "codemaker": "^1.20.1", + "codemaker": "^1.21.0", "fast-json-patch": "^3.0.0-1", "fs-extra": "^9.1.0", "yargs": "^16.2.0" diff --git a/tools/eslint-plugin-cdk/package.json b/tools/eslint-plugin-cdk/package.json index e92e010ef1ca5..2c412f30e739e 100644 --- a/tools/eslint-plugin-cdk/package.json +++ b/tools/eslint-plugin-cdk/package.json @@ -15,14 +15,14 @@ "@types/eslint": "^7.2.6", "@types/fs-extra": "^8.1.1", "@types/jest": "^26.0.20", - "@types/node": "^10.17.51", + "@types/node": "^10.17.54", "eslint-plugin-rulesdir": "^0.1.0", "jest": "^26.6.3", - "typescript": "~3.9.7" + "typescript": "~3.9.9" }, "dependencies": { - "@typescript-eslint/parser": "^4.14.2", - "eslint": "^7.19.0", + "@typescript-eslint/parser": "^4.15.1", + "eslint": "^7.20.0", "fs-extra": "^9.1.0" }, "jest": { diff --git a/tools/nodeunit-shim/package.json b/tools/nodeunit-shim/package.json index 675f0cbf3e649..bc18b8dafe37c 100644 --- a/tools/nodeunit-shim/package.json +++ b/tools/nodeunit-shim/package.json @@ -13,8 +13,8 @@ }, "devDependencies": { "@types/jest": "^26.0.20", - "@types/node": "^10.17.51", - "typescript": "~3.9.7" + "@types/node": "^10.17.54", + "typescript": "~3.9.9" }, "dependencies": { "jest": "^26.6.3" diff --git a/tools/pkglint/lib/rules.ts b/tools/pkglint/lib/rules.ts index 0d75c3b1113cf..67e26c9634712 100644 --- a/tools/pkglint/lib/rules.ts +++ b/tools/pkglint/lib/rules.ts @@ -46,9 +46,38 @@ export class DescriptionIsRequired extends ValidationRule { } } +/** + * Verify that all packages have a publishConfig with a publish tag set. + */ +export class PublishConfigTagIsRequired extends ValidationRule { + public readonly name = 'package-info/publish-config-tag'; + + public validate(pkg: PackageJson): void { + if (pkg.json.private) { return; } + + // While v2 is still under development, we publish all v2 packages with the 'next' + // distribution tag, while still tagging all v1 packages as 'latest'. + // The one exception is 'aws-cdk-lib', since it's a new package for v2. + const newV2Packages = ['aws-cdk-lib']; + const defaultPublishTag = (cdkMajorVersion() === 2 && !newV2Packages.includes(pkg.json.name)) ? 'next' : 'latest'; + + if (pkg.json.publishConfig?.tag !== defaultPublishTag) { + pkg.report({ + ruleName: this.name, + message: `publishConfig.tag must be ${defaultPublishTag}`, + fix: (() => { + const publishConfig = pkg.json.publishConfig ?? {}; + publishConfig.tag = defaultPublishTag; + pkg.json.publishConfig = publishConfig; + }), + }); + } + } +} + /** * Verify cdk.out directory is included in npmignore since we should not be - * publihsing it. + * publishing it. */ export class CdkOutMustBeNpmIgnored extends ValidationRule { diff --git a/tools/pkglint/package.json b/tools/pkglint/package.json index c4bbd7e87c0ba..0bfea5465a4a0 100644 --- a/tools/pkglint/package.json +++ b/tools/pkglint/package.json @@ -40,7 +40,7 @@ "@types/yargs": "^15.0.13", "eslint-plugin-cdk": "0.0.0", "jest": "^26.6.3", - "typescript": "~3.9.7" + "typescript": "~3.9.9" }, "dependencies": { "case": "^1.6.3", diff --git a/tools/ubergen/package.json b/tools/ubergen/package.json index bac96b9391693..65c88331540a8 100644 --- a/tools/ubergen/package.json +++ b/tools/ubergen/package.json @@ -33,7 +33,7 @@ }, "dependencies": { "fs-extra": "^9.1.0", - "typescript": "~3.9.7" + "typescript": "~3.9.9" }, "keywords": [ "aws", diff --git a/tools/yarn-cling/package.json b/tools/yarn-cling/package.json index 6cc21f56b710d..7a5f00b076fb3 100644 --- a/tools/yarn-cling/package.json +++ b/tools/yarn-cling/package.json @@ -39,11 +39,11 @@ }, "devDependencies": { "@types/jest": "^26.0.20", - "@types/node": "^10.17.51", + "@types/node": "^10.17.54", "@types/yarnpkg__lockfile": "^1.1.4", "jest": "^26.6.3", "pkglint": "0.0.0", - "typescript": "~3.9.7" + "typescript": "~3.9.9" }, "dependencies": { "@yarnpkg/lockfile": "^1.1.0" diff --git a/version.v1.json b/version.v1.json index 345b477275b1d..aa566c6d404ff 100644 --- a/version.v1.json +++ b/version.v1.json @@ -1,3 +1,3 @@ { - "version": "1.89.0" + "version": "1.91.0" } diff --git a/yarn.lock b/yarn.lock index 6755dc79c2a92..5a1cb28a9d233 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,13 @@ # yarn lockfile v1 +"@babel/code-frame@7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" + integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== + dependencies: + "@babel/highlight" "^7.10.4" + "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658" @@ -9,36 +16,52 @@ dependencies: "@babel/highlight" "^7.12.13" +"@babel/compat-data@^7.13.0": + version "7.13.6" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.13.6.tgz#11972d07db4c2317afdbf41d6feb3a730301ef4e" + integrity sha512-VhgqKOWYVm7lQXlvbJnWOzwfAQATd2nV52koT0HZ/LdDH0m4DUDwkKYsH+IwpXb+bKPyBJzawA4I6nBKqZcpQw== + "@babel/core@^7.1.0", "@babel/core@^7.7.5": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.13.tgz#b73a87a3a3e7d142a66248bf6ad88b9ceb093425" - integrity sha512-BQKE9kXkPlXHPeqissfxo0lySWJcYdEP0hdtJOH/iJfDdhOCcgtNCjftCJg3qqauB4h+lz2N6ixM++b9DN1Tcw== + version "7.13.1" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.13.1.tgz#7ddd027176debe40f13bb88bac0c21218c5b1ecf" + integrity sha512-FzeKfFBG2rmFtGiiMdXZPFt/5R5DXubVi82uYhjGX4Msf+pgYQMCFIqFXZWs5vbIYbf14VeBIgdGI03CDOOM1w== dependencies: "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.12.13" - "@babel/helper-module-transforms" "^7.12.13" - "@babel/helpers" "^7.12.13" - "@babel/parser" "^7.12.13" + "@babel/generator" "^7.13.0" + "@babel/helper-compilation-targets" "^7.13.0" + "@babel/helper-module-transforms" "^7.13.0" + "@babel/helpers" "^7.13.0" + "@babel/parser" "^7.13.0" "@babel/template" "^7.12.13" - "@babel/traverse" "^7.12.13" - "@babel/types" "^7.12.13" + "@babel/traverse" "^7.13.0" + "@babel/types" "^7.13.0" convert-source-map "^1.7.0" debug "^4.1.0" - gensync "^1.0.0-beta.1" + gensync "^1.0.0-beta.2" json5 "^2.1.2" lodash "^4.17.19" - semver "^5.4.1" + semver "7.0.0" source-map "^0.5.0" -"@babel/generator@^7.12.13", "@babel/generator@^7.4.0": - version "7.12.15" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.12.15.tgz#4617b5d0b25cc572474cc1aafee1edeaf9b5368f" - integrity sha512-6F2xHxBiFXWNSGb7vyCUTBF8RCLY66rS0zEPcP8t/nQyXjha5EuK4z7H5o7fWG8B4M7y6mqVWq1J+1PuwRhecQ== +"@babel/generator@^7.13.0", "@babel/generator@^7.4.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.13.0.tgz#bd00d4394ca22f220390c56a0b5b85568ec1ec0c" + integrity sha512-zBZfgvBB/ywjx0Rgc2+BwoH/3H+lDtlgD4hBOpEv5LxRnYsm/753iRuLepqnYlynpjC3AdQxtxsoeHJoEEwOAw== dependencies: - "@babel/types" "^7.12.13" + "@babel/types" "^7.13.0" jsesc "^2.5.1" source-map "^0.5.0" +"@babel/helper-compilation-targets@^7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.0.tgz#c9cf29b82a76fd637f0faa35544c4ace60a155a1" + integrity sha512-SOWD0JK9+MMIhTQiUVd4ng8f3NXhPVQvTv7D3UN4wbp/6cAHnB2EmMaU1zZA2Hh1gwme+THBrVSqTFxHczTh0Q== + dependencies: + "@babel/compat-data" "^7.13.0" + "@babel/helper-validator-option" "^7.12.17" + browserslist "^4.14.5" + semver "7.0.0" + "@babel/helper-function-name@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz#93ad656db3c3c2232559fd7b2c3dbdcbe0eb377a" @@ -55,12 +78,12 @@ dependencies: "@babel/types" "^7.12.13" -"@babel/helper-member-expression-to-functions@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.13.tgz#c5715695b4f8bab32660dbdcdc2341dec7e3df40" - integrity sha512-B+7nN0gIL8FZ8SvMcF+EPyB21KnCcZHQZFczCxbiNGV/O0rsrSBlWGLzmtBJ3GMjSVMIm4lpFhR+VdVBuIsUcQ== +"@babel/helper-member-expression-to-functions@^7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.0.tgz#6aa4bb678e0f8c22f58cdb79451d30494461b091" + integrity sha512-yvRf8Ivk62JwisqV1rFRMxiSMDGnN6KH1/mDMmIrij4jztpQNRoHqqMG3U6apYbGRPJpgPalhva9Yd06HlUxJQ== dependencies: - "@babel/types" "^7.12.13" + "@babel/types" "^7.13.0" "@babel/helper-module-imports@^7.12.13": version "7.12.13" @@ -69,19 +92,19 @@ dependencies: "@babel/types" "^7.12.13" -"@babel/helper-module-transforms@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.12.13.tgz#01afb052dcad2044289b7b20beb3fa8bd0265bea" - integrity sha512-acKF7EjqOR67ASIlDTupwkKM1eUisNAjaSduo5Cz+793ikfnpe7p4Q7B7EWU2PCoSTPWsQkR7hRUWEIZPiVLGA== +"@babel/helper-module-transforms@^7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.13.0.tgz#42eb4bd8eea68bab46751212c357bfed8b40f6f1" + integrity sha512-Ls8/VBwH577+pw7Ku1QkUWIyRRNHpYlts7+qSqBBFCW3I8QteB9DxfcZ5YJpOwH6Ihe/wn8ch7fMGOP1OhEIvw== dependencies: "@babel/helper-module-imports" "^7.12.13" - "@babel/helper-replace-supers" "^7.12.13" + "@babel/helper-replace-supers" "^7.13.0" "@babel/helper-simple-access" "^7.12.13" "@babel/helper-split-export-declaration" "^7.12.13" "@babel/helper-validator-identifier" "^7.12.11" "@babel/template" "^7.12.13" - "@babel/traverse" "^7.12.13" - "@babel/types" "^7.12.13" + "@babel/traverse" "^7.13.0" + "@babel/types" "^7.13.0" lodash "^4.17.19" "@babel/helper-optimise-call-expression@^7.12.13": @@ -92,19 +115,19 @@ "@babel/types" "^7.12.13" "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.8.0": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.12.13.tgz#174254d0f2424d8aefb4dd48057511247b0a9eeb" - integrity sha512-C+10MXCXJLiR6IeG9+Wiejt9jmtFpxUc3MQqCmPY8hfCjyUGl9kT+B2okzEZrtykiwrc4dbCPdDoz0A/HQbDaA== + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz#806526ce125aed03373bc416a828321e3a6a33af" + integrity sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ== -"@babel/helper-replace-supers@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.12.13.tgz#00ec4fb6862546bd3d0aff9aac56074277173121" - integrity sha512-pctAOIAMVStI2TMLhozPKbf5yTEXc0OJa0eENheb4w09SrgOWEs+P4nTOZYJQCqs8JlErGLDPDJTiGIp3ygbLg== +"@babel/helper-replace-supers@^7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.13.0.tgz#6034b7b51943094cb41627848cb219cb02be1d24" + integrity sha512-Segd5me1+Pz+rmN/NFBOplMbZG3SqRJOBlY+mA0SxAv6rjj7zJqr1AVr3SfzUVTLCv7ZLU5FycOM/SBGuLPbZw== dependencies: - "@babel/helper-member-expression-to-functions" "^7.12.13" + "@babel/helper-member-expression-to-functions" "^7.13.0" "@babel/helper-optimise-call-expression" "^7.12.13" - "@babel/traverse" "^7.12.13" - "@babel/types" "^7.12.13" + "@babel/traverse" "^7.13.0" + "@babel/types" "^7.13.0" "@babel/helper-simple-access@^7.12.13": version "7.12.13" @@ -125,16 +148,21 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== -"@babel/helpers@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.12.13.tgz#3c75e993632e4dadc0274eae219c73eb7645ba47" - integrity sha512-oohVzLRZ3GQEk4Cjhfs9YkJA4TdIDTObdBEZGrd6F/T0GPSnuV6l22eMcxlvcvzVIPH3VTtxbseudM1zIE+rPQ== +"@babel/helper-validator-option@^7.12.17": + version "7.12.17" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz#d1fbf012e1a79b7eebbfdc6d270baaf8d9eb9831" + integrity sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw== + +"@babel/helpers@^7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.13.0.tgz#7647ae57377b4f0408bf4f8a7af01c42e41badc0" + integrity sha512-aan1MeFPxFacZeSz6Ld7YZo5aPuqnKlD7+HZY75xQsueczFccP9A7V05+oe0XpLwHK3oLorPe9eaAUljL7WEaQ== dependencies: "@babel/template" "^7.12.13" - "@babel/traverse" "^7.12.13" - "@babel/types" "^7.12.13" + "@babel/traverse" "^7.13.0" + "@babel/types" "^7.13.0" -"@babel/highlight@^7.12.13": +"@babel/highlight@^7.10.4", "@babel/highlight@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.12.13.tgz#8ab538393e00370b26271b01fa08f7f27f2e795c" integrity sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww== @@ -143,10 +171,10 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.12.13", "@babel/parser@^7.4.3": - version "7.12.15" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.15.tgz#2b20de7f0b4b332d9b119dd9c33409c538b8aacf" - integrity sha512-AQBOU2Z9kWwSZMd6lNjCX0GUgFonL1wAM1db8L8PMk9UDaGsRCArBkU4Sc+UCM3AE4hjbXx+h58Lb3QT4oRmrA== +"@babel/parser@^7.1.0", "@babel/parser@^7.12.13", "@babel/parser@^7.13.0", "@babel/parser@^7.4.3": + version "7.13.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.4.tgz#340211b0da94a351a6f10e63671fa727333d13ab" + integrity sha512-uvoOulWHhI+0+1f9L4BoozY7U5cIkZ9PgJqvb041d6vypgUmtVPG4vmGm4pSggjl8BELzvHyUeJSUyEMY6b+qA== "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" @@ -241,25 +269,25 @@ "@babel/parser" "^7.12.13" "@babel/types" "^7.12.13" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.12.13", "@babel/traverse@^7.4.3": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.13.tgz#689f0e4b4c08587ad26622832632735fb8c4e0c0" - integrity sha512-3Zb4w7eE/OslI0fTp8c7b286/cQps3+vdLW3UcwC8VSJC6GbKn55aeVVu2QJNuCDoeKyptLOFrPq8WqZZBodyA== +"@babel/traverse@^7.1.0", "@babel/traverse@^7.13.0", "@babel/traverse@^7.4.3": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.13.0.tgz#6d95752475f86ee7ded06536de309a65fc8966cc" + integrity sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ== dependencies: "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.12.13" + "@babel/generator" "^7.13.0" "@babel/helper-function-name" "^7.12.13" "@babel/helper-split-export-declaration" "^7.12.13" - "@babel/parser" "^7.12.13" - "@babel/types" "^7.12.13" + "@babel/parser" "^7.13.0" + "@babel/types" "^7.13.0" debug "^4.1.0" globals "^11.1.0" lodash "^4.17.19" -"@babel/types@^7.0.0", "@babel/types@^7.12.13", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.0": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.13.tgz#8be1aa8f2c876da11a9cf650c0ecf656913ad611" - integrity sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ== +"@babel/types@^7.0.0", "@babel/types@^7.12.13", "@babel/types@^7.13.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.0.tgz#74424d2816f0171b4100f0ab34e9a374efdf7f80" + integrity sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA== dependencies: "@babel/helper-validator-identifier" "^7.12.11" lodash "^4.17.19" @@ -385,9 +413,9 @@ resolve-from "^5.0.0" "@istanbuljs/schema@^0.1.2": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" - integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== "@jest/console@^26.6.2": version "26.6.2" @@ -560,10 +588,10 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" -"@jsii/spec@^1.20.1": - version "1.20.1" - resolved "https://registry.yarnpkg.com/@jsii/spec/-/spec-1.20.1.tgz#931a4e8280ab2f2314452a92fb91f0b40d5e8f77" - integrity sha512-+ot9SPb/lFnRiPlhWUGLMp8owpr/pnpFX0/iIUhZ0kJ1LIAUde7TSuaz70mV6x+ES2wvVXKsgfu2WTMFHIAwZQ== +"@jsii/spec@^1.21.0", "@jsii/spec@^1.22.0": + version "1.22.0" + resolved "https://registry.yarnpkg.com/@jsii/spec/-/spec-1.22.0.tgz#8c96a263ca9068590238323d8b689b4b9f13f0de" + integrity sha512-OI9LOxU3YhVyzUVvzh5nKDCalFZm0CjPaCdo6X/lL0TaVcpkYyJ8qDRuGF8WCW9PJEORkOhBwC7ySoFl/RVv9A== dependencies: jsonschema "^1.4.0" @@ -1323,10 +1351,10 @@ "@octokit/types" "^6.0.3" universal-user-agent "^6.0.0" -"@octokit/openapi-types@^4.0.2": - version "4.0.2" - resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-4.0.2.tgz#4b2bb553a16ab9e0fdeb29bd453b1c88cf129929" - integrity sha512-quqmeGTjcVks8YaatVGCpt7QpUTs2PK0D3mW5aEQqmFKOuIZ/CxwWrgnggPjqP3CNp6eALdQRgf0jUpcG8X1/Q== +"@octokit/openapi-types@^5.1.0": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-5.1.1.tgz#d01ae6e2879c589edcea7800e3a427455ece619f" + integrity sha512-yMyaX9EDWCiyv7m85/K8L7bLFj1wrLdfDkKcZEZ6gNmepSW5mfSMFJnYwRINN7lF58wvevKPWvw0MYy6sxcFlQ== "@octokit/plugin-enterprise-rest@^6.0.1": version "6.0.1" @@ -1341,11 +1369,11 @@ "@octokit/types" "^2.0.1" "@octokit/plugin-paginate-rest@^2.6.2": - version "2.9.1" - resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.9.1.tgz#e9bb34a89b7ed5b801f1c976feeb9b0078ecd201" - integrity sha512-8wnuWGjwDIEobbBet2xAjZwgiMVTgIer5wBsnGXzV3lJ4yqphLU2FEMpkhSrDx7y+WkZDfZ+V+1cFMZ1mAaFag== + version "2.10.0" + resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.10.0.tgz#5925156d809c94b7bfc47b28e17488415548fa67" + integrity sha512-71OsKBSMcQEu/6lfVbhv5C5ikU1rn10rKot/WiV7do7fyfElQ2eCUQFogHPbj0ci5lnKAjvahOiMAr6lcvL8Qw== dependencies: - "@octokit/types" "^6.8.0" + "@octokit/types" "^6.10.0" "@octokit/plugin-request-log@^1.0.0", "@octokit/plugin-request-log@^1.0.2": version "1.0.3" @@ -1360,12 +1388,12 @@ "@octokit/types" "^2.0.1" deprecation "^2.3.1" -"@octokit/plugin-rest-endpoint-methods@4.10.1": - version "4.10.1" - resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.10.1.tgz#b7a9181d1f52fef70a13945c5b49cffa51862da1" - integrity sha512-YGMiEidTORzgUmYZu0eH4q2k8kgQSHQMuBOBYiKxUYs/nXea4q/Ze6tDzjcRAPmHNJYXrENs1bEMlcdGKT+8ug== +"@octokit/plugin-rest-endpoint-methods@4.12.2": + version "4.12.2" + resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.12.2.tgz#d2bd0b794d6c11a13113db6199baf44a39b06f50" + integrity sha512-5+MmGusB7wPw7OholtcGaMyjfrsFSpFqtJW8VsrbfU/TuaiQepY4wgVkS7P3TAObX257jrTbbGo/sJLcoGf16g== dependencies: - "@octokit/types" "^6.8.2" + "@octokit/types" "^6.10.1" deprecation "^2.3.1" "@octokit/request-error@^1.0.2": @@ -1422,15 +1450,15 @@ once "^1.4.0" universal-user-agent "^4.0.0" -"@octokit/rest@^18.1.0": - version "18.1.0" - resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.1.0.tgz#9bf72604911a3433165bcc924263c9a706d32804" - integrity sha512-YQfpTzWV3jdzDPyXQVO54f5I2t1zxk/S53Vbe+Aa5vQj6MdTx6sNEWzmUzUO8lSVowbGOnjcQHzW1A8ATr+/7g== +"@octokit/rest@^18.2.0": + version "18.2.1" + resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.2.1.tgz#04835fe9ab0d90ca2a93898cde2aa944c78c70bc" + integrity sha512-DdQ1vps41JSyB2axyL1mBwJiXAPibgugIQPOmt0mL/yhwheQ6iuq2aKiJWgGWa9ldMfe3v9gIFYlrFgxQ5ThGQ== dependencies: "@octokit/core" "^3.2.3" "@octokit/plugin-paginate-rest" "^2.6.2" "@octokit/plugin-request-log" "^1.0.2" - "@octokit/plugin-rest-endpoint-methods" "4.10.1" + "@octokit/plugin-rest-endpoint-methods" "4.12.2" "@octokit/types@^2.0.0", "@octokit/types@^2.0.1": version "2.16.2" @@ -1439,13 +1467,12 @@ dependencies: "@types/node" ">= 8" -"@octokit/types@^6.0.3", "@octokit/types@^6.7.1", "@octokit/types@^6.8.0", "@octokit/types@^6.8.2": - version "6.8.3" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.8.3.tgz#1960951103c836ab2e55fe47a8da2bf76402824f" - integrity sha512-ZNAy8z77ewKZ5LCX0KaUm4tWdgloWQ6FWJCh06qgahq/MH13sQefIPKSo0dBdPU3bcioltyZUcC0k8oHHfjvnQ== +"@octokit/types@^6.0.3", "@octokit/types@^6.10.0", "@octokit/types@^6.10.1", "@octokit/types@^6.7.1": + version "6.10.1" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.10.1.tgz#5955dc0cf344bb82a46283a0c332651f5dd9f1ad" + integrity sha512-hgNC5jxKG8/RlqxU/6GThkGrvFpz25+cPzjQjyiXTNBvhyltn2Z4GhFY25+kbtXwZ4Co4zM0goW5jak1KLp1ug== dependencies: - "@octokit/openapi-types" "^4.0.2" - "@types/node" ">= 8" + "@octokit/openapi-types" "^5.1.0" "@sinonjs/commons@^1.6.0", "@sinonjs/commons@^1.7.0", "@sinonjs/commons@^1.8.1": version "1.8.2" @@ -1487,10 +1514,10 @@ dependencies: "@types/glob" "*" -"@types/aws-lambda@^8.10.71": - version "8.10.71" - resolved "https://registry.yarnpkg.com/@types/aws-lambda/-/aws-lambda-8.10.71.tgz#ab3084038411ce42f63b975e67aafb163f3aa353" - integrity sha512-l0Lag6qq06AlKllprAJ3pbgVUbXCjRGRb7VpHow8IMn2BMHTPR0t5OD97/w8CR1+wA5XZuWQoXLjYvdlk2kQrQ== +"@types/aws-lambda@^8.10.72": + version "8.10.72" + resolved "https://registry.yarnpkg.com/@types/aws-lambda/-/aws-lambda-8.10.72.tgz#af2a6eeaf39be9674e3856f1870d9d15cf75e2e0" + integrity sha512-jOrTwAhSiUtBIN/QsWNKlI4+4aDtpZ0sr2BRvKW6XQZdspgHUSHPcuzxbzCRiHUiDQ+0026u5TSE38VyIhNnfA== "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7": version "7.1.12" @@ -1554,9 +1581,9 @@ "@types/node" "*" "@types/graceful-fs@^4.1.2": - version "4.1.4" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.4.tgz#4ff9f641a7c6d1a3508ff88bc3141b152772e753" - integrity sha512-mWA/4zFQhfvOA8zWkXobwJvBD7vzcxgrOQ0J5CH1votGqdq9m7+FwtGaqyCZqC3NyyBkc9z4m+iry4LlqcMWJg== + version "4.1.5" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" + integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== dependencies: "@types/node" "*" @@ -1609,7 +1636,7 @@ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.168.tgz#fe24632e79b7ade3f132891afff86caa5e5ce008" integrity sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q== -"@types/md5@^2.2.1": +"@types/md5@^2.3.0": version "2.3.0" resolved "https://registry.yarnpkg.com/@types/md5/-/md5-2.3.0.tgz#3b6a623091160f4dc75be3173e25f2110dc3fa1f" integrity sha512-556YJ7ejzxIqSSxzyGGpctuZOarNZJt/zlEkhmmDc1f/slOEANHuwu2ZX7YaZ40rMiWoxt8GvAhoDpW1cmSy6A== @@ -1639,14 +1666,14 @@ integrity sha1-m6It838H43gP/4Ux0aOOYz+UV6U= "@types/node@*", "@types/node@>= 8": - version "14.14.25" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.25.tgz#15967a7b577ff81383f9b888aa6705d43fbbae93" - integrity sha512-EPpXLOVqDvisVxtlbvzfyqSsFeQxltFbluZNRndIb8tr9KiBnYNLzrc1N3pyKUCww2RNrfHDViqDWWE1LCJQtQ== + version "14.14.31" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.31.tgz#72286bd33d137aa0d152d47ec7c1762563d34055" + integrity sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g== -"@types/node@^10.17.51": - version "10.17.51" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.51.tgz#639538575befbcf3d3861f95c41de8e47124d674" - integrity sha512-KANw+MkL626tq90l++hGelbl67irOJzGhUJk6a1Bt8QHOeh9tztJx+L0AqttraWKinmZn7Qi5lJZJzx45Gq0dg== +"@types/node@^10.17.54": + version "10.17.54" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.54.tgz#a737488631aca3ec7bd9f6229d77f1079e444793" + integrity sha512-c8Lm7+hXdSPmWH4B9z/P/xIXhFK3mCQin4yCYMd2p1qpMG5AfgyJuYZ+3q2dT7qLiMMMGMd5dnkFpdqJARlvtQ== "@types/nodeunit@^0.0.31": version "0.0.31" @@ -1659,9 +1686,9 @@ integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA== "@types/prettier@^2.0.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.2.0.tgz#a4e8205a4955690eef712a6d0394a1d2e121e721" - integrity sha512-O3SQC6+6AySHwrspYn2UvC6tjo6jCTMMmylxZUFhE1CulVu5l3AxU6ca9lrJDTQDVllF62LIxVSx5fuYL6LiZg== + version "2.2.1" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.2.1.tgz#374e31645d58cb18a07b3ecd8e9dede4deb2cccd" + integrity sha512-DxZZbyMAM9GWEzXL+BMZROWz9oo6A9EilwwOMET2UVu2uZTqMWS5S69KVtuVKaRjCUpcrOXRalet86/OpG4kqw== "@types/promptly@^3.0.1": version "3.0.1" @@ -1709,10 +1736,10 @@ dependencies: string-width "*" -"@types/table@^5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@types/table/-/table-5.0.0.tgz#67c3821138eb41d538c3d9286771c6cdeeac7172" - integrity sha512-fQLtGLZXor264zUPWI95WNDsZ3QV43/c0lJpR/h1hhLJumXRmHNsrvBfEzW2YMhb0EWCsn4U6h82IgwsajAuTA== +"@types/table@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@types/table/-/table-6.0.0.tgz#c3e8f1e0d80525036a7655fd650409e0230f1ead" + integrity sha512-RSmRiYetRzpcZcgNo4x6C1VSsPGBHCGGDO7Rbnz5esVLbGONxBP1CUcn8JhAkVzUVLO+AY8yOSkb27jvfauLyg== "@types/uuid@^8.3.0": version "8.3.0" @@ -1755,13 +1782,13 @@ resolved "https://registry.yarnpkg.com/@types/yarnpkg__lockfile/-/yarnpkg__lockfile-1.1.4.tgz#445251eb00bd9c1e751f82c7c6bf4f714edfd464" integrity sha512-/emrKCfQMQmFCqRqqBJ0JueHBT06jBRM3e8OgnvDUcvuExONujIk2hFA5dNsN9Nt41ljGVDdChvCydATZ+KOZw== -"@typescript-eslint/eslint-plugin@^4.15.0": - version "4.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.15.0.tgz#13a5a07cf30d0d5781e43480aa2a8d38d308b084" - integrity sha512-DJgdGZW+8CFUTz5C/dnn4ONcUm2h2T0itWD85Ob5/V27Ndie8hUoX5HKyGssvR8sUMkAIlUc/AMK67Lqa3kBIQ== +"@typescript-eslint/eslint-plugin@^4.15.1": + version "4.15.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.15.2.tgz#981b26b4076c62a5a55873fbef3fe98f83360c61" + integrity sha512-uiQQeu9tWl3f1+oK0yoAv9lt/KXO24iafxgQTkIYO/kitruILGx3uH+QtIAHqxFV+yIsdnJH+alel9KuE3J15Q== dependencies: - "@typescript-eslint/experimental-utils" "4.15.0" - "@typescript-eslint/scope-manager" "4.15.0" + "@typescript-eslint/experimental-utils" "4.15.2" + "@typescript-eslint/scope-manager" "4.15.2" debug "^4.1.1" functional-red-black-tree "^1.0.1" lodash "^4.17.15" @@ -1769,60 +1796,60 @@ semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/experimental-utils@4.15.0", "@typescript-eslint/experimental-utils@^4.0.1": - version "4.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.15.0.tgz#b87c36410a9b23f637689427be85007a2ec1a9c6" - integrity sha512-V4vaDWvxA2zgesg4KPgEGiomWEBpJXvY4ZX34Y3qxK8LUm5I87L+qGIOTd9tHZOARXNRt9pLbblSKiYBlGMawg== +"@typescript-eslint/experimental-utils@4.15.2", "@typescript-eslint/experimental-utils@^4.0.1": + version "4.15.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.15.2.tgz#5efd12355bd5b535e1831282e6cf465b9a71cf36" + integrity sha512-Fxoshw8+R5X3/Vmqwsjc8nRO/7iTysRtDqx6rlfLZ7HbT8TZhPeQqbPjTyk2RheH3L8afumecTQnUc9EeXxohQ== dependencies: "@types/json-schema" "^7.0.3" - "@typescript-eslint/scope-manager" "4.15.0" - "@typescript-eslint/types" "4.15.0" - "@typescript-eslint/typescript-estree" "4.15.0" + "@typescript-eslint/scope-manager" "4.15.2" + "@typescript-eslint/types" "4.15.2" + "@typescript-eslint/typescript-estree" "4.15.2" eslint-scope "^5.0.0" eslint-utils "^2.0.0" -"@typescript-eslint/parser@^4.14.2": - version "4.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.15.0.tgz#8df94365b4b7161f9e8514fe28aef19954810b6b" - integrity sha512-L6Dtbq8Bc7g2aZwnIBETpmUa9XDKCMzKVwAArnGp5Mn7PRNFjf3mUzq8UeBjL3K8t311hvevnyqXAMSmxO8Gpg== +"@typescript-eslint/parser@^4.15.1": + version "4.15.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.15.2.tgz#c804474321ef76a3955aec03664808f0d6e7872e" + integrity sha512-SHeF8xbsC6z2FKXsaTb1tBCf0QZsjJ94H6Bo51Y1aVEZ4XAefaw5ZAilMoDPlGghe+qtq7XdTiDlGfVTOmvA+Q== dependencies: - "@typescript-eslint/scope-manager" "4.15.0" - "@typescript-eslint/types" "4.15.0" - "@typescript-eslint/typescript-estree" "4.15.0" + "@typescript-eslint/scope-manager" "4.15.2" + "@typescript-eslint/types" "4.15.2" + "@typescript-eslint/typescript-estree" "4.15.2" debug "^4.1.1" -"@typescript-eslint/scope-manager@4.15.0": - version "4.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.15.0.tgz#c42703558ea6daaaba51a9c3a86f2902dbab9432" - integrity sha512-CSNBZnCC2jEA/a+pR9Ljh8Y+5TY5qgbPz7ICEk9WCpSEgT6Pi7H2RIjxfrrbUXvotd6ta+i27sssKEH8Azm75g== +"@typescript-eslint/scope-manager@4.15.2": + version "4.15.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.15.2.tgz#5725bda656995960ae1d004bfd1cd70320f37f4f" + integrity sha512-Zm0tf/MSKuX6aeJmuXexgdVyxT9/oJJhaCkijv0DvJVT3ui4zY6XYd6iwIo/8GEZGy43cd7w1rFMiCLHbRzAPQ== dependencies: - "@typescript-eslint/types" "4.15.0" - "@typescript-eslint/visitor-keys" "4.15.0" + "@typescript-eslint/types" "4.15.2" + "@typescript-eslint/visitor-keys" "4.15.2" -"@typescript-eslint/types@4.15.0": - version "4.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.15.0.tgz#3011ae1ac3299bb9a5ac56bdd297cccf679d3662" - integrity sha512-su4RHkJhS+iFwyqyXHcS8EGPlUVoC+XREfy5daivjLur9JP8GhvTmDipuRpcujtGC4M+GYhUOJCPDE3rC5NJrg== +"@typescript-eslint/types@4.15.2": + version "4.15.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.15.2.tgz#04acf3a2dc8001a88985291744241e732ef22c60" + integrity sha512-r7lW7HFkAarfUylJ2tKndyO9njwSyoy6cpfDKWPX6/ctZA+QyaYscAHXVAfJqtnY6aaTwDYrOhp+ginlbc7HfQ== -"@typescript-eslint/typescript-estree@4.15.0": - version "4.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.15.0.tgz#402c86a7d2111c1f7a2513022f22a38a395b7f93" - integrity sha512-jG6xTmcNbi6xzZq0SdWh7wQ9cMb2pqXaUp6bUZOMsIlu5aOlxGxgE/t6L/gPybybQGvdguajXGkZKSndZJpksA== +"@typescript-eslint/typescript-estree@4.15.2": + version "4.15.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.15.2.tgz#c2f7a1e94f3428d229d5ecff3ead6581ee9b62fa" + integrity sha512-cGR8C2g5SPtHTQvAymEODeqx90pJHadWsgTtx6GbnTWKqsg7yp6Eaya9nFzUd4KrKhxdYTTFBiYeTPQaz/l8bw== dependencies: - "@typescript-eslint/types" "4.15.0" - "@typescript-eslint/visitor-keys" "4.15.0" + "@typescript-eslint/types" "4.15.2" + "@typescript-eslint/visitor-keys" "4.15.2" debug "^4.1.1" globby "^11.0.1" is-glob "^4.0.1" semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/visitor-keys@4.15.0": - version "4.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.15.0.tgz#2a07768df30c8a5673f1bce406338a07fdec38ca" - integrity sha512-RnDtJwOwFucWFAMjG3ghCG/ikImFJFEg20DI7mn4pHEx3vC48lIAoyjhffvfHmErRDboUPC7p9Z2il4CLb7qxA== +"@typescript-eslint/visitor-keys@4.15.2": + version "4.15.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.15.2.tgz#3d1c7979ce75bf6acf9691109bd0d6b5706192b9" + integrity sha512-TME1VgSb7wTwgENN5KVj4Nqg25hP8DisXxNBojM4Nn31rYaNDIocNm5cmjOFfh42n7NVERxWrDFoETO/76ePyg== dependencies: - "@typescript-eslint/types" "4.15.0" + "@typescript-eslint/types" "4.15.2" eslint-visitor-keys "^2.0.0" "@yarnpkg/lockfile@^1.1.0": @@ -1932,9 +1959,9 @@ ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4: uri-js "^4.2.2" ajv@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-7.0.4.tgz#827e5f5ae32f5e5c1637db61f253a112229b5e2f" - integrity sha512-xzzzaqgEQfmuhbhAoqjJ8T/1okb6gAzXn/eQRNpAN1AEUoHJTNF9xCDRTtf/s3SKldtZfa+RJeTs+BQq+eZ/sw== + version "7.1.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-7.1.1.tgz#1e6b37a454021fa9941713f38b952fc1c8d32a84" + integrity sha512-ga/aqDYnUy/o7vbsRTFhhTsNeXiYb5JWDIcRIeZfwRNCefwjNTVYCGdGSUrEmiu3yDK3vFvNbgJxvrQW4JXrYQ== dependencies: fast-deep-equal "^3.1.1" json-schema-traverse "^1.0.0" @@ -2137,14 +2164,14 @@ array-ify@^1.0.0: integrity sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4= array-includes@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.2.tgz#a8db03e0b88c8c6aeddc49cb132f9bcab4ebf9c8" - integrity sha512-w2GspexNQpx+PutG3QpT437/BenZBj0M/MZGn5mzv/MofYqo0xmRHzn4lFsoDlWJ+THYsGJmFlW68WlDFx7VRw== + version "3.1.3" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.3.tgz#c7f619b382ad2afaf5326cddfdc0afc61af7690a" + integrity sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A== dependencies: - call-bind "^1.0.0" + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" - get-intrinsic "^1.0.1" + es-abstract "^1.18.0-next.2" + get-intrinsic "^1.1.1" is-string "^1.0.5" array-union@^1.0.2: @@ -2258,10 +2285,10 @@ aws-sdk-mock@^5.1.0: sinon "^9.0.1" traverse "^0.6.6" -aws-sdk@^2.596.0, aws-sdk@^2.637.0, aws-sdk@^2.830.0: - version "2.841.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.841.0.tgz#a29314f6696bdf02a4c952b6f7c791042fa61eaa" - integrity sha512-pMgFr0B4WFIZEKc6EPAcyrvafkqoE1JwU6DJuE4UmT2ntat87DnbWUzFRP2HB4HuJvP1F7KNmElMz8p8j8bkNg== +aws-sdk@^2.596.0, aws-sdk@^2.637.0, aws-sdk@^2.848.0: + version "2.852.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.852.0.tgz#f6639bf8e70258e77f7e8ce454c403cdcb23ecd9" + integrity sha512-Oj3ZWsHly5o+TiayKDbuWZSq5SkqoNZF/wLxmqolP3tlQ55zfGme1s/5J7vcuVIz4+PlISMlgE5kAhxhjAieyg== dependencies: buffer "4.9.2" events "1.1.1" @@ -2441,6 +2468,17 @@ browser-process-hrtime@^1.0.0: resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== +browserslist@^4.14.5: + version "4.16.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.3.tgz#340aa46940d7db878748567c5dea24a48ddf3717" + integrity sha512-vIyhWmIkULaq04Gt93txdh+j02yX/JzlyhLYbV3YQCn/zvES3JnY7TifHHvvr1w5hTDluNKMkV05cs4vy8Q7sw== + dependencies: + caniuse-lite "^1.0.30001181" + colorette "^1.2.1" + electron-to-chromium "^1.3.649" + escalade "^3.1.1" + node-releases "^1.1.70" + bs-logger@0.x: version "0.2.6" resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" @@ -2646,6 +2684,11 @@ camelcase@^6.0.0, camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== +caniuse-lite@^1.0.30001181: + version "1.0.30001192" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001192.tgz#b848ebc0ab230cf313d194a4775a30155d50ae40" + integrity sha512-63OrUnwJj5T1rUmoyqYTdRWBqFFxZFlyZnRRjDR8NSUQFB6A+j/uBORU/SyJ5WzDLg4SPiZH40hQCBNdZ/jmAw== + capture-exit@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" @@ -2826,10 +2869,10 @@ code-point-at@^1.0.0: resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= -codemaker@^1.20.1: - version "1.20.1" - resolved "https://registry.yarnpkg.com/codemaker/-/codemaker-1.20.1.tgz#5ac56a9c3f2b290ebd57538b340ba64fc908cdc1" - integrity sha512-AhDdoC0jhSw8VhbHBH2WN8CDp8PZKnO0YMAlZXG9BRLJnu4ztOQkYuB8BWipNydRHS3Zj1LQX4lPtTQkJN4vWg== +codemaker@^1.21.0, codemaker@^1.22.0: + version "1.22.0" + resolved "https://registry.yarnpkg.com/codemaker/-/codemaker-1.22.0.tgz#8bad330e985f3507963815ea3662f084170c5e72" + integrity sha512-0c77XXwpCOR9SrlKqNtaBhvzi0zo2tYuiUMuTISq+qclyunpDzgkKH27SxyGG1Ju6gNtv10bME7A/8zlWstICw== dependencies: camelcase "^6.2.0" decamelize "^5.0.0" @@ -2877,6 +2920,11 @@ color-support@^1.1.0: resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== +colorette@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" + integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w== + colors@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" @@ -2979,9 +3027,9 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= constructs@^3.2.0: - version "3.3.18" - resolved "https://registry.yarnpkg.com/constructs/-/constructs-3.3.18.tgz#10d416b7eadff449a82c076698305ab98cbce70f" - integrity sha512-aoFeZLctXI17AYApAc9Ilg/kTY3m7e29VbxeGnNiKvrsj9+UyC1setKozYPxtxr1dVC0UTUrOEYdP1rIAVGffQ== + version "3.3.43" + resolved "https://registry.yarnpkg.com/constructs/-/constructs-3.3.43.tgz#0fb826212fa25ad783b70332504e1c4f9a61dc5a" + integrity sha512-4Fi9XuoYAPkVrimpU/fo3SOUxB3cS/WjP77DGeJl1o0vsYsggqeBHRLK6GxRG7vpmnOhiyDlBIazJkMuR6YWuQ== contains-path@^0.1.0: version "0.1.0" @@ -3158,28 +3206,28 @@ conventional-commits-filter@^2.0.2, conventional-commits-filter@^2.0.7: modify-values "^1.0.0" conventional-commits-parser@^3.0.3, conventional-commits-parser@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-3.2.0.tgz#9e261b139ca4b7b29bcebbc54460da36894004ca" - integrity sha512-XmJiXPxsF0JhAKyfA2Nn+rZwYKJ60nanlbSWwwkGwLQFbugsc0gv1rzc7VbbUWAzJfR1qR87/pNgv9NgmxtBMQ== + version "3.2.1" + resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-3.2.1.tgz#ba44f0b3b6588da2ee9fd8da508ebff50d116ce2" + integrity sha512-OG9kQtmMZBJD/32NEw5IhN5+HnBqVjy03eC+I71I0oQRFA5rOgA4OtPOYG7mz1GkCfCNxn3gKIX8EiHJYuf1cA== dependencies: JSONStream "^1.0.4" is-text-path "^1.0.1" lodash "^4.17.15" meow "^8.0.0" - split2 "^2.0.0" + split2 "^3.0.0" through2 "^4.0.0" trim-off-newlines "^1.0.0" -conventional-recommended-bump@6.0.11: - version "6.0.11" - resolved "https://registry.yarnpkg.com/conventional-recommended-bump/-/conventional-recommended-bump-6.0.11.tgz#fcc39acb51d1946b63fc478737d1e52712f36356" - integrity sha512-FciYBMwzwwBZ1K4NS8c57rsOfSc51e1V6UVSNIosrjH+A6xXkyiA4ELwoWyRKdMhJ+m3O6ru9ZJ7F2QFjjYJdQ== +conventional-recommended-bump@6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/conventional-recommended-bump/-/conventional-recommended-bump-6.1.0.tgz#cfa623285d1de554012f2ffde70d9c8a22231f55" + integrity sha512-uiApbSiNGM/kkdL9GTOLAqC4hbptObFo4wW2QRyHsKciGAfQuLU1ShZ1BIVI/+K2BE/W1AWYQMCXAsv4dyKPaw== dependencies: concat-stream "^2.0.0" conventional-changelog-preset-loader "^2.3.4" conventional-commits-filter "^2.0.7" conventional-commits-parser "^3.2.0" - git-raw-commits "2.0.0" + git-raw-commits "^2.0.8" git-semver-tags "^4.1.1" meow "^8.0.0" q "^1.5.1" @@ -3551,10 +3599,10 @@ degenerator@^2.2.0: escodegen "^1.8.1" esprima "^4.0.0" -delay@4.4.1: - version "4.4.1" - resolved "https://registry.yarnpkg.com/delay/-/delay-4.4.1.tgz#6e02d02946a1b6ab98b39262ced965acba2ac4d1" - integrity sha512-aL3AhqtfhOlT/3ai6sWXeqwnw63ATNpnUiN4HL7x9q+My5QtHlO3OIkasmug9LKzpheLdmUKGRKnYXYAS7FQkQ== +delay@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" + integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== delayed-stream@~1.0.0: version "1.0.0" @@ -3734,6 +3782,11 @@ ejs@^2.5.2: resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba" integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA== +electron-to-chromium@^1.3.649: + version "1.3.674" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.674.tgz#d97feefdf1d9411fdc9d56d17e1b9d67b818e710" + integrity sha512-DBmEKRVYLZAoQSW+AmLcTF5Bpwhk4RUkobtzXVDlfPPYIlbsH3Jfg3QbBjAfFcRARzMIo4YiMhp3N+RnMuo1Eg== + emittery@^0.7.1: version "0.7.2" resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82" @@ -3797,7 +3850,7 @@ error-ex@^1.2.0, error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.18.0-next.1: +es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2: version "1.18.0-next.2" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.2.tgz#088101a55f0541f595e7e057199e27ddc8f3a5c2" integrity sha512-Ih4ZMFHEtZupnUh6497zEL4y2+w8+1ljnCyaTa+adcoafI1GOvMwFlDjBLfWR7y9VLfrjRJe9ocuHY1PSR9jjw== @@ -3862,10 +3915,10 @@ es6-promisify@^5.0.0: dependencies: es6-promise "^4.0.3" -esbuild@^0.8.42: - version "0.8.44" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.8.44.tgz#2a74f48fe20579081c9d8fe99be6fb8d2848c887" - integrity sha512-m9yyBZMgWuAB7e7tA2g9L4PovoLa5Xb73+Yg9uBBR2w3Fe4P9/nxqj/HLrw1k/rjdjF1eX1kNJRytboqOtRCCQ== +esbuild@^0.8.50: + version "0.8.52" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.8.52.tgz#6dabf11c517af449a96d66da20dfc204ee7b5294" + integrity sha512-b5KzFweLLXoXQwdC/e2+Z80c8uo2M5MgP7yQEEebkFw6In4T9CvYcNoM2ElvJt8ByO04zAZUV0fZkXmXoi2s9A== escalade@^3.1.1: version "3.1.1" @@ -3912,10 +3965,10 @@ eslint-import-resolver-node@^0.3.4: debug "^2.6.9" resolve "^1.13.1" -eslint-import-resolver-typescript@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.3.0.tgz#0870988098bc6c6419c87705e6b42bee89425445" - integrity sha512-MHSXvmj5e0SGOOBhBbt7C+fWj1bJbtSYFAD85Xeg8nvUtuooTod2HQb8bfhE9f5QyyNxEfgzqOYFCvmdDIcCuw== +eslint-import-resolver-typescript@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.4.0.tgz#ec1e7063ebe807f0362a7320543aaed6fe1100e1" + integrity sha512-useJKURidCcldRLCNKWemr1fFQL1SzB3G4a0li6lFGvlc5xGe1hY343bvG07cbpCzPuM/lK19FIJB3XGFSkplA== dependencies: debug "^4.1.1" glob "^7.1.6" @@ -3958,10 +4011,10 @@ eslint-plugin-import@^2.22.1: resolve "^1.17.0" tsconfig-paths "^3.9.0" -eslint-plugin-jest@^24.1.3: - version "24.1.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.1.3.tgz#fa3db864f06c5623ff43485ca6c0e8fc5fe8ba0c" - integrity sha512-dNGGjzuEzCE3d5EPZQ/QGtmlMotqnYWD/QpCZ1UuZlrMAdhG5rldh0N0haCvhGnUkSeuORS5VNROwF9Hrgn3Lg== +eslint-plugin-jest@^24.1.5: + version "24.1.5" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.1.5.tgz#1e866a9f0deac587d0a3d5d7cefe99815a580de2" + integrity sha512-FIP3lwC8EzEG+rOs1y96cOJmMVpdFNreoDJv29B5vIupVssRi8zrSY3QadogT0K3h1Y8TMxJ6ZSAzYUmFCp2hg== dependencies: "@typescript-eslint/experimental-utils" "^4.0.1" @@ -3977,7 +4030,7 @@ eslint-plugin-node@^11.1.0: resolve "^1.10.1" semver "^6.1.0" -eslint-plugin-promise@^4.2.1: +eslint-plugin-promise@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.3.1.tgz#61485df2a359e03149fdafc0a68b0e030ad2ac45" integrity sha512-bY2sGqyptzFBDLh/GMbAxfdJC+b0f23ME63FOE4+Jao0oZ3E1LEwFtWJX/1pGMJLiTtrSSern2CRM/g+dfc0eQ== @@ -4017,12 +4070,12 @@ eslint-visitor-keys@^2.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8" integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== -eslint@^7.19.0: - version "7.19.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.19.0.tgz#6719621b196b5fad72e43387981314e5d0dc3f41" - integrity sha512-CGlMgJY56JZ9ZSYhJuhow61lMPPjUzWmChFya71Z/jilVos7mR/jPgaEfVGgMBY5DshbKdG8Ezb8FDCHcoMEMg== +eslint@^7.20.0: + version "7.20.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.20.0.tgz#db07c4ca4eda2e2316e7aa57ac7fc91ec550bdc7" + integrity sha512-qGi0CTcOGP2OtCQBgWZlQjcTuP0XkIpYFj25XtRTQSHC+umNnp7UMshr2G8SLsRFYDdAPFeHOsiteadmMH02Yw== dependencies: - "@babel/code-frame" "^7.0.0" + "@babel/code-frame" "7.12.11" "@eslint/eslintrc" "^0.3.0" ajv "^6.10.0" chalk "^4.0.0" @@ -4034,7 +4087,7 @@ eslint@^7.19.0: eslint-utils "^2.1.0" eslint-visitor-keys "^2.0.0" espree "^7.3.1" - esquery "^1.2.0" + esquery "^1.4.0" esutils "^2.0.2" file-entry-cache "^6.0.0" functional-red-black-tree "^1.0.1" @@ -4079,7 +4132,7 @@ esprima@^4.0.0, esprima@^4.0.1: resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.2.0: +esquery@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== @@ -4244,10 +4297,10 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= -fast-check@^2.12.1: - version "2.12.1" - resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-2.12.1.tgz#457d13e36952dd0d660cf781d942a43c067a47ca" - integrity sha512-zXCxkvFVlVWbBVky+TPaD1H+g6SC4R7IQYZ5gcxU3lUKHyrOFiLXtWy+xHVDmm9bv+3NJbSzOmeVvhgpnjR7Sw== +fast-check@^2.13.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-2.13.0.tgz#92a50a6a39b58760d4b0b52b12f98f28a9f020f6" + integrity sha512-IOfzKm/SCA+jpUEgAfqAuxHYPmgtmpnnwljQmYPRGrqYczcTKApXKHza/SNxFxYkecWfZilYa0DJdBvqz1bcSw== dependencies: pure-rand "^4.1.1" @@ -4308,9 +4361,9 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= fastq@^1.6.0: - version "1.10.1" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.10.1.tgz#8b8f2ac8bf3632d67afcd65dac248d5fdc45385e" - integrity sha512-AWuv6Ery3pM+dY7LYS8YIaCiQvUaos9OB1RyNgaOWnaX+Tik7Onvcsf8x8c+YtDeT0maYLniBip2hox5KtEXXA== + version "1.11.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.11.0.tgz#bb9fb955a07130a918eb63c1f5161cc32a5d0858" + integrity sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g== dependencies: reusify "^1.0.4" @@ -4341,9 +4394,9 @@ figures@^3.1.0: escape-string-regexp "^1.0.5" file-entry-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.0.tgz#7921a89c391c6d93efec2169ac6bf300c527ea0a" - integrity sha512-fqoO76jZ3ZnYrXLDRxBR1YvOvc0k844kcOg40bgsPrE25LAb/PDqTY+ho64Xh2c8ZXgIKldchCFHczG2UVRcWA== + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== dependencies: flat-cache "^3.0.4" @@ -4634,7 +4687,7 @@ genfun@^5.0.0: resolved "https://registry.yarnpkg.com/genfun/-/genfun-5.0.0.tgz#9dd9710a06900a5c4a5bf57aca5da4e52fe76537" integrity sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA== -gensync@^1.0.0-beta.1: +gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== @@ -4644,7 +4697,7 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.0.1, get-intrinsic@^1.0.2, get-intrinsic@^1.1.0: +get-intrinsic@^1.0.1, get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== @@ -4870,7 +4923,7 @@ globby@^9.2.0: pify "^4.0.1" slash "^2.0.0" -graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.4, graceful-fs@^4.2.5: +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.4, graceful-fs@^4.2.6: version "4.2.6" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== @@ -4881,9 +4934,9 @@ growly@^1.3.0: integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= handlebars@^4.7.6: - version "4.7.6" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.6.tgz#d4c05c1baf90e9945f77aa68a7a219aa4a7df74e" - integrity sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA== + version "4.7.7" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" + integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== dependencies: minimist "^1.2.5" neo-async "^2.6.0" @@ -5313,7 +5366,7 @@ is-ci@^2.0.0: dependencies: ci-info "^2.0.0" -is-core-module@^2.1.0: +is-core-module@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a" integrity sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ== @@ -5539,13 +5592,13 @@ is-text-path@^1.0.1: text-extensions "^1.0.0" is-typed-array@^1.1.3: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.4.tgz#1f66f34a283a3c94a4335434661ca53fff801120" - integrity sha512-ILaRgn4zaSrVNXNGtON6iFNotXW3hAPF3+0fB1usg2jFlWqo5fEDdmJkz0zBfoi7Dgskr8Khi2xZ8cXqZEfXNA== + version "1.1.5" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.5.tgz#f32e6e096455e329eb7b423862456aa213f0eb4e" + integrity sha512-S+GRDgJlR3PyEbsX/Fobd9cqpZBuvUS+8asRqYDMLCb2qMzt1oz5m5oxQCxOgUDxiWsOVNi4yaF+/uvdlHlYug== dependencies: available-typed-arrays "^1.0.2" - call-bind "^1.0.0" - es-abstract "^1.18.0-next.1" + call-bind "^1.0.2" + es-abstract "^1.18.0-next.2" foreach "^2.0.5" has-symbols "^1.0.1" @@ -6179,65 +6232,65 @@ jsesc@^2.5.1: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== -jsii-diff@^1.20.1: - version "1.20.1" - resolved "https://registry.yarnpkg.com/jsii-diff/-/jsii-diff-1.20.1.tgz#ea7a6ded96b896287a1f36198d235bf1eb7420a4" - integrity sha512-5k6W9Xi0zhX9yHYhHBkhKrRo76ydcVKSRGJCaS7t4qtZut8mAsEXU9dleUhxhILXMhJ59XBEw8nMgp71wzNKdQ== +jsii-diff@^1.21.0: + version "1.22.0" + resolved "https://registry.yarnpkg.com/jsii-diff/-/jsii-diff-1.22.0.tgz#f306d4e6947e21e7960bb9605493ad719f4bda27" + integrity sha512-0MfVd+MXXyfrGR7RuGpZhChDQu74yrpj0QC3dRchgd9GDeorLbe+vUmYr188hHVSJU6F2KeXBEdKn2I+p60jIQ== dependencies: - "@jsii/spec" "^1.20.1" + "@jsii/spec" "^1.22.0" fs-extra "^9.1.0" - jsii-reflect "^1.20.1" + jsii-reflect "^1.22.0" log4js "^6.3.0" - typescript "~3.9.7" + typescript "~3.9.9" yargs "^16.2.0" -jsii-pacmak@^1.20.1: - version "1.20.1" - resolved "https://registry.yarnpkg.com/jsii-pacmak/-/jsii-pacmak-1.20.1.tgz#9f5b1a816b560afa577d42fb573b643921fc1edb" - integrity sha512-mNViMzB+wqDKowjmcOMa4qLmkhZ4GAs2wOjNiHcWTN9ZtdyjG5BoRgJrKChlRYQfjRuE+EmqiHpZyH8IzPo8SQ== +jsii-pacmak@^1.21.0: + version "1.22.0" + resolved "https://registry.yarnpkg.com/jsii-pacmak/-/jsii-pacmak-1.22.0.tgz#1c60a66d3d19ac3b09e1ce3601f4695c36e07492" + integrity sha512-s1X++lvN8oPTE2e8XI4qADBZ7MUXjfzw0Bjr2at5XwhW8QaSSnGe2KHuqjj0JTUhdlVsRar9JlWXKDwMraYBww== dependencies: - "@jsii/spec" "^1.20.1" + "@jsii/spec" "^1.22.0" clone "^2.1.2" - codemaker "^1.20.1" + codemaker "^1.22.0" commonmark "^0.29.3" escape-string-regexp "^4.0.0" fs-extra "^9.1.0" - jsii-reflect "^1.20.1" - jsii-rosetta "^1.20.1" + jsii-reflect "^1.22.0" + jsii-rosetta "^1.22.0" semver "^7.3.4" spdx-license-list "^6.4.0" xmlbuilder "^15.1.1" yargs "^16.2.0" -jsii-reflect@^1.20.1: - version "1.20.1" - resolved "https://registry.yarnpkg.com/jsii-reflect/-/jsii-reflect-1.20.1.tgz#25b3146e923e728202c8fcac1c611eb261fa3a6c" - integrity sha512-TkimkYu25H6YtfKRz7D/ZXbquXbhylS60TxgSPZC85iItCpZMwTlbIdvnpBKasx8e7MtJO6xYoAHEYHRhs8djQ== +jsii-reflect@^1.21.0, jsii-reflect@^1.22.0: + version "1.22.0" + resolved "https://registry.yarnpkg.com/jsii-reflect/-/jsii-reflect-1.22.0.tgz#1cbc696fea903e14ba97a162b221d69e542d57ee" + integrity sha512-EsPL/mXNaUsBeF50IHOMizX3R2B8mcKCBEhxvfptXpgMT6BzssNUK4v9MC7tY3c3fR8CNs2dr+I2Bqdgs0ogOg== dependencies: - "@jsii/spec" "^1.20.1" + "@jsii/spec" "^1.22.0" colors "^1.4.0" fs-extra "^9.1.0" - oo-ascii-tree "^1.20.1" + oo-ascii-tree "^1.22.0" yargs "^16.2.0" -jsii-rosetta@^1.20.1: - version "1.20.1" - resolved "https://registry.yarnpkg.com/jsii-rosetta/-/jsii-rosetta-1.20.1.tgz#ecba41af1862405a37ea974d09932f403a073c6c" - integrity sha512-3F01+B8zahWD4GhTMWPzlaGhuGvdPdYyIdhIe1bkHCYJuL1ttcf+ulCxVeF4qkBAxB2+/cfHBvEMHfSMoYCISA== +jsii-rosetta@^1.21.0, jsii-rosetta@^1.22.0: + version "1.22.0" + resolved "https://registry.yarnpkg.com/jsii-rosetta/-/jsii-rosetta-1.22.0.tgz#ed4ed8d30c52844e9f2f1a576033d0027e1bf58d" + integrity sha512-d+f5vwbaAQCQI+EJLnfSTGYsTWYeUdzb3NJvRLEKiR0y31DWVuMU7y7c+IKrXjNY8vOvphWjPgZ21ECV6/r54g== dependencies: - "@jsii/spec" "^1.20.1" + "@jsii/spec" "^1.22.0" commonmark "^0.29.3" fs-extra "^9.1.0" - typescript "~3.9.7" + typescript "~3.9.9" xmldom "^0.4.0" yargs "^16.2.0" -jsii@^1.20.1: - version "1.20.1" - resolved "https://registry.yarnpkg.com/jsii/-/jsii-1.20.1.tgz#e41b32a3968e781aec1348099e441c3fa5509639" - integrity sha512-e4LS9u4QhhsqDN/JlK7JHDhYXhg3fiw+nq1xU5EeAtHQJvmM7CXTXhgDT9FjtnkWbnnjCOd0hgLcE8yIIZ8Lkw== +jsii@^1.21.0: + version "1.22.0" + resolved "https://registry.yarnpkg.com/jsii/-/jsii-1.22.0.tgz#13cfa9c32b5598e56f080f7a93aff2ee19934b4e" + integrity sha512-iBYlf/wSCsaohM14JSpN3NsIrfsqWi0FXrKvW0tU52z+ED/ZyNQWJKT/JfGuO+EAd5GpjPmpK7r4R9ZGGQW0rQ== dependencies: - "@jsii/spec" "^1.20.1" + "@jsii/spec" "^1.22.0" case "^1.6.3" colors "^1.4.0" deep-equal "^2.0.5" @@ -6247,7 +6300,7 @@ jsii@^1.20.1: semver-intersect "^1.4.0" sort-json "^2.0.0" spdx-license-list "^6.4.0" - typescript "~3.9.7" + typescript "~3.9.9" yargs "^16.2.0" json-diff@^0.5.4: @@ -6361,7 +6414,7 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -jszip@*, jszip@^3.5.0: +jszip@*, jszip@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.6.0.tgz#839b72812e3f97819cc13ac4134ffced95dd6af9" integrity sha512-jgnQoG9LKnWO3mnVNBnfhkh0QknICd1FGSrXcgrl67zioyJ4wgx25o9ZqwNtrROSflGBCGYnJfjrIyRIby1OoQ== @@ -6656,10 +6709,10 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@4.x, lodash@^4.17.12, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.2.1: - version "4.17.20" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" - integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== +lodash@4.x, lodash@^4.17.12, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.2.1: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== log-driver@^1.2.7: version "1.2.7" @@ -6952,17 +7005,17 @@ micromatch@^4.0.2: braces "^3.0.1" picomatch "^2.0.5" -mime-db@1.45.0: - version "1.45.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.45.0.tgz#cceeda21ccd7c3a745eba2decd55d4b73e7879ea" - integrity sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w== +mime-db@1.46.0: + version "1.46.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.46.0.tgz#6267748a7f799594de3cbc8cde91def349661cee" + integrity sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ== mime-types@^2.1.12, mime-types@~2.1.19: - version "2.1.28" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.28.tgz#1160c4757eab2c5363888e005273ecf79d2a0ecd" - integrity sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ== + version "2.1.29" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.29.tgz#1d4ab77da64b91f5f72489df29236563754bb1b2" + integrity sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ== dependencies: - mime-db "1.45.0" + mime-db "1.46.0" mimic-fn@^1.0.0: version "1.2.0" @@ -7192,9 +7245,9 @@ nice-try@^1.0.4: integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== nise@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/nise/-/nise-4.0.4.tgz#d73dea3e5731e6561992b8f570be9e363c4512dd" - integrity sha512-bTTRUNlemx6deJa+ZyoCUTRvH3liK5+N6VQZ4NIw90AgDXY6iPnsqplNFf6STcj+ePk0H/xqxnP75Lr0J0Fq3A== + version "4.1.0" + resolved "https://registry.yarnpkg.com/nise/-/nise-4.1.0.tgz#8fb75a26e90b99202fa1e63f448f58efbcdedaf6" + integrity sha512-eQMEmGN/8arp0xsvGoQ+B1qvSkR73B1nWSCh7nOt5neMCtwcQVYQGdzQMhcNscktTsWB54xnlSQFzOAPJD8nXA== dependencies: "@sinonjs/commons" "^1.7.0" "@sinonjs/fake-timers" "^6.0.0" @@ -7203,9 +7256,9 @@ nise@^4.0.4: path-to-regexp "^1.7.0" nock@^13.0.7: - version "13.0.7" - resolved "https://registry.yarnpkg.com/nock/-/nock-13.0.7.tgz#9bc718c66bd0862dfa14601a9ba678a406127910" - integrity sha512-WBz73VYIjdbO6BwmXODRQLtn7B5tldA9pNpWJe5QTtTEscQlY5KXU4srnGzBOK2fWakkXj69gfTnXGzmrsaRWw== + version "13.0.8" + resolved "https://registry.yarnpkg.com/nock/-/nock-13.0.8.tgz#1375f878b4ce8c3f9cf9e4b06acf670543a99e3e" + integrity sha512-LVv0buXfE52eT3CTkNBDcfTelWQGxaX3AJPVRzOFxLMR76EnFvbqaPXuDRikXYoOOmc4ie1uBUHw/G/sc6gVOg== dependencies: debug "^4.1.0" json-stringify-safe "^5.0.1" @@ -7272,6 +7325,11 @@ node-preload@^0.2.1: dependencies: process-on-spawn "^1.0.0" +node-releases@^1.1.70: + version "1.1.71" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.71.tgz#cb1334b179896b1c89ecfdd4b725fb7bbdfc7dbb" + integrity sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg== + nodeunit@^0.11.3: version "0.11.3" resolved "https://registry.yarnpkg.com/nodeunit/-/nodeunit-0.11.3.tgz#313afae26cd11b407b731ff774b8e35e5d6f9568" @@ -7507,11 +7565,11 @@ object-inspect@^1.9.0: integrity sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw== object-is@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.4.tgz#63d6c83c00a43f4cbc9434eb9757c8a5b8565068" - integrity sha512-1ZvAZ4wlF7IyPVOcE1Omikt7UpaFlOQq0HlSti+ZvDH3UiD2brwGMwDbyV43jao2bKJ+4+WdPJHSd7kgzKYVqg== + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== dependencies: - call-bind "^1.0.0" + call-bind "^1.0.2" define-properties "^1.1.3" object-keys@^1.0.12, object-keys@^1.1.1: @@ -7537,13 +7595,13 @@ object.assign@^4.1.2: object-keys "^1.1.1" object.getownpropertydescriptors@^2.0.3: - version "2.1.1" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.1.tgz#0dfda8d108074d9c563e80490c883b6661091544" - integrity sha512-6DtXgZ/lIZ9hqx4GtZETobXLR/ZLaa0aqV0kzbn80Rf8Z2e/XFnhA0I7p07N2wH8bBBltr2xQPi6sbKWAY2Eng== + version "2.1.2" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz#1bd63aeacf0d5d2d2f31b5e393b03a7c601a23f7" + integrity sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ== dependencies: - call-bind "^1.0.0" + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" + es-abstract "^1.18.0-next.2" object.pick@^1.3.0: version "1.3.0" @@ -7553,13 +7611,13 @@ object.pick@^1.3.0: isobject "^3.0.1" object.values@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.2.tgz#7a2015e06fcb0f546bd652486ce8583a4731c731" - integrity sha512-MYC0jvJopr8EK6dPBiO8Nb9mvjdypOachO5REGk6MXzujbBrAisKo3HmdEI6kZDL6fC31Mwee/5YbtMebixeag== + version "1.1.3" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.3.tgz#eaa8b1e17589f02f698db093f7c62ee1699742ee" + integrity sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw== dependencies: - call-bind "^1.0.0" + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" + es-abstract "^1.18.0-next.2" has "^1.0.3" octokit-pagination-methods@^1.1.0: @@ -7588,10 +7646,10 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" -oo-ascii-tree@^1.20.1: - version "1.20.1" - resolved "https://registry.yarnpkg.com/oo-ascii-tree/-/oo-ascii-tree-1.20.1.tgz#685317abe5000398374eede506cba57dcba6092a" - integrity sha512-imKW5pdztAEqtl5pmNTM9Rva53XOcuY91YL9jTuwFGJpBGqT6pnyxXJOFdwc5TRaQr9+GdpWTpByGRvgNPbdvQ== +oo-ascii-tree@^1.22.0: + version "1.22.0" + resolved "https://registry.yarnpkg.com/oo-ascii-tree/-/oo-ascii-tree-1.22.0.tgz#d7ee24b55502ba51e48ff54596db3a851f0086c3" + integrity sha512-IoB8ybGGYKZ2hu4TQts9+AB2T4VHu3Bf896mOt3m1XzV9Xo5fZvO29rFn7Xfy3SaVzm6IjbaXGcxUcCHhz7hRQ== opener@^1.5.1: version "1.5.2" @@ -8624,11 +8682,11 @@ resolve-url@^0.2.1: integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= resolve@^1.1.6, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.11.1, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.18.1: - version "1.19.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c" - integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg== + version "1.20.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" + integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== dependencies: - is-core-module "^2.1.0" + is-core-module "^2.2.0" path-parse "^1.0.6" restore-cursor@^2.0.0: @@ -8698,9 +8756,9 @@ run-queue@^1.0.0, run-queue@^1.0.3: aproba "^1.1.1" rxjs@^6.4.0: - version "6.6.3" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.3.tgz#8ca84635c4daa900c0d3967a6ee7ac60271ee552" - integrity sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ== + version "6.6.6" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.6.tgz#14d8417aa5a07c5e633995b525e1e3c0dec03b70" + integrity sha512-/oTwee4N4iWzAMAL9xdGKjkEHmIwupR3oXbQjCKywF1BeFohswF3vZdogbmEF6pZkOsXTzWkrZszrWpQTByYVg== dependencies: tslib "^1.9.0" @@ -8770,6 +8828,11 @@ semver-intersect@^1.4.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== +semver@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + semver@7.x, semver@^7.1.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4: version "7.3.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" @@ -9159,16 +9222,16 @@ stack-utils@^2.0.2: dependencies: escape-string-regexp "^2.0.0" -standard-version@^9.1.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/standard-version/-/standard-version-9.1.0.tgz#07589469324d967ffe665fa86ef612949a858a80" - integrity sha512-EJcbKUGKBuHjiDSUL5XjPhT1KGVM+UCvv/ti70fHnJwJyJqTSJWl0mWj/Wj0WwsoskyvKWURESzBsZmCCMUZzg== +standard-version@^9.1.1: + version "9.1.1" + resolved "https://registry.yarnpkg.com/standard-version/-/standard-version-9.1.1.tgz#7561df6351b075a44544ce3d3ebcffcb9582ba5a" + integrity sha512-PF9JnRauBwH7DAkmefYu1mB2Kx0MVG13udqDTFmDUiogbyikBAHBdMrVuauxtAb2YIkyZ3FMYCNv0hqUKMOPww== dependencies: chalk "^2.4.2" conventional-changelog "3.1.24" conventional-changelog-config-spec "2.1.0" conventional-changelog-conventionalcommits "4.5.0" - conventional-recommended-bump "6.0.11" + conventional-recommended-bump "6.1.0" detect-indent "^6.0.0" detect-newline "^3.1.0" dotgitignore "^2.1.0" @@ -9178,7 +9241,7 @@ standard-version@^9.1.0: git-semver-tags "^4.0.0" semver "^7.1.1" stringify-package "^1.0.1" - yargs "^15.3.1" + yargs "^16.0.0" static-extend@^0.1.1: version "0.1.2" @@ -9274,19 +9337,19 @@ string.prototype.repeat@^0.2.0: integrity sha1-q6Nt4I3O5qWjN9SbLqHaGyj8Ds8= string.prototype.trimend@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz#a22bd53cca5c7cf44d7c9d5c732118873d6cd18b" - integrity sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw== + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" + integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== dependencies: - call-bind "^1.0.0" + call-bind "^1.0.2" define-properties "^1.1.3" string.prototype.trimstart@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz#9b4cb590e123bb36564401d59824298de50fd5aa" - integrity sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg== + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" + integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== dependencies: - call-bind "^1.0.0" + call-bind "^1.0.2" define-properties "^1.1.3" string_decoder@^1.1.1: @@ -9787,10 +9850,10 @@ trivial-deferred@^1.0.1: resolved "https://registry.yarnpkg.com/trivial-deferred/-/trivial-deferred-1.0.1.tgz#376d4d29d951d6368a6f7a0ae85c2f4d5e0658f3" integrity sha1-N21NKdlR1jaKb3oK6FwvTV4GWPM= -ts-jest@^26.5.0: - version "26.5.1" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.5.1.tgz#4d53ee4481552f57c1624f0bd3425c8b17996150" - integrity sha512-G7Rmo3OJMvlqE79amJX8VJKDiRcd7/r61wh9fnvvG8cAjhA9edklGw/dCxRSQmfZ/z8NDums5srSVgwZos1qfg== +ts-jest@^26.5.1: + version "26.5.2" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.5.2.tgz#5281d6b44c2f94f71205728a389edc3d7995b0c4" + integrity sha512-bwyJ2zJieSugf7RB+o8fgkMeoMVMM2KPDE0UklRLuACxjwJsOrZNo6chrcScmK33YavPSwhARffy8dZx5LJdUQ== dependencies: "@types/jest" "26.x" bs-logger "0.x" @@ -9932,10 +9995,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript-json-schema@^0.48.0: - version "0.48.0" - resolved "https://registry.yarnpkg.com/typescript-json-schema/-/typescript-json-schema-0.48.0.tgz#d30e287319a09617e87d10c17f484077412a55e7" - integrity sha512-RDs66ANmjiqcSQ7dAeFIarF0ON6b+dxb5Fl1x53PK0p/QcqEoSN3kHsJTB0lgw+zWz6wdObCzk3jIwik3maK1Q== +typescript-json-schema@^0.49.0: + version "0.49.0" + resolved "https://registry.yarnpkg.com/typescript-json-schema/-/typescript-json-schema-0.49.0.tgz#442f6347ca85fb0d9811f217fb0d6537b68734b3" + integrity sha512-PumZkTmEE3T8TVyoJU6ZCp3K6VCmCb3Ei6fUaRIuDsIzYtmdJc6jV1D0RyBe5sd5mJ1iB6Zckm4KAKbqXs9oDw== dependencies: "@types/json-schema" "^7.0.6" glob "^7.1.6" @@ -9944,15 +10007,15 @@ typescript-json-schema@^0.48.0: typescript "^4.1.3" yargs "^16.2.0" -typescript@^3.3.3, typescript@~3.9.7: +typescript@^3.3.3, typescript@~3.9.9: version "3.9.9" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.9.tgz#e69905c54bc0681d0518bd4d587cc6f2d0b1a674" integrity sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w== typescript@^4.1.3: - version "4.1.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.5.tgz#123a3b214aaff3be32926f0d8f1f6e704eb89a72" - integrity sha512-6OSu9PTIzmn9TCDiovULTnET6BgXtDYL4Gg4szY+cGsc3JP1dQL8qvE8kShTRx1NIw4Q9IBHlwODjkjWEtMUyA== + version "4.2.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.2.tgz#1450f020618f872db0ea17317d16d8da8ddb8c4c" + integrity sha512-tbb+NVrLfnsJy3M59lsDgrzWIflR4d4TIUjz+heUnHZwdF7YsrMTKoRERiIvI2lvBG95dfpLxB21WZhys1bgaQ== typescript@~3.8.3: version "3.8.3" @@ -9965,9 +10028,9 @@ uc.micro@^1.0.1, uc.micro@^1.0.5: integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== uglify-js@^3.1.4: - version "3.12.7" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.12.7.tgz#be4f06142a67bd91ef868b4e111dc241e151bff3" - integrity sha512-SIZhkoh+U/wjW+BHGhVwE9nt8tWJspncloBcFapkpGRwNPqcH8pzX36BXe3TPBjzHWPMUZotpCigak/udWNr1Q== + version "3.12.8" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.12.8.tgz#a82e6e53c9be14f7382de3d068ef1e26e7d4aaf8" + integrity sha512-fvBeuXOsvqjecUtF/l1dwsrrf5y2BCUk9AOJGzGcm6tE7vegku5u/YvqjyDaAGr422PLoLnrxg3EnRvTqsdC1w== uid-number@0.0.6: version "0.0.6" @@ -10485,9 +10548,9 @@ yapool@^1.0.0: integrity sha1-9pPymjFbUNmp2iZGp6ZkXJaYW2o= yargs-parser@20.x, yargs-parser@^20.2.2, yargs-parser@^20.2.3: - version "20.2.4" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" - integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== + version "20.2.6" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.6.tgz#69f920addf61aafc0b8b89002f5d66e28f2d8b20" + integrity sha512-AP1+fQIWSM/sMiET8fyayjx/J+JmTPt2Mr0FkrgqB4todtfa53sOsrSAcIrJRD5XS20bKUwaDIuMkWKCEiQLKA== yargs-parser@^13.0.0, yargs-parser@^13.1.2: version "13.1.2" @@ -10546,7 +10609,7 @@ yargs@^14.2.2: y18n "^4.0.0" yargs-parser "^15.0.1" -yargs@^15.0.2, yargs@^15.3.1, yargs@^15.4.1: +yargs@^15.0.2, yargs@^15.4.1: version "15.4.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== @@ -10563,7 +10626,7 @@ yargs@^15.0.2, yargs@^15.3.1, yargs@^15.4.1: y18n "^4.0.0" yargs-parser "^18.1.2" -yargs@^16.0.3, yargs@^16.2.0: +yargs@^16.0.0, yargs@^16.0.3, yargs@^16.2.0: version "16.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==