diff --git a/.devcontainer.json b/.devcontainer.json new file mode 100644 index 0000000000000..c40157671ce76 --- /dev/null +++ b/.devcontainer.json @@ -0,0 +1,8 @@ +{ + "name": "Dev Container Definition - AWS CDK", + "image": "jsii/superchain", + "postCreateCommand": "yarn build --skip-test --no-bail --skip-prereqs --skip-compat", + "extensions": [ + "dbaeumer.vscode-eslint@2.1.5" + ] +} \ No newline at end of file diff --git a/.github/workflows/issue-label-assign.yml b/.github/workflows/issue-label-assign.yml index 67e411ca6f887..c4fee2baac7d5 100644 --- a/.github/workflows/issue-label-assign.yml +++ b/.github/workflows/issue-label-assign.yml @@ -13,7 +13,7 @@ jobs: title-or-body: 'title' parameters: > [ - {"keywords":["[cli]","[command line]"],"labels":["package/tools"],"assignees":["shivlaks"]}, + {"keywords":["[cli]","[command line]"],"labels":["package/tools"],"assignees":["rix0rrr"]}, {"keywords":["[@aws-cdk/alexa-ask]","[alexa-ask]","[alexa ask]"],"labels":["@aws-cdk/alexa-ask"],"assignees":["MrArnoldPalmer"]}, {"keywords":["[@aws-cdk/app-delivery]","[app-delivery]","[app delivery]"],"labels":["@aws-cdk/app-delivery"],"assignees":["skinny85"]}, {"keywords":["[@aws-cdk/assert]","[assert]"],"labels":["@aws-cdk/assert"],"assignees":["nija-at"]}, diff --git a/.github/workflows/yarn-upgrade.yml b/.github/workflows/yarn-upgrade.yml new file mode 100644 index 0000000000000..214f38b73f988 --- /dev/null +++ b/.github/workflows/yarn-upgrade.yml @@ -0,0 +1,76 @@ +name: Yarn Upgrade + +on: + schedule: + # Every wednesday at 13:37 UTC + - cron: 37 13 * * 3 + workflow_dispatch: {} + +jobs: + upgrade: + name: Yarn Upgrade + runs-on: ubuntu-latest + steps: + + - name: Check Out + uses: actions/checkout@v2 + + - name: Set up Node + uses: actions/setup-node@v2.1.0 + with: + node-version: 10 + + - name: Locate Yarn cache + id: yarn-cache + run: echo "::set-output name=dir::$(yarn cache dir)" + + - name: Restore Yarn cache + uses: actions/cache@v2 + with: + path: ${{ steps.yarn-cache.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: |- + ${{ runner.os }}-yarn- + - name: Install Tools + run: |- + npm -g install lerna npm-check-updates@^9.0.0 + - name: List Mono-Repo Packages + id: list-packages + # These need to be ignored from the `ncu` runs! + run: |- + echo -n "::set-output name=list::" + node -p "$(lerna ls --all --json 2>/dev/null).map(item => item.name).join(',')" + - name: Run "ncu -u" + # We special-case @types/node because we want to stay on the current major (minimum supported node release) + # We special-case @types/fs-extra because the current major (9.x) is broken with @types/node >= 10 + # We special-case aws-sdk because of breaking changes with TS interface exports in recent minor versions - https://github.com/aws/aws-sdk-js/issues/3453 + # We special-case typescript because it's not semantically versionned + run: |- + # Upgrade dependencies at repository root + ncu --upgrade --filter=@types/node,@types/fs-extra --target=minor + ncu --upgrade --filter=typescript --target=patch + ncu --upgrade --reject=@types/node,@types/fs-extra,typescript --target=minor + # Upgrade all the packages + lerna exec --parallel ncu -- --upgrade --filter=@types/node,@types/fs-extra --target=minor + lerna exec --parallel ncu -- --upgrade --filter=typescript --target=patch + lerna exec --parallel ncu -- --upgrade --reject='@types/node,@types/fs-extra,typescript,aws-sdk,${{ steps.list-packages.outputs.list }}' --target=minor + # This will create a brand new `yarn.lock` file (this is more efficient than `yarn install && yarn upgrade`) + - name: Run "yarn install --force" + run: yarn install --force + + - name: Make Pull Request + uses: peter-evans/create-pull-request@v2 + with: + # Git commit details + branch: automation/yarn-upgrade + commit-message: |- + chore: npm-check-updates && yarn upgrade + Ran npm-check-updates and yarn upgrade to keep the `yarn.lock` file up-to-date. + # Pull Request details + 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 + team-reviewers: aws-cdk-team + # Privileged token so automated PR validation happens + token: ${{ secrets.AUTOMATION_GITHUB_TOKEN }} diff --git a/.mergify.yml b/.mergify.yml index 9be52c560afde..ee41466232847 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -6,7 +6,7 @@ pull_request_rules: label: add: [ contribution/core ] conditions: - - author~=^(eladb|RomainMuller|garnaat|nija-at|shivlaks|skinny85|rix0rrr|NGL321|Jerry-AWS|SomayaB|MrArnoldPalmer|NetaNir|iliapolo|njlynch|ericzbeard|ccfife|fulghum|pkandasamy91|SoManyHs|uttarasridhar|BryanPan342|comcalvi|kaizen3031593|)$ + - author~=^(eladb|RomainMuller|garnaat|nija-at|shivlaks|skinny85|rix0rrr|NGL321|Jerry-AWS|SomayaB|MrArnoldPalmer|NetaNir|iliapolo|njlynch|ericzbeard|ccfife|fulghum|pkandasamy91|SoManyHs|uttarasridhar)$ - -label~="contribution/core" - name: automatic merge actions: @@ -29,7 +29,6 @@ pull_request_rules: - -approved-reviews-by~=author - "#changes-requested-reviews-by=0" - status-success~=AWS CodeBuild us-east-1 - #- status-success=Semantic Pull Request - status-success=validate-pr - name: automatic merge (2+ approvers) actions: @@ -53,7 +52,6 @@ pull_request_rules: - -approved-reviews-by~=author - "#changes-requested-reviews-by=0" - status-success~=AWS CodeBuild us-east-1 - #- status-success=Semantic Pull Request - status-success=validate-pr - name: automatic merge (no-squash) actions: @@ -78,7 +76,6 @@ pull_request_rules: - -approved-reviews-by~=author - "#changes-requested-reviews-by=0" - status-success~=AWS CodeBuild us-east-1 - #- status-success=Semantic Pull Request - status-success=validate-pr - name: remove stale reviews actions: @@ -121,5 +118,4 @@ pull_request_rules: - "#approved-reviews-by>=1" - "#changes-requested-reviews-by=0" - status-success~=AWS CodeBuild us-east-1 - #- status-success=Semantic Pull Request - status-success=validate-pr diff --git a/README.md b/README.md index c413d0df84cb2..8979eef888e5b 100644 --- a/README.md +++ b/README.md @@ -134,7 +134,7 @@ You may also find help on these community resources: and tag it with `aws-cdk` * Come join the AWS CDK community on [Gitter](https://gitter.im/awslabs/aws-cdk) * Talk in the CDK channel of the [AWS Developers Slack workspace](https://awsdevelopers.slack.com) (invite required) -* Check out the [partitions.io board](https://partitions.io/cdk) +* A community-driven Slack channel is also available, invite at [cdk.dev](https://cdk.dev) ### Roadmap diff --git a/allowed-breaking-changes.txt b/allowed-breaking-changes.txt index dc8b4b8f8c9cd..9217e4ca2e773 100644 --- a/allowed-breaking-changes.txt +++ b/allowed-breaking-changes.txt @@ -35,3 +35,14 @@ removed:@aws-cdk/core.DefaultStackSynthesizer.synthesizeStackArtifacts removed:@aws-cdk/core.LegacyStackSynthesizer.synthesizeStackArtifacts removed:@aws-cdk/core.NestedStackSynthesizer.synthesizeStackArtifacts removed:@aws-cdk/core.IStackSynthesizer.synthesizeStackArtifacts + +# DockerVolumeConfiguration.labels has changed types from string[] to map +# The string[] was actually a latent bug we weren't aware of because we passing volumes through +# to the underlying CFN resource as Lazy.anyValue. +# The change to map caused all these inputs to break. +incompatible-argument:@aws-cdk/aws-ecs.Ec2TaskDefinition. +incompatible-argument:@aws-cdk/aws-ecs.Ec2TaskDefinition.addVolume +incompatible-argument:@aws-cdk/aws-ecs.FargateTaskDefinition. +incompatible-argument:@aws-cdk/aws-ecs.FargateTaskDefinition.addVolume +incompatible-argument:@aws-cdk/aws-ecs.TaskDefinition. +incompatible-argument:@aws-cdk/aws-ecs.TaskDefinition.addVolume \ No newline at end of file diff --git a/package.json b/package.json index 1367e774bff77..330289aef2e5d 100644 --- a/package.json +++ b/package.json @@ -18,9 +18,9 @@ "fs-extra": "^9.0.1", "graceful-fs": "^4.2.4", "jest-junit": "^11.1.0", - "jsii-diff": "^1.11.0", - "jsii-pacmak": "^1.11.0", - "jsii-rosetta": "^1.11.0", + "jsii-diff": "^1.12.0", + "jsii-pacmak": "^1.12.0", + "jsii-rosetta": "^1.12.0", "lerna": "^3.22.1", "standard-version": "^9.0.0", "typescript": "~3.9.7" @@ -61,14 +61,14 @@ "@aws-cdk/cloud-assembly-schema/jsonschema/**", "@aws-cdk/cloud-assembly-schema/semver", "@aws-cdk/cloud-assembly-schema/semver/**", - "@aws-cdk/cloudformation-include/yaml", - "@aws-cdk/cloudformation-include/yaml/**", "@aws-cdk/core/fs-extra", "@aws-cdk/core/fs-extra/**", "@aws-cdk/core/minimatch", "@aws-cdk/core/minimatch/**", "@aws-cdk/cx-api/semver", "@aws-cdk/cx-api/semver/**", + "@aws-cdk/yaml-cfn/yaml", + "@aws-cdk/yaml-cfn/yaml/**", "aws-cdk-lib/case", "aws-cdk-lib/case/**", "aws-cdk-lib/fs-extra", diff --git a/packages/@aws-cdk/app-delivery/package.json b/packages/@aws-cdk/app-delivery/package.json index d08cca8111305..c85209e9eef41 100644 --- a/packages/@aws-cdk/app-delivery/package.json +++ b/packages/@aws-cdk/app-delivery/package.json @@ -58,7 +58,7 @@ "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", - "fast-check": "^1.26.0", + "fast-check": "^2.3.0", "nodeunit": "^0.11.3", "pkglint": "0.0.0" }, diff --git a/packages/@aws-cdk/assert/lib/assertions/have-resource-matchers.ts b/packages/@aws-cdk/assert/lib/assertions/have-resource-matchers.ts index f5edc878f95fb..deb64b769ff16 100644 --- a/packages/@aws-cdk/assert/lib/assertions/have-resource-matchers.ts +++ b/packages/@aws-cdk/assert/lib/assertions/have-resource-matchers.ts @@ -318,6 +318,7 @@ export class Capture { /** * A Capture object that captures a custom type */ + // eslint-disable-next-line @typescript-eslint/no-shadow public static a(validator: TypeValidator): Capture { return new Capture(validator); } @@ -426,4 +427,4 @@ export function matcherFrom(matcher: any): PropertyMatcher { export function annotateMatcher(how: A, matcher: PropertyMatcher): PropertyMatcher { (matcher as any).toJSON = () => how; return matcher; -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/assert/package.json b/packages/@aws-cdk/assert/package.json index e86bfffd47709..3a6e1aab011c1 100644 --- a/packages/@aws-cdk/assert/package.json +++ b/packages/@aws-cdk/assert/package.json @@ -21,11 +21,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.10", + "@types/jest": "^26.0.14", "cdk-build-tools": "0.0.0", "jest": "^26.4.2", "pkglint": "0.0.0", - "ts-jest": "^26.2.0" + "ts-jest": "^26.3.0" }, "dependencies": { "@aws-cdk/cloud-assembly-schema": "0.0.0", diff --git a/packages/@aws-cdk/aws-apigatewayv2/package.json b/packages/@aws-cdk/aws-apigatewayv2/package.json index 5068cb8ede434..945cb89bb4586 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2/package.json @@ -100,6 +100,7 @@ ] }, "stability": "experimental", + "maturity": "experimental", "features": [ { "name": "Higher level constructs for HTTP APIs", diff --git a/packages/@aws-cdk/aws-applicationautoscaling/package.json b/packages/@aws-cdk/aws-applicationautoscaling/package.json index 6874af24e976a..e866816981b40 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/package.json +++ b/packages/@aws-cdk/aws-applicationautoscaling/package.json @@ -67,7 +67,7 @@ "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "fast-check": "^1.26.0", + "fast-check": "^2.3.0", "nodeunit": "^0.11.3", "pkglint": "0.0.0" }, diff --git a/packages/@aws-cdk/aws-applicationinsights/.eslintrc.js b/packages/@aws-cdk/aws-applicationinsights/.eslintrc.js new file mode 100644 index 0000000000000..61dd8dd001f63 --- /dev/null +++ b/packages/@aws-cdk/aws-applicationinsights/.eslintrc.js @@ -0,0 +1,3 @@ +const baseConfig = require('cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-applicationinsights/.gitignore b/packages/@aws-cdk/aws-applicationinsights/.gitignore new file mode 100644 index 0000000000000..62ebc95d75ce6 --- /dev/null +++ b/packages/@aws-cdk/aws-applicationinsights/.gitignore @@ -0,0 +1,19 @@ +*.js +*.js.map +*.d.ts +tsconfig.json +node_modules +*.generated.ts +dist +.jsii + +.LAST_BUILD +.nyc_output +coverage +.nycrc +.LAST_PACKAGE +*.snk +nyc.config.js +!.eslintrc.js +!jest.config.js +junit.xml diff --git a/packages/@aws-cdk/aws-applicationinsights/.npmignore b/packages/@aws-cdk/aws-applicationinsights/.npmignore new file mode 100644 index 0000000000000..7633957caec65 --- /dev/null +++ b/packages/@aws-cdk/aws-applicationinsights/.npmignore @@ -0,0 +1,27 @@ +# Don't include original .ts files when doing `npm pack` +*.ts +!*.d.ts +coverage +.nyc_output +*.tgz + +dist +.LAST_PACKAGE +.LAST_BUILD +!*.js + +# Include .jsii +!.jsii + +*.snk + +*.tsbuildinfo + +tsconfig.json + +.eslintrc.js +jest.config.js + +# exclude cdk artifacts +**/cdk.out +junit.xml diff --git a/packages/@aws-cdk/aws-applicationinsights/LICENSE b/packages/@aws-cdk/aws-applicationinsights/LICENSE new file mode 100644 index 0000000000000..b71ec1688783a --- /dev/null +++ b/packages/@aws-cdk/aws-applicationinsights/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/@aws-cdk/aws-applicationinsights/NOTICE b/packages/@aws-cdk/aws-applicationinsights/NOTICE new file mode 100644 index 0000000000000..bfccac9a7f69c --- /dev/null +++ b/packages/@aws-cdk/aws-applicationinsights/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/aws-applicationinsights/README.md b/packages/@aws-cdk/aws-applicationinsights/README.md new file mode 100644 index 0000000000000..b4e6e05197b26 --- /dev/null +++ b/packages/@aws-cdk/aws-applicationinsights/README.md @@ -0,0 +1,16 @@ +## AWS::ApplicationInsights Construct Library + +--- + +![cfn-resources: Stable](https://img.shields.io/badge/cfn--resources-stable-success.svg?style=for-the-badge) + +> All classes with the `Cfn` prefix in this module ([CFN Resources](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) are always stable and safe to use. + +--- + + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts +import applicationinsights = require('@aws-cdk/aws-applicationinsights'); +``` diff --git a/packages/@aws-cdk/aws-applicationinsights/jest.config.js b/packages/@aws-cdk/aws-applicationinsights/jest.config.js new file mode 100644 index 0000000000000..54e28beb9798b --- /dev/null +++ b/packages/@aws-cdk/aws-applicationinsights/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-applicationinsights/lib/index.ts b/packages/@aws-cdk/aws-applicationinsights/lib/index.ts new file mode 100644 index 0000000000000..2af597d5caeae --- /dev/null +++ b/packages/@aws-cdk/aws-applicationinsights/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::ApplicationInsights CloudFormation Resources: +export * from './applicationinsights.generated'; diff --git a/packages/@aws-cdk/aws-applicationinsights/package.json b/packages/@aws-cdk/aws-applicationinsights/package.json new file mode 100644 index 0000000000000..a4a83155b62a9 --- /dev/null +++ b/packages/@aws-cdk/aws-applicationinsights/package.json @@ -0,0 +1,88 @@ +{ + "name": "@aws-cdk/aws-applicationinsights", + "version": "0.0.0", + "description": "The CDK Construct Library for AWS::ApplicationInsights", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "projectReferences": true, + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.ApplicationInsights", + "packageId": "Amazon.CDK.AWS.ApplicationInsights", + "signAssembly": true, + "assemblyOriginatorKeyFile": "../../key.snk", + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png" + }, + "java": { + "package": "software.amazon.awscdk.services.applicationinsights", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "applicationinsights" + } + }, + "python": { + "distName": "aws-cdk.aws-applicationinsights", + "module": "aws_cdk.aws_applicationinsights" + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-applicationinsights" + }, + "homepage": "https://github.com/aws/aws-cdk", + "scripts": { + "build": "cdk-build", + "watch": "cdk-watch", + "lint": "cdk-lint", + "test": "cdk-test", + "integ": "cdk-integ", + "pkglint": "pkglint -f", + "package": "cdk-package", + "awslint": "cdk-awslint", + "cfn2ts": "cfn2ts", + "build+test+package": "npm run build+test && npm run package", + "build+test": "npm run build && npm test", + "compat": "cdk-compat" + }, + "cdk-build": { + "cloudformation": "AWS::ApplicationInsights", + "jest": true + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::ApplicationInsights", + "aws-applicationinsights" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/assert": "0.0.0", + "cdk-build-tools": "0.0.0", + "cfn2ts": "0.0.0", + "pkglint": "0.0.0" + }, + "dependencies": { + "@aws-cdk/core": "0.0.0" + }, + "peerDependencies": { + "@aws-cdk/core": "0.0.0" + }, + "engines": { + "node": ">= 10.13.0 <13 || >=13.7.0" + }, + "stability": "experimental", + "maturity": "cfn-only", + "awscdkio": { + "announce": false + } +} diff --git a/packages/@aws-cdk/aws-applicationinsights/test/applicationinsights.test.ts b/packages/@aws-cdk/aws-applicationinsights/test/applicationinsights.test.ts new file mode 100644 index 0000000000000..e394ef336bfb4 --- /dev/null +++ b/packages/@aws-cdk/aws-applicationinsights/test/applicationinsights.test.ts @@ -0,0 +1,6 @@ +import '@aws-cdk/assert/jest'; +import {} from '../lib'; + +test('No tests are specified for this package', () => { + expect(true).toBe(true); +}); diff --git a/packages/@aws-cdk/aws-appsync/package.json b/packages/@aws-cdk/aws-appsync/package.json index 32291bb17258f..87f8c66b231e7 100644 --- a/packages/@aws-cdk/aws-appsync/package.json +++ b/packages/@aws-cdk/aws-appsync/package.json @@ -68,7 +68,7 @@ "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "pkglint": "0.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-autoscaling-common/package.json b/packages/@aws-cdk/aws-autoscaling-common/package.json index 2a08a5bbb531c..8c423257b0285 100644 --- a/packages/@aws-cdk/aws-autoscaling-common/package.json +++ b/packages/@aws-cdk/aws-autoscaling-common/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": "^1.26.0", + "fast-check": "^2.3.0", "nodeunit": "^0.11.3", "pkglint": "0.0.0" }, diff --git a/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json b/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json index 4e85a8e5091de..a2013f4b2d29a 100644 --- a/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json +++ b/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json @@ -64,7 +64,7 @@ "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "pkglint": "0.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-batch/package.json b/packages/@aws-cdk/aws-batch/package.json index 3eee48ef2d1ca..ad24cb4da40c8 100644 --- a/packages/@aws-cdk/aws-batch/package.json +++ b/packages/@aws-cdk/aws-batch/package.json @@ -68,7 +68,7 @@ "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "pkglint": "0.0.0" }, "dependencies": { 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 377aff5edcb80..648a622e525ce 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 @@ -28,16 +28,16 @@ "license": "Apache-2.0", "devDependencies": { "aws-sdk": "^2.596.0", - "aws-sdk-mock": "^5.0.0", - "eslint": "^6.8.0", - "eslint-config-standard": "^14.1.0", - "eslint-plugin-import": "^2.19.1", - "eslint-plugin-node": "^10.0.0", + "aws-sdk-mock": "^5.1.0", + "eslint": "^7.9.0", + "eslint-config-standard": "^14.1.1", + "eslint-plugin-import": "^2.22.0", + "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^4.2.1", "eslint-plugin-standard": "^4.0.1", - "jest": "^25.5.0", + "jest": "^26.4.2", "lambda-tester": "^3.6.0", - "nock": "^11.7.0", - "ts-jest": "^25.3.1" + "nock": "^13.0.4", + "ts-jest": "^26.3.0" } } diff --git a/packages/@aws-cdk/aws-cloudformation/package.json b/packages/@aws-cdk/aws-cloudformation/package.json index 86384aab85a60..4eabd9c3a914b 100644 --- a/packages/@aws-cdk/aws-cloudformation/package.json +++ b/packages/@aws-cdk/aws-cloudformation/package.json @@ -1,7 +1,7 @@ { "name": "@aws-cdk/aws-cloudformation", "version": "0.0.0", - "description": "CDK Constructs for AWS CloudFormation", + "description": "The CDK Construct Library for AWS::CloudFormation", "main": "lib/index.js", "types": "lib/index.d.ts", "jsii": { @@ -69,7 +69,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.61", + "@types/aws-lambda": "^8.10.62", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudfront-origins/package.json b/packages/@aws-cdk/aws-cloudfront-origins/package.json index 39da8785c4949..851ffefd9e715 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/package.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/package.json @@ -1,7 +1,7 @@ { "name": "@aws-cdk/aws-cloudfront-origins", "version": "0.0.0", - "description": "CDK Constructs for AWS CloudFront Origins", + "description": "The CDK Construct Library for AWS CloudFront Origins", "main": "lib/index.js", "types": "lib/index.d.ts", "jsii": { diff --git a/packages/@aws-cdk/aws-cloudfront/package.json b/packages/@aws-cdk/aws-cloudfront/package.json index f1a90c70944ba..f1853646cda47 100644 --- a/packages/@aws-cdk/aws-cloudfront/package.json +++ b/packages/@aws-cdk/aws-cloudfront/package.json @@ -1,7 +1,7 @@ { "name": "@aws-cdk/aws-cloudfront", "version": "0.0.0", - "description": "CDK Constructs for AWS CloudFront", + "description": "The CDK Construct Library for AWS::CloudFront", "main": "lib/index.js", "types": "lib/index.d.ts", "jsii": { @@ -95,6 +95,7 @@ "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", + "maturity": "experimental", "features": [ { "name": "Higher level constructs for Distribution", diff --git a/packages/@aws-cdk/aws-cloudtrail/package.json b/packages/@aws-cdk/aws-cloudtrail/package.json index be0a1486e125a..773aedf8a1c9a 100644 --- a/packages/@aws-cdk/aws-cloudtrail/package.json +++ b/packages/@aws-cdk/aws-cloudtrail/package.json @@ -1,7 +1,7 @@ { "name": "@aws-cdk/aws-cloudtrail", "version": "0.0.0", - "description": "CDK Constructs for AWS CloudTrail", + "description": "The CDK Construct Library for AWS::CloudTrail", "main": "lib/index.js", "types": "lib/index.d.ts", "jsii": { @@ -70,7 +70,7 @@ "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "colors": "^1.4.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "pkglint": "0.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-cloudwatch-actions/package.json b/packages/@aws-cdk/aws-cloudwatch-actions/package.json index d3c33a5a5e83d..b399039dafee7 100644 --- a/packages/@aws-cdk/aws-cloudwatch-actions/package.json +++ b/packages/@aws-cdk/aws-cloudwatch-actions/package.json @@ -64,7 +64,7 @@ "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "pkglint": "0.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-cloudwatch/lib/alarm.ts b/packages/@aws-cdk/aws-cloudwatch/lib/alarm.ts index d1ebea096629e..a159a97f36cbe 100644 --- a/packages/@aws-cdk/aws-cloudwatch/lib/alarm.ts +++ b/packages/@aws-cdk/aws-cloudwatch/lib/alarm.ts @@ -69,7 +69,7 @@ const OPERATOR_SYMBOLS: {[key: string]: string} = { GreaterThanOrEqualToThreshold: '>=', GreaterThanThreshold: '>', LessThanThreshold: '<', - LessThanOrEqualToThreshold: '>=', + LessThanOrEqualToThreshold: '<=', }; /** diff --git a/packages/@aws-cdk/aws-cloudwatch/package.json b/packages/@aws-cdk/aws-cloudwatch/package.json index 522d45c2c65f6..ecf3d2229f8a6 100644 --- a/packages/@aws-cdk/aws-cloudwatch/package.json +++ b/packages/@aws-cdk/aws-cloudwatch/package.json @@ -1,7 +1,7 @@ { "name": "@aws-cdk/aws-cloudwatch", "version": "0.0.0", - "description": "CDK Constructs for AWS CloudWatch", + "description": "The CDK Construct Library for AWS::CloudWatch", "main": "lib/index.js", "types": "lib/index.d.ts", "jsii": { diff --git a/packages/@aws-cdk/aws-codebuild/lib/project.ts b/packages/@aws-cdk/aws-codebuild/lib/project.ts index a18149a1d3209..4c1ec9ca6b752 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/project.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/project.ts @@ -751,7 +751,7 @@ export class Project extends ProjectBase { artifacts: artifactsConfig.artifactsProperty, serviceRole: this.role.roleArn, environment: this.renderEnvironment(props.environment, environmentVariables), - fileSystemLocations: this.renderFileSystemLocations(), + fileSystemLocations: Lazy.anyValue({ produce: () => this.renderFileSystemLocations() }), // lazy, because we have a setter for it in setEncryptionKey encryptionKey: Lazy.stringValue({ produce: () => this._encryptionKey && this._encryptionKey.keyArn }), badgeEnabled: props.badge, diff --git a/packages/@aws-cdk/aws-codebuild/package.json b/packages/@aws-cdk/aws-codebuild/package.json index 5dcdb021dff7c..edb147d12b59a 100644 --- a/packages/@aws-cdk/aws-codebuild/package.json +++ b/packages/@aws-cdk/aws-codebuild/package.json @@ -1,7 +1,7 @@ { "name": "@aws-cdk/aws-codebuild", "version": "0.0.0", - "description": "CDK Constructs for AWS CodeBuild", + "description": "The CDK Construct Library for AWS::CodeBuild", "main": "lib/index.js", "types": "lib/index.d.ts", "jsii": { diff --git a/packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts b/packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts index a3450446606d2..8a5a9decfc1e2 100644 --- a/packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts +++ b/packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts @@ -1036,12 +1036,6 @@ export = { buildSpec: codebuild.BuildSpec.fromObject({ version: '0.2', }), - fileSystemLocations: [codebuild.FileSystemLocation.efs({ - identifier: 'myidentifier2', - location: 'myclodation.mydnsroot.com:/loc', - mountPoint: '/media', - mountOptions: 'opts', - })], }); project.addFileSystemLocation(codebuild.FileSystemLocation.efs({ identifier: 'myidentifier3', @@ -1052,13 +1046,6 @@ export = { expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { 'FileSystemLocations': [ - { - 'Identifier': 'myidentifier2', - 'MountPoint': '/media', - 'MountOptions': 'opts', - 'Location': 'myclodation.mydnsroot.com:/loc', - 'Type': 'EFS', - }, { 'Identifier': 'myidentifier3', 'MountPoint': '/media', diff --git a/packages/@aws-cdk/aws-codecommit/package.json b/packages/@aws-cdk/aws-codecommit/package.json index 98ee6418e8c12..1b83f89ecef25 100644 --- a/packages/@aws-cdk/aws-codecommit/package.json +++ b/packages/@aws-cdk/aws-codecommit/package.json @@ -1,7 +1,7 @@ { "name": "@aws-cdk/aws-codecommit", "version": "0.0.0", - "description": "CDK Constructs for AWS CodeCommit", + "description": "The CDK Construct Library for AWS::CodeCommit", "main": "lib/index.js", "types": "lib/index.d.ts", "jsii": { diff --git a/packages/@aws-cdk/aws-codedeploy/lib/lambda/deployment-group.ts b/packages/@aws-cdk/aws-codedeploy/lib/lambda/deployment-group.ts index 074667136417f..c3cc9ba0fab15 100644 --- a/packages/@aws-cdk/aws-codedeploy/lib/lambda/deployment-group.ts +++ b/packages/@aws-cdk/aws-codedeploy/lib/lambda/deployment-group.ts @@ -158,7 +158,7 @@ export class LambdaDeploymentGroup extends cdk.Resource implements ILambdaDeploy assumedBy: new iam.ServicePrincipal('codedeploy.amazonaws.com'), }); - this.role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSCodeDeployRoleForLambda')); + this.role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSCodeDeployRoleForLambdaLimited')); this.deploymentConfig = props.deploymentConfig || LambdaDeploymentConfig.CANARY_10PERCENT_5MINUTES; const resource = new CfnDeploymentGroup(this, 'Resource', { diff --git a/packages/@aws-cdk/aws-codedeploy/test/lambda/integ.deployment-group.expected.json b/packages/@aws-cdk/aws-codedeploy/test/lambda/integ.deployment-group.expected.json index c8c928c92f1a5..734b7109ad8a1 100644 --- a/packages/@aws-cdk/aws-codedeploy/test/lambda/integ.deployment-group.expected.json +++ b/packages/@aws-cdk/aws-codedeploy/test/lambda/integ.deployment-group.expected.json @@ -468,7 +468,7 @@ { "Ref": "AWS::Partition" }, - ":iam::aws:policy/service-role/AWSCodeDeployRoleForLambda" + ":iam::aws:policy/service-role/AWSCodeDeployRoleForLambdaLimited" ] ] } diff --git a/packages/@aws-cdk/aws-codedeploy/test/lambda/test.deployment-group.ts b/packages/@aws-cdk/aws-codedeploy/test/lambda/test.deployment-group.ts index 7d5824f047f31..267cdc193a602 100644 --- a/packages/@aws-cdk/aws-codedeploy/test/lambda/test.deployment-group.ts +++ b/packages/@aws-cdk/aws-codedeploy/test/lambda/test.deployment-group.ts @@ -101,7 +101,7 @@ export = { [ 'arn:', { Ref: 'AWS::Partition' }, - ':iam::aws:policy/service-role/AWSCodeDeployRoleForLambda', + ':iam::aws:policy/service-role/AWSCodeDeployRoleForLambdaLimited', ], ], }, @@ -160,7 +160,7 @@ export = { [ 'arn:', { Ref: 'AWS::Partition' }, - ':iam::aws:policy/service-role/AWSCodeDeployRoleForLambda', + ':iam::aws:policy/service-role/AWSCodeDeployRoleForLambdaLimited', ], ], }, diff --git a/packages/@aws-cdk/aws-codegurureviewer/.eslintrc.js b/packages/@aws-cdk/aws-codegurureviewer/.eslintrc.js new file mode 100644 index 0000000000000..61dd8dd001f63 --- /dev/null +++ b/packages/@aws-cdk/aws-codegurureviewer/.eslintrc.js @@ -0,0 +1,3 @@ +const baseConfig = require('cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codegurureviewer/.gitignore b/packages/@aws-cdk/aws-codegurureviewer/.gitignore new file mode 100644 index 0000000000000..62ebc95d75ce6 --- /dev/null +++ b/packages/@aws-cdk/aws-codegurureviewer/.gitignore @@ -0,0 +1,19 @@ +*.js +*.js.map +*.d.ts +tsconfig.json +node_modules +*.generated.ts +dist +.jsii + +.LAST_BUILD +.nyc_output +coverage +.nycrc +.LAST_PACKAGE +*.snk +nyc.config.js +!.eslintrc.js +!jest.config.js +junit.xml diff --git a/packages/@aws-cdk/aws-codegurureviewer/.npmignore b/packages/@aws-cdk/aws-codegurureviewer/.npmignore new file mode 100644 index 0000000000000..72b7fcab0a22a --- /dev/null +++ b/packages/@aws-cdk/aws-codegurureviewer/.npmignore @@ -0,0 +1,26 @@ +# Don't include original .ts files when doing `npm pack` +*.ts +!*.d.ts +coverage +.nyc_output +*.tgz + +dist +.LAST_PACKAGE +.LAST_BUILD +!*.js + +# Include .jsii +!.jsii + +*.snk + +*.tsbuildinfo + +tsconfig.json + +.eslintrc.js +jest.config.js +# exclude cdk artifacts +**/cdk.out +junit.xml diff --git a/packages/@aws-cdk/aws-codegurureviewer/LICENSE b/packages/@aws-cdk/aws-codegurureviewer/LICENSE new file mode 100644 index 0000000000000..b71ec1688783a --- /dev/null +++ b/packages/@aws-cdk/aws-codegurureviewer/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/@aws-cdk/aws-codegurureviewer/NOTICE b/packages/@aws-cdk/aws-codegurureviewer/NOTICE new file mode 100644 index 0000000000000..bfccac9a7f69c --- /dev/null +++ b/packages/@aws-cdk/aws-codegurureviewer/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/aws-codegurureviewer/README.md b/packages/@aws-cdk/aws-codegurureviewer/README.md new file mode 100644 index 0000000000000..cd8ce1a29a9cc --- /dev/null +++ b/packages/@aws-cdk/aws-codegurureviewer/README.md @@ -0,0 +1,16 @@ +## AWS::CodeGuruReviewer Construct Library + +--- + +![cfn-resources: Stable](https://img.shields.io/badge/cfn--resources-stable-success.svg?style=for-the-badge) + +> All classes with the `Cfn` prefix in this module ([CFN Resources](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) are always stable and safe to use. + +--- + + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts +import codegurureviewer = require('@aws-cdk/aws-codegurureviewer'); +``` diff --git a/packages/@aws-cdk/aws-codegurureviewer/jest.config.js b/packages/@aws-cdk/aws-codegurureviewer/jest.config.js new file mode 100644 index 0000000000000..54e28beb9798b --- /dev/null +++ b/packages/@aws-cdk/aws-codegurureviewer/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-codegurureviewer/lib/index.ts b/packages/@aws-cdk/aws-codegurureviewer/lib/index.ts new file mode 100644 index 0000000000000..6b307ac407c24 --- /dev/null +++ b/packages/@aws-cdk/aws-codegurureviewer/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::CodeGuruReviewer CloudFormation Resources: +export * from './codegurureviewer.generated'; diff --git a/packages/@aws-cdk/aws-codegurureviewer/package.json b/packages/@aws-cdk/aws-codegurureviewer/package.json new file mode 100644 index 0000000000000..637e03e8f98ec --- /dev/null +++ b/packages/@aws-cdk/aws-codegurureviewer/package.json @@ -0,0 +1,88 @@ +{ + "name": "@aws-cdk/aws-codegurureviewer", + "version": "0.0.0", + "description": "The CDK Construct Library for AWS::CodeGuruReviewer", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "projectReferences": true, + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.CodeGuruReviewer", + "packageId": "Amazon.CDK.AWS.CodeGuruReviewer", + "signAssembly": true, + "assemblyOriginatorKeyFile": "../../key.snk", + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png" + }, + "java": { + "package": "software.amazon.awscdk.services.codegurureviewer", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "codegurureviewer" + } + }, + "python": { + "distName": "aws-cdk.aws-codegurureviewer", + "module": "aws_cdk.aws_codegurureviewer" + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-codegurureviewer" + }, + "homepage": "https://github.com/aws/aws-cdk", + "scripts": { + "build": "cdk-build", + "watch": "cdk-watch", + "lint": "cdk-lint", + "test": "cdk-test", + "integ": "cdk-integ", + "pkglint": "pkglint -f", + "package": "cdk-package", + "awslint": "cdk-awslint", + "cfn2ts": "cfn2ts", + "build+test+package": "npm run build+test && npm run package", + "build+test": "npm run build && npm test", + "compat": "cdk-compat" + }, + "cdk-build": { + "cloudformation": "AWS::CodeGuruReviewer", + "jest": true + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::CodeGuruReviewer", + "aws-codegurureviewer" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/assert": "0.0.0", + "cdk-build-tools": "0.0.0", + "cfn2ts": "0.0.0", + "pkglint": "0.0.0" + }, + "dependencies": { + "@aws-cdk/core": "0.0.0" + }, + "peerDependencies": { + "@aws-cdk/core": "0.0.0" + }, + "engines": { + "node": ">= 10.13.0 <13 || >=13.7.0" + }, + "stability": "experimental", + "maturity": "cfn-only", + "awscdkio": { + "announce": false + } +} diff --git a/packages/@aws-cdk/aws-codegurureviewer/test/codegurureviewer.test.ts b/packages/@aws-cdk/aws-codegurureviewer/test/codegurureviewer.test.ts new file mode 100644 index 0000000000000..e394ef336bfb4 --- /dev/null +++ b/packages/@aws-cdk/aws-codegurureviewer/test/codegurureviewer.test.ts @@ -0,0 +1,6 @@ +import '@aws-cdk/assert/jest'; +import {} from '../lib'; + +test('No tests are specified for this package', () => { + expect(true).toBe(true); +}); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/README.md b/packages/@aws-cdk/aws-codepipeline-actions/README.md index 27860da603548..39874e001cb4b 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/README.md +++ b/packages/@aws-cdk/aws-codepipeline-actions/README.md @@ -68,9 +68,13 @@ If you want to use a GitHub repository as the source, you must create: * A [GitHub Access Token](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line), with scopes **repo** and **admin:repo_hook**. -* A [Secrets Manager PlainText Secret](https://docs.aws.amazon.com/secretsmanager/latest/userguide/manage_create-basic-secret.html) - with the value of the **GitHub Access Token**. Pick whatever name you want - (for example `my-github-token`) and pass it as the argument of `oauthToken`. +* A [Secrets Manager Secret](https://docs.aws.amazon.com/secretsmanager/latest/userguide/manage_create-basic-secret.html) + with the value of the **GitHub Access Token**. Pick whatever name you want (for example `my-github-token`). + This token can be stored either as Plaintext or as a Secret key/value. + If you stored the token as Plaintext, + set `cdk.SecretValue.secretsManager('my-github-token')` as the value of `oauthToken`. + If you stored it as a Secret key/value, + you must set `cdk.SecretValue.secretsManager('my-github-token', { jsonField : 'my-github-token' })` as the value of `oauthToken`. To use GitHub as the source of a CodePipeline: diff --git a/packages/@aws-cdk/aws-codepipeline-actions/package.json b/packages/@aws-cdk/aws-codepipeline-actions/package.json index eacc0661163b4..e95142fed69b5 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/package.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/package.json @@ -65,7 +65,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-cloudtrail": "0.0.0", - "@types/lodash": "^4.14.160", + "@types/lodash": "^4.14.161", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts b/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts index 6f751998af367..f43a42238745b 100644 --- a/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts +++ b/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts @@ -150,7 +150,7 @@ abstract class PipelineBase extends Resource implements IPipeline { * const pipeline = new Pipeline(this, 'Pipeline'); * * // add a stage - * const sourceStage = pipeline.addStage({ name: 'Source' }); + * const sourceStage = pipeline.addStage({ stageName: 'Source' }); * * // add a source action to the stage * sourceStage.addAction(new codepipeline_actions.CodeCommitSourceAction({ diff --git a/packages/@aws-cdk/aws-cognito/README.md b/packages/@aws-cdk/aws-cognito/README.md index 8efbc0447324d..4a2b87840ecbb 100644 --- a/packages/@aws-cdk/aws-cognito/README.md +++ b/packages/@aws-cdk/aws-cognito/README.md @@ -472,6 +472,7 @@ pool.addClient('app-client', { }, scopes: [ OAuthScope.OPENID ], callbackUrls: [ 'https://my-app-domain.com/welcome' ], + logoutUrls: [ 'https://my-app-domain.com/signin' ], } }); ``` diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts index 4913153552fcb..b799eb2035fa1 100644 --- a/packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts @@ -56,6 +56,12 @@ export interface OAuthSettings { */ readonly callbackUrls?: string[]; + /** + * List of allowed logout URLs for the identity providers. + * @default - no logout URLs + */ + readonly logoutUrls?: string[]; + /** * OAuth scopes that are allowed with this client. * @see https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-app-idp-settings.html @@ -315,6 +321,7 @@ export class UserPoolClient extends Resource implements IUserPoolClient { allowedOAuthFlows: props.disableOAuth ? undefined : this.configureOAuthFlows(), allowedOAuthScopes: props.disableOAuth ? undefined : this.configureOAuthScopes(props.oAuth), callbackUrLs: callbackUrls && callbackUrls.length > 0 ? callbackUrls : undefined, + logoutUrLs: props.oAuth?.logoutUrls, allowedOAuthFlowsUserPoolClient: !props.disableOAuth, preventUserExistenceErrors: this.configurePreventUserExistenceErrors(props.preventUserExistenceErrors), supportedIdentityProviders: this.configureIdentityProviders(props), diff --git a/packages/@aws-cdk/aws-cognito/package.json b/packages/@aws-cdk/aws-cognito/package.json index 0affaf0812b44..68fc9bdcf835c 100644 --- a/packages/@aws-cdk/aws-cognito/package.json +++ b/packages/@aws-cdk/aws-cognito/package.json @@ -69,7 +69,7 @@ "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "nodeunit": "^0.11.3", "pkglint": "0.0.0" }, @@ -103,6 +103,7 @@ ] }, "stability": "experimental", + "maturity": "developer-preview", "features": [ { "name": "Higher level constructs for User Pools", diff --git a/packages/@aws-cdk/aws-cognito/test/user-pool-client.test.ts b/packages/@aws-cdk/aws-cognito/test/user-pool-client.test.ts index 349bf72e1b6a3..8266b73e61fbb 100644 --- a/packages/@aws-cdk/aws-cognito/test/user-pool-client.test.ts +++ b/packages/@aws-cdk/aws-cognito/test/user-pool-client.test.ts @@ -201,6 +201,21 @@ describe('User Pool Client', () => { })).not.toThrow(); }); + test('logoutUrls can be set', () => { + const stack = new Stack(); + const pool = new UserPool(stack, 'Pool'); + + pool.addClient('Client', { + oAuth: { + logoutUrls: ['https://example.com'], + }, + }); + + expect(stack).toHaveResourceLike('AWS::Cognito::UserPoolClient', { + LogoutURLs: ['https://example.com'], + }); + }); + test('fails when clientCredentials OAuth flow is selected along with codeGrant or implicitGrant', () => { const stack = new Stack(); const pool = new UserPool(stack, 'Pool'); diff --git a/packages/@aws-cdk/aws-config/README.md b/packages/@aws-cdk/aws-config/README.md index c004579117aef..c2fbf8b3722b3 100644 --- a/packages/@aws-cdk/aws-config/README.md +++ b/packages/@aws-cdk/aws-config/README.md @@ -19,7 +19,7 @@ Supported: * Config rules Not supported -* Configuration recoder +* Configuration recorder * Delivery channel * Aggregation diff --git a/packages/@aws-cdk/aws-config/lib/managed-rules.ts b/packages/@aws-cdk/aws-config/lib/managed-rules.ts index 5b1821b9598a0..0ce7c21018c7c 100644 --- a/packages/@aws-cdk/aws-config/lib/managed-rules.ts +++ b/packages/@aws-cdk/aws-config/lib/managed-rules.ts @@ -56,7 +56,7 @@ export interface CloudFormationStackDriftDetectionCheckProps extends RuleProps { * permissions and `ReadOnlyAccess` policy permissions. For specific policy permissions, * refer to https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-stack-drift.html. * - * @default a role will be created + * @default - A role will be created */ readonly role?: iam.IRole; } diff --git a/packages/@aws-cdk/aws-config/lib/rule.ts b/packages/@aws-cdk/aws-config/lib/rule.ts index a7ccb08e7d10b..5a734a0fdb2bc 100644 --- a/packages/@aws-cdk/aws-config/lib/rule.ts +++ b/packages/@aws-cdk/aws-config/lib/rule.ts @@ -193,28 +193,28 @@ export interface RuleProps { /** * A name for the AWS Config rule. * - * @default a CloudFormation generated name + * @default - CloudFormation generated name */ readonly configRuleName?: string; /** * A description about this AWS Config rule. * - * @default no description + * @default - No description */ readonly description?: string; /** * Input parameter values that are passed to the AWS Config rule. * - * @default no input parameters + * @default - No input parameters */ readonly inputParameters?: { [key: string]: any }; /** * The maximum frequency at which the AWS Config rule runs evaluations. * - * @default 24 hours + * @default MaximumExecutionFrequency.TWENTY_FOUR_HOURS */ readonly maximumExecutionFrequency?: MaximumExecutionFrequency } @@ -276,7 +276,7 @@ export class ManagedRule extends RuleNew { } /** - * Consruction properties for a CustomRule. + * Construction properties for a CustomRule. */ export interface CustomRuleProps extends RuleProps { /** 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 f3a9fcb2d92fa..b8a0e149587ad 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 @@ -28,15 +28,15 @@ "license": "Apache-2.0", "devDependencies": { "aws-sdk": "^2.596.0", - "aws-sdk-mock": "^5.0.0", - "eslint": "^6.8.0", - "eslint-config-standard": "^14.1.0", - "eslint-plugin-import": "^2.19.1", - "eslint-plugin-node": "^10.0.0", + "aws-sdk-mock": "^5.1.0", + "eslint": "^7.9.0", + "eslint-config-standard": "^14.1.1", + "eslint-plugin-import": "^2.22.0", + "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^4.2.1", "eslint-plugin-standard": "^4.0.1", - "jest": "^25.5.0", + "jest": "^26.4.2", "lambda-tester": "^3.6.0", - "nock": "^11.7.0" + "nock": "^13.0.4" } } diff --git a/packages/@aws-cdk/aws-dynamodb/lib/table.ts b/packages/@aws-cdk/aws-dynamodb/lib/table.ts index 20c99168d08f8..ead9ef4ff990c 100644 --- a/packages/@aws-cdk/aws-dynamodb/lib/table.ts +++ b/packages/@aws-cdk/aws-dynamodb/lib/table.ts @@ -1333,8 +1333,8 @@ export class Table extends TableBase { encryptionType = props.encryptionKey != null // If there is a configured encyptionKey, the encryption is implicitly CUSTOMER_MANAGED ? TableEncryption.CUSTOMER_MANAGED - // Otherwise, if severSideEncryption is enabled, it's AWS_MANAGED; else DEFAULT - : props.serverSideEncryption ? TableEncryption.AWS_MANAGED : TableEncryption.DEFAULT; + // Otherwise, if severSideEncryption is enabled, it's AWS_MANAGED; else undefined (do not set anything) + : props.serverSideEncryption ? TableEncryption.AWS_MANAGED : undefined; } if (encryptionType !== TableEncryption.CUSTOMER_MANAGED && props.encryptionKey) { @@ -1362,6 +1362,9 @@ export class Table extends TableBase { return { sseSpecification: { sseEnabled: true } }; case TableEncryption.DEFAULT: + return { sseSpecification: { sseEnabled: false } }; + + case undefined: // Not specifying "sseEnabled: false" here because it would cause phony changes to existing stacks. return { sseSpecification: undefined }; diff --git a/packages/@aws-cdk/aws-dynamodb/package.json b/packages/@aws-cdk/aws-dynamodb/package.json index 41bc2d44ead24..d52338c60123e 100644 --- a/packages/@aws-cdk/aws-dynamodb/package.json +++ b/packages/@aws-cdk/aws-dynamodb/package.json @@ -1,7 +1,7 @@ { "name": "@aws-cdk/aws-dynamodb", "version": "0.0.0", - "description": "CDK Constructs for AWS DynamoDB", + "description": "The CDK Construct Library for AWS::DynamoDB", "main": "lib/index.js", "types": "lib/index.d.ts", "jsii": { @@ -65,16 +65,16 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/jest": "^26.0.10", + "@types/jest": "^26.0.14", "aws-sdk": "^2.739.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "pkglint": "0.0.0", "sinon": "^9.0.3", - "ts-jest": "^26.2.0" + "ts-jest": "^26.3.0" }, "dependencies": { "@aws-cdk/aws-applicationautoscaling": "0.0.0", 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 3a3b5788fd907..c8e4ada3c14bd 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 @@ -507,6 +507,9 @@ "ProvisionedThroughput": { "ReadCapacityUnits": 5, "WriteCapacityUnits": 5 + }, + "SSESpecification": { + "SSEEnabled": false } }, "UpdateReplacePolicy": "Delete", diff --git a/packages/@aws-cdk/aws-ec2/README.md b/packages/@aws-cdk/aws-ec2/README.md index bf26132b35a07..27dcabd8b69cd 100644 --- a/packages/@aws-cdk/aws-ec2/README.md +++ b/packages/@aws-cdk/aws-ec2/README.md @@ -163,6 +163,8 @@ Which subnets are selected is evaluated as follows: in the given availability zones will be returned. * `onePerAz`: per availability zone, a maximum of one subnet will be returned (Useful for resource types that do not allow creating two ENIs in the same availability zone). +* `subnetFilters`: additional filtering on subnets using any number of user-provided filters which + extend the SubnetFilter class. ### Using NAT instances diff --git a/packages/@aws-cdk/aws-ec2/lib/cfn-init-elements.ts b/packages/@aws-cdk/aws-ec2/lib/cfn-init-elements.ts index 73153cd1025a3..ed2aef6fb14ed 100644 --- a/packages/@aws-cdk/aws-ec2/lib/cfn-init-elements.ts +++ b/packages/@aws-cdk/aws-ec2/lib/cfn-init-elements.ts @@ -489,7 +489,9 @@ export abstract class InitFile extends InitElement { if (fileOptions.group || fileOptions.owner || fileOptions.mode) { throw new Error('Owner, group, and mode options not supported for Windows.'); } - return {}; + return { + [this.fileName]: { ...contentVars }, + }; } return { diff --git a/packages/@aws-cdk/aws-ec2/lib/index.ts b/packages/@aws-cdk/aws-ec2/lib/index.ts index ff7f7131d53e4..ca25a02f3f8d1 100644 --- a/packages/@aws-cdk/aws-ec2/lib/index.ts +++ b/packages/@aws-cdk/aws-ec2/lib/index.ts @@ -10,6 +10,7 @@ export * from './network-acl'; export * from './network-acl-types'; export * from './port'; export * from './security-group'; +export * from './subnet'; export * from './peer'; export * from './volume'; export * from './vpc'; diff --git a/packages/@aws-cdk/aws-ec2/lib/machine-image.ts b/packages/@aws-cdk/aws-ec2/lib/machine-image.ts index 503441ff8d711..34405181774a1 100644 --- a/packages/@aws-cdk/aws-ec2/lib/machine-image.ts +++ b/packages/@aws-cdk/aws-ec2/lib/machine-image.ts @@ -65,6 +65,22 @@ export abstract class MachineImage { return new GenericWindowsImage(amiMap, props); } + /** + * An image specified in SSM parameter store that is automatically kept up-to-date + * + * This Machine Image automatically updates to the latest version on every + * deployment. Be aware this will cause your instances to be replaced when a + * new version of the image becomes available. Do not store stateful information + * on the instance if you are using this image. + * + * @param parameterName The name of SSM parameter containing the AMi id + * @param os The operating system type of the AMI + * @param userData optional user data for the given image + */ + public static fromSSMParameter(parameterName: string, os: OperatingSystemType, userData?: UserData): IMachineImage { + return new GenericSSMParameterImage(parameterName, os, userData); + } + /** * Look up a shared Machine Image using DescribeImages * @@ -102,6 +118,34 @@ export interface MachineImageConfig { readonly userData: UserData; } +/** + * Select the image based on a given SSM parameter + * + * This Machine Image automatically updates to the latest version on every + * deployment. Be aware this will cause your instances to be replaced when a + * new version of the image becomes available. Do not store stateful information + * on the instance if you are using this image. + * + * The AMI ID is selected using the values published to the SSM parameter store. + */ +export class GenericSSMParameterImage implements IMachineImage { + + constructor(private readonly parameterName: string, private readonly os: OperatingSystemType, private readonly userData?: UserData) { + } + + /** + * Return the image to use in the given context + */ + public getImage(scope: Construct): MachineImageConfig { + const ami = ssm.StringParameter.valueForTypedStringParameter(scope, this.parameterName, ssm.ParameterType.AWS_EC2_IMAGE_ID); + return { + imageId: ami, + osType: this.os, + userData: this.userData ?? (this.os === OperatingSystemType.WINDOWS ? UserData.forWindows() : UserData.forLinux()), + }; + } +} + /** * Configuration options for WindowsImage */ @@ -126,28 +170,9 @@ export interface WindowsImageProps { * * https://aws.amazon.com/blogs/mt/query-for-the-latest-windows-ami-using-systems-manager-parameter-store/ */ -export class WindowsImage implements IMachineImage { - constructor(private readonly version: WindowsVersion, private readonly props: WindowsImageProps = {}) { - } - - /** - * Return the image to use in the given context - */ - public getImage(scope: Construct): MachineImageConfig { - const parameterName = this.imageParameterName(); - const ami = ssm.StringParameter.valueForTypedStringParameter(scope, parameterName, ssm.ParameterType.AWS_EC2_IMAGE_ID); - return { - imageId: ami, - userData: this.props.userData ?? UserData.forWindows(), - osType: OperatingSystemType.WINDOWS, - }; - } - - /** - * Construct the SSM parameter name for the given Windows image - */ - private imageParameterName(): string { - return '/aws/service/ami-windows-latest/' + this.version; +export class WindowsImage extends GenericSSMParameterImage { + constructor(version: WindowsVersion, props: WindowsImageProps = {}) { + super('/aws/service/ami-windows-latest/' + version, OperatingSystemType.WINDOWS, props.userData); } } @@ -223,42 +248,25 @@ export interface AmazonLinuxImageProps { * * The AMI ID is selected using the values published to the SSM parameter store. */ -export class AmazonLinuxImage implements IMachineImage { - private readonly generation: AmazonLinuxGeneration; - private readonly edition: AmazonLinuxEdition; - private readonly virtualization: AmazonLinuxVirt; - private readonly storage: AmazonLinuxStorage; - private readonly cpu: AmazonLinuxCpuType; - - constructor(private readonly props: AmazonLinuxImageProps = {}) { - this.generation = (props && props.generation) || AmazonLinuxGeneration.AMAZON_LINUX; - this.edition = (props && props.edition) || AmazonLinuxEdition.STANDARD; - this.virtualization = (props && props.virtualization) || AmazonLinuxVirt.HVM; - this.storage = (props && props.storage) || AmazonLinuxStorage.GENERAL_PURPOSE; - this.cpu = (props && props.cpuType) || AmazonLinuxCpuType.X86_64; - } - - /** - * Return the image to use in the given context - */ - public getImage(scope: Construct): MachineImageConfig { +export class AmazonLinuxImage extends GenericSSMParameterImage { + + constructor(props: AmazonLinuxImageProps = {}) { + const generation = (props && props.generation) || AmazonLinuxGeneration.AMAZON_LINUX; + const edition = (props && props.edition) || AmazonLinuxEdition.STANDARD; + const virtualization = (props && props.virtualization) || AmazonLinuxVirt.HVM; + const storage = (props && props.storage) || AmazonLinuxStorage.GENERAL_PURPOSE; + const cpu = (props && props.cpuType) || AmazonLinuxCpuType.X86_64; const parts: Array = [ - this.generation, + generation, 'ami', - this.edition !== AmazonLinuxEdition.STANDARD ? this.edition : undefined, - this.virtualization, - this.cpu, - this.storage, + edition !== AmazonLinuxEdition.STANDARD ? edition : undefined, + virtualization, + cpu, + storage, ].filter(x => x !== undefined); // Get rid of undefineds const parameterName = '/aws/service/ami-amazon-linux-latest/' + parts.join('-'); - const ami = ssm.StringParameter.valueForTypedStringParameter(scope, parameterName, ssm.ParameterType.AWS_EC2_IMAGE_ID); - - return { - imageId: ami, - userData: this.props.userData ?? UserData.forLinux(), - osType: OperatingSystemType.LINUX, - }; + super(parameterName, OperatingSystemType.LINUX, props.userData); } } diff --git a/packages/@aws-cdk/aws-ec2/lib/subnet.ts b/packages/@aws-cdk/aws-ec2/lib/subnet.ts new file mode 100644 index 0000000000000..204c81957c929 --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/lib/subnet.ts @@ -0,0 +1,115 @@ +import { CidrBlock, NetworkUtils } from './network-util'; +import { ISubnet } from './vpc'; + +/** + * Contains logic which chooses a set of subnets from a larger list, in conjunction + * with SubnetSelection, to determine where to place AWS resources such as VPC + * endpoints, EC2 instances, etc. + */ +export abstract class SubnetFilter { + + /** + * Chooses subnets which are in one of the given availability zones. + */ + public static availabilityZones(availabilityZones: string[]): SubnetFilter { + return new AvailabilityZoneSubnetFilter(availabilityZones); + } + + /** + * Chooses subnets such that there is at most one per availability zone. + */ + public static onePerAz(): SubnetFilter { + return new OnePerAZSubnetFilter(); + } + + /** + * Chooses subnets which contain any of the specified IP addresses. + */ + public static containsIpAddresses(ipv4addrs: string[]): SubnetFilter { + return new ContainsIpAddressesSubnetFilter(ipv4addrs); + } + + /** + * Executes the subnet filtering logic, returning a filtered set of subnets. + */ + public selectSubnets(_subnets: ISubnet[]): ISubnet[] { + throw new Error('Cannot select subnets with an abstract SubnetFilter. `selectSubnets` needs to be implmemented.'); + } +} + +/** + * Chooses subnets which are in one of the given availability zones. + */ +class AvailabilityZoneSubnetFilter extends SubnetFilter { + + private readonly availabilityZones: string[]; + + constructor(availabilityZones: string[]) { + super(); + this.availabilityZones = availabilityZones; + } + + /** + * Executes the subnet filtering logic. + */ + public selectSubnets(subnets: ISubnet[]): ISubnet[] { + return subnets.filter(s => this.availabilityZones.includes(s.availabilityZone)); + } +} + +/** + * Chooses subnets such that there is at most one per availability zone. + */ +class OnePerAZSubnetFilter extends SubnetFilter { + + constructor() { + super(); + } + + /** + * Executes the subnet filtering logic. + */ + public selectSubnets(subnets: ISubnet[]): ISubnet[] { + return this.retainOnePerAz(subnets); + } + + private retainOnePerAz(subnets: ISubnet[]): ISubnet[] { + const azsSeen = new Set(); + return subnets.filter(subnet => { + if (azsSeen.has(subnet.availabilityZone)) { return false; } + azsSeen.add(subnet.availabilityZone); + return true; + }); + } +} + +/** + * Chooses subnets which contain any of the specified IP addresses. + */ +class ContainsIpAddressesSubnetFilter extends SubnetFilter { + + private readonly ipAddresses: string[]; + + constructor(ipAddresses: string[]) { + super(); + this.ipAddresses = ipAddresses; + } + + /** + * Executes the subnet filtering logic. + */ + public selectSubnets(subnets: ISubnet[]): ISubnet[] { + return this.retainByIp(subnets, this.ipAddresses); + } + + private retainByIp(subnets: ISubnet[], ips: string[]): ISubnet[] { + const cidrBlockObjs = ips.map(ip => { + const ipNum = NetworkUtils.ipToNum(ip); + return new CidrBlock(ipNum, 32); + }); + return subnets.filter(s => { + const subnetCidrBlock = new CidrBlock(s.ipv4CidrBlock); + return cidrBlockObjs.some(cidr => subnetCidrBlock.containsCidr(cidr)); + }); + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index 63118badb5977..18ea936893ccb 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -11,6 +11,7 @@ import { import { NatProvider } from './nat'; import { INetworkAcl, NetworkAcl, SubnetNetworkAclAssociation } from './network-acl'; import { NetworkBuilder } from './network-util'; +import { SubnetFilter } from './subnet'; import { allRouteTableIds, defaultSubnetName, flatten, ImportSubnetGroup, subnetGroupNameFromConstructId, subnetId } from './util'; import { GatewayVpcEndpoint, GatewayVpcEndpointAwsService, GatewayVpcEndpointOptions, InterfaceVpcEndpoint, InterfaceVpcEndpointOptions } from './vpc-endpoint'; import { FlowLog, FlowLogOptions, FlowLogResourceType } from './vpc-flow-logs'; @@ -36,6 +37,11 @@ export interface ISubnet extends IResource { */ readonly internetConnectivityEstablished: IDependable; + /** + * The IPv4 CIDR block for this subnet + */ + readonly ipv4CidrBlock: string; + /** * The route table for this subnet */ @@ -236,6 +242,13 @@ export interface SubnetSelection { */ readonly onePerAz?: boolean; + /** + * List of provided subnet filters. + * + * @default - none + */ + readonly subnetFilters?: SubnetFilter[]; + /** * Explicitly select individual subnets * @@ -460,17 +473,21 @@ abstract class VpcBase extends Resource implements IVpc { subnets = this.selectSubnetObjectsByType(type); } - if (selection.availabilityZones !== undefined) { // Filter by AZs, if specified - subnets = retainByAZ(subnets, selection.availabilityZones); - } - - if (!!selection.onePerAz && subnets.length > 0) { // Ensure one per AZ if specified - subnets = retainOnePerAz(subnets); - } + // Apply all the filters + subnets = this.applySubnetFilters(subnets, selection.subnetFilters ?? []); return subnets; } + private applySubnetFilters(subnets: ISubnet[], filters: SubnetFilter[]): ISubnet[] { + let filtered = subnets; + // Apply each filter in sequence + for (const filter of filters) { + filtered = filter.selectSubnets(filtered); + } + return filtered; + } + private selectSubnetObjectsByName(groupName: string) { const allSubnets = [...this.publicSubnets, ...this.privateSubnets, ...this.isolatedSubnets]; const subnets = allSubnets.filter(s => subnetGroupNameFromConstructId(s) === groupName); @@ -510,9 +527,12 @@ abstract class VpcBase extends Resource implements IVpc { * PUBLIC (in that order) that has any subnets. */ private reifySelectionDefaults(placement: SubnetSelection): SubnetSelection { + if (placement.subnetName !== undefined) { if (placement.subnetGroupName !== undefined) { throw new Error('Please use only \'subnetGroupName\' (\'subnetName\' is deprecated and has the same behavior)'); + } else { + Annotations.of(this).addWarning('Usage of \'subnetName\' in SubnetSelection is deprecated, use \'subnetGroupName\' instead'); } placement = { ...placement, subnetGroupName: placement.subnetName }; } @@ -525,42 +545,27 @@ abstract class VpcBase extends Resource implements IVpc { if (placement.subnetType === undefined && placement.subnetGroupName === undefined && placement.subnets === undefined) { // Return default subnet type based on subnets that actually exist - if (this.privateSubnets.length > 0) { - return { - subnetType: SubnetType.PRIVATE, - onePerAz: placement.onePerAz, - availabilityZones: placement.availabilityZones, - }; - } - if (this.isolatedSubnets.length > 0) { - return { - subnetType: SubnetType.ISOLATED, - onePerAz: placement.onePerAz, - availabilityZones: placement.availabilityZones, - }; - } - return { - subnetType: SubnetType.PUBLIC, - onePerAz: placement.onePerAz, - availabilityZones: placement.availabilityZones, - }; + let subnetType = this.privateSubnets.length ? SubnetType.PRIVATE : this.isolatedSubnets.length ? SubnetType.ISOLATED : SubnetType.PUBLIC; + placement = { ...placement, subnetType: subnetType }; } - return placement; - } -} + // Establish which subnet filters are going to be used + let subnetFilters = placement.subnetFilters ?? []; -function retainByAZ(subnets: ISubnet[], azs: string[]): ISubnet[] { - return subnets.filter(s => azs.includes(s.availabilityZone)); -} + // Backwards compatibility with existing `availabilityZones` and `onePerAz` functionality + if (placement.availabilityZones !== undefined) { // Filter by AZs, if specified + subnetFilters.push(SubnetFilter.availabilityZones(placement.availabilityZones)); + } + if (!!placement.onePerAz) { // Ensure one per AZ if specified + subnetFilters.push(SubnetFilter.onePerAz()); + } + + // Overwrite the provided placement filters and remove the availabilityZones and onePerAz properties + placement = { ...placement, subnetFilters: subnetFilters, availabilityZones: undefined, onePerAz: undefined }; + const { availabilityZones, onePerAz, ...rest } = placement; -function retainOnePerAz(subnets: ISubnet[]): ISubnet[] { - const azsSeen = new Set(); - return subnets.filter(subnet => { - if (azsSeen.has(subnet.availabilityZone)) { return false; } - azsSeen.add(subnet.availabilityZone); - return true; - }); + return rest; + } } /** @@ -654,6 +659,7 @@ export interface VpcAttributes { } export interface SubnetAttributes { + /** * The Availability Zone the subnet is located in * @@ -662,9 +668,11 @@ export interface SubnetAttributes { readonly availabilityZone?: string; /** - * The subnetId for this particular subnet + * The IPv4 CIDR block associated with the subnet + * + * @default - No CIDR information, cannot use CIDR filter features */ - readonly subnetId: string; + readonly ipv4CidrBlock?: string; /** * The ID of the route table for this particular subnet @@ -672,6 +680,11 @@ export interface SubnetAttributes { * @default - No route table information, cannot create VPC endpoints */ readonly routeTableId?: string; + + /** + * The subnetId for this particular subnet + */ + readonly subnetId: string; } /** @@ -1432,7 +1445,7 @@ export class Subnet extends Resource implements ISubnet { /** * Import existing subnet from id. */ - // eslint-disable-next-line no-shadow + // eslint-disable-next-line @typescript-eslint/no-shadow public static fromSubnetId(scope: Construct, id: string, subnetId: string): ISubnet { return this.fromSubnetAttributes(scope, id, { subnetId }); } @@ -1442,6 +1455,11 @@ export class Subnet extends Resource implements ISubnet { */ public readonly availabilityZone: string; + /** + * @attribute + */ + public readonly ipv4CidrBlock: string; + /** * The subnetId for this particular subnet */ @@ -1491,6 +1509,7 @@ export class Subnet extends Resource implements ISubnet { Tags.of(this).add(NAME_TAG, this.node.path); this.availabilityZone = props.availabilityZone; + this.ipv4CidrBlock = props.cidrBlock; const subnet = new CfnSubnet(this, 'Subnet', { vpcId: props.vpcId, cidrBlock: props.cidrBlock, @@ -1890,6 +1909,7 @@ class ImportedSubnet extends Resource implements ISubnet, IPublicSubnet, IPrivat public readonly subnetId: string; public readonly routeTable: IRouteTable; private readonly _availabilityZone?: string; + private readonly _ipv4CidrBlock?: string; constructor(scope: Construct, id: string, attrs: SubnetAttributes) { super(scope, id); @@ -1902,6 +1922,7 @@ class ImportedSubnet extends Resource implements ISubnet, IPublicSubnet, IPrivat Annotations.of(this).addWarning(`No routeTableId was provided to the subnet ${ref}. Attempting to read its .routeTable.routeTableId will return null/undefined. (More info: https://github.com/aws/aws-cdk/pull/3171)`); } + this._ipv4CidrBlock = attrs.ipv4CidrBlock; this._availabilityZone = attrs.availabilityZone; this.subnetId = attrs.subnetId; this.routeTable = { @@ -1913,11 +1934,19 @@ class ImportedSubnet extends Resource implements ISubnet, IPublicSubnet, IPrivat public get availabilityZone(): string { if (!this._availabilityZone) { // eslint-disable-next-line max-len - throw new Error("You cannot reference a Subnet's availability zone if it was not supplied. Add the availabilityZone when importing using Subnet.fromSubnetAttributes()"); + throw new Error('You cannot reference a Subnet\'s availability zone if it was not supplied. Add the availabilityZone when importing using Subnet.fromSubnetAttributes()'); } return this._availabilityZone; } + public get ipv4CidrBlock(): string { + if (!this._ipv4CidrBlock) { + // tslint:disable-next-line: max-line-length + throw new Error('You cannot reference an imported Subnet\'s IPv4 CIDR if it was not supplied. Add the ipv4CidrBlock when importing using Subnet.fromSubnetAttributes()'); + } + return this._ipv4CidrBlock; + } + public associateNetworkAcl(id: string, networkAcl: INetworkAcl): void { const scope = Construct.isConstruct(networkAcl) ? networkAcl : this; const other = Construct.isConstruct(networkAcl) ? this : networkAcl; diff --git a/packages/@aws-cdk/aws-ec2/package.json b/packages/@aws-cdk/aws-ec2/package.json index 9dc2e0c6a261b..da082c3f5571b 100644 --- a/packages/@aws-cdk/aws-ec2/package.json +++ b/packages/@aws-cdk/aws-ec2/package.json @@ -1,7 +1,7 @@ { "name": "@aws-cdk/aws-ec2", "version": "0.0.0", - "description": "CDK Constructs for AWS EC2", + "description": "The CDK Construct Library for AWS::EC2", "main": "lib/index.js", "types": "lib/index.d.ts", "jsii": { diff --git a/packages/@aws-cdk/aws-ec2/test/cfn-init-element.test.ts b/packages/@aws-cdk/aws-ec2/test/cfn-init-element.test.ts index 1fc7399f63c60..2f81ff04acbbe 100644 --- a/packages/@aws-cdk/aws-ec2/test/cfn-init-element.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/cfn-init-element.test.ts @@ -177,6 +177,22 @@ describe('InitFile', () => { }).toThrow('Owner, group, and mode options not supported for Windows.'); }); + test('file renders properly on Windows', () => { + // GIVEN + const file = ec2.InitFile.fromString('/tmp/foo', 'My content'); + + // WHEN + const rendered = getElementConfig(file, InitPlatform.WINDOWS); + + // THEN + expect(rendered).toEqual({ + '/tmp/foo': { + content: 'My content', + encoding: 'plain', + }, + }); + }); + test('symlink throws an error if mode is set incorrectly', () => { expect(() => { ec2.InitFile.symlink('/tmp/foo', '/tmp/bar', { diff --git a/packages/@aws-cdk/aws-ec2/test/example.images.lit.ts b/packages/@aws-cdk/aws-ec2/test/example.images.lit.ts index 7e5e4924097f7..4fbff22fb86a4 100644 --- a/packages/@aws-cdk/aws-ec2/test/example.images.lit.ts +++ b/packages/@aws-cdk/aws-ec2/test/example.images.lit.ts @@ -14,6 +14,9 @@ const amznLinux = ec2.MachineImage.latestAmazonLinux({ // Pick a Windows edition to use const windows = ec2.MachineImage.latestWindows(ec2.WindowsVersion.WINDOWS_SERVER_2019_ENGLISH_FULL_BASE); +// Read AMI id from SSM parameter store +const ssm = ec2.MachineImage.fromSSMParameter('/my/ami', ec2.OperatingSystemType.LINUX); + // Look up the most recent image matching a set of AMI filters. // In this case, look up the NAT instance AMI, by using a wildcard // in the 'name' field: @@ -42,5 +45,6 @@ const genericWindows = ec2.MachineImage.genericWindows({ Array.isArray(windows); Array.isArray(amznLinux); Array.isArray(linux); +Array.isArray(ssm); Array.isArray(genericWindows); Array.isArray(natAmi); diff --git a/packages/@aws-cdk/aws-ec2/test/machine-image.test.ts b/packages/@aws-cdk/aws-ec2/test/machine-image.test.ts index 62b04368209c4..2fcf7e2980be9 100644 --- a/packages/@aws-cdk/aws-ec2/test/machine-image.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/machine-image.test.ts @@ -23,6 +23,16 @@ test('can make and use a Windows image', () => { expect(details.osType).toEqual(ec2.OperatingSystemType.WINDOWS); }); +test('can make and use a Generic SSM image', () => { + // WHEN + const image = new ec2.GenericSSMParameterImage('testParam', ec2.OperatingSystemType.LINUX); + + // THEN + const details = image.getImage(stack); + expect(details.imageId).toContain('TOKEN'); + expect(details.osType).toEqual(ec2.OperatingSystemType.LINUX); +}); + test('WindowsImage retains userdata if given', () => { // WHEN const ud = ec2.UserData.forWindows(); diff --git a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts index 87752fef51bdb..9163a210738f8 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts @@ -2,9 +2,9 @@ import { countResources, expect, haveResource, haveResourceLike, isSuperObject, import { CfnOutput, Lazy, Stack, Tags } from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import { - AclCidr, AclTraffic, CfnSubnet, CfnVPC, DefaultInstanceTenancy, GenericLinuxImage, InstanceType, InterfaceVpcEndpoint, - InterfaceVpcEndpointService, NatProvider, NetworkAcl, NetworkAclEntry, Peer, Port, PrivateSubnet, PublicSubnet, - RouterType, Subnet, SubnetType, TrafficDirection, Vpc, + AclCidr, AclTraffic, BastionHostLinux, CfnSubnet, CfnVPC, SubnetFilter, DefaultInstanceTenancy, GenericLinuxImage, + InstanceType, InterfaceVpcEndpoint, InterfaceVpcEndpointService, NatProvider, NetworkAcl, NetworkAclEntry, Peer, Port, PrivateSubnet, + PublicSubnet, RouterType, Subnet, SubnetType, TrafficDirection, Vpc, } from '../lib'; nodeunitShim({ @@ -1381,6 +1381,74 @@ nodeunitShim({ })); test.done(); }, + + 'can filter by single IP address'(test: Test) { + // GIVEN + const stack = getTestStack(); + + // IP space is split into 6 pieces, one public/one private per AZ + const vpc = new Vpc(stack, 'VPC', { + cidr: '10.0.0.0/16', + maxAzs: 3, + }); + + // WHEN + // We want to place this bastion host in the same subnet as this IPv4 + // address. + new BastionHostLinux(stack, 'Bastion', { + vpc, + subnetSelection: { + subnetFilters: [SubnetFilter.containsIpAddresses(['10.0.160.0'])], + }, + }); + + // THEN + // 10.0.160.0/19 is the third subnet, sequentially, if you split + // 10.0.0.0/16 into 6 pieces + expect(stack).to(haveResource('AWS::EC2::Instance', { + SubnetId: { + Ref: 'VPCPrivateSubnet3Subnet3EDCD457', + }, + })); + test.done(); + }, + + 'can filter by multiple IP addresses'(test: Test) { + // GIVEN + const stack = getTestStack(); + + // IP space is split into 6 pieces, one public/one private per AZ + const vpc = new Vpc(stack, 'VPC', { + cidr: '10.0.0.0/16', + maxAzs: 3, + }); + + // WHEN + // We want to place this endpoint in the same subnets as these IPv4 + // address. + // WHEN + new InterfaceVpcEndpoint(stack, 'VPC Endpoint', { + vpc, + service: new InterfaceVpcEndpointService('com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', 443), + subnets: { + subnetFilters: [SubnetFilter.containsIpAddresses(['10.0.96.0', '10.0.160.0'])], + }, + }); + + // THEN + expect(stack).to(haveResource('AWS::EC2::VPCEndpoint', { + ServiceName: 'com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', + SubnetIds: [ + { + Ref: 'VPCPrivateSubnet1Subnet8BCA10E0', + }, + { + Ref: 'VPCPrivateSubnet3Subnet3EDCD457', + }, + ], + })); + test.done(); + }, }, }); diff --git a/packages/@aws-cdk/aws-ecs-patterns/package.json b/packages/@aws-cdk/aws-ecs-patterns/package.json index d0f8222a497ea..a6f5c320dc9aa 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/package.json +++ b/packages/@aws-cdk/aws-ecs-patterns/package.json @@ -1,7 +1,7 @@ { "name": "@aws-cdk/aws-ecs-patterns", "version": "0.0.0", - "description": "CDK Constructs for AWS ECS", + "description": "The CDK Construct Library for AWS::ECS", "main": "lib/index.js", "types": "lib/index.d.ts", "jsii": { @@ -65,7 +65,7 @@ "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "nodeunit": "^0.11.3", "pkglint": "0.0.0" }, diff --git a/packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts b/packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts index 1d1480ee8831d..a27c65a6a34b2 100644 --- a/packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts +++ b/packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts @@ -297,7 +297,7 @@ export class TaskDefinition extends TaskDefinitionBase { const taskDef = new CfnTaskDefinition(this, 'Resource', { containerDefinitions: Lazy.anyValue({ produce: () => this.renderContainers() }, { omitEmptyArray: true }), - volumes: Lazy.anyValue({ produce: () => this.volumes }, { omitEmptyArray: true }), + volumes: Lazy.anyValue({ produce: () => this.renderVolumes() }, { omitEmptyArray: true }), executionRoleArn: Lazy.stringValue({ produce: () => this.executionRole && this.executionRole.roleArn }), family: this.family, taskRoleArn: this.taskRole.roleArn, @@ -328,6 +328,32 @@ export class TaskDefinition extends TaskDefinitionBase { return this._executionRole; } + private renderVolumes(): CfnTaskDefinition.VolumeProperty[] { + return this.volumes.map(renderVolume); + + function renderVolume(spec: Volume): CfnTaskDefinition.VolumeProperty { + return { + host: spec.host, + name: spec.name, + dockerVolumeConfiguration: spec.dockerVolumeConfiguration && { + autoprovision: spec.dockerVolumeConfiguration.autoprovision, + driver: spec.dockerVolumeConfiguration.driver, + driverOpts: spec.dockerVolumeConfiguration.driverOpts, + labels: spec.dockerVolumeConfiguration.labels, + scope: spec.dockerVolumeConfiguration.scope, + }, + efsVolumeConfiguration: spec.efsVolumeConfiguration && { + filesystemId: spec.efsVolumeConfiguration.fileSystemId, + authorizationConfig: spec.efsVolumeConfiguration.authorizationConfig, + rootDirectory: spec.efsVolumeConfiguration.rootDirectory, + transitEncryption: spec.efsVolumeConfiguration.transitEncryption, + transitEncryptionPort: spec.efsVolumeConfiguration.transitEncryptionPort, + + }, + }; + } + } + /** * Validate the existence of the input target and set default values. * @@ -713,7 +739,7 @@ export interface DockerVolumeConfiguration { * * @default No labels */ - readonly labels?: string[]; + readonly labels?: { [key: string]: string; } /** * The scope for the Docker volume that determines its lifecycle. */ diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-task-definition.ts b/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-task-definition.ts index 9688e649b545c..362c040ae97ba 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-task-definition.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-task-definition.ts @@ -1006,8 +1006,8 @@ export = { Family: 'Ec2TaskDef', Volumes: [{ Name: 'scratch', - EfsVolumeConfiguration: { - FileSystemId: 'local', + EFSVolumeConfiguration: { + FilesystemId: 'local', }, }], })); diff --git a/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/cluster.ts b/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/cluster.ts index d11a0a04f7233..4dc909113ac91 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/cluster.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/cluster.ts @@ -123,7 +123,7 @@ export class ClusterResourceHandler extends ResourceHandler { throw new Error(`Cannot replace cluster "${this.oldProps.name}" since it has an explicit physical name. Either rename the cluster or remove the "name" configuration`); } - return await this.onCreate(); + return this.onCreate(); } // if a version update is required, issue the version update @@ -132,7 +132,7 @@ export class ClusterResourceHandler extends ResourceHandler { throw new Error(`Cannot remove cluster version configuration. Current version is ${this.oldProps.version}`); } - return await this.updateClusterVersion(this.newProps.version); + return this.updateClusterVersion(this.newProps.version); } if (updates.updateLogging || updates.updateAccess) { diff --git a/packages/@aws-cdk/aws-eks/lib/cluster.ts b/packages/@aws-cdk/aws-eks/lib/cluster.ts index 361d396c9651a..c753b7b81f784 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster.ts @@ -848,11 +848,6 @@ export class Cluster extends ClusterBase { description: 'EKS Control Plane Security Group', }); - this.connections = new ec2.Connections({ - securityGroups: [securityGroup], - defaultPort: ec2.Port.tcp(443), // Control Plane has an HTTPS API - }); - this.vpcSubnets = props.vpcSubnets ?? [{ subnetType: ec2.SubnetType.PUBLIC }, { subnetType: ec2.SubnetType.PRIVATE }]; // Get subnetIds for all selected subnets @@ -916,17 +911,9 @@ export class Cluster extends ClusterBase { this.kubectlPrivateSubnets = privateSubents; - this.kubectlSecurityGroup = new ec2.SecurityGroup(this, 'KubectlProviderSecurityGroup', { - vpc: this.vpc, - description: 'Comminication between KubectlProvider and EKS Control Plane', - }); - - // grant the kubectl provider access to the cluster control plane. - this.connections.allowFrom(this.kubectlSecurityGroup, this.connections.defaultPort!); - - // the security group and vpc must exist in order to properly delete the cluster (since we run `kubectl delete`). + // the vpc must exist in order to properly delete the cluster (since we run `kubectl delete`). // this ensures that. - this._clusterResource.node.addDependency(this.kubectlSecurityGroup, this.vpc); + this._clusterResource.node.addDependency(this.vpc); } this.adminRole = resource.adminRole; @@ -951,6 +938,17 @@ export class Cluster extends ClusterBase { this.clusterSecurityGroupId = resource.attrClusterSecurityGroupId; this.clusterEncryptionConfigKeyArn = resource.attrEncryptionConfigKeyArn; + const clusterSecurityGroup = ec2.SecurityGroup.fromSecurityGroupId(this, 'ClusterSecurityGroup', this.clusterSecurityGroupId); + + this.connections = new ec2.Connections({ + securityGroups: [clusterSecurityGroup, securityGroup], + defaultPort: ec2.Port.tcp(443), // Control Plane has an HTTPS API + }); + + // we can use the cluster security group since its already attached to the cluster + // and configured to allow connections from itself. + this.kubectlSecurityGroup = clusterSecurityGroup; + // use the cluster creation role to issue kubectl commands against the cluster because when the // cluster is first created, that's the only role that has "system:masters" permissions this.kubectlRole = this.adminRole; @@ -1587,7 +1585,7 @@ class ImportedCluster extends ClusterBase implements ICluster { this.kubectlRole = props.kubectlRoleArn ? iam.Role.fromRoleArn(this, 'KubectlRole', props.kubectlRoleArn) : undefined; this.kubectlSecurityGroup = props.kubectlSecurityGroupId ? ec2.SecurityGroup.fromSecurityGroupId(this, 'KubectlSecurityGroup', props.kubectlSecurityGroupId) : undefined; this.kubectlEnvironment = props.kubectlEnvironment; - this.kubectlPrivateSubnets = props.kubectlPrivateSubnetIds ? props.kubectlPrivateSubnetIds.map(subnetid => ec2.Subnet.fromSubnetId(this, `KubectlSubnet${subnetid}`, subnetid)) : undefined; + this.kubectlPrivateSubnets = props.kubectlPrivateSubnetIds ? props.kubectlPrivateSubnetIds.map((subnetid, index) => ec2.Subnet.fromSubnetId(this, `KubectlSubnet${index}`, subnetid)) : undefined; this.kubectlLayer = props.kubectlLayer; let i = 1; @@ -1595,6 +1593,10 @@ class ImportedCluster extends ClusterBase implements ICluster { this.connections.addSecurityGroup(ec2.SecurityGroup.fromSecurityGroupId(this, `SecurityGroup${i}`, sgid)); i++; } + + if (props.clusterSecurityGroupId) { + this.connections.addSecurityGroup(ec2.SecurityGroup.fromSecurityGroupId(this, 'ClusterSecurityGroup', props.clusterSecurityGroupId)); + } } public get vpc() { diff --git a/packages/@aws-cdk/aws-eks/package.json b/packages/@aws-cdk/aws-eks/package.json index 66643584593eb..8dfe97519e1d3 100644 --- a/packages/@aws-cdk/aws-eks/package.json +++ b/packages/@aws-cdk/aws-eks/package.json @@ -65,7 +65,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", - "@types/yaml": "1.2.0", + "@types/yaml": "1.9.6", "aws-sdk": "^2.739.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", 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 6f10ead0fe30d..13bba49cd6cf4 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 @@ -581,27 +581,6 @@ } } }, - "ClusterControlPlaneSecurityGroupfromawscdkeksclusterprivateendpointtestClusterKubectlProviderSecurityGroup6A0B729C443DF3A2707": { - "Type": "AWS::EC2::SecurityGroupIngress", - "Properties": { - "IpProtocol": "tcp", - "Description": "from awscdkeksclusterprivateendpointtestClusterKubectlProviderSecurityGroup6A0B729C:443", - "FromPort": 443, - "GroupId": { - "Fn::GetAtt": [ - "ClusterControlPlaneSecurityGroupD274242C", - "GroupId" - ] - }, - "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "ClusterKubectlProviderSecurityGroup2D90691C", - "GroupId" - ] - }, - "ToPort": 443 - } - }, "ClusterCreationRole360249B6": { "Type": "AWS::IAM::Role", "Properties": { @@ -630,7 +609,6 @@ } }, "DependsOn": [ - "ClusterKubectlProviderSecurityGroup2D90691C", "VpcIGWD7BA715C", "VpcPrivateSubnet1DefaultRouteBE02A9ED", "VpcPrivateSubnet1RouteTableB2C5B500", @@ -753,7 +731,6 @@ ] }, "DependsOn": [ - "ClusterKubectlProviderSecurityGroup2D90691C", "VpcIGWD7BA715C", "VpcPrivateSubnet1DefaultRouteBE02A9ED", "VpcPrivateSubnet1RouteTableB2C5B500", @@ -844,7 +821,6 @@ "AttributesRevision": 2 }, "DependsOn": [ - "ClusterKubectlProviderSecurityGroup2D90691C", "ClusterCreationRoleDefaultPolicyE8BDFC7B", "ClusterCreationRole360249B6", "VpcIGWD7BA715C", @@ -880,22 +856,6 @@ "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, - "ClusterKubectlProviderSecurityGroup2D90691C": { - "Type": "AWS::EC2::SecurityGroup", - "Properties": { - "GroupDescription": "Comminication between KubectlProvider and EKS Control Plane", - "SecurityGroupEgress": [ - { - "CidrIp": "0.0.0.0/0", - "Description": "Allow all outbound traffic by default", - "IpProtocol": "-1" - } - ], - "VpcId": { - "Ref": "Vpc8378EB38" - } - } - }, "ClusterKubectlReadyBarrier200052AF": { "Type": "AWS::SSM::Parameter", "Properties": { @@ -1168,7 +1128,7 @@ }, "/", { - "Ref": "AssetParametersdaac37af2b50452c854a73ef7e2c57d5229667e390db39773ffb9dfb497bbd20S3Bucket12418C8C" + "Ref": "AssetParameterse843c57c7bcb07856b1680280dc9387725661764509856e890ae6e18a5e40796S3Bucket39E2BF35" }, "/", { @@ -1178,7 +1138,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdaac37af2b50452c854a73ef7e2c57d5229667e390db39773ffb9dfb497bbd20S3VersionKey8C9B24CA" + "Ref": "AssetParameterse843c57c7bcb07856b1680280dc9387725661764509856e890ae6e18a5e40796S3VersionKey0218A255" } ] } @@ -1191,7 +1151,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdaac37af2b50452c854a73ef7e2c57d5229667e390db39773ffb9dfb497bbd20S3VersionKey8C9B24CA" + "Ref": "AssetParameterse843c57c7bcb07856b1680280dc9387725661764509856e890ae6e18a5e40796S3VersionKey0218A255" } ] } @@ -1228,10 +1188,10 @@ "referencetoawscdkeksclusterprivateendpointtestVpcPrivateSubnet3SubnetC47FD39ARef": { "Ref": "VpcPrivateSubnet3SubnetF258B56E" }, - "referencetoawscdkeksclusterprivateendpointtestClusterKubectlProviderSecurityGroup67FA4325GroupId": { + "referencetoawscdkeksclusterprivateendpointtestClusterF4CF4FE8ClusterSecurityGroupId": { "Fn::GetAtt": [ - "ClusterKubectlProviderSecurityGroup2D90691C", - "GroupId" + "Cluster9EE0221C", + "ClusterSecurityGroupId" ] }, "referencetoawscdkeksclusterprivateendpointtestAssetParameters34131c2e554ab57ad3a47fc0a13173a5c2a4b65a7582fe9622277b3d04c8e1e1S3Bucket41FE7429Ref": { @@ -1335,17 +1295,17 @@ "Type": "String", "Description": "Artifact hash for asset \"570f91ed45d0c45e8ff145969f7499419312e806c83f009b76539ce989960e51\"" }, - "AssetParametersdaac37af2b50452c854a73ef7e2c57d5229667e390db39773ffb9dfb497bbd20S3Bucket12418C8C": { + "AssetParameterse843c57c7bcb07856b1680280dc9387725661764509856e890ae6e18a5e40796S3Bucket39E2BF35": { "Type": "String", - "Description": "S3 bucket for asset \"daac37af2b50452c854a73ef7e2c57d5229667e390db39773ffb9dfb497bbd20\"" + "Description": "S3 bucket for asset \"e843c57c7bcb07856b1680280dc9387725661764509856e890ae6e18a5e40796\"" }, - "AssetParametersdaac37af2b50452c854a73ef7e2c57d5229667e390db39773ffb9dfb497bbd20S3VersionKey8C9B24CA": { + "AssetParameterse843c57c7bcb07856b1680280dc9387725661764509856e890ae6e18a5e40796S3VersionKey0218A255": { "Type": "String", - "Description": "S3 key for asset version \"daac37af2b50452c854a73ef7e2c57d5229667e390db39773ffb9dfb497bbd20\"" + "Description": "S3 key for asset version \"e843c57c7bcb07856b1680280dc9387725661764509856e890ae6e18a5e40796\"" }, - "AssetParametersdaac37af2b50452c854a73ef7e2c57d5229667e390db39773ffb9dfb497bbd20ArtifactHash90BA6C4A": { + "AssetParameterse843c57c7bcb07856b1680280dc9387725661764509856e890ae6e18a5e40796ArtifactHash0AFD7EAC": { "Type": "String", - "Description": "Artifact hash for asset \"daac37af2b50452c854a73ef7e2c57d5229667e390db39773ffb9dfb497bbd20\"" + "Description": "Artifact hash for asset \"e843c57c7bcb07856b1680280dc9387725661764509856e890ae6e18a5e40796\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json index de3b921a2755b..b015b80826d45 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 @@ -4,24 +4,26 @@ "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { - "Statement": [{ - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::12345678:root" + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::12345678:root" + ] ] - ] + } } } - }], + ], "Version": "2012-10-17" } } @@ -30,41 +32,43 @@ "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::12345678:root" + "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::12345678:root" + ] ] - ] - } - }, - "Resource": "*" - }], + } + }, + "Resource": "*" + } + ], "Version": "2012-10-17" } }, @@ -78,10 +82,12 @@ "EnableDnsHostnames": true, "EnableDnsSupport": true, "InstanceTenancy": "default", - "Tags": [{ - "Key": "Name", - "Value": "aws-cdk-eks-cluster-test/Vpc" - }] + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-eks-cluster-test/Vpc" + } + ] } }, "VpcPublicSubnet1Subnet5C2D37C4": { @@ -93,7 +99,8 @@ }, "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": true, - "Tags": [{ + "Tags": [ + { "Key": "aws-cdk:subnet-name", "Value": "Public" }, @@ -118,7 +125,8 @@ "VpcId": { "Ref": "Vpc8378EB38" }, - "Tags": [{ + "Tags": [ + { "Key": "kubernetes.io/role/elb", "Value": "1" }, @@ -159,7 +167,8 @@ "Type": "AWS::EC2::EIP", "Properties": { "Domain": "vpc", - "Tags": [{ + "Tags": [ + { "Key": "kubernetes.io/role/elb", "Value": "1" }, @@ -182,7 +191,8 @@ "SubnetId": { "Ref": "VpcPublicSubnet1Subnet5C2D37C4" }, - "Tags": [{ + "Tags": [ + { "Key": "kubernetes.io/role/elb", "Value": "1" }, @@ -202,7 +212,8 @@ }, "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": true, - "Tags": [{ + "Tags": [ + { "Key": "aws-cdk:subnet-name", "Value": "Public" }, @@ -227,7 +238,8 @@ "VpcId": { "Ref": "Vpc8378EB38" }, - "Tags": [{ + "Tags": [ + { "Key": "kubernetes.io/role/elb", "Value": "1" }, @@ -273,7 +285,8 @@ }, "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": true, - "Tags": [{ + "Tags": [ + { "Key": "aws-cdk:subnet-name", "Value": "Public" }, @@ -298,7 +311,8 @@ "VpcId": { "Ref": "Vpc8378EB38" }, - "Tags": [{ + "Tags": [ + { "Key": "kubernetes.io/role/elb", "Value": "1" }, @@ -344,7 +358,8 @@ }, "AvailabilityZone": "test-region-1a", "MapPublicIpOnLaunch": false, - "Tags": [{ + "Tags": [ + { "Key": "aws-cdk:subnet-name", "Value": "Private" }, @@ -369,7 +384,8 @@ "VpcId": { "Ref": "Vpc8378EB38" }, - "Tags": [{ + "Tags": [ + { "Key": "kubernetes.io/role/internal-elb", "Value": "1" }, @@ -412,7 +428,8 @@ }, "AvailabilityZone": "test-region-1b", "MapPublicIpOnLaunch": false, - "Tags": [{ + "Tags": [ + { "Key": "aws-cdk:subnet-name", "Value": "Private" }, @@ -437,7 +454,8 @@ "VpcId": { "Ref": "Vpc8378EB38" }, - "Tags": [{ + "Tags": [ + { "Key": "kubernetes.io/role/internal-elb", "Value": "1" }, @@ -480,7 +498,8 @@ }, "AvailabilityZone": "test-region-1c", "MapPublicIpOnLaunch": false, - "Tags": [{ + "Tags": [ + { "Key": "aws-cdk:subnet-name", "Value": "Private" }, @@ -505,7 +524,8 @@ "VpcId": { "Ref": "Vpc8378EB38" }, - "Tags": [{ + "Tags": [ + { "Key": "kubernetes.io/role/internal-elb", "Value": "1" }, @@ -542,10 +562,12 @@ "VpcIGWD7BA715C": { "Type": "AWS::EC2::InternetGateway", "Properties": { - "Tags": [{ - "Key": "Name", - "Value": "aws-cdk-eks-cluster-test/Vpc" - }] + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-eks-cluster-test/Vpc" + } + ] } }, "VpcVPCGWBF912B6E": { @@ -563,64 +585,49 @@ "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { - "Statement": [{ - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "eks.amazonaws.com" + "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" + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/AmazonEKSClusterPolicy" + ] ] - ] - }] + } + ] } }, "ClusterControlPlaneSecurityGroupD274242C": { "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" - }], + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], "VpcId": { "Ref": "Vpc8378EB38" } } }, - "ClusterControlPlaneSecurityGroupfromawscdkeksclustertestClusterKubectlProviderSecurityGroup0285626644359187EDA": { - "Type": "AWS::EC2::SecurityGroupIngress", - "Properties": { - "IpProtocol": "tcp", - "Description": "from awscdkeksclustertestClusterKubectlProviderSecurityGroup02856266:443", - "FromPort": 443, - "GroupId": { - "Fn::GetAtt": [ - "ClusterControlPlaneSecurityGroupD274242C", - "GroupId" - ] - }, - "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "ClusterKubectlProviderSecurityGroup2D90691C", - "GroupId" - ] - }, - "ToPort": 443 - } - }, "ClusterControlPlaneSecurityGroupfromawscdkeksclustertestClusterNodesInstanceSecurityGroupD0B64C54443795AF111": { "Type": "AWS::EC2::SecurityGroupIngress", "Properties": { @@ -730,29 +737,30 @@ "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { - "Statement": [{ - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::12345678:root" + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::12345678:root" + ] ] - ] + } } } - }], + ], "Version": "2012-10-17" } }, "DependsOn": [ - "ClusterKubectlProviderSecurityGroup2D90691C", "VpcIGWD7BA715C", "VpcPrivateSubnet1DefaultRouteBE02A9ED", "VpcPrivateSubnet1RouteTableB2C5B500", @@ -788,7 +796,8 @@ "Type": "AWS::IAM::Policy", "Properties": { "PolicyDocument": { - "Statement": [{ + "Statement": [ + { "Action": "iam:PassRole", "Effect": "Allow", "Resource": { @@ -892,12 +901,13 @@ "Version": "2012-10-17" }, "PolicyName": "ClusterCreationRoleDefaultPolicyE8BDFC7B", - "Roles": [{ - "Ref": "ClusterCreationRole360249B6" - }] + "Roles": [ + { + "Ref": "ClusterCreationRole360249B6" + } + ] }, "DependsOn": [ - "ClusterKubectlProviderSecurityGroup2D90691C", "VpcIGWD7BA715C", "VpcPrivateSubnet1DefaultRouteBE02A9ED", "VpcPrivateSubnet1RouteTableB2C5B500", @@ -946,21 +956,24 @@ "Arn" ] }, - "encryptionConfig": [{ - "provider": { - "keyArn": { - "Fn::GetAtt": [ - "SecretsKey317DCF94", - "Arn" - ] - } - }, - "resources": [ - "secrets" - ] - }], + "encryptionConfig": [ + { + "provider": { + "keyArn": { + "Fn::GetAtt": [ + "SecretsKey317DCF94", + "Arn" + ] + } + }, + "resources": [ + "secrets" + ] + } + ], "resourcesVpcConfig": { - "subnetIds": [{ + "subnetIds": [ + { "Ref": "VpcPublicSubnet1Subnet5C2D37C4" }, { @@ -979,12 +992,14 @@ "Ref": "VpcPrivateSubnet3SubnetF258B56E" } ], - "securityGroupIds": [{ - "Fn::GetAtt": [ - "ClusterControlPlaneSecurityGroupD274242C", - "GroupId" - ] - }], + "securityGroupIds": [ + { + "Fn::GetAtt": [ + "ClusterControlPlaneSecurityGroupD274242C", + "GroupId" + ] + } + ], "endpointPublicAccess": true, "endpointPrivateAccess": true } @@ -998,7 +1013,6 @@ "AttributesRevision": 2 }, "DependsOn": [ - "ClusterKubectlProviderSecurityGroup2D90691C", "ClusterCreationRoleDefaultPolicyE8BDFC7B", "ClusterCreationRole360249B6", "VpcIGWD7BA715C", @@ -1034,20 +1048,6 @@ "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, - "ClusterKubectlProviderSecurityGroup2D90691C": { - "Type": "AWS::EC2::SecurityGroup", - "Properties": { - "GroupDescription": "Comminication between KubectlProvider and EKS Control Plane", - "SecurityGroupEgress": [{ - "CidrIp": "0.0.0.0/0", - "Description": "Allow all outbound traffic by default", - "IpProtocol": "-1" - }], - "VpcId": { - "Ref": "Vpc8378EB38" - } - } - }, "ClusterKubectlReadyBarrier200052AF": { "Type": "AWS::SSM::Parameter", "Properties": { @@ -1062,6 +1062,111 @@ "Cluster9EE0221C" ] }, + "ClusterClusterSecurityGroupfromawscdkeksclustertestClusterNodesInstanceSecurityGroupD0B64C544432C10EDB4": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "Description": "from awscdkeksclustertestClusterNodesInstanceSecurityGroupD0B64C54:443", + "FromPort": 443, + "GroupId": { + "Fn::GetAtt": [ + "Cluster9EE0221C", + "ClusterSecurityGroupId" + ] + }, + "SourceSecurityGroupId": { + "Fn::GetAtt": [ + "ClusterNodesInstanceSecurityGroup899246BD", + "GroupId" + ] + }, + "ToPort": 443 + } + }, + "ClusterClusterSecurityGroupfromawscdkeksclustertestClusterNodesArmInstanceSecurityGroup52C45858443A88C1345": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "Description": "from awscdkeksclustertestClusterNodesArmInstanceSecurityGroup52C45858:443", + "FromPort": 443, + "GroupId": { + "Fn::GetAtt": [ + "Cluster9EE0221C", + "ClusterSecurityGroupId" + ] + }, + "SourceSecurityGroupId": { + "Fn::GetAtt": [ + "ClusterNodesArmInstanceSecurityGroup599F388B", + "GroupId" + ] + }, + "ToPort": 443 + } + }, + "ClusterClusterSecurityGroupfromawscdkeksclustertestClusterBottlerocketNodesInstanceSecurityGroup83FE7914443A80EB501": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "Description": "from awscdkeksclustertestClusterBottlerocketNodesInstanceSecurityGroup83FE7914:443", + "FromPort": 443, + "GroupId": { + "Fn::GetAtt": [ + "Cluster9EE0221C", + "ClusterSecurityGroupId" + ] + }, + "SourceSecurityGroupId": { + "Fn::GetAtt": [ + "ClusterBottlerocketNodesInstanceSecurityGroup3794A94B", + "GroupId" + ] + }, + "ToPort": 443 + } + }, + "ClusterClusterSecurityGroupfromawscdkeksclustertestClusterspotInstanceSecurityGroupF50F5D474432A818F38": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "Description": "from awscdkeksclustertestClusterspotInstanceSecurityGroupF50F5D47:443", + "FromPort": 443, + "GroupId": { + "Fn::GetAtt": [ + "Cluster9EE0221C", + "ClusterSecurityGroupId" + ] + }, + "SourceSecurityGroupId": { + "Fn::GetAtt": [ + "ClusterspotInstanceSecurityGroup01F7B1CE", + "GroupId" + ] + }, + "ToPort": 443 + } + }, + "ClusterClusterSecurityGroupfromawscdkeksclustertestClusterInferenceInstancesInstanceSecurityGroup42C57C5144320402117": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "Description": "from awscdkeksclustertestClusterInferenceInstancesInstanceSecurityGroup42C57C51:443", + "FromPort": 443, + "GroupId": { + "Fn::GetAtt": [ + "Cluster9EE0221C", + "ClusterSecurityGroupId" + ] + }, + "SourceSecurityGroupId": { + "Fn::GetAtt": [ + "ClusterInferenceInstancesInstanceSecurityGroupECB3FC45", + "GroupId" + ] + }, + "ToPort": 443 + } + }, "ClusterAwsAuthmanifestFE51F8AE": { "Type": "Custom::AWSCDK-EKS-KubernetesResource", "Properties": { @@ -1183,26 +1288,29 @@ "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { - "Statement": [{ - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": { - "Fn::Join": [ - "", - [ - "ec2.", - { - "Ref": "AWS::URLSuffix" - } + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ec2.", + { + "Ref": "AWS::URLSuffix" + } + ] ] - ] + } } } - }], + ], "Version": "2012-10-17" }, - "ManagedPolicyArns": [{ + "ManagedPolicyArns": [ + { "Fn::Join": [ "", [ @@ -1253,7 +1361,8 @@ "Arn" ] }, - "Subnets": [{ + "Subnets": [ + { "Ref": "VpcPrivateSubnet1Subnet536B997A" }, { @@ -1279,27 +1388,31 @@ "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { - "Statement": [{ - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "eks-fargate-pods.amazonaws.com" + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "eks-fargate-pods.amazonaws.com" + } } - }], + ], "Version": "2012-10-17" }, - "ManagedPolicyArns": [{ - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::aws:policy/AmazonEKSFargatePodExecutionRolePolicy" + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/AmazonEKSFargatePodExecutionRolePolicy" + ] ] - ] - }] + } + ] } }, "ClusterfargateprofiledefaultEFC59F14": { @@ -1327,9 +1440,11 @@ "Arn" ] }, - "selectors": [{ - "namespace": "default" - }] + "selectors": [ + { + "namespace": "default" + } + ] } }, "UpdateReplacePolicy": "Delete", @@ -1339,12 +1454,15 @@ "Type": "AWS::EC2::SecurityGroup", "Properties": { "GroupDescription": "aws-cdk-eks-cluster-test/Cluster/Nodes/InstanceSecurityGroup", - "SecurityGroupEgress": [{ - "CidrIp": "0.0.0.0/0", - "Description": "Allow all outbound traffic by default", - "IpProtocol": "-1" - }], - "Tags": [{ + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "Tags": [ + { "Key": { "Fn::Join": [ "", @@ -1387,6 +1505,27 @@ } } }, + "ClusterNodesInstanceSecurityGroupfromawscdkeksclustertestClusterClusterSecurityGroupF7265A32443DC7FAF39": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "Description": "from awscdkeksclustertestClusterClusterSecurityGroupF7265A32:443", + "FromPort": 443, + "GroupId": { + "Fn::GetAtt": [ + "ClusterNodesInstanceSecurityGroup899246BD", + "GroupId" + ] + }, + "SourceSecurityGroupId": { + "Fn::GetAtt": [ + "Cluster9EE0221C", + "ClusterSecurityGroupId" + ] + }, + "ToPort": 443 + } + }, "ClusterNodesInstanceSecurityGroupfromawscdkeksclustertestClusterControlPlaneSecurityGroup2F130134443AE10EB12": { "Type": "AWS::EC2::SecurityGroupIngress", "Properties": { @@ -1408,6 +1547,27 @@ "ToPort": 443 } }, + "ClusterNodesInstanceSecurityGroupfromawscdkeksclustertestClusterClusterSecurityGroupF7265A32102565535D6A46ADB": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "Description": "from awscdkeksclustertestClusterClusterSecurityGroupF7265A32:1025-65535", + "FromPort": 1025, + "GroupId": { + "Fn::GetAtt": [ + "ClusterNodesInstanceSecurityGroup899246BD", + "GroupId" + ] + }, + "SourceSecurityGroupId": { + "Fn::GetAtt": [ + "Cluster9EE0221C", + "ClusterSecurityGroupId" + ] + }, + "ToPort": 65535 + } + }, "ClusterNodesInstanceSecurityGroupfromawscdkeksclustertestClusterControlPlaneSecurityGroup2F1301341025655359F401D0D": { "Type": "AWS::EC2::SecurityGroupIngress", "Properties": { @@ -1433,26 +1593,29 @@ "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { - "Statement": [{ - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": { - "Fn::Join": [ - "", - [ - "ec2.", - { - "Ref": "AWS::URLSuffix" - } + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ec2.", + { + "Ref": "AWS::URLSuffix" + } + ] ] - ] + } } } - }], + ], "Version": "2012-10-17" }, - "ManagedPolicyArns": [{ + "ManagedPolicyArns": [ + { "Fn::Join": [ "", [ @@ -1489,7 +1652,8 @@ ] } ], - "Tags": [{ + "Tags": [ + { "Key": { "Fn::Join": [ "", @@ -1513,9 +1677,11 @@ "ClusterNodesInstanceProfileF2DD0E21": { "Type": "AWS::IAM::InstanceProfile", "Properties": { - "Roles": [{ - "Ref": "ClusterNodesInstanceRoleC3C01328" - }] + "Roles": [ + { + "Ref": "ClusterNodesInstanceRoleC3C01328" + } + ] } }, "ClusterNodesLaunchConfig7C420A27": { @@ -1528,12 +1694,14 @@ "IamInstanceProfile": { "Ref": "ClusterNodesInstanceProfileF2DD0E21" }, - "SecurityGroups": [{ - "Fn::GetAtt": [ - "ClusterNodesInstanceSecurityGroup899246BD", - "GroupId" - ] - }], + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "ClusterNodesInstanceSecurityGroup899246BD", + "GroupId" + ] + } + ], "UserData": { "Fn::Base64": { "Fn::Join": [ @@ -1561,7 +1729,8 @@ "LaunchConfigurationName": { "Ref": "ClusterNodesLaunchConfig7C420A27" }, - "Tags": [{ + "Tags": [ + { "Key": { "Fn::Join": [ "", @@ -1582,7 +1751,8 @@ "Value": "aws-cdk-eks-cluster-test/Cluster/Nodes" } ], - "VPCZoneIdentifier": [{ + "VPCZoneIdentifier": [ + { "Ref": "VpcPrivateSubnet1Subnet536B997A" }, { @@ -1603,12 +1773,15 @@ "Type": "AWS::EC2::SecurityGroup", "Properties": { "GroupDescription": "aws-cdk-eks-cluster-test/Cluster/NodesArm/InstanceSecurityGroup", - "SecurityGroupEgress": [{ - "CidrIp": "0.0.0.0/0", - "Description": "Allow all outbound traffic by default", - "IpProtocol": "-1" - }], - "Tags": [{ + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "Tags": [ + { "Key": { "Fn::Join": [ "", @@ -1651,6 +1824,27 @@ } } }, + "ClusterNodesArmInstanceSecurityGroupfromawscdkeksclustertestClusterClusterSecurityGroupF7265A32443AC8AE5BF": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "Description": "from awscdkeksclustertestClusterClusterSecurityGroupF7265A32:443", + "FromPort": 443, + "GroupId": { + "Fn::GetAtt": [ + "ClusterNodesArmInstanceSecurityGroup599F388B", + "GroupId" + ] + }, + "SourceSecurityGroupId": { + "Fn::GetAtt": [ + "Cluster9EE0221C", + "ClusterSecurityGroupId" + ] + }, + "ToPort": 443 + } + }, "ClusterNodesArmInstanceSecurityGroupfromawscdkeksclustertestClusterControlPlaneSecurityGroup2F13013444328ED4211": { "Type": "AWS::EC2::SecurityGroupIngress", "Properties": { @@ -1672,6 +1866,27 @@ "ToPort": 443 } }, + "ClusterNodesArmInstanceSecurityGroupfromawscdkeksclustertestClusterClusterSecurityGroupF7265A32102565535F5718241": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "Description": "from awscdkeksclustertestClusterClusterSecurityGroupF7265A32:1025-65535", + "FromPort": 1025, + "GroupId": { + "Fn::GetAtt": [ + "ClusterNodesArmInstanceSecurityGroup599F388B", + "GroupId" + ] + }, + "SourceSecurityGroupId": { + "Fn::GetAtt": [ + "Cluster9EE0221C", + "ClusterSecurityGroupId" + ] + }, + "ToPort": 65535 + } + }, "ClusterNodesArmInstanceSecurityGroupfromawscdkeksclustertestClusterControlPlaneSecurityGroup2F13013410256553586052D07": { "Type": "AWS::EC2::SecurityGroupIngress", "Properties": { @@ -1697,26 +1912,29 @@ "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { - "Statement": [{ - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": { - "Fn::Join": [ - "", - [ - "ec2.", - { - "Ref": "AWS::URLSuffix" - } + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ec2.", + { + "Ref": "AWS::URLSuffix" + } + ] ] - ] + } } } - }], + ], "Version": "2012-10-17" }, - "ManagedPolicyArns": [{ + "ManagedPolicyArns": [ + { "Fn::Join": [ "", [ @@ -1753,7 +1971,8 @@ ] } ], - "Tags": [{ + "Tags": [ + { "Key": { "Fn::Join": [ "", @@ -1777,9 +1996,11 @@ "ClusterNodesArmInstanceProfile158C5C9F": { "Type": "AWS::IAM::InstanceProfile", "Properties": { - "Roles": [{ - "Ref": "ClusterNodesArmInstanceRoleB93D3298" - }] + "Roles": [ + { + "Ref": "ClusterNodesArmInstanceRoleB93D3298" + } + ] } }, "ClusterNodesArmLaunchConfigAAF61344": { @@ -1792,12 +2013,14 @@ "IamInstanceProfile": { "Ref": "ClusterNodesArmInstanceProfile158C5C9F" }, - "SecurityGroups": [{ - "Fn::GetAtt": [ - "ClusterNodesArmInstanceSecurityGroup599F388B", - "GroupId" - ] - }], + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "ClusterNodesArmInstanceSecurityGroup599F388B", + "GroupId" + ] + } + ], "UserData": { "Fn::Base64": { "Fn::Join": [ @@ -1825,7 +2048,8 @@ "LaunchConfigurationName": { "Ref": "ClusterNodesArmLaunchConfigAAF61344" }, - "Tags": [{ + "Tags": [ + { "Key": { "Fn::Join": [ "", @@ -1846,7 +2070,8 @@ "Value": "aws-cdk-eks-cluster-test/Cluster/NodesArm" } ], - "VPCZoneIdentifier": [{ + "VPCZoneIdentifier": [ + { "Ref": "VpcPrivateSubnet1Subnet536B997A" }, { @@ -1867,12 +2092,15 @@ "Type": "AWS::EC2::SecurityGroup", "Properties": { "GroupDescription": "aws-cdk-eks-cluster-test/Cluster/BottlerocketNodes/InstanceSecurityGroup", - "SecurityGroupEgress": [{ - "CidrIp": "0.0.0.0/0", - "Description": "Allow all outbound traffic by default", - "IpProtocol": "-1" - }], - "Tags": [{ + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "Tags": [ + { "Key": { "Fn::Join": [ "", @@ -1915,6 +2143,27 @@ } } }, + "ClusterBottlerocketNodesInstanceSecurityGroupfromawscdkeksclustertestClusterClusterSecurityGroupF7265A32443D1686B16": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "Description": "from awscdkeksclustertestClusterClusterSecurityGroupF7265A32:443", + "FromPort": 443, + "GroupId": { + "Fn::GetAtt": [ + "ClusterBottlerocketNodesInstanceSecurityGroup3794A94B", + "GroupId" + ] + }, + "SourceSecurityGroupId": { + "Fn::GetAtt": [ + "Cluster9EE0221C", + "ClusterSecurityGroupId" + ] + }, + "ToPort": 443 + } + }, "ClusterBottlerocketNodesInstanceSecurityGroupfromawscdkeksclustertestClusterControlPlaneSecurityGroup2F130134443A6D43789": { "Type": "AWS::EC2::SecurityGroupIngress", "Properties": { @@ -1936,6 +2185,27 @@ "ToPort": 443 } }, + "ClusterBottlerocketNodesInstanceSecurityGroupfromawscdkeksclustertestClusterClusterSecurityGroupF7265A32102565535674E85A7": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "Description": "from awscdkeksclustertestClusterClusterSecurityGroupF7265A32:1025-65535", + "FromPort": 1025, + "GroupId": { + "Fn::GetAtt": [ + "ClusterBottlerocketNodesInstanceSecurityGroup3794A94B", + "GroupId" + ] + }, + "SourceSecurityGroupId": { + "Fn::GetAtt": [ + "Cluster9EE0221C", + "ClusterSecurityGroupId" + ] + }, + "ToPort": 65535 + } + }, "ClusterBottlerocketNodesInstanceSecurityGroupfromawscdkeksclustertestClusterControlPlaneSecurityGroup2F1301341025655352CE8AD9A": { "Type": "AWS::EC2::SecurityGroupIngress", "Properties": { @@ -1961,26 +2231,29 @@ "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { - "Statement": [{ - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": { - "Fn::Join": [ - "", - [ - "ec2.", - { - "Ref": "AWS::URLSuffix" - } + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ec2.", + { + "Ref": "AWS::URLSuffix" + } + ] ] - ] + } } } - }], + ], "Version": "2012-10-17" }, - "ManagedPolicyArns": [{ + "ManagedPolicyArns": [ + { "Fn::Join": [ "", [ @@ -2017,7 +2290,8 @@ ] } ], - "Tags": [{ + "Tags": [ + { "Key": { "Fn::Join": [ "", @@ -2041,9 +2315,11 @@ "ClusterBottlerocketNodesInstanceProfileB6E2F25A": { "Type": "AWS::IAM::InstanceProfile", "Properties": { - "Roles": [{ - "Ref": "ClusterBottlerocketNodesInstanceRole68E4BCFB" - }] + "Roles": [ + { + "Ref": "ClusterBottlerocketNodesInstanceRole68E4BCFB" + } + ] } }, "ClusterBottlerocketNodesLaunchConfig76D7BEBE": { @@ -2056,12 +2332,14 @@ "IamInstanceProfile": { "Ref": "ClusterBottlerocketNodesInstanceProfileB6E2F25A" }, - "SecurityGroups": [{ - "Fn::GetAtt": [ - "ClusterBottlerocketNodesInstanceSecurityGroup3794A94B", - "GroupId" - ] - }], + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "ClusterBottlerocketNodesInstanceSecurityGroup3794A94B", + "GroupId" + ] + } + ], "UserData": { "Fn::Base64": { "Fn::Join": [ @@ -2103,7 +2381,8 @@ "LaunchConfigurationName": { "Ref": "ClusterBottlerocketNodesLaunchConfig76D7BEBE" }, - "Tags": [{ + "Tags": [ + { "Key": { "Fn::Join": [ "", @@ -2124,7 +2403,8 @@ "Value": "aws-cdk-eks-cluster-test/Cluster/BottlerocketNodes" } ], - "VPCZoneIdentifier": [{ + "VPCZoneIdentifier": [ + { "Ref": "VpcPrivateSubnet1Subnet536B997A" }, { @@ -2145,12 +2425,15 @@ "Type": "AWS::EC2::SecurityGroup", "Properties": { "GroupDescription": "aws-cdk-eks-cluster-test/Cluster/spot/InstanceSecurityGroup", - "SecurityGroupEgress": [{ - "CidrIp": "0.0.0.0/0", - "Description": "Allow all outbound traffic by default", - "IpProtocol": "-1" - }], - "Tags": [{ + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "Tags": [ + { "Key": { "Fn::Join": [ "", @@ -2187,10 +2470,31 @@ }, "SourceSecurityGroupId": { "Fn::GetAtt": [ - "ClusterspotInstanceSecurityGroup01F7B1CE", - "GroupId" + "ClusterspotInstanceSecurityGroup01F7B1CE", + "GroupId" + ] + } + } + }, + "ClusterspotInstanceSecurityGroupfromawscdkeksclustertestClusterClusterSecurityGroupF7265A324438F751704": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "Description": "from awscdkeksclustertestClusterClusterSecurityGroupF7265A32:443", + "FromPort": 443, + "GroupId": { + "Fn::GetAtt": [ + "ClusterspotInstanceSecurityGroup01F7B1CE", + "GroupId" + ] + }, + "SourceSecurityGroupId": { + "Fn::GetAtt": [ + "Cluster9EE0221C", + "ClusterSecurityGroupId" ] - } + }, + "ToPort": 443 } }, "ClusterspotInstanceSecurityGroupfromawscdkeksclustertestClusterControlPlaneSecurityGroup2F1301344430650F325": { @@ -2214,6 +2518,27 @@ "ToPort": 443 } }, + "ClusterspotInstanceSecurityGroupfromawscdkeksclustertestClusterClusterSecurityGroupF7265A321025655350D837827": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "Description": "from awscdkeksclustertestClusterClusterSecurityGroupF7265A32:1025-65535", + "FromPort": 1025, + "GroupId": { + "Fn::GetAtt": [ + "ClusterspotInstanceSecurityGroup01F7B1CE", + "GroupId" + ] + }, + "SourceSecurityGroupId": { + "Fn::GetAtt": [ + "Cluster9EE0221C", + "ClusterSecurityGroupId" + ] + }, + "ToPort": 65535 + } + }, "ClusterspotInstanceSecurityGroupfromawscdkeksclustertestClusterControlPlaneSecurityGroup2F130134102565535C7203235": { "Type": "AWS::EC2::SecurityGroupIngress", "Properties": { @@ -2239,26 +2564,29 @@ "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { - "Statement": [{ - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": { - "Fn::Join": [ - "", - [ - "ec2.", - { - "Ref": "AWS::URLSuffix" - } + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ec2.", + { + "Ref": "AWS::URLSuffix" + } + ] ] - ] + } } } - }], + ], "Version": "2012-10-17" }, - "ManagedPolicyArns": [{ + "ManagedPolicyArns": [ + { "Fn::Join": [ "", [ @@ -2295,7 +2623,8 @@ ] } ], - "Tags": [{ + "Tags": [ + { "Key": { "Fn::Join": [ "", @@ -2319,9 +2648,11 @@ "ClusterspotInstanceProfileAB88D077": { "Type": "AWS::IAM::InstanceProfile", "Properties": { - "Roles": [{ - "Ref": "ClusterspotInstanceRole39043830" - }] + "Roles": [ + { + "Ref": "ClusterspotInstanceRole39043830" + } + ] } }, "ClusterspotLaunchConfigCC19F2E6": { @@ -2334,12 +2665,14 @@ "IamInstanceProfile": { "Ref": "ClusterspotInstanceProfileAB88D077" }, - "SecurityGroups": [{ - "Fn::GetAtt": [ - "ClusterspotInstanceSecurityGroup01F7B1CE", - "GroupId" - ] - }], + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "ClusterspotInstanceSecurityGroup01F7B1CE", + "GroupId" + ] + } + ], "SpotPrice": "0.1094", "UserData": { "Fn::Base64": { @@ -2368,7 +2701,8 @@ "LaunchConfigurationName": { "Ref": "ClusterspotLaunchConfigCC19F2E6" }, - "Tags": [{ + "Tags": [ + { "Key": { "Fn::Join": [ "", @@ -2389,7 +2723,8 @@ "Value": "aws-cdk-eks-cluster-test/Cluster/spot" } ], - "VPCZoneIdentifier": [{ + "VPCZoneIdentifier": [ + { "Ref": "VpcPrivateSubnet1Subnet536B997A" }, { @@ -2442,12 +2777,15 @@ "Type": "AWS::EC2::SecurityGroup", "Properties": { "GroupDescription": "aws-cdk-eks-cluster-test/Cluster/InferenceInstances/InstanceSecurityGroup", - "SecurityGroupEgress": [{ - "CidrIp": "0.0.0.0/0", - "Description": "Allow all outbound traffic by default", - "IpProtocol": "-1" - }], - "Tags": [{ + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "Tags": [ + { "Key": { "Fn::Join": [ "", @@ -2490,6 +2828,27 @@ } } }, + "ClusterInferenceInstancesInstanceSecurityGroupfromawscdkeksclustertestClusterClusterSecurityGroupF7265A32443F6A7B9A5": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "Description": "from awscdkeksclustertestClusterClusterSecurityGroupF7265A32:443", + "FromPort": 443, + "GroupId": { + "Fn::GetAtt": [ + "ClusterInferenceInstancesInstanceSecurityGroupECB3FC45", + "GroupId" + ] + }, + "SourceSecurityGroupId": { + "Fn::GetAtt": [ + "Cluster9EE0221C", + "ClusterSecurityGroupId" + ] + }, + "ToPort": 443 + } + }, "ClusterInferenceInstancesInstanceSecurityGroupfromawscdkeksclustertestClusterControlPlaneSecurityGroup2F1301344437B48FD33": { "Type": "AWS::EC2::SecurityGroupIngress", "Properties": { @@ -2511,6 +2870,27 @@ "ToPort": 443 } }, + "ClusterInferenceInstancesInstanceSecurityGroupfromawscdkeksclustertestClusterClusterSecurityGroupF7265A321025655351C7B1E72": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "Description": "from awscdkeksclustertestClusterClusterSecurityGroupF7265A32:1025-65535", + "FromPort": 1025, + "GroupId": { + "Fn::GetAtt": [ + "ClusterInferenceInstancesInstanceSecurityGroupECB3FC45", + "GroupId" + ] + }, + "SourceSecurityGroupId": { + "Fn::GetAtt": [ + "Cluster9EE0221C", + "ClusterSecurityGroupId" + ] + }, + "ToPort": 65535 + } + }, "ClusterInferenceInstancesInstanceSecurityGroupfromawscdkeksclustertestClusterControlPlaneSecurityGroup2F130134102565535A460F673": { "Type": "AWS::EC2::SecurityGroupIngress", "Properties": { @@ -2536,26 +2916,29 @@ "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { - "Statement": [{ - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": { - "Fn::Join": [ - "", - [ - "ec2.", - { - "Ref": "AWS::URLSuffix" - } + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ec2.", + { + "Ref": "AWS::URLSuffix" + } + ] ] - ] + } } } - }], + ], "Version": "2012-10-17" }, - "ManagedPolicyArns": [{ + "ManagedPolicyArns": [ + { "Fn::Join": [ "", [ @@ -2592,7 +2975,8 @@ ] } ], - "Tags": [{ + "Tags": [ + { "Key": { "Fn::Join": [ "", @@ -2616,9 +3000,11 @@ "ClusterInferenceInstancesInstanceProfile5A1209B4": { "Type": "AWS::IAM::InstanceProfile", "Properties": { - "Roles": [{ - "Ref": "ClusterInferenceInstancesInstanceRole59AC6F56" - }] + "Roles": [ + { + "Ref": "ClusterInferenceInstancesInstanceRole59AC6F56" + } + ] } }, "ClusterInferenceInstancesLaunchConfig03BF48FE": { @@ -2631,12 +3017,14 @@ "IamInstanceProfile": { "Ref": "ClusterInferenceInstancesInstanceProfile5A1209B4" }, - "SecurityGroups": [{ - "Fn::GetAtt": [ - "ClusterInferenceInstancesInstanceSecurityGroupECB3FC45", - "GroupId" - ] - }], + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "ClusterInferenceInstancesInstanceSecurityGroupECB3FC45", + "GroupId" + ] + } + ], "UserData": { "Fn::Base64": { "Fn::Join": [ @@ -2664,7 +3052,8 @@ "LaunchConfigurationName": { "Ref": "ClusterInferenceInstancesLaunchConfig03BF48FE" }, - "Tags": [{ + "Tags": [ + { "Key": { "Fn::Join": [ "", @@ -2685,7 +3074,8 @@ "Value": "aws-cdk-eks-cluster-test/Cluster/InferenceInstances" } ], - "VPCZoneIdentifier": [{ + "VPCZoneIdentifier": [ + { "Ref": "VpcPrivateSubnet1Subnet536B997A" }, { @@ -2732,26 +3122,29 @@ "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { - "Statement": [{ - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": { - "Fn::Join": [ - "", - [ - "ec2.", - { - "Ref": "AWS::URLSuffix" - } + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ec2.", + { + "Ref": "AWS::URLSuffix" + } + ] ] - ] + } } } - }], + ], "Version": "2012-10-17" }, - "ManagedPolicyArns": [{ + "ManagedPolicyArns": [ + { "Fn::Join": [ "", [ @@ -2802,7 +3195,8 @@ "Arn" ] }, - "Subnets": [{ + "Subnets": [ + { "Ref": "VpcPrivateSubnet1Subnet536B997A" }, { @@ -2828,26 +3222,29 @@ "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { - "Statement": [{ - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": { - "Fn::Join": [ - "", - [ - "ec2.", - { - "Ref": "AWS::URLSuffix" - } + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ec2.", + { + "Ref": "AWS::URLSuffix" + } + ] ] - ] + } } } - }], + ], "Version": "2012-10-17" }, - "ManagedPolicyArns": [{ + "ManagedPolicyArns": [ + { "Fn::Join": [ "", [ @@ -2898,7 +3295,8 @@ "Arn" ] }, - "Subnets": [{ + "Subnets": [ + { "Ref": "VpcPrivateSubnet1Subnet536B997A" }, { @@ -2932,7 +3330,8 @@ "Arn" ] }, - "Subnets": [{ + "Subnets": [ + { "Ref": "VpcPrivateSubnet1Subnet536B997A" }, { @@ -3114,23 +3513,25 @@ "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { - "Statement": [{ - "Action": "sts:AssumeRoleWithWebIdentity", - "Condition": { - "StringEquals": { - "Fn::GetAtt": [ - "ClusterMyServiceAccountConditionJson671C0633", - "Value" - ] - } - }, - "Effect": "Allow", - "Principal": { - "Federated": { - "Ref": "ClusterOpenIdConnectProviderE7EB0530" + "Statement": [ + { + "Action": "sts:AssumeRoleWithWebIdentity", + "Condition": { + "StringEquals": { + "Fn::GetAtt": [ + "ClusterMyServiceAccountConditionJson671C0633", + "Value" + ] + } + }, + "Effect": "Allow", + "Principal": { + "Federated": { + "Ref": "ClusterOpenIdConnectProviderE7EB0530" + } } } - }], + ], "Version": "2012-10-17" } } @@ -3376,7 +3777,7 @@ }, "/", { - "Ref": "AssetParametersa298dd278c9ef814ebac4c9d8b2dc8e1b8374a14c5b7d0e79f041a296668f5dcS3BucketCA7ADF01" + "Ref": "AssetParameters215e9f40bd76e7102c690b24b0922eb4963d2d24938eec175e107db683455d11S3BucketC456B560" }, "/", { @@ -3386,7 +3787,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersa298dd278c9ef814ebac4c9d8b2dc8e1b8374a14c5b7d0e79f041a296668f5dcS3VersionKey822F0346" + "Ref": "AssetParameters215e9f40bd76e7102c690b24b0922eb4963d2d24938eec175e107db683455d11S3VersionKeyA1DAD649" } ] } @@ -3399,7 +3800,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersa298dd278c9ef814ebac4c9d8b2dc8e1b8374a14c5b7d0e79f041a296668f5dcS3VersionKey822F0346" + "Ref": "AssetParameters215e9f40bd76e7102c690b24b0922eb4963d2d24938eec175e107db683455d11S3VersionKeyA1DAD649" } ] } @@ -3436,10 +3837,10 @@ "referencetoawscdkeksclustertestVpcPrivateSubnet3Subnet7F5D6918Ref": { "Ref": "VpcPrivateSubnet3SubnetF258B56E" }, - "referencetoawscdkeksclustertestClusterKubectlProviderSecurityGroupD167EE6BGroupId": { + "referencetoawscdkeksclustertestClusterD76DFF87ClusterSecurityGroupId": { "Fn::GetAtt": [ - "ClusterKubectlProviderSecurityGroup2D90691C", - "GroupId" + "Cluster9EE0221C", + "ClusterSecurityGroupId" ] }, "referencetoawscdkeksclustertestAssetParameters34131c2e554ab57ad3a47fc0a13173a5c2a4b65a7582fe9622277b3d04c8e1e1S3Bucket85526CA7Ref": { @@ -3480,17 +3881,21 @@ "Properties": { "AssumeRolePolicyDocument": { "Version": "2012-10-17", - "Statement": [{ - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "lambda.amazonaws.com" + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } } - }] + ] }, - "ManagedPolicyArns": [{ - "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - }] + "ManagedPolicyArns": [ + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + } + ] } }, "AWSCDKCfnUtilsProviderCustomResourceProviderHandlerCF82AA57": { @@ -3503,7 +3908,8 @@ "S3Key": { "Fn::Join": [ "", - [{ + [ + { "Fn::Select": [ 0, { @@ -3553,34 +3959,42 @@ "Properties": { "AssumeRolePolicyDocument": { "Version": "2012-10-17", - "Statement": [{ - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "lambda.amazonaws.com" - } - }] - }, - "ManagedPolicyArns": [{ - "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - }], - "Policies": [{ - "PolicyName": "Inline", - "PolicyDocument": { - "Version": "2012-10-17", - "Statement": [{ + "Statement": [ + { + "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": "*", - "Action": [ - "iam:CreateOpenIDConnectProvider", - "iam:DeleteOpenIDConnectProvider", - "iam:UpdateOpenIDConnectProviderThumbprint", - "iam:AddClientIDToOpenIDConnectProvider", - "iam:RemoveClientIDFromOpenIDConnectProvider" + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ] + }, + "ManagedPolicyArns": [ + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + } + ], + "Policies": [ + { + "PolicyName": "Inline", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Resource": "*", + "Action": [ + "iam:CreateOpenIDConnectProvider", + "iam:DeleteOpenIDConnectProvider", + "iam:UpdateOpenIDConnectProviderThumbprint", + "iam:AddClientIDToOpenIDConnectProvider", + "iam:RemoveClientIDFromOpenIDConnectProvider" + ] + } ] - }] + } } - }] + ] } }, "CustomAWSCDKOpenIdConnectProviderCustomResourceProviderHandlerF2C543E0": { @@ -3593,7 +4007,8 @@ "S3Key": { "Fn::Join": [ "", - [{ + [ + { "Fn::Select": [ 0, { @@ -3642,11 +4057,13 @@ "Type": "AWS::EC2::SecurityGroup", "Properties": { "GroupDescription": "aws-cdk-eks-cluster-test/WebServiceSecurityGroup", - "SecurityGroupEgress": [{ - "CidrIp": "0.0.0.0/0", - "Description": "Allow all outbound traffic by default", - "IpProtocol": "-1" - }], + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], "VpcId": { "Ref": "Vpc8378EB38" } @@ -3677,16 +4094,19 @@ "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { - "Statement": [{ - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "lambda.amazonaws.com" + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } } - }], + ], "Version": "2012-10-17" }, - "ManagedPolicyArns": [{ + "ManagedPolicyArns": [ + { "Fn::Join": [ "", [ @@ -3723,7 +4143,8 @@ "S3Key": { "Fn::Join": [ "", - [{ + [ + { "Fn::Select": [ 0, { @@ -3763,13 +4184,16 @@ "Runtime": "python3.6", "Timeout": 600, "VpcConfig": { - "SecurityGroupIds": [{ - "Fn::GetAtt": [ - "WebServiceSecurityGroupA556AEB5", - "GroupId" - ] - }], - "SubnetIds": [{ + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "WebServiceSecurityGroupA556AEB5", + "GroupId" + ] + } + ], + "SubnetIds": [ + { "Ref": "VpcPrivateSubnet1Subnet536B997A" }, { @@ -3789,49 +4213,57 @@ "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { - "Statement": [{ - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "lambda.amazonaws.com" + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } } - }], + ], "Version": "2012-10-17" }, - "ManagedPolicyArns": [{ - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] ] - ] - }] + } + ] } }, "ServicePingerProviderframeworkonEventServiceRoleDefaultPolicyD142E8F7": { "Type": "AWS::IAM::Policy", "Properties": { "PolicyDocument": { - "Statement": [{ - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "ServicePingerFunctionADF51BAF", - "Arn" - ] + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "ServicePingerFunctionADF51BAF", + "Arn" + ] + } } - }], + ], "Version": "2012-10-17" }, "PolicyName": "ServicePingerProviderframeworkonEventServiceRoleDefaultPolicyD142E8F7", - "Roles": [{ - "Ref": "ServicePingerProviderframeworkonEventServiceRole3DB083B7" - }] + "Roles": [ + { + "Ref": "ServicePingerProviderframeworkonEventServiceRole3DB083B7" + } + ] } }, "ServicePingerProviderframeworkonEventEC59DE20": { @@ -3844,7 +4276,8 @@ "S3Key": { "Fn::Join": [ "", - [{ + [ + { "Fn::Select": [ 0, { @@ -4109,17 +4542,17 @@ "Type": "String", "Description": "Artifact hash for asset \"04fa2d485a51abd8261468eb6fa053d3a72242fc068fa75683232a52960b30cf\"" }, - "AssetParametersa298dd278c9ef814ebac4c9d8b2dc8e1b8374a14c5b7d0e79f041a296668f5dcS3BucketCA7ADF01": { + "AssetParameters215e9f40bd76e7102c690b24b0922eb4963d2d24938eec175e107db683455d11S3BucketC456B560": { "Type": "String", - "Description": "S3 bucket for asset \"a298dd278c9ef814ebac4c9d8b2dc8e1b8374a14c5b7d0e79f041a296668f5dc\"" + "Description": "S3 bucket for asset \"215e9f40bd76e7102c690b24b0922eb4963d2d24938eec175e107db683455d11\"" }, - "AssetParametersa298dd278c9ef814ebac4c9d8b2dc8e1b8374a14c5b7d0e79f041a296668f5dcS3VersionKey822F0346": { + "AssetParameters215e9f40bd76e7102c690b24b0922eb4963d2d24938eec175e107db683455d11S3VersionKeyA1DAD649": { "Type": "String", - "Description": "S3 key for asset version \"a298dd278c9ef814ebac4c9d8b2dc8e1b8374a14c5b7d0e79f041a296668f5dc\"" + "Description": "S3 key for asset version \"215e9f40bd76e7102c690b24b0922eb4963d2d24938eec175e107db683455d11\"" }, - "AssetParametersa298dd278c9ef814ebac4c9d8b2dc8e1b8374a14c5b7d0e79f041a296668f5dcArtifactHashA688F4F0": { + "AssetParameters215e9f40bd76e7102c690b24b0922eb4963d2d24938eec175e107db683455d11ArtifactHash95B6846D": { "Type": "String", - "Description": "Artifact hash for asset \"a298dd278c9ef814ebac4c9d8b2dc8e1b8374a14c5b7d0e79f041a296668f5dc\"" + "Description": "Artifact hash for asset \"215e9f40bd76e7102c690b24b0922eb4963d2d24938eec175e107db683455d11\"" }, "SsmParameterValueawsserviceeksoptimizedami117amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { "Type": "AWS::SSM::Parameter::Value", @@ -4142,4 +4575,4 @@ "Default": "/aws/service/eks/optimized-ami/1.14/amazon-linux-2/recommended/image_id" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/test.cluster.ts b/packages/@aws-cdk/aws-eks/test/test.cluster.ts index 15875190fc877..cd32b5ce42566 100644 --- a/packages/@aws-cdk/aws-eks/test/test.cluster.ts +++ b/packages/@aws-cdk/aws-eks/test/test.cluster.ts @@ -20,6 +20,61 @@ const CLUSTER_VERSION = eks.KubernetesVersion.V1_16; export = { + 'cluster connections include both control plane and cluster security group'(test: Test) { + + const { stack } = testFixture(); + + const cluster = new eks.Cluster(stack, 'Cluster', { + version: eks.KubernetesVersion.V1_17, + }); + + test.deepEqual(cluster.connections.securityGroups.map(sg => stack.resolve(sg.securityGroupId)), [ + { 'Fn::GetAtt': ['Cluster9EE0221C', 'ClusterSecurityGroupId'] }, + { 'Fn::GetAtt': ['ClusterControlPlaneSecurityGroupD274242C', 'GroupId'] }, + ]); + + test.done(); + + }, + + 'can declare a security group from a different stack'(test: Test) { + + class ClusterStack extends cdk.Stack { + public eksCluster: eks.Cluster; + + constructor(scope: cdk.Construct, id: string, props: { sg: ec2.ISecurityGroup, vpc: ec2.IVpc }) { + super(scope, id); + this.eksCluster = new eks.Cluster(this, 'Cluster', { + version: eks.KubernetesVersion.V1_17, + securityGroup: props.sg, + vpc: props.vpc, + }); + } + } + + class NetworkStack extends cdk.Stack { + + public readonly securityGroup: ec2.ISecurityGroup; + public readonly vpc: ec2.IVpc; + + constructor(scope: cdk.Construct, id: string) { + super(scope, id); + this.vpc = new ec2.Vpc(this, 'Vpc'); + this.securityGroup = new ec2.SecurityGroup(this, 'SecurityGroup', { vpc: this.vpc }); + } + + } + + const { app } = testFixture(); + const networkStack = new NetworkStack(app, 'NetworkStack'); + new ClusterStack(app, 'ClusterStack', { sg: networkStack.securityGroup, vpc: networkStack.vpc }); + + // make sure we can synth (no circular dependencies between the stacks) + app.synth(); + + test.done(); + }, + 'can declare a manifest with a token from a different stack than the cluster that depends on the cluster stack'(test: Test) { class ClusterStack extends cdk.Stack { @@ -540,6 +595,29 @@ export = { test.done(); }, + 'import cluster with new kubectl private subnets'(test: Test) { + + const { stack, vpc } = testFixture(); + + const cluster = eks.Cluster.fromClusterAttributes(stack, 'Cluster', { + clusterName: 'cluster', + kubectlPrivateSubnetIds: vpc.privateSubnets.map(s => s.subnetId), + }); + + test.deepEqual(cluster.kubectlPrivateSubnets?.map(s => stack.resolve(s.subnetId)), [ + { Ref: 'VPCPrivateSubnet1Subnet8BCA10E0' }, + { Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A' }, + ]); + + test.deepEqual(cluster.kubectlPrivateSubnets?.map(s => s.node.id), [ + 'KubectlSubnet0', + 'KubectlSubnet1', + ]); + + test.done(); + + }, + 'exercise export/import'(test: Test) { // GIVEN const { stack: stack1, vpc, app } = testFixture(); @@ -1987,7 +2065,7 @@ export = { VpcConfig: { SecurityGroupIds: [ { - Ref: 'referencetoStackCluster1KubectlProviderSecurityGroupDF05D03AGroupId', + Ref: 'referencetoStackCluster18DFEAC17ClusterSecurityGroupId', }, ], SubnetIds: [ @@ -2102,7 +2180,7 @@ export = { VpcConfig: { SecurityGroupIds: [ { - Ref: 'referencetoStackCluster1KubectlProviderSecurityGroupDF05D03AGroupId', + Ref: 'referencetoStackCluster18DFEAC17ClusterSecurityGroupId', }, ], SubnetIds: [ diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/package.json b/packages/@aws-cdk/aws-elasticloadbalancing/package.json index 961544e9e33ab..bbd613800a969 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancing/package.json @@ -1,7 +1,7 @@ { "name": "@aws-cdk/aws-elasticloadbalancing", "version": "0.0.0", - "description": "CDK Constructs for AWS ElasticLoadBalancing", + "description": "The CDK Construct Library for AWS::ElasticLoadBalancing", "main": "lib/index.js", "types": "lib/index.d.ts", "jsii": { diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json index ff40789ebd426..69a2275f1c0d8 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json @@ -63,7 +63,7 @@ "@aws-cdk/assert": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", - "jest": "^25.5.2", + "jest": "^26.4.2", "pkglint": "0.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json index 008084ce1034c..bff2591ecdc89 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json @@ -63,7 +63,7 @@ "@aws-cdk/assert": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "pkglint": "0.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-events-targets/lib/ecs-task.ts b/packages/@aws-cdk/aws-events-targets/lib/ecs-task.ts index 3a31758c3a8c0..a4b19981dd0b1 100644 --- a/packages/@aws-cdk/aws-events-targets/lib/ecs-task.ts +++ b/packages/@aws-cdk/aws-events-targets/lib/ecs-task.ts @@ -69,6 +69,17 @@ export interface EcsTaskProps { * @default A new IAM role is created */ readonly role?: iam.IRole; + + /** + * The platform version on which to run your task + * + * Unless you have specific compatibility requirements, you don't need to specify this. + * + * @see https://docs.aws.amazon.com/AmazonECS/latest/developerguide/platform_versions.html + * + * @default - ECS will set the Fargate platform version to 'LATEST' + */ + readonly platformVersion?: ecs.FargatePlatformVersion; } /** @@ -95,6 +106,7 @@ export class EcsTask implements events.IRuleTarget { private readonly taskDefinition: ecs.TaskDefinition; private readonly taskCount: number; private readonly role: iam.IRole; + private readonly platformVersion?: ecs.FargatePlatformVersion; constructor(private readonly props: EcsTaskProps) { if (props.securityGroup !== undefined && props.securityGroups !== undefined) { @@ -104,6 +116,7 @@ export class EcsTask implements events.IRuleTarget { this.cluster = props.cluster; this.taskDefinition = props.taskDefinition; this.taskCount = props.taskCount !== undefined ? props.taskCount : 1; + this.platformVersion = props.platformVersion; if (props.role) { const role = props.role; @@ -151,6 +164,7 @@ export class EcsTask implements events.IRuleTarget { ? { ...baseEcsParameters, launchType: this.taskDefinition.isEc2Compatible ? 'EC2' : 'FARGATE', + platformVersion: this.platformVersion, networkConfiguration: { awsVpcConfiguration: { subnets: this.props.cluster.vpc.selectSubnets(subnetSelection).subnetIds, diff --git a/packages/@aws-cdk/aws-events-targets/package.json b/packages/@aws-cdk/aws-events-targets/package.json index 1d5b00a5f6308..80a1d52f9240b 100644 --- a/packages/@aws-cdk/aws-events-targets/package.json +++ b/packages/@aws-cdk/aws-events-targets/package.json @@ -73,7 +73,7 @@ "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "pkglint": "0.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-events-targets/test/ecs/event-rule-target.test.ts b/packages/@aws-cdk/aws-events-targets/test/ecs/event-rule-target.test.ts index bcac71ae05d6e..4ac8347d02ec3 100644 --- a/packages/@aws-cdk/aws-events-targets/test/ecs/event-rule-target.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/ecs/event-rule-target.test.ts @@ -403,3 +403,50 @@ test('uses existing IAM role', () => { ], }); }); + +test('uses the specific fargate platform version', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + const platformVersion = ecs.FargatePlatformVersion.VERSION1_4; + + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'TaskDef'); + taskDefinition.addContainer('TheContainer', { + image: ecs.ContainerImage.fromRegistry('henk'), + }); + + const rule = new events.Rule(stack, 'Rule', { + schedule: events.Schedule.expression('rate(1 min)'), + }); + + // WHEN + rule.addTarget(new targets.EcsTask({ + cluster, + taskDefinition, + taskCount: 1, + containerOverrides: [{ + containerName: 'TheContainer', + command: ['echo', events.EventField.fromPath('$.detail.event')], + }], + platformVersion, + })); + + // THEN + expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Targets: [ + { + Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, + EcsParameters: { + LaunchType: 'FARGATE', + TaskCount: 1, + TaskDefinitionArn: { + Ref: 'TaskDef54694570', + }, + PlatformVersion: '1.4.0', + }, + Id: 'Target0', + }, + ], + }); +}); diff --git a/packages/@aws-cdk/aws-events/README.md b/packages/@aws-cdk/aws-events/README.md index cdd45921fff57..3c0782339b665 100644 --- a/packages/@aws-cdk/aws-events/README.md +++ b/packages/@aws-cdk/aws-events/README.md @@ -97,7 +97,11 @@ new Rule(this, 'ScheduleRule', { }); ``` -More details in [ScheduledEvents](https://docs.aws.amazon.com/eventbridge/latest/userguide/scheduled-events.html) documentation page. +If you want to specify Fargate platform version, set `platformVersion` in EcsTask's props like the following example: +```ts +const platformVersion = ecs.FargatePlatformVersion.VERSION1_4; +const ecsTaskTarget = new EcsTask({ cluster, taskDefinition, role, platformVersion }); +``` ## Event Targets diff --git a/packages/@aws-cdk/aws-glue/package.json b/packages/@aws-cdk/aws-glue/package.json index 478b8e5fb75ca..ca858971dd057 100644 --- a/packages/@aws-cdk/aws-glue/package.json +++ b/packages/@aws-cdk/aws-glue/package.json @@ -69,7 +69,7 @@ "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "pkglint": "0.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-iam/lib/role.ts b/packages/@aws-cdk/aws-iam/lib/role.ts index 4e4174de420cd..42ccfc707582b 100644 --- a/packages/@aws-cdk/aws-iam/lib/role.ts +++ b/packages/@aws-cdk/aws-iam/lib/role.ts @@ -101,7 +101,7 @@ export interface RoleProps { * Acknowledging IAM Resources in AWS CloudFormation Templates. * * @default - AWS CloudFormation generates a unique physical ID and uses that ID - * for the group name. + * for the role name. */ readonly roleName?: string; diff --git a/packages/@aws-cdk/aws-iam/package.json b/packages/@aws-cdk/aws-iam/package.json index fb49de1b4f2f7..3ff154d1e52ba 100644 --- a/packages/@aws-cdk/aws-iam/package.json +++ b/packages/@aws-cdk/aws-iam/package.json @@ -68,7 +68,7 @@ "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "pkglint": "0.0.0", "sinon": "^9.0.3" }, diff --git a/packages/@aws-cdk/aws-iam/test/oidc-provider.test.ts b/packages/@aws-cdk/aws-iam/test/oidc-provider.test.ts index 37b19b96cbfa0..99fe98419457b 100644 --- a/packages/@aws-cdk/aws-iam/test/oidc-provider.test.ts +++ b/packages/@aws-cdk/aws-iam/test/oidc-provider.test.ts @@ -389,5 +389,5 @@ describe('arrayDiff', () => { }); async function invokeHandler(event: Partial) { - return await handler.handler(event as any); + return handler.handler(event as any); } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-kendra/.eslintrc.js b/packages/@aws-cdk/aws-kendra/.eslintrc.js new file mode 100644 index 0000000000000..61dd8dd001f63 --- /dev/null +++ b/packages/@aws-cdk/aws-kendra/.eslintrc.js @@ -0,0 +1,3 @@ +const baseConfig = require('cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kendra/.gitignore b/packages/@aws-cdk/aws-kendra/.gitignore new file mode 100644 index 0000000000000..5b0f33aaa6d08 --- /dev/null +++ b/packages/@aws-cdk/aws-kendra/.gitignore @@ -0,0 +1,19 @@ +*.js +*.js.map +*.d.ts +tsconfig.json +node_modules +*.generated.ts +dist +.jsii + +.LAST_BUILD +.nyc_output +coverage +.nycrc +.LAST_PACKAGE +*.snk +nyc.config.js +!.eslintrc.js +!jest.config.js +junit.xml \ No newline at end of file diff --git a/packages/@aws-cdk/aws-kendra/.npmignore b/packages/@aws-cdk/aws-kendra/.npmignore new file mode 100644 index 0000000000000..72b7fcab0a22a --- /dev/null +++ b/packages/@aws-cdk/aws-kendra/.npmignore @@ -0,0 +1,26 @@ +# Don't include original .ts files when doing `npm pack` +*.ts +!*.d.ts +coverage +.nyc_output +*.tgz + +dist +.LAST_PACKAGE +.LAST_BUILD +!*.js + +# Include .jsii +!.jsii + +*.snk + +*.tsbuildinfo + +tsconfig.json + +.eslintrc.js +jest.config.js +# exclude cdk artifacts +**/cdk.out +junit.xml diff --git a/packages/@aws-cdk/aws-kendra/LICENSE b/packages/@aws-cdk/aws-kendra/LICENSE new file mode 100644 index 0000000000000..b71ec1688783a --- /dev/null +++ b/packages/@aws-cdk/aws-kendra/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/@aws-cdk/aws-kendra/NOTICE b/packages/@aws-cdk/aws-kendra/NOTICE new file mode 100644 index 0000000000000..bfccac9a7f69c --- /dev/null +++ b/packages/@aws-cdk/aws-kendra/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/aws-kendra/README.md b/packages/@aws-cdk/aws-kendra/README.md new file mode 100644 index 0000000000000..8a71d718fa68a --- /dev/null +++ b/packages/@aws-cdk/aws-kendra/README.md @@ -0,0 +1,16 @@ +## AWS::Kendra Construct Library + +--- + +![cfn-resources: Stable](https://img.shields.io/badge/cfn--resources-stable-success.svg?style=for-the-badge) + +> All classes with the `Cfn` prefix in this module ([CFN Resources](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) are always stable and safe to use. + +--- + + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts +import kendra = require('@aws-cdk/aws-kendra'); +``` diff --git a/packages/@aws-cdk/aws-kendra/jest.config.js b/packages/@aws-cdk/aws-kendra/jest.config.js new file mode 100644 index 0000000000000..54e28beb9798b --- /dev/null +++ b/packages/@aws-cdk/aws-kendra/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-kendra/lib/index.ts b/packages/@aws-cdk/aws-kendra/lib/index.ts new file mode 100644 index 0000000000000..5b3fc5e230a3e --- /dev/null +++ b/packages/@aws-cdk/aws-kendra/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::Kendra CloudFormation Resources: +export * from './kendra.generated'; diff --git a/packages/@aws-cdk/aws-kendra/package.json b/packages/@aws-cdk/aws-kendra/package.json new file mode 100644 index 0000000000000..08d6d1209c917 --- /dev/null +++ b/packages/@aws-cdk/aws-kendra/package.json @@ -0,0 +1,88 @@ +{ + "name": "@aws-cdk/aws-kendra", + "version": "0.0.0", + "description": "The CDK Construct Library for AWS::Kendra", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "projectReferences": true, + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.Kendra", + "packageId": "Amazon.CDK.AWS.Kendra", + "signAssembly": true, + "assemblyOriginatorKeyFile": "../../key.snk", + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png" + }, + "java": { + "package": "software.amazon.awscdk.services.kendra", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "kendra" + } + }, + "python": { + "distName": "aws-cdk.aws-kendra", + "module": "aws_cdk.aws_kendra" + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-kendra" + }, + "homepage": "https://github.com/aws/aws-cdk", + "scripts": { + "build": "cdk-build", + "watch": "cdk-watch", + "lint": "cdk-lint", + "test": "cdk-test", + "integ": "cdk-integ", + "pkglint": "pkglint -f", + "package": "cdk-package", + "awslint": "cdk-awslint", + "cfn2ts": "cfn2ts", + "build+test+package": "npm run build+test && npm run package", + "build+test": "npm run build && npm test", + "compat": "cdk-compat" + }, + "cdk-build": { + "cloudformation": "AWS::Kendra", + "jest": true + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::Kendra", + "aws-kendra" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/assert": "0.0.0", + "cdk-build-tools": "0.0.0", + "cfn2ts": "0.0.0", + "pkglint": "0.0.0" + }, + "dependencies": { + "@aws-cdk/core": "0.0.0" + }, + "peerDependencies": { + "@aws-cdk/core": "0.0.0" + }, + "engines": { + "node": ">= 10.13.0 <13 || >=13.7.0" + }, + "stability": "experimental", + "maturity": "cfn-only", + "awscdkio": { + "announce": false + } +} diff --git a/packages/@aws-cdk/aws-kendra/test/kendra.test.ts b/packages/@aws-cdk/aws-kendra/test/kendra.test.ts new file mode 100644 index 0000000000000..e394ef336bfb4 --- /dev/null +++ b/packages/@aws-cdk/aws-kendra/test/kendra.test.ts @@ -0,0 +1,6 @@ +import '@aws-cdk/assert/jest'; +import {} from '../lib'; + +test('No tests are specified for this package', () => { + expect(true).toBe(true); +}); diff --git a/packages/@aws-cdk/aws-kinesis/package.json b/packages/@aws-cdk/aws-kinesis/package.json index 70bedee84671b..976e507c78e0e 100644 --- a/packages/@aws-cdk/aws-kinesis/package.json +++ b/packages/@aws-cdk/aws-kinesis/package.json @@ -1,7 +1,7 @@ { "name": "@aws-cdk/aws-kinesis", "version": "0.0.0", - "description": "CDK Constructs for AWS Kinesis", + "description": "The CDK Construct Library for AWS::Kinesis", "main": "lib/index.js", "types": "lib/index.d.ts", "jsii": { diff --git a/packages/@aws-cdk/aws-kms/package.json b/packages/@aws-cdk/aws-kms/package.json index de8e5ea22cec5..31f79371871ad 100644 --- a/packages/@aws-cdk/aws-kms/package.json +++ b/packages/@aws-cdk/aws-kms/package.json @@ -1,7 +1,7 @@ { "name": "@aws-cdk/aws-kms", "version": "0.0.0", - "description": "CDK Constructs for AWS KMS", + "description": "The CDK Construct Library for AWS::KMS", "main": "lib/index.js", "types": "lib/index.d.ts", "jsii": { diff --git a/packages/@aws-cdk/aws-lambda-destinations/package.json b/packages/@aws-cdk/aws-lambda-destinations/package.json index 0741d9fe40341..1e6783dd4f334 100644 --- a/packages/@aws-cdk/aws-lambda-destinations/package.json +++ b/packages/@aws-cdk/aws-lambda-destinations/package.json @@ -63,7 +63,7 @@ "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "pkglint": "0.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.s3.expected.json b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.s3.expected.json index a59e90cbe486d..afac04a03e5fb 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.s3.expected.json +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.s3.expected.json @@ -50,28 +50,6 @@ "FServiceRole3AC82EE1" ] }, - "FAllowBucketNotificationsFromlambdaeventsources3B101C8CFBA8EBB2AA": { - "Type": "AWS::Lambda::Permission", - "Properties": { - "Action": "lambda:InvokeFunction", - "FunctionName": { - "Fn::GetAtt": [ - "FC4345940", - "Arn" - ] - }, - "Principal": "s3.amazonaws.com", - "SourceAccount": { - "Ref": "AWS::AccountId" - }, - "SourceArn": { - "Fn::GetAtt": [ - "B08E7C7AF", - "Arn" - ] - } - } - }, "B08E7C7AF": { "Type": "AWS::S3::Bucket", "UpdateReplacePolicy": "Delete", @@ -116,9 +94,31 @@ } }, "DependsOn": [ - "FAllowBucketNotificationsFromlambdaeventsources3B101C8CFBA8EBB2AA" + "BAllowBucketNotificationsTolambdaeventsources3F741608059EF9F709" ] }, + "BAllowBucketNotificationsTolambdaeventsources3F741608059EF9F709": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "FC4345940", + "Arn" + ] + }, + "Principal": "s3.amazonaws.com", + "SourceAccount": { + "Ref": "AWS::AccountId" + }, + "SourceArn": { + "Fn::GetAtt": [ + "B08E7C7AF", + "Arn" + ] + } + } + }, "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleB6FB88EC": { "Type": "AWS::IAM::Role", "Properties": { diff --git a/packages/@aws-cdk/aws-lambda-nodejs/README.md b/packages/@aws-cdk/aws-lambda-nodejs/README.md index 49381a8588523..7b1e260e53676 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/README.md +++ b/packages/@aws-cdk/aws-lambda-nodejs/README.md @@ -45,12 +45,11 @@ All other properties of `lambda.Function` are supported, see also the [AWS Lambd The `NodejsFunction` construct automatically [reuses existing connections](https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/node-reusing-connections.html) when working with the AWS SDK for JavaScript. Set the `awsSdkConnectionReuse` prop to `false` to disable it. -Use the `containerEnvironment` prop to pass environments variables to the Docker container -running Parcel: +Use the `parcelEnvironment` prop to define environments variables when Parcel runs: ```ts new lambda.NodejsFunction(this, 'my-handler', { - containerEnvironment: { + parcelEnvironment: { NODE_ENV: 'production', }, }); diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundlers.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundlers.ts index fd0d69d960b92..0ba132012ddc3 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundlers.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundlers.ts @@ -24,32 +24,36 @@ interface LocalBundlerProps extends BundlerProps { * Local Parcel bundler */ export class LocalBundler implements cdk.ILocalBundling { - public static get runsLocally(): boolean { - if (LocalBundler._runsLocally !== undefined) { - return LocalBundler._runsLocally; + public static runsLocally(resolvePath: string): boolean { + if (LocalBundler._runsLocally[resolvePath] !== undefined) { + return LocalBundler._runsLocally[resolvePath]; } if (os.platform() === 'win32') { // TODO: add Windows support return false; } try { - const parcel = spawnSync(require.resolve('parcel'), ['--version']); + const parcel = spawnSync(require.resolve('parcel', { paths: [resolvePath] }), ['--version']); const version = parcel.stdout.toString().trim(); - LocalBundler._runsLocally = new RegExp(`^${PARCEL_VERSION}`).test(version); // Cache result to avoid unnecessary spawns - if (!LocalBundler._runsLocally) { + LocalBundler._runsLocally[resolvePath] = new RegExp(`^${PARCEL_VERSION}`).test(version); // Cache result to avoid unnecessary spawns + if (!LocalBundler._runsLocally[resolvePath]) { process.stderr.write(`Incorrect parcel version detected: ${version} <> ${PARCEL_VERSION}. Switching to Docker bundling.\n`); } - return LocalBundler._runsLocally; - } catch { + return LocalBundler._runsLocally[resolvePath]; + } catch (err) { return false; } } - public static _runsLocally?: boolean; // public for testing purposes + public static clearRunsLocallyCache(): void { // for tests + LocalBundler._runsLocally = {}; + } + + private static _runsLocally: { [key: string]: boolean } = {}; constructor(private readonly props: LocalBundlerProps) {} public tryBundle(outputDir: string) { - if (!LocalBundler.runsLocally) { + if (!LocalBundler.runsLocally(this.props.projectRoot)) { return false; } @@ -61,6 +65,7 @@ export class LocalBundler implements cdk.ILocalBundling { dependencies: this.props.dependencies, installer: this.props.installer, lockFile: this.props.lockFile, + bundlingEnvironment: BundlingEnvironment.LOCAL, }); exec('bash', ['-c', localCommand], { @@ -109,6 +114,7 @@ export class DockerBundler { installer: props.installer, lockFile: props.lockFile, dependencies: props.dependencies, + bundlingEnvironment: BundlingEnvironment.DOCKER, }); this.bundlingOptions = { @@ -122,6 +128,12 @@ export class DockerBundler { interface BundlingCommandOptions extends LocalBundlerProps { outputDir: string; + bundlingEnvironment: BundlingEnvironment; +} + +enum BundlingEnvironment { + DOCKER = 'docker', + LOCAL = 'local', } /** @@ -130,9 +142,13 @@ interface BundlingCommandOptions extends LocalBundlerProps { function createBundlingCommand(options: BundlingCommandOptions): string { const entryPath = path.join(options.projectRoot, options.relativeEntryPath); const distFile = path.basename(options.relativeEntryPath).replace(/\.(jsx|tsx?)$/, '.js'); + const parcelResolvePath = options.bundlingEnvironment === BundlingEnvironment.DOCKER + ? '/' // Force using parcel installed at / in the image + : entryPath; // Look up starting from entry path + const parcelCommand: string = chain([ [ - '$(node -p "require.resolve(\'parcel\')")', // Parcel is not globally installed, find its "bin" + `$(node -p "require.resolve(\'parcel\', { paths: ['${parcelResolvePath}'] })")`, // Parcel is not globally installed, find its "bin" 'build', entryPath.replace(/\\/g, '/'), // Always use POSIX paths in the container '--target', 'cdk-lambda', '--dist-dir', options.outputDir, // Output bundle in outputDir (will have the same name as the entry) diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts index 9c946d4879e37..5160904878e11 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts @@ -203,7 +203,7 @@ export class Bundling { cacheDir: options.cacheDir, environment: options.parcelEnvironment, bundlingDockerImage: options.bundlingDockerImage, - buildImage: !LocalBundler.runsLocally || options.forceDockerBundling, + buildImage: !LocalBundler.runsLocally(projectRoot) || options.forceDockerBundling, // build image only if we can't run locally buildArgs: options.buildArgs, parcelVersion: options.parcelVersion, dependencies, @@ -212,7 +212,7 @@ export class Bundling { }); return lambda.Code.fromAsset(projectRoot, { - assetHashType: cdk.AssetHashType.BUNDLE, + assetHashType: cdk.AssetHashType.OUTPUT, bundling: { local: localBundler, ...dockerBundler.bundlingOptions, diff --git a/packages/@aws-cdk/aws-lambda-nodejs/package.json b/packages/@aws-cdk/aws-lambda-nodejs/package.json index e6020349ab914..30f04975ca65b 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/package.json +++ b/packages/@aws-cdk/aws-lambda-nodejs/package.json @@ -1,7 +1,7 @@ { "name": "@aws-cdk/aws-lambda-nodejs", "version": "0.0.0", - "description": "CDK Constructs for AWS Lambda in Node.js", + "description": "The CDK Construct Library for AWS Lambda in Node.js", "main": "lib/index.js", "types": "lib/index.d.ts", "jsii": { diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts b/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts index 0caa440ec1b8a..654e3b49f9029 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts @@ -18,6 +18,7 @@ const fromAssetMock = jest.spyOn(BundlingDockerImage, 'fromAsset'); let findUpMock: jest.SpyInstance; beforeEach(() => { jest.clearAllMocks(); + LocalBundler.clearRunsLocallyCache(); findUpMock = jest.spyOn(util, 'findUp').mockImplementation((name: string, directory) => { if (name === 'package.json') { return path.join(__dirname, '..'); @@ -39,7 +40,7 @@ test('Parcel bundling', () => { // Correctly bundles with parcel expect(Code.fromAsset).toHaveBeenCalledWith('/project', { - assetHashType: AssetHashType.BUNDLE, + assetHashType: AssetHashType.OUTPUT, bundling: expect.objectContaining({ local: { props: expect.objectContaining({ @@ -53,7 +54,7 @@ test('Parcel bundling', () => { command: [ 'bash', '-c', [ - '$(node -p "require.resolve(\'parcel\')") build /asset-input/folder/entry.ts --target cdk-lambda --dist-dir /asset-output --no-autoinstall --no-scope-hoist --cache-dir /asset-input/cache-dir', + '$(node -p "require.resolve(\'parcel\', { paths: [\'/\'] })") build /asset-input/folder/entry.ts --target cdk-lambda --dist-dir /asset-output --no-autoinstall --no-scope-hoist --cache-dir /asset-input/cache-dir', 'mv /asset-output/entry.js /asset-output/index.js', ].join(' && '), ], @@ -92,11 +93,11 @@ test('Parcel bundling with handler named index.ts', () => { // Correctly bundles with parcel expect(Code.fromAsset).toHaveBeenCalledWith('/project', { - assetHashType: AssetHashType.BUNDLE, + assetHashType: AssetHashType.OUTPUT, bundling: expect.objectContaining({ command: [ 'bash', '-c', - '$(node -p "require.resolve(\'parcel\')") build /asset-input/folder/index.ts --target cdk-lambda --dist-dir /asset-output --no-autoinstall --no-scope-hoist', + '$(node -p "require.resolve(\'parcel\', { paths: [\'/\'] })") build /asset-input/folder/index.ts --target cdk-lambda --dist-dir /asset-output --no-autoinstall --no-scope-hoist', ], }), }); @@ -111,12 +112,12 @@ test('Parcel bundling with tsx handler', () => { // Correctly bundles with parcel expect(Code.fromAsset).toHaveBeenCalledWith('/project', { - assetHashType: AssetHashType.BUNDLE, + assetHashType: AssetHashType.OUTPUT, bundling: expect.objectContaining({ command: [ 'bash', '-c', [ - '$(node -p "require.resolve(\'parcel\')") build /asset-input/folder/handler.tsx --target cdk-lambda --dist-dir /asset-output --no-autoinstall --no-scope-hoist', + '$(node -p "require.resolve(\'parcel\', { paths: [\'/\'] })") build /asset-input/folder/handler.tsx --target cdk-lambda --dist-dir /asset-output --no-autoinstall --no-scope-hoist', 'mv /asset-output/handler.js /asset-output/index.js', ].join(' && '), ], @@ -151,12 +152,12 @@ test('Parcel bundling with externals and dependencies', () => { // Correctly bundles with parcel expect(Code.fromAsset).toHaveBeenCalledWith('/project', { - assetHashType: AssetHashType.BUNDLE, + assetHashType: AssetHashType.OUTPUT, bundling: expect.objectContaining({ command: [ 'bash', '-c', [ - '$(node -p "require.resolve(\'parcel\')") build /asset-input/folder/entry.ts --target cdk-lambda --dist-dir /asset-output --no-autoinstall --no-scope-hoist', + '$(node -p "require.resolve(\'parcel\', { paths: [\'/\'] })") build /asset-input/folder/entry.ts --target cdk-lambda --dist-dir /asset-output --no-autoinstall --no-scope-hoist', 'mv /asset-output/entry.js /asset-output/index.js', `echo \'{\"dependencies\":{\"delay\":\"${delayVersion}\"}}\' > /asset-output/package.json`, 'cd /asset-output', @@ -198,7 +199,7 @@ test('Detects yarn.lock', () => { // Correctly bundles with parcel expect(Code.fromAsset).toHaveBeenCalledWith('/project', { - assetHashType: AssetHashType.BUNDLE, + assetHashType: AssetHashType.OUTPUT, bundling: expect.objectContaining({ command: expect.arrayContaining([ expect.stringMatching(/yarn\.lock.+yarn install/), @@ -229,7 +230,7 @@ test('Local bundling', () => { const spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValue({ status: 0, stderr: Buffer.from('stderr'), - stdout: Buffer.from('stdout'), + stdout: Buffer.from('2.0.0-beta.1'), pid: 123, output: ['stdout', 'stderr'], signal: null, @@ -237,7 +238,7 @@ test('Local bundling', () => { const bundler = new LocalBundler({ installer: Installer.NPM, - projectRoot: '/project', + projectRoot: __dirname, relativeEntryPath: 'folder/entry.ts', dependencies: { dep: 'version', @@ -251,20 +252,11 @@ test('Local bundling', () => { bundler.tryBundle('/outdir'); expect(spawnSyncMock).toHaveBeenCalledWith( - 'bash', [ - '-c', - [ - '$(node -p \"require.resolve(\'parcel\')\") build /project/folder/entry.ts --target cdk-lambda --dist-dir /outdir --no-autoinstall --no-scope-hoist', - 'mv /outdir/entry.js /outdir/index.js', - 'echo \'{\"dependencies\":{\"dep\":\"version\"}}\' > /outdir/package.json', - 'cp /project/package-lock.json /outdir/package-lock.json', - 'cd /outdir', - 'npm install', - ].join(' && '), - ], + 'bash', + expect.arrayContaining(['-c', expect.stringContaining(__dirname)]), expect.objectContaining({ env: expect.objectContaining({ KEY: 'value' }), - cwd: '/project/folder', + cwd: expect.stringContaining(path.join(__dirname, 'folder')), }), ); @@ -273,8 +265,6 @@ test('Local bundling', () => { }); test('LocalBundler.runsLocally checks parcel version and caches results', () => { - LocalBundler._runsLocally = undefined; - const spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValue({ status: 0, stderr: Buffer.from('stderr'), @@ -284,15 +274,13 @@ test('LocalBundler.runsLocally checks parcel version and caches results', () => signal: null, }); - expect(LocalBundler.runsLocally).toBe(true); - expect(LocalBundler.runsLocally).toBe(true); + expect(LocalBundler.runsLocally(__dirname)).toBe(true); + expect(LocalBundler.runsLocally(__dirname)).toBe(true); expect(spawnSyncMock).toHaveBeenCalledTimes(1); expect(spawnSyncMock).toHaveBeenCalledWith(expect.stringContaining('parcel'), ['--version']); }); test('LocalBundler.runsLocally with incorrect parcel version', () => { - LocalBundler._runsLocally = undefined; - jest.spyOn(child_process, 'spawnSync').mockReturnValue({ status: 0, stderr: Buffer.from('stderr'), @@ -302,7 +290,7 @@ test('LocalBundler.runsLocally with incorrect parcel version', () => { signal: null, }); - expect(LocalBundler.runsLocally).toBe(false); + expect(LocalBundler.runsLocally(__dirname)).toBe(false); }); test('Project root detection', () => { @@ -328,7 +316,7 @@ test('Custom bundling docker image', () => { }); expect(Code.fromAsset).toHaveBeenCalledWith('/project', { - assetHashType: AssetHashType.BUNDLE, + assetHashType: AssetHashType.OUTPUT, bundling: expect.objectContaining({ image: { image: 'my-custom-image' }, }), diff --git a/packages/@aws-cdk/aws-lambda-python/package.json b/packages/@aws-cdk/aws-lambda-python/package.json index 1696063ef8729..5715093b14f88 100644 --- a/packages/@aws-cdk/aws-lambda-python/package.json +++ b/packages/@aws-cdk/aws-lambda-python/package.json @@ -1,7 +1,7 @@ { "name": "@aws-cdk/aws-lambda-python", "version": "0.0.0", - "description": "CDK Constructs for AWS Lambda in Python", + "description": "The CDK Construct Library for AWS Lambda in Python", "main": "lib/index.js", "types": "lib/index.d.ts", "jsii": { diff --git a/packages/@aws-cdk/aws-lambda/lib/alias.ts b/packages/@aws-cdk/aws-lambda/lib/alias.ts index 7a49ea6eb28bc..dc330db3f7ec9 100644 --- a/packages/@aws-cdk/aws-lambda/lib/alias.ts +++ b/packages/@aws-cdk/aws-lambda/lib/alias.ts @@ -97,7 +97,7 @@ export class Alias extends QualifiedFunctionBase implements IAlias { public readonly grantPrincipal = attrs.aliasVersion.grantPrincipal; public readonly role = attrs.aliasVersion.role; - protected readonly canCreatePermissions = false; + protected readonly canCreatePermissions = this._isStackAccount(); protected readonly qualifier = attrs.aliasName; } return new Imported(scope, id); diff --git a/packages/@aws-cdk/aws-lambda/lib/event-source-mapping.ts b/packages/@aws-cdk/aws-lambda/lib/event-source-mapping.ts index 760aca4f71e4d..a9fbc97bdea0e 100644 --- a/packages/@aws-cdk/aws-lambda/lib/event-source-mapping.ts +++ b/packages/@aws-cdk/aws-lambda/lib/event-source-mapping.ts @@ -17,7 +17,7 @@ export interface EventSourceMappingOptions { * * Valid Range: Minimum value of 1. Maximum value of 10000. * - * @default - Amazon Kinesis and Amazon DynamoDB is 100 records. + * @default - Amazon Kinesis, Amazon DynamoDB, and Amazon MSK is 100 records. * Both the default and maximum for Amazon SQS are 10 messages. */ readonly batchSize?: number; @@ -44,12 +44,12 @@ export interface EventSourceMappingOptions { readonly enabled?: boolean; /** - * The position in the DynamoDB or Kinesis stream where AWS Lambda should + * The position in the DynamoDB, Kinesis or MSK stream where AWS Lambda should * start reading. * * @see https://docs.aws.amazon.com/kinesis/latest/APIReference/API_GetShardIterator.html#Kinesis-GetShardIterator-request-ShardIteratorType * - * @default - Required for Amazon Kinesis and Amazon DynamoDB Streams sources. + * @default - Required for Amazon Kinesis, Amazon DynamoDB, and Amazon MSK Streams sources. */ readonly startingPosition?: StartingPosition; @@ -91,6 +91,13 @@ export interface EventSourceMappingOptions { * @default 1 */ readonly parallelizationFactor?: number; + + /** + * The name of the Kafka topic. + * + * @default - no topic + */ + readonly kafkaTopic?: string; } /** @@ -185,13 +192,14 @@ export class EventSourceMapping extends cdk.Resource implements IEventSourceMapp maximumRecordAgeInSeconds: props.maxRecordAge?.toSeconds(), maximumRetryAttempts: props.retryAttempts, parallelizationFactor: props.parallelizationFactor, + topics: props.kafkaTopic !== undefined ? [props.kafkaTopic] : undefined, }); this.eventSourceMappingId = cfnEventSourceMapping.ref; } } /** - * The position in the DynamoDB or Kinesis stream where AWS Lambda should start + * The position in the DynamoDB, Kinesis or MSK stream where AWS Lambda should start * reading. */ export enum StartingPosition { diff --git a/packages/@aws-cdk/aws-lambda/lib/function-base.ts b/packages/@aws-cdk/aws-lambda/lib/function-base.ts index 96eb204852563..7e6c309a3853e 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function-base.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function-base.ts @@ -1,7 +1,7 @@ import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; -import { ConstructNode, IResource, Resource } from '@aws-cdk/core'; +import { ConstructNode, IResource, Resource, Token } from '@aws-cdk/core'; import { AliasOptions } from './alias'; import { EventInvokeConfig, EventInvokeConfigOptions } from './event-invoke-config'; import { IEventSource } from './event-source'; @@ -182,7 +182,8 @@ export abstract class FunctionBase extends Resource implements IFunction { /** * Whether the addPermission() call adds any permissions * - * True for new Lambdas, false for imported Lambdas (they might live in different accounts). + * True for new Lambdas, false for version $LATEST and imported Lambdas + * from different accounts. */ protected abstract readonly canCreatePermissions: boolean; @@ -346,6 +347,27 @@ export abstract class FunctionBase extends Resource implements IFunction { return this.node; } + /** + * Given the function arn, check if the account id matches this account + * + * Function ARNs look like this: + * + * arn:aws:lambda:region:account-id:function:function-name + * + * ..which means that in order to extract the `account-id` component from the ARN, we can + * split the ARN using ":" and select the component in index 4. + * + * @returns true if account id of function matches this account + * + * @internal + */ + protected _isStackAccount(): boolean { + if (Token.isUnresolved(this.stack.account) || Token.isUnresolved(this.functionArn)) { + return false; + } + return this.stack.parseArn(this.functionArn).account === this.stack.account; + } + /** * Translate IPrincipal to something we can pass to AWS::Lambda::Permissions * @@ -431,7 +453,7 @@ class LatestVersion extends FunctionBase implements IVersion { public readonly version = '$LATEST'; public readonly permissionsNode = this.node; - protected readonly canCreatePermissions = true; + protected readonly canCreatePermissions = false; constructor(lambda: FunctionBase) { super(lambda, '$LATEST'); diff --git a/packages/@aws-cdk/aws-lambda/lib/function.ts b/packages/@aws-cdk/aws-lambda/lib/function.ts index 7ab131b094c56..b7a6546077c26 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function.ts @@ -382,7 +382,7 @@ export class Function extends FunctionBase { public readonly role = role; public readonly permissionsNode = this.node; - protected readonly canCreatePermissions = false; + protected readonly canCreatePermissions = this._isStackAccount(); constructor(s: Construct, i: string) { super(s, i); diff --git a/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts b/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts index 34ef68dc93e1a..b62523fd0ef45 100644 --- a/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts +++ b/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts @@ -128,7 +128,7 @@ export class Version extends QualifiedFunctionBase implements IVersion { public readonly role = lambda.role; protected readonly qualifier = version; - protected readonly canCreatePermissions = false; + protected readonly canCreatePermissions = this._isStackAccount(); public addAlias(name: string, opts: AliasOptions = { }): Alias { return addAlias(this, this, name, opts); @@ -154,7 +154,7 @@ export class Version extends QualifiedFunctionBase implements IVersion { public readonly role = attrs.lambda.role; protected readonly qualifier = attrs.version; - protected readonly canCreatePermissions = false; + protected readonly canCreatePermissions = this._isStackAccount(); public addAlias(name: string, opts: AliasOptions = { }): Alias { return addAlias(this, this, name, opts); diff --git a/packages/@aws-cdk/aws-lambda/package.json b/packages/@aws-cdk/aws-lambda/package.json index 0e41ad7c9ba8a..ae6fc1bd3506a 100644 --- a/packages/@aws-cdk/aws-lambda/package.json +++ b/packages/@aws-cdk/aws-lambda/package.json @@ -1,7 +1,7 @@ { "name": "@aws-cdk/aws-lambda", "version": "0.0.0", - "description": "CDK Constructs for AWS Lambda", + "description": "The CDK Construct Library for AWS::Lambda", "main": "lib/index.js", "types": "lib/index.d.ts", "jsii": { @@ -68,8 +68,8 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/aws-lambda": "^8.10.61", - "@types/lodash": "^4.14.160", + "@types/aws-lambda": "^8.10.62", + "@types/lodash": "^4.14.161", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda/test/test.event-source-mapping.ts b/packages/@aws-cdk/aws-lambda/test/test.event-source-mapping.ts index 4de8108b609d2..bc9492f1d2f7e 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.event-source-mapping.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.event-source-mapping.ts @@ -1,3 +1,4 @@ +import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; import { Code, EventSourceMapping, Function, Runtime } from '../lib'; @@ -185,4 +186,31 @@ export = { test.equals(imported.stack.stackName, 'test-stack'); test.done(); }, + + 'accepts if kafkaTopic is a parameter'(test: Test) { + const stack = new cdk.Stack(); + const topicNameParam = new cdk.CfnParameter(stack, 'TopicNameParam', { + type: 'String', + }); + + const fn = new Function(stack, 'fn', { + handler: 'index.handler', + code: Code.fromInline('exports.handler = ${handler.toString()}'), + runtime: Runtime.NODEJS_10_X, + }); + + new EventSourceMapping(stack, 'test', { + target: fn, + eventSourceArn: '', + kafkaTopic: topicNameParam.valueAsString, + }); + + expect(stack).to(haveResourceLike('AWS::Lambda::EventSourceMapping', { + Topics: [{ + Ref: 'TopicNameParam', + }], + })); + + test.done(); + }, }; diff --git a/packages/@aws-cdk/aws-lambda/test/test.lambda.ts b/packages/@aws-cdk/aws-lambda/test/test.lambda.ts index c399a70e5e6ec..69309e609517f 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.lambda.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.lambda.ts @@ -283,6 +283,59 @@ export = { // THEN test.deepEqual(imported.functionArn, 'arn:aws:lambda:us-east-1:123456789012:function:ProcessKinesisRecords'); test.deepEqual(imported.functionName, 'ProcessKinesisRecords'); + expect(stack2).notTo(haveResource('AWS::Lambda::Permission')); + test.done(); + }, + + 'imported Function w/ resolved account and function arn can addPermissions'(test: Test) { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Imports', { + env: { account: '123456789012', region: 'us-east-1' }, + }); + const stack2 = new cdk.Stack(app, 'imported', { + env: { account: '123456789012', region: 'us-east-1' }, + }); + new lambda.Function(stack, 'BaseFunction', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + }); + + // WHEN + const iFunc = lambda.Function.fromFunctionAttributes(stack2, 'iFunc', { + functionArn: 'arn:aws:lambda:us-east-1:123456789012:function:BaseFunction', + }); + iFunc.addPermission('iFunc', { + principal: new iam.ServicePrincipal('cloudformation.amazonaws.com'), + }); + + // THEN + expect(stack2).to(haveResource('AWS::Lambda::Permission')); + test.done(); + }, + + 'imported Function w/o account cannot addPermissions'(test: Test) { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Base'); + const importedStack = new cdk.Stack(app, 'Imported'); + new lambda.Function(stack, 'BaseFunction', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + }); + + // WHEN + const iFunc = lambda.Function.fromFunctionAttributes(importedStack, 'iFunc', { + functionArn: 'arn:aws:lambda:us-east-1:123456789012:function:BaseFunction', + }); + iFunc.addPermission('iFunc', { + principal: new iam.ServicePrincipal('cloudformation.amazonaws.com'), + }); + + // THEN + expect(importedStack).notTo(haveResource('AWS::Lambda::Permission')); test.done(); }, diff --git a/packages/@aws-cdk/aws-logs-destinations/package.json b/packages/@aws-cdk/aws-logs-destinations/package.json index 8b66e13d572b8..e5c3a3ef14f78 100644 --- a/packages/@aws-cdk/aws-logs-destinations/package.json +++ b/packages/@aws-cdk/aws-logs-destinations/package.json @@ -63,7 +63,7 @@ "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "pkglint": "0.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-logs/package.json b/packages/@aws-cdk/aws-logs/package.json index 1fbeeb100e682..91e847e740955 100644 --- a/packages/@aws-cdk/aws-logs/package.json +++ b/packages/@aws-cdk/aws-logs/package.json @@ -70,10 +70,10 @@ "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "nock": "^13.0.2", + "nock": "^13.0.4", "nodeunit": "^0.11.3", "pkglint": "0.0.0", - "sinon": "^9.0.2" + "sinon": "^9.0.3" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-rds/README.md b/packages/@aws-cdk/aws-rds/README.md index 1a5d4165d7409..cc8be1361bca8 100644 --- a/packages/@aws-cdk/aws-rds/README.md +++ b/packages/@aws-cdk/aws-rds/README.md @@ -268,20 +268,22 @@ const cpuUtilization = cluster.metricCPUUtilization(); const readLatency = instance.metric('ReadLatency', { statistic: 'Average', periodSec: 60 }); ``` -### Enabling S3 integration to a cluster (non-serverless Aurora only) +### Enabling S3 integration -Data in S3 buckets can be imported to and exported from Aurora databases using SQL queries. To enable this +Data in S3 buckets can be imported to and exported from certain database engines using SQL queries. To enable this functionality, set the `s3ImportBuckets` and `s3ExportBuckets` properties for import and export respectively. When configured, the CDK automatically creates and configures IAM roles as required. Additionally, the `s3ImportRole` and `s3ExportRole` properties can be used to set this role directly. -For Aurora MySQL, read more about [loading data from -S3](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Integrating.LoadFromS3.html) and [saving -data into S3](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Integrating.SaveIntoS3.html). +You can read more about loading data to (or from) S3 here: -For Aurora PostgreSQL, read more about [loading data from -S3](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Migrating.html) and [saving -data into S3](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/postgresql-s3-export.html). +* Aurora MySQL - [import](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Integrating.LoadFromS3.html) + and [export](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Integrating.SaveIntoS3.html). +* Aurora PostgreSQL - [import](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Migrating.html) + and [export](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/postgresql-s3-export.html). +* Microsoft SQL Server - [import & export](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/SQLServer.Procedural.Importing.html) +* PostgreSQL - [import](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/PostgreSQL.Procedural.Importing.html) +* Oracle - [import & export](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/oracle-s3-integration.html) The following snippet sets up a database cluster with different S3 buckets where the data is imported and exported - diff --git a/packages/@aws-cdk/aws-rds/lib/cluster-engine.ts b/packages/@aws-cdk/aws-rds/lib/cluster-engine.ts index 3b334d4127971..a25200ac22205 100644 --- a/packages/@aws-cdk/aws-rds/lib/cluster-engine.ts +++ b/packages/@aws-cdk/aws-rds/lib/cluster-engine.ts @@ -49,6 +49,36 @@ export interface ClusterEngineConfig { * @default - use the default port for clusters (3306) */ readonly port?: number; + + /** + * Features supported by the database engine. + * + * @see https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DBEngineVersion.html + * + * @default - no features + */ + readonly features?: ClusterEngineFeatures; +} + +/** + * Represents Database Engine features + */ +export interface ClusterEngineFeatures { + /** + * Feature name for the DB instance that the IAM role to access the S3 bucket for import + * is to be associated with. + * + * @default - no s3Import feature name + */ + readonly s3Import?: string; + + /** + * Feature name for the DB instance that the IAM role to export to S3 bucket is to be + * associated with. + * + * @default - no s3Export feature name + */ + readonly s3Export?: string; } /** @@ -76,6 +106,7 @@ interface ClusterEngineBaseProps { readonly multiUserRotationApplication: secretsmanager.SecretRotationApplication; readonly defaultPort?: number; readonly engineVersion?: EngineVersion; + readonly features?: ClusterEngineFeatures; } abstract class ClusterEngineBase implements IClusterEngine { @@ -87,9 +118,11 @@ abstract class ClusterEngineBase implements IClusterEngine { public abstract readonly supportedLogTypes: string[]; private readonly defaultPort?: number; + private readonly features?: ClusterEngineFeatures; constructor(props: ClusterEngineBaseProps) { this.engineType = props.engineType; + this.features = props.features; this.singleUserRotationApplication = props.singleUserRotationApplication; this.multiUserRotationApplication = props.multiUserRotationApplication; this.defaultPort = props.defaultPort; @@ -102,6 +135,7 @@ abstract class ClusterEngineBase implements IClusterEngine { return { parameterGroup, port: this.defaultPort, + features: this.features, }; } @@ -288,6 +322,10 @@ export class AuroraMysqlEngineVersion { public static readonly VER_2_08_0 = AuroraMysqlEngineVersion.builtIn_5_7('2.08.0'); /** Version "5.7.mysql_aurora.2.08.1". */ public static readonly VER_2_08_1 = AuroraMysqlEngineVersion.builtIn_5_7('2.08.1'); + /** Version "5.7.mysql_aurora.2.08.2". */ + public static readonly VER_2_08_2 = AuroraMysqlEngineVersion.builtIn_5_7('2.08.2'); + /** Version "5.7.mysql_aurora.2.09.0". */ + public static readonly VER_2_09_0 = AuroraMysqlEngineVersion.builtIn_5_7('2.09.0'); /** * Create a new AuroraMysqlEngineVersion with an arbitrary version. @@ -345,6 +383,25 @@ class AuroraMysqlClusterEngine extends MySqlClusterEngineBase { } } +/** + * Features supported by this version of the Aurora Postgres cluster engine. + */ +export interface AuroraPostgresEngineFeatures { + /** + * Whether this version of the Aurora Postgres cluster engine supports the S3 data import feature. + * + * @default false + */ + readonly s3Import?: boolean; + + /** + * Whether this version of the Aurora Postgres cluster engine supports the S3 data import feature. + * + * @default false + */ + readonly s3Export?: boolean; +} + /** * The versions for the Aurora PostgreSQL cluster engine * (those returned by {@link DatabaseClusterEngine.auroraPostgres}). @@ -369,17 +426,17 @@ export class AuroraPostgresEngineVersion { /** Version "10.6". */ public static readonly VER_10_6 = AuroraPostgresEngineVersion.of('10.6', '10'); /** Version "10.7". */ - public static readonly VER_10_7 = AuroraPostgresEngineVersion.of('10.7', '10'); + public static readonly VER_10_7 = AuroraPostgresEngineVersion.of('10.7', '10', { s3Import: true }); /** Version "10.11". */ - public static readonly VER_10_11 = AuroraPostgresEngineVersion.of('10.11', '10'); + public static readonly VER_10_11 = AuroraPostgresEngineVersion.of('10.11', '10', { s3Import: true, s3Export: true }); /** Version "10.12". */ - public static readonly VER_10_12 = AuroraPostgresEngineVersion.of('10.12', '10'); + public static readonly VER_10_12 = AuroraPostgresEngineVersion.of('10.12', '10', { s3Import: true, s3Export: true }); /** Version "11.4". */ - public static readonly VER_11_4 = AuroraPostgresEngineVersion.of('11.4', '11'); + public static readonly VER_11_4 = AuroraPostgresEngineVersion.of('11.4', '11', { s3Import: true }); /** Version "11.6". */ - public static readonly VER_11_6 = AuroraPostgresEngineVersion.of('11.6', '11'); + public static readonly VER_11_6 = AuroraPostgresEngineVersion.of('11.6', '11', { s3Import: true, s3Export: true }); /** Version "11.7". */ - public static readonly VER_11_7 = AuroraPostgresEngineVersion.of('11.7', '11'); + public static readonly VER_11_7 = AuroraPostgresEngineVersion.of('11.7', '11', { s3Import: true, s3Export: true }); /** * Create a new AuroraPostgresEngineVersion with an arbitrary version. @@ -389,18 +446,30 @@ export class AuroraPostgresEngineVersion { * @param auroraPostgresMajorVersion the major version of the engine, * for example "9.6" */ - public static of(auroraPostgresFullVersion: string, auroraPostgresMajorVersion: string): AuroraPostgresEngineVersion { - return new AuroraPostgresEngineVersion(auroraPostgresFullVersion, auroraPostgresMajorVersion); + public static of(auroraPostgresFullVersion: string, auroraPostgresMajorVersion: string, + auroraPostgresFeatures?: AuroraPostgresEngineFeatures): AuroraPostgresEngineVersion { + + return new AuroraPostgresEngineVersion(auroraPostgresFullVersion, auroraPostgresMajorVersion, auroraPostgresFeatures); } /** The full version string, for example, "9.6.25.1". */ public readonly auroraPostgresFullVersion: string; /** The major version of the engine, for example, "9.6". */ public readonly auroraPostgresMajorVersion: string; + /** + * The supported features for the DB engine + * + * @internal + */ + public readonly _features: ClusterEngineFeatures; - private constructor(auroraPostgresFullVersion: string, auroraPostgresMajorVersion: string) { + private constructor(auroraPostgresFullVersion: string, auroraPostgresMajorVersion: string, auroraPostgresFeatures?: AuroraPostgresEngineFeatures) { this.auroraPostgresFullVersion = auroraPostgresFullVersion; this.auroraPostgresMajorVersion = auroraPostgresMajorVersion; + this._features = { + s3Import: auroraPostgresFeatures?.s3Import ? 's3Import' : undefined, + s3Export: auroraPostgresFeatures?.s3Export ? 's3Export' : undefined, + }; } } @@ -414,6 +483,16 @@ export interface AuroraPostgresClusterEngineProps { } class AuroraPostgresClusterEngine extends ClusterEngineBase { + /** + * feature name for the S3 data import feature + */ + private static readonly S3_IMPORT_FEATURE_NAME = 's3Import'; + + /** + * feature name for the S3 data export feature + */ + private static readonly S3_EXPORT_FEATURE_NAME = 's3Export'; + public readonly supportedLogTypes: string[] = ['postgresql']; constructor(version?: AuroraPostgresEngineVersion) { @@ -428,9 +507,32 @@ class AuroraPostgresClusterEngine extends ClusterEngineBase { majorVersion: version.auroraPostgresMajorVersion, } : undefined, + features: version + ? { + s3Import: version._features.s3Import ? AuroraPostgresClusterEngine.S3_IMPORT_FEATURE_NAME : undefined, + s3Export: version._features.s3Export ? AuroraPostgresClusterEngine.S3_EXPORT_FEATURE_NAME : undefined, + } + : { + s3Import: AuroraPostgresClusterEngine.S3_IMPORT_FEATURE_NAME, + s3Export: AuroraPostgresClusterEngine.S3_EXPORT_FEATURE_NAME, + }, }); } + public bindToCluster(scope: core.Construct, options: ClusterEngineBindOptions): ClusterEngineConfig { + const config = super.bindToCluster(scope, options); + // skip validation for unversioned as it might be supported/unsupported. we cannot reliably tell at compile-time + if (this.engineVersion?.fullVersion) { + if (options.s3ImportRole && !(config.features?.s3Import)) { + throw new Error(`s3Import is not supported for Postgres version: ${this.engineVersion.fullVersion}. Use a version that supports the s3Import feature.`); + } + if (options.s3ExportRole && !(config.features?.s3Export)) { + throw new Error(`s3Export is not supported for Postgres version: ${this.engineVersion.fullVersion}. Use a version that supports the s3Export feature.`); + } + } + return config; + } + protected defaultParameterGroup(scope: core.Construct): IParameterGroup | undefined { if (!this.parameterGroupFamily) { throw new Error('Could not create a new ParameterGroup for an unversioned aurora-postgresql cluster engine. ' + diff --git a/packages/@aws-cdk/aws-rds/lib/cluster.ts b/packages/@aws-cdk/aws-rds/lib/cluster.ts index 9939a6de78a57..9bd29be6e64e0 100644 --- a/packages/@aws-cdk/aws-rds/lib/cluster.ts +++ b/packages/@aws-cdk/aws-rds/lib/cluster.ts @@ -4,15 +4,17 @@ 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 secretsmanager from '@aws-cdk/aws-secretsmanager'; -import { Annotations, CfnDeletionPolicy, Construct, Duration, RemovalPolicy, Resource, Token } from '@aws-cdk/core'; +import { Annotations, Construct, Duration, RemovalPolicy, Resource, Token } from '@aws-cdk/core'; import { IClusterEngine } from './cluster-engine'; import { DatabaseClusterAttributes, IDatabaseCluster } from './cluster-ref'; import { DatabaseSecret } from './database-secret'; import { Endpoint } from './endpoint'; import { IParameterGroup } from './parameter-group'; +import { applyRemovalPolicy, defaultDeletionProtection, setupS3ImportExport } from './private/util'; import { BackupProps, InstanceProps, Login, PerformanceInsightRetention, RotationMultiUserOptions } from './props'; import { DatabaseProxy, DatabaseProxyOptions, ProxyTarget } from './proxy'; -import { CfnDBCluster, CfnDBClusterProps, CfnDBInstance, CfnDBSubnetGroup } from './rds.generated'; +import { CfnDBCluster, CfnDBClusterProps, CfnDBInstance } from './rds.generated'; +import { ISubnetGroup, SubnetGroup } from './subnet-group'; /** * Common properties for a new database cluster or cluster from snapshot. @@ -81,7 +83,7 @@ interface DatabaseClusterBaseProps { /** * Indicates whether the DB cluster should have deletion protection enabled. * - * @default false + * @default - true if ``removalPolicy`` is RETAIN, false otherwise */ readonly deletionProtection?: boolean; @@ -212,6 +214,13 @@ interface DatabaseClusterBaseProps { * @default - None */ readonly s3ExportBuckets?: s3.IBucket[]; + + /** + * Existing subnet group for the cluster. + * + * @default - a new subnet group will be created. + */ + readonly subnetGroup?: ISubnetGroup; } /** @@ -277,8 +286,8 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { public readonly instanceEndpoints: Endpoint[] = []; protected readonly newCfnProps: CfnDBClusterProps; - protected readonly subnetGroup: CfnDBSubnetGroup; protected readonly securityGroups: ec2.ISecurityGroup[]; + protected readonly subnetGroup: ISubnetGroup; constructor(scope: Construct, id: string, props: DatabaseClusterBaseProps) { super(scope, id); @@ -290,13 +299,12 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { Annotations.of(this).addError(`Cluster requires at least 2 subnets, got ${subnetIds.length}`); } - this.subnetGroup = new CfnDBSubnetGroup(this, 'Subnets', { - dbSubnetGroupDescription: `Subnets for ${id} database`, - subnetIds, + this.subnetGroup = props.subnetGroup ?? new SubnetGroup(this, 'Subnets', { + description: `Subnets for ${id} database`, + vpc: props.instanceProps.vpc, + vpcSubnets: props.instanceProps.vpcSubnets, + removalPolicy: props.removalPolicy === RemovalPolicy.RETAIN ? props.removalPolicy : undefined, }); - if (props.removalPolicy === RemovalPolicy.RETAIN) { - this.subnetGroup.applyRemovalPolicy(RemovalPolicy.RETAIN); - } this.securityGroups = props.instanceProps.securityGroups ?? [ new ec2.SecurityGroup(this, 'SecurityGroup', { @@ -305,21 +313,22 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { }), ]; - const clusterAssociatedRoles: CfnDBCluster.DBClusterRoleProperty[] = []; - let { s3ImportRole, s3ExportRole } = this.setupS3ImportExport(props); - if (s3ImportRole) { - clusterAssociatedRoles.push({ roleArn: s3ImportRole.roleArn }); - } - if (s3ExportRole) { - clusterAssociatedRoles.push({ roleArn: s3ExportRole.roleArn }); - } - + let { s3ImportRole, s3ExportRole } = setupS3ImportExport(this, props); // bind the engine to the Cluster const clusterEngineBindConfig = props.engine.bindToCluster(this, { s3ImportRole, s3ExportRole, parameterGroup: props.parameterGroup, }); + + const clusterAssociatedRoles: CfnDBCluster.DBClusterRoleProperty[] = []; + if (s3ImportRole) { + clusterAssociatedRoles.push({ roleArn: s3ImportRole.roleArn, featureName: clusterEngineBindConfig.features?.s3Import }); + } + if (s3ExportRole) { + clusterAssociatedRoles.push({ roleArn: s3ExportRole.roleArn, featureName: clusterEngineBindConfig.features?.s3Export }); + } + const clusterParameterGroup = props.parameterGroup ?? clusterEngineBindConfig.parameterGroup; const clusterParameterGroupConfig = clusterParameterGroup?.bindToCluster({}); @@ -328,12 +337,12 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { engine: props.engine.engineType, engineVersion: props.engine.engineVersion?.fullVersion, dbClusterIdentifier: props.clusterIdentifier, - dbSubnetGroupName: this.subnetGroup.ref, + dbSubnetGroupName: this.subnetGroup.subnetGroupName, vpcSecurityGroupIds: this.securityGroups.map(sg => sg.securityGroupId), port: props.port ?? clusterEngineBindConfig.port, dbClusterParameterGroupName: clusterParameterGroupConfig?.parameterGroupName, associatedRoles: clusterAssociatedRoles.length > 0 ? clusterAssociatedRoles : undefined, - deletionProtection: props.deletionProtection, + deletionProtection: defaultDeletionProtection(props.deletionProtection, props.removalPolicy), // Admin backupRetentionPeriod: props.backup?.retention?.toDays(), preferredBackupWindow: props.backup?.preferredWindow, @@ -342,51 +351,6 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { enableCloudwatchLogsExports: props.cloudwatchLogsExports, }; } - - protected setRemovalPolicy(cluster: CfnDBCluster, removalPolicy?: RemovalPolicy) { - // if removalPolicy was not specified, - // leave it as the default, which is Snapshot - if (removalPolicy) { - cluster.applyRemovalPolicy(removalPolicy); - } else { - // The CFN default makes sense for DeletionPolicy, - // but doesn't cover UpdateReplacePolicy. - // Fix that here. - cluster.cfnOptions.updateReplacePolicy = CfnDeletionPolicy.SNAPSHOT; - } - } - - private setupS3ImportExport(props: DatabaseClusterBaseProps): { s3ImportRole?: IRole, s3ExportRole?: IRole } { - let s3ImportRole = props.s3ImportRole; - if (props.s3ImportBuckets && props.s3ImportBuckets.length > 0) { - if (props.s3ImportRole) { - throw new Error('Only one of s3ImportRole or s3ImportBuckets must be specified, not both.'); - } - - s3ImportRole = new Role(this, 'S3ImportRole', { - assumedBy: new ServicePrincipal('rds.amazonaws.com'), - }); - for (const bucket of props.s3ImportBuckets) { - bucket.grantRead(s3ImportRole); - } - } - - let s3ExportRole = props.s3ExportRole; - if (props.s3ExportBuckets && props.s3ExportBuckets.length > 0) { - if (props.s3ExportRole) { - throw new Error('Only one of s3ExportRole or s3ExportBuckets must be specified, not both.'); - } - - s3ExportRole = new Role(this, 'S3ExportRole', { - assumedBy: new ServicePrincipal('rds.amazonaws.com'), - }); - for (const bucket of props.s3ExportBuckets) { - bucket.grantReadWrite(s3ExportRole); - } - } - - return { s3ImportRole, s3ExportRole }; - } } /** @@ -545,7 +509,7 @@ export class DatabaseCluster extends DatabaseClusterNew { defaultPort: ec2.Port.tcp(this.clusterEndpoint.port), }); - this.setRemovalPolicy(cluster, props.removalPolicy); + applyRemovalPolicy(cluster, props.removalPolicy); if (secret) { this.secret = secret.attach(this); @@ -643,7 +607,7 @@ export class DatabaseClusterFromSnapshot extends DatabaseClusterNew { defaultPort: ec2.Port.tcp(this.clusterEndpoint.port), }); - this.setRemovalPolicy(cluster, props.removalPolicy); + applyRemovalPolicy(cluster, props.removalPolicy); setLogRetention(this, props); createInstances(this, props, this.subnetGroup); @@ -684,7 +648,7 @@ interface InstanceConfig { * A function rather than a protected method on ``DatabaseClusterNew`` to avoid exposing * ``DatabaseClusterNew`` and ``DatabaseClusterBaseProps`` in the API. */ -function createInstances(cluster: DatabaseClusterNew, props: DatabaseClusterBaseProps, subnetGroup: CfnDBSubnetGroup): InstanceConfig { +function createInstances(cluster: DatabaseClusterNew, props: DatabaseClusterBaseProps, subnetGroup: ISubnetGroup): InstanceConfig { const instanceCount = props.instances != null ? props.instances : 2; if (instanceCount < 1) { throw new Error('At least one instance is required'); @@ -739,7 +703,7 @@ function createInstances(cluster: DatabaseClusterNew, props: DatabaseClusterBase ? (instanceProps.performanceInsightRetention || PerformanceInsightRetention.DEFAULT) : undefined, // This is already set on the Cluster. Unclear to me whether it should be repeated or not. Better yes. - dbSubnetGroupName: subnetGroup.ref, + dbSubnetGroupName: subnetGroup.subnetGroupName, dbParameterGroupName: instanceParameterGroupConfig?.parameterGroupName, monitoringInterval: props.monitoringInterval && props.monitoringInterval.toSeconds(), monitoringRoleArn: monitoringRole && monitoringRole.roleArn, @@ -750,7 +714,7 @@ function createInstances(cluster: DatabaseClusterNew, props: DatabaseClusterBase // Because of that, in this case, // we can safely use the CFN default of Delete for DbInstances with dbClusterIdentifier set. if (props.removalPolicy) { - instance.applyRemovalPolicy(props.removalPolicy); + applyRemovalPolicy(instance, props.removalPolicy); } // We must have a dependency on the NAT gateway provider here to create diff --git a/packages/@aws-cdk/aws-rds/lib/index.ts b/packages/@aws-cdk/aws-rds/lib/index.ts index d03d0ce49bb39..ba53d97021234 100644 --- a/packages/@aws-cdk/aws-rds/lib/index.ts +++ b/packages/@aws-cdk/aws-rds/lib/index.ts @@ -11,6 +11,7 @@ export * from './endpoint'; export * from './option-group'; export * from './instance'; export * from './proxy'; +export * from './subnet-group'; // AWS::RDS CloudFormation Resources: export * from './rds.generated'; diff --git a/packages/@aws-cdk/aws-rds/lib/instance-engine.ts b/packages/@aws-cdk/aws-rds/lib/instance-engine.ts index 5c0062aba2771..3b2310212dbf8 100644 --- a/packages/@aws-cdk/aws-rds/lib/instance-engine.ts +++ b/packages/@aws-cdk/aws-rds/lib/instance-engine.ts @@ -1,7 +1,9 @@ +import * as iam from '@aws-cdk/aws-iam'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; import * as core from '@aws-cdk/core'; import { IEngine } from './engine'; import { EngineVersion } from './engine-version'; +import { IOptionGroup, OptionGroup } from './option-group'; /** * The options passed to {@link IInstanceEngine.bind}. @@ -20,14 +22,69 @@ export interface InstanceEngineBindOptions { * @default - none (it's an optional field) */ readonly timezone?: string; + + /** + * The role used for S3 importing. + * + * @default - none + */ + readonly s3ImportRole?: iam.IRole; + + /** + * The role used for S3 exporting. + * + * @default - none + */ + readonly s3ExportRole?: iam.IRole; + + /** + * The option group of the database + * + * @default - none + */ + readonly optionGroup?: IOptionGroup; } /** * The type returned from the {@link IInstanceEngine.bind} method. - * Empty for now, - * but there might be fields added to it in the future. */ export interface InstanceEngineConfig { + /** + * Features supported by the database engine. + * + * @see https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DBEngineVersion.html + * + * @default - no features + */ + readonly features?: InstanceEngineFeatures; + + /** + * Option group of the database. + * + * @default - none + */ + readonly optionGroup?: IOptionGroup; +} + +/** + * Represents Database Engine features + */ +export interface InstanceEngineFeatures { + /** + * Feature name for the DB instance that the IAM role to access the S3 bucket for import + * is to be associated with. + * + * @default - no s3Import feature name + */ + readonly s3Import?: string; + + /** + * Feature name for the DB instance that the IAM role to export to S3 bucket is to be + * associated with. + * + * @default - no s3Export feature name + */ + readonly s3Export?: string; } /** @@ -52,6 +109,7 @@ interface InstanceEngineBaseProps { readonly multiUserRotationApplication: secretsmanager.SecretRotationApplication; readonly version?: EngineVersion; readonly parameterGroupFamily?: string; + readonly features?: InstanceEngineFeatures; } abstract class InstanceEngineBase implements IInstanceEngine { @@ -61,8 +119,11 @@ abstract class InstanceEngineBase implements IInstanceEngine { public readonly singleUserRotationApplication: secretsmanager.SecretRotationApplication; public readonly multiUserRotationApplication: secretsmanager.SecretRotationApplication; + private readonly features?: InstanceEngineFeatures; + constructor(props: InstanceEngineBaseProps) { this.engineType = props.engineType; + this.features = props.features; this.singleUserRotationApplication = props.singleUserRotationApplication; this.multiUserRotationApplication = props.multiUserRotationApplication; this.engineVersion = props.version; @@ -71,12 +132,17 @@ abstract class InstanceEngineBase implements IInstanceEngine { } public bindToInstance(_scope: core.Construct, options: InstanceEngineBindOptions): InstanceEngineConfig { - if (options.timezone) { - throw new Error(`timezone property can be configured only for Microsoft SQL Server, not ${this.engineType}`); + if (options.timezone && !this.supportsTimezone) { + throw new Error(`timezone property can not be configured for ${this.engineType}`); } return { + features: this.features, + optionGroup: options.optionGroup, }; } + + /** Defines whether this Instance Engine can support timezone properties. */ + protected get supportsTimezone() { return false; } } /** @@ -329,6 +395,18 @@ class MySqlInstanceEngine extends InstanceEngineBase { } } +/** + * Features supported by the Postgres database engine + */ +export interface PostgresEngineFeatures { + /** + * Whether this version of the Postgres engine supports the S3 data import feature. + * + * @default false + */ + readonly s3Import?: boolean; +} + /** * The versions for the PostgreSQL instance engines * (those returned by {@link DatabaseInstanceEngine.postgres}). @@ -415,41 +493,41 @@ export class PostgresEngineVersion { /** Version "10.6". */ public static readonly VER_10_6 = PostgresEngineVersion.of('10.6', '10'); /** Version "10.7". */ - public static readonly VER_10_7 = PostgresEngineVersion.of('10.7', '10'); + public static readonly VER_10_7 = PostgresEngineVersion.of('10.7', '10', { s3Import: true }); /** Version "10.9". */ - public static readonly VER_10_9 = PostgresEngineVersion.of('10.9', '10'); + public static readonly VER_10_9 = PostgresEngineVersion.of('10.9', '10', { s3Import: true }); /** Version "10.10". */ - public static readonly VER_10_10 = PostgresEngineVersion.of('10.10', '10'); + public static readonly VER_10_10 = PostgresEngineVersion.of('10.10', '10', { s3Import: true }); /** Version "10.11". */ - public static readonly VER_10_11 = PostgresEngineVersion.of('10.11', '10'); + public static readonly VER_10_11 = PostgresEngineVersion.of('10.11', '10', { s3Import: true }); /** Version "10.12". */ - public static readonly VER_10_12 = PostgresEngineVersion.of('10.12', '10'); + public static readonly VER_10_12 = PostgresEngineVersion.of('10.12', '10', { s3Import: true }); /** Version "10.13". */ - public static readonly VER_10_13 = PostgresEngineVersion.of('10.13', '10'); + public static readonly VER_10_13 = PostgresEngineVersion.of('10.13', '10', { s3Import: true }); /** Version "11" (only a major version, without a specific minor version). */ - public static readonly VER_11 = PostgresEngineVersion.of('11', '11'); + public static readonly VER_11 = PostgresEngineVersion.of('11', '11', { s3Import: true }); /** Version "11.1". */ - public static readonly VER_11_1 = PostgresEngineVersion.of('11.1', '11'); + public static readonly VER_11_1 = PostgresEngineVersion.of('11.1', '11', { s3Import: true }); /** Version "11.2". */ - public static readonly VER_11_2 = PostgresEngineVersion.of('11.2', '11'); + public static readonly VER_11_2 = PostgresEngineVersion.of('11.2', '11', { s3Import: true }); /** Version "11.4". */ - public static readonly VER_11_4 = PostgresEngineVersion.of('11.4', '11'); + public static readonly VER_11_4 = PostgresEngineVersion.of('11.4', '11', { s3Import: true }); /** Version "11.5". */ - public static readonly VER_11_5 = PostgresEngineVersion.of('11.5', '11'); + public static readonly VER_11_5 = PostgresEngineVersion.of('11.5', '11', { s3Import: true }); /** Version "11.6". */ - public static readonly VER_11_6 = PostgresEngineVersion.of('11.6', '11'); + public static readonly VER_11_6 = PostgresEngineVersion.of('11.6', '11', { s3Import: true }); /** Version "11.7". */ - public static readonly VER_11_7 = PostgresEngineVersion.of('11.7', '11'); + public static readonly VER_11_7 = PostgresEngineVersion.of('11.7', '11', { s3Import: true }); /** Version "11.8". */ - public static readonly VER_11_8 = PostgresEngineVersion.of('11.8', '11'); + public static readonly VER_11_8 = PostgresEngineVersion.of('11.8', '11', { s3Import: true }); /** Version "12" (only a major version, without a specific minor version). */ - public static readonly VER_12 = PostgresEngineVersion.of('12', '12'); + public static readonly VER_12 = PostgresEngineVersion.of('12', '12', { s3Import: true }); /** Version "12.2". */ - public static readonly VER_12_2 = PostgresEngineVersion.of('12.2', '12'); + public static readonly VER_12_2 = PostgresEngineVersion.of('12.2', '12', { s3Import: true }); /** Version "12.3". */ - public static readonly VER_12_3 = PostgresEngineVersion.of('12.3', '12'); + public static readonly VER_12_3 = PostgresEngineVersion.of('12.3', '12', { s3Import: true }); /** * Create a new PostgresEngineVersion with an arbitrary version. @@ -459,8 +537,8 @@ export class PostgresEngineVersion { * @param postgresMajorVersion the major version of the engine, * for example "13" */ - public static of(postgresFullVersion: string, postgresMajorVersion: string): PostgresEngineVersion { - return new PostgresEngineVersion(postgresFullVersion, postgresMajorVersion); + public static of(postgresFullVersion: string, postgresMajorVersion: string, postgresFeatures?: PostgresEngineFeatures): PostgresEngineVersion { + return new PostgresEngineVersion(postgresFullVersion, postgresMajorVersion, postgresFeatures); } /** The full version string, for example, "13.11". */ @@ -468,9 +546,18 @@ export class PostgresEngineVersion { /** The major version of the engine, for example, "13". */ public readonly postgresMajorVersion: string; - private constructor(postgresFullVersion: string, postgresMajorVersion: string) { + /** + * The supported features for the DB engine + * @internal + */ + public readonly _features: InstanceEngineFeatures; + + private constructor(postgresFullVersion: string, postgresMajorVersion: string, postgresFeatures?: PostgresEngineFeatures) { this.postgresFullVersion = postgresFullVersion; this.postgresMajorVersion = postgresMajorVersion; + this._features = { + s3Import: postgresFeatures?.s3Import ? 's3Import' : undefined, + }; } } @@ -498,6 +585,7 @@ class PostgresInstanceEngine extends InstanceEngineBase { majorVersion: version.postgresMajorVersion, } : undefined, + features: version ? version?._features : { s3Import: 's3Import' }, }); } } @@ -700,8 +788,36 @@ abstract class OracleInstanceEngineBase extends InstanceEngineBase { singleUserRotationApplication: secretsmanager.SecretRotationApplication.ORACLE_ROTATION_SINGLE_USER, multiUserRotationApplication: secretsmanager.SecretRotationApplication.ORACLE_ROTATION_MULTI_USER, parameterGroupFamily: props.version ? `${props.engineType}-${props.version.majorVersion}` : undefined, + features: { + s3Import: 'S3_INTEGRATION', + s3Export: 'S3_INTEGRATION', + }, }); } + + public bindToInstance(scope: core.Construct, options: InstanceEngineBindOptions): InstanceEngineConfig { + const config = super.bindToInstance(scope, options); + + let optionGroup = options.optionGroup; + if (options.s3ImportRole || options.s3ExportRole) { + if (!optionGroup) { + optionGroup = new OptionGroup(scope, 'InstanceOptionGroup', { + engine: this, + configurations: [], + }); + } + // https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/oracle-s3-integration.html + optionGroup.addConfiguration({ + name: 'S3_INTEGRATION', + version: '1.0', + }); + } + + return { + ...config, + optionGroup, + }; + } } interface OracleInstanceEngineProps { @@ -876,6 +992,11 @@ export class SqlServerEngineVersion { /** Version "14.00.3192.2.v1". */ public static readonly VER_14_00_3192_2_V1 = SqlServerEngineVersion.of('14.00.3192.2.v1', '14.00'); + /** Version "15.00" (only a major version, without a specific minor version). */ + public static readonly VER_15 = SqlServerEngineVersion.of('15.00', '15.00'); + /** Version "15.00.4043.16.v1". */ + public static readonly VER_15_00_4043_16_V1 = SqlServerEngineVersion.of('15.00.4043.16.v1', '15.00'); + /** * Create a new SqlServerEngineVersion with an arbitrary version. * @@ -928,13 +1049,43 @@ abstract class SqlServerInstanceEngineBase extends InstanceEngineBase { ? props.version.sqlServerMajorVersion.slice(0, -1) : props.version.sqlServerMajorVersion}` : undefined, + features: { + s3Import: 'S3_INTEGRATION', + s3Export: 'S3_INTEGRATION', + }, }); } - public bindToInstance(_scope: core.Construct, _options: InstanceEngineBindOptions): InstanceEngineConfig { + public bindToInstance(scope: core.Construct, options: InstanceEngineBindOptions): InstanceEngineConfig { + const config = super.bindToInstance(scope, options); + + let optionGroup = options.optionGroup; + const s3Role = options.s3ImportRole ?? options.s3ExportRole; + if (s3Role) { + if (options.s3ImportRole && options.s3ExportRole && options.s3ImportRole !== options.s3ExportRole) { + throw new Error('S3 import and export roles must be the same for SQL Server engines'); + } + + if (!optionGroup) { + optionGroup = new OptionGroup(scope, 'InstanceOptionGroup', { + engine: this, + configurations: [], + }); + } + // https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.SQLServer.Options.BackupRestore.html + optionGroup.addConfiguration({ + name: 'SQLSERVER_BACKUP_RESTORE', + settings: { IAM_ROLE_ARN: s3Role.roleArn }, + }); + } + return { + ...config, + optionGroup, }; } + + protected get supportsTimezone() { return true; } } /** diff --git a/packages/@aws-cdk/aws-rds/lib/instance.ts b/packages/@aws-cdk/aws-rds/lib/instance.ts index 24a9c51d5d23a..1339306e9553f 100644 --- a/packages/@aws-cdk/aws-rds/lib/instance.ts +++ b/packages/@aws-cdk/aws-rds/lib/instance.ts @@ -3,16 +3,19 @@ import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as logs from '@aws-cdk/aws-logs'; +import * as s3 from '@aws-cdk/aws-s3'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; -import { CfnDeletionPolicy, Construct, Duration, IResource, Lazy, RemovalPolicy, Resource, SecretValue, Stack, Token } from '@aws-cdk/core'; +import { Construct, Duration, IResource, Lazy, RemovalPolicy, Resource, SecretValue, Stack, Token } from '@aws-cdk/core'; import { DatabaseSecret } from './database-secret'; import { Endpoint } from './endpoint'; import { IInstanceEngine } from './instance-engine'; import { IOptionGroup } from './option-group'; import { IParameterGroup } from './parameter-group'; +import { applyRemovalPolicy, defaultDeletionProtection, engineDescription, setupS3ImportExport } from './private/util'; import { PerformanceInsightRetention, RotationMultiUserOptions } from './props'; import { DatabaseProxy, DatabaseProxyOptions, ProxyTarget } from './proxy'; -import { CfnDBInstance, CfnDBInstanceProps, CfnDBSubnetGroup } from './rds.generated'; +import { CfnDBInstance, CfnDBInstanceProps } from './rds.generated'; +import { ISubnetGroup, SubnetGroup } from './subnet-group'; /** * A database instance @@ -466,7 +469,7 @@ export interface DatabaseInstanceNewProps { /** * Indicates whether the DB instance should have deletion protection enabled. * - * @default true + * @default - true if ``removalPolicy`` is RETAIN, false otherwise */ readonly deletionProtection?: boolean; @@ -499,6 +502,77 @@ export interface DatabaseInstanceNewProps { * @default - The role will be created for you if {@link DatabaseInstanceNewProps#domain} is specified */ readonly domainRole?: iam.IRole; + + /** + * Existing subnet group for the instance. + * + * @default - a new subnet group will be created. + */ + readonly subnetGroup?: ISubnetGroup; + + /** + * Role that will be associated with this DB instance to enable S3 import. + * This feature is only supported by the Microsoft SQL Server, Oracle, and PostgreSQL engines. + * + * This property must not be used if `s3ImportBuckets` is used. + * + * For Microsoft SQL Server: + * @see https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/SQLServer.Procedural.Importing.html + * For Oracle: + * @see https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/oracle-s3-integration.html + * For PostgreSQL: + * @see https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/PostgreSQL.Procedural.Importing.html + * + * @default - New role is created if `s3ImportBuckets` is set, no role is defined otherwise + */ + readonly s3ImportRole?: iam.IRole; + + /** + * S3 buckets that you want to load data from. + * This feature is only supported by the Microsoft SQL Server, Oracle, and PostgreSQL engines. + * + * This property must not be used if `s3ImportRole` is used. + * + * For Microsoft SQL Server: + * @see https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/SQLServer.Procedural.Importing.html + * For Oracle: + * @see https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/oracle-s3-integration.html + * For PostgreSQL: + * @see https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/PostgreSQL.Procedural.Importing.html + * + * @default - None + */ + readonly s3ImportBuckets?: s3.IBucket[]; + + /** + * Role that will be associated with this DB instance to enable S3 export. + * This feature is only supported by the Microsoft SQL Server and Oracle engines. + * + * This property must not be used if `s3ExportBuckets` is used. + * + * For Microsoft SQL Server: + * @see https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/SQLServer.Procedural.Importing.html + * For Oracle: + * @see https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/oracle-s3-integration.html + * + * @default - New role is created if `s3ExportBuckets` is set, no role is defined otherwise + */ + readonly s3ExportRole?: iam.IRole; + + /** + * S3 buckets that you want to load data into. + * This feature is only supported by the Microsoft SQL Server and Oracle engines. + * + * This property must not be used if `s3ExportRole` is used. + * + * For Microsoft SQL Server: + * @see https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/SQLServer.Procedural.Importing.html + * For Oracle: + * @see https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/oracle-s3-integration.html + * + * @default - None + */ + readonly s3ExportBuckets?: s3.IBucket[]; } /** @@ -535,11 +609,11 @@ abstract class DatabaseInstanceNew extends DatabaseInstanceBase implements IData } this.vpcPlacement = props.vpcSubnets ?? props.vpcPlacement; - const { subnetIds } = props.vpc.selectSubnets(this.vpcPlacement); - - const subnetGroup = new CfnDBSubnetGroup(this, 'SubnetGroup', { - dbSubnetGroupDescription: `Subnet group for ${this.node.id} database`, - subnetIds, + const subnetGroup = props.subnetGroup ?? new SubnetGroup(this, 'SubnetGroup', { + description: `Subnet group for ${this.node.id} database`, + vpc: this.vpc, + vpcSubnets: this.vpcPlacement, + removalPolicy: props.removalPolicy === RemovalPolicy.RETAIN ? props.removalPolicy : undefined, }); const securityGroups = props.securityGroups || [new ec2.SecurityGroup(this, 'SecurityGroup', { @@ -560,7 +634,6 @@ abstract class DatabaseInstanceNew extends DatabaseInstanceBase implements IData }); } - const deletionProtection = props.deletionProtection !== undefined ? props.deletionProtection : true; const storageType = props.storageType || StorageType.GP2; const iops = storageType === StorageType.IO1 ? (props.iops || 1000) : undefined; @@ -592,9 +665,9 @@ abstract class DatabaseInstanceNew extends DatabaseInstanceBase implements IData copyTagsToSnapshot: props.copyTagsToSnapshot !== undefined ? props.copyTagsToSnapshot : true, dbInstanceClass: Lazy.stringValue({ produce: () => `db.${this.instanceType}` }), dbInstanceIdentifier: props.instanceIdentifier, - dbSubnetGroupName: subnetGroup.ref, + dbSubnetGroupName: subnetGroup.subnetGroupName, deleteAutomatedBackups: props.deleteAutomatedBackups, - deletionProtection, + deletionProtection: defaultDeletionProtection(props.deletionProtection, props.removalPolicy), enableCloudwatchLogsExports: this.cloudwatchLogsExports, enableIamDatabaseAuthentication: Lazy.anyValue({ produce: () => this.enableIamAuthentication }), enablePerformanceInsights: enablePerformanceInsights || props.enablePerformanceInsights, // fall back to undefined if not set, @@ -602,7 +675,7 @@ abstract class DatabaseInstanceNew extends DatabaseInstanceBase implements IData monitoringInterval: props.monitoringInterval && props.monitoringInterval.toSeconds(), monitoringRoleArn: monitoringRole && monitoringRole.roleArn, multiAz: props.multiAz, - optionGroupName: props.optionGroup && props.optionGroup.optionGroupName, + optionGroupName: props.optionGroup?.optionGroupName, performanceInsightsKmsKeyId: props.performanceInsightEncryptionKey?.keyArn, performanceInsightsRetentionPeriod: enablePerformanceInsights ? (props.performanceInsightRetention || PerformanceInsightRetention.DEFAULT) @@ -727,12 +800,38 @@ abstract class DatabaseInstanceSource extends DatabaseInstanceNew implements IDa this.singleUserRotationApplication = props.engine.singleUserRotationApplication; this.multiUserRotationApplication = props.engine.multiUserRotationApplication; - props.engine.bindToInstance(this, props); + let { s3ImportRole, s3ExportRole } = setupS3ImportExport(this, props, true); + const engineConfig = props.engine.bindToInstance(this, { + ...props, + s3ImportRole, + s3ExportRole, + }); + + const instanceAssociatedRoles: CfnDBInstance.DBInstanceRoleProperty[] = []; + const engineFeatures = engineConfig.features; + if (s3ImportRole) { + if (!engineFeatures?.s3Import) { + throw new Error(`Engine '${engineDescription(props.engine)}' does not support S3 import`); + } + instanceAssociatedRoles.push({ roleArn: s3ImportRole.roleArn, featureName: engineFeatures?.s3Import }); + } + if (s3ExportRole) { + if (!engineFeatures?.s3Export) { + throw new Error(`Engine '${engineDescription(props.engine)}' does not support S3 export`); + } + // Only add the export role and feature if they are different from the import role & feature. + if (s3ImportRole !== s3ExportRole || engineFeatures.s3Import !== engineFeatures?.s3Export) { + instanceAssociatedRoles.push({ roleArn: s3ExportRole.roleArn, featureName: engineFeatures?.s3Export }); + } + } + this.instanceType = props.instanceType ?? ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.LARGE); const instanceParameterGroupConfig = props.parameterGroup?.bindToInstance({}); this.sourceCfnProps = { ...this.newCfnProps, + associatedRoles: instanceAssociatedRoles.length > 0 ? instanceAssociatedRoles : undefined, + optionGroupName: engineConfig.optionGroup?.optionGroupName, allocatedStorage: props.allocatedStorage ? props.allocatedStorage.toString() : '100', allowMajorVersionUpgrade: props.allowMajorVersionUpgrade, dbName: props.databaseName, @@ -864,7 +963,7 @@ export class DatabaseInstance extends DatabaseInstanceSource implements IDatabas const portAttribute = Token.asNumber(instance.attrEndpointPort); this.instanceEndpoint = new Endpoint(instance.attrEndpointAddress, portAttribute); - applyInstanceDeletionPolicy(instance, props.removalPolicy); + applyRemovalPolicy(instance, props.removalPolicy); if (secret) { this.secret = secret.attach(this); @@ -960,7 +1059,7 @@ export class DatabaseInstanceFromSnapshot extends DatabaseInstanceSource impleme const portAttribute = Token.asNumber(instance.attrEndpointPort); this.instanceEndpoint = new Endpoint(instance.attrEndpointAddress, portAttribute); - applyInstanceDeletionPolicy(instance, props.removalPolicy); + applyRemovalPolicy(instance, props.removalPolicy); if (secret) { this.secret = secret.attach(this); @@ -1035,7 +1134,7 @@ export class DatabaseInstanceReadReplica extends DatabaseInstanceNew implements const portAttribute = Token.asNumber(instance.attrEndpointPort); this.instanceEndpoint = new Endpoint(instance.attrEndpointAddress, portAttribute); - applyInstanceDeletionPolicy(instance, props.removalPolicy); + applyRemovalPolicy(instance, props.removalPolicy); this.setLogRetention(); } @@ -1051,14 +1150,3 @@ function renderProcessorFeatures(features: ProcessorFeatures): CfnDBInstance.Pro return featuresList.length === 0 ? undefined : featuresList; } - -function applyInstanceDeletionPolicy(cfnDbInstance: CfnDBInstance, removalPolicy: RemovalPolicy | undefined): void { - if (!removalPolicy) { - // the default DeletionPolicy is 'Snapshot', which is fine, - // but we should also make it 'Snapshot' for UpdateReplace policy - cfnDbInstance.cfnOptions.updateReplacePolicy = CfnDeletionPolicy.SNAPSHOT; - } else { - // just apply whatever removal policy the customer explicitly provided - cfnDbInstance.applyRemovalPolicy(removalPolicy); - } -} diff --git a/packages/@aws-cdk/aws-rds/lib/option-group.ts b/packages/@aws-cdk/aws-rds/lib/option-group.ts index f2e8ddf69078d..bb85497663558 100644 --- a/packages/@aws-cdk/aws-rds/lib/option-group.ts +++ b/packages/@aws-cdk/aws-rds/lib/option-group.ts @@ -1,5 +1,5 @@ import * as ec2 from '@aws-cdk/aws-ec2'; -import { Construct, IResource, Resource } from '@aws-cdk/core'; +import { Construct, IResource, Lazy, Resource } from '@aws-cdk/core'; import { IInstanceEngine } from './instance-engine'; import { CfnOptionGroup } from './rds.generated'; @@ -13,6 +13,14 @@ export interface IOptionGroup extends IResource { * @attribute */ readonly optionGroupName: string; + + /** + * Adds a configuration to this OptionGroup. + * This method is a no-op for an imported OptionGroup. + * + * @returns true if the OptionConfiguration was successfully added. + */ + addConfiguration(configuration: OptionConfiguration): boolean; } /** @@ -95,6 +103,7 @@ export class OptionGroup extends Resource implements IOptionGroup { public static fromOptionGroupName(scope: Construct, id: string, optionGroupName: string): IOptionGroup { class Import extends Resource { public readonly optionGroupName = optionGroupName; + public addConfiguration(_: OptionConfiguration) { return false; } } return new Import(scope, id); } @@ -109,6 +118,8 @@ export class OptionGroup extends Resource implements IOptionGroup { */ public readonly optionConnections: { [key: string]: ec2.Connections } = {}; + private readonly configurations: OptionConfiguration[] = []; + constructor(scope: Construct, id: string, props: OptionGroupProps) { super(scope, id); @@ -116,53 +127,60 @@ export class OptionGroup extends Resource implements IOptionGroup { if (!majorEngineVersion) { throw new Error("OptionGroup cannot be used with an engine that doesn't specify a version"); } + + props.configurations.forEach(config => this.addConfiguration(config)); + const optionGroup = new CfnOptionGroup(this, 'Resource', { engineName: props.engine.engineType, majorEngineVersion, optionGroupDescription: props.description || `Option group for ${props.engine.engineType} ${majorEngineVersion}`, - optionConfigurations: this.renderConfigurations(props.configurations), + optionConfigurations: Lazy.anyValue({ produce: () => this.renderConfigurations(this.configurations) }), }); this.optionGroupName = optionGroup.ref; } + public addConfiguration(configuration: OptionConfiguration) { + this.configurations.push(configuration); + + if (configuration.port) { + if (!configuration.vpc) { + throw new Error('`port` and `vpc` must be specified together.'); + } + + const securityGroups = configuration.securityGroups && configuration.securityGroups.length > 0 + ? configuration.securityGroups + : [new ec2.SecurityGroup(this, `SecurityGroup${configuration.name}`, { + description: `Security group for ${configuration.name} option`, + vpc: configuration.vpc, + })]; + + this.optionConnections[configuration.name] = new ec2.Connections({ + securityGroups: securityGroups, + defaultPort: ec2.Port.tcp(configuration.port), + }); + } + + return true; + } + /** * Renders the option configurations specifications. */ private renderConfigurations(configurations: OptionConfiguration[]): CfnOptionGroup.OptionConfigurationProperty[] { const configs: CfnOptionGroup.OptionConfigurationProperty[] = []; for (const config of configurations) { - let configuration: CfnOptionGroup.OptionConfigurationProperty = { + const securityGroups = config.vpc + ? this.optionConnections[config.name].securityGroups.map(sg => sg.securityGroupId) + : undefined; + + configs.push({ optionName: config.name, optionSettings: config.settings && Object.entries(config.settings).map(([name, value]) => ({ name, value })), optionVersion: config.version, - }; - - if (config.port) { - if (!config.vpc) { - throw new Error('`port` and `vpc` must be specified together.'); - } - - const securityGroups = config.securityGroups && config.securityGroups.length > 0 - ? config.securityGroups - : [new ec2.SecurityGroup(this, `SecurityGroup${config.name}`, { - description: `Security group for ${config.name} option`, - vpc: config.vpc, - })]; - - this.optionConnections[config.name] = new ec2.Connections({ - securityGroups: securityGroups, - defaultPort: ec2.Port.tcp(config.port), - }); - - configuration = { - ...configuration, - port: config.port, - vpcSecurityGroupMemberships: securityGroups.map(sg => sg.securityGroupId), - }; - } - - configs.push(configuration); + port: config.port, + vpcSecurityGroupMemberships: securityGroups, + }); } return configs; diff --git a/packages/@aws-cdk/aws-rds/lib/private/util.ts b/packages/@aws-cdk/aws-rds/lib/private/util.ts new file mode 100644 index 0000000000000..0caf78551b88d --- /dev/null +++ b/packages/@aws-cdk/aws-rds/lib/private/util.ts @@ -0,0 +1,82 @@ +import * as iam from '@aws-cdk/aws-iam'; +import * as s3 from '@aws-cdk/aws-s3'; +import { Construct, CfnDeletionPolicy, CfnResource, RemovalPolicy } from '@aws-cdk/core'; +import { IInstanceEngine } from '../instance-engine'; + +/** Common base of `DatabaseInstanceProps` and `DatabaseClusterBaseProps` that has only the S3 props */ +export interface DatabaseS3ImportExportProps { + readonly s3ImportRole?: iam.IRole; + readonly s3ImportBuckets?: s3.IBucket[]; + readonly s3ExportRole?: iam.IRole; + readonly s3ExportBuckets?: s3.IBucket[]; +} + +/** + * Validates the S3 import/export props and returns the import/export roles, if any. + * If `combineRoles` is true, will reuse the import role for export (or vice versa) if possible. + * + * Notably, `combineRoles` is (by default) set to true for instances, but false for clusters. + * This is because the `combineRoles` functionality is most applicable to instances and didn't exist + * for the initial clusters implementation. To maintain backwards compatibility, it is set to false for clusters. + */ +export function setupS3ImportExport( + scope: Construct, + props: DatabaseS3ImportExportProps, + combineRoles?: boolean): { s3ImportRole?: iam.IRole, s3ExportRole?: iam.IRole } { + + let s3ImportRole = props.s3ImportRole; + let s3ExportRole = props.s3ExportRole; + + if (props.s3ImportBuckets && props.s3ImportBuckets.length > 0) { + if (props.s3ImportRole) { + throw new Error('Only one of s3ImportRole or s3ImportBuckets must be specified, not both.'); + } + + s3ImportRole = (combineRoles && s3ExportRole) ? s3ExportRole : new iam.Role(scope, 'S3ImportRole', { + assumedBy: new iam.ServicePrincipal('rds.amazonaws.com'), + }); + for (const bucket of props.s3ImportBuckets) { + bucket.grantRead(s3ImportRole); + } + } + + if (props.s3ExportBuckets && props.s3ExportBuckets.length > 0) { + if (props.s3ExportRole) { + throw new Error('Only one of s3ExportRole or s3ExportBuckets must be specified, not both.'); + } + + s3ExportRole = (combineRoles && s3ImportRole) ? s3ImportRole : new iam.Role(scope, 'S3ExportRole', { + assumedBy: new iam.ServicePrincipal('rds.amazonaws.com'), + }); + for (const bucket of props.s3ExportBuckets) { + bucket.grantReadWrite(s3ExportRole); + } + } + + return { s3ImportRole, s3ExportRole }; +} + +export function engineDescription(engine: IInstanceEngine) { + 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 + */ +export function defaultDeletionProtection(deletionProtection?: boolean, removalPolicy?: RemovalPolicy): boolean | undefined { + return deletionProtection !== undefined + ? deletionProtection + : (removalPolicy === RemovalPolicy.RETAIN ? true : undefined); +} diff --git a/packages/@aws-cdk/aws-rds/lib/subnet-group.ts b/packages/@aws-cdk/aws-rds/lib/subnet-group.ts new file mode 100644 index 0000000000000..9237cb596da13 --- /dev/null +++ b/packages/@aws-cdk/aws-rds/lib/subnet-group.ts @@ -0,0 +1,89 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; +import { Construct, IResource, RemovalPolicy, Resource } from '@aws-cdk/core'; +import { CfnDBSubnetGroup } from './rds.generated'; + +/** + * Interface for a subnet group. + */ +export interface ISubnetGroup extends IResource { + /** + * The name of the subnet group. + * @attribute + */ + readonly subnetGroupName: string; +} + +/** + * Properties for creating a SubnetGroup. + */ +export interface SubnetGroupProps { + /** + * Description of the subnet group. + */ + readonly description: string; + + /** + * The VPC to place the subnet group in. + */ + readonly vpc: ec2.IVpc; + + /** + * The name of the subnet group. + * + * @default - a name is generated + */ + readonly subnetGroupName?: string; + + /** + * Which subnets within the VPC to associate with this group. + * + * @default - private subnets + */ + readonly vpcSubnets?: ec2.SubnetSelection; + + /** + * The removal policy to apply when the subnet group are removed + * from the stack or replaced during an update. + * + * @default RemovalPolicy.DESTROY + */ + readonly removalPolicy?: RemovalPolicy +} + +/** + * Class for creating a RDS DB subnet group + * + * @resource AWS::RDS::DBSubnetGroup + */ +export class SubnetGroup extends Resource implements ISubnetGroup { + + /** + * Imports an existing subnet group by name. + */ + public static fromSubnetGroupName(scope: Construct, id: string, subnetGroupName: string): ISubnetGroup { + return new class extends Resource implements ISubnetGroup { + public readonly subnetGroupName = subnetGroupName; + }(scope, id); + } + + public readonly subnetGroupName: string; + + constructor(scope: Construct, id: string, props: SubnetGroupProps) { + super(scope, id); + + const { subnetIds } = props.vpc.selectSubnets(props.vpcSubnets ?? { subnetType: ec2.SubnetType.PRIVATE }); + + // Using 'Default' as the resource id for historical reasons (usage from `Instance` and `Cluster`). + const subnetGroup = new CfnDBSubnetGroup(this, 'Default', { + dbSubnetGroupDescription: props.description, + dbSubnetGroupName: props.subnetGroupName, + subnetIds, + }); + + if (props.removalPolicy) { + subnetGroup.applyRemovalPolicy(props.removalPolicy); + } + + this.subnetGroupName = subnetGroup.ref; + } +} diff --git a/packages/@aws-cdk/aws-rds/package.json b/packages/@aws-cdk/aws-rds/package.json index 9ad9b40911c7c..e45b2851a108f 100644 --- a/packages/@aws-cdk/aws-rds/package.json +++ b/packages/@aws-cdk/aws-rds/package.json @@ -1,7 +1,7 @@ { "name": "@aws-cdk/aws-rds", "version": "0.0.0", - "description": "CDK Constructs for AWS RDS", + "description": "The CDK Construct Library for AWS::RDS", "main": "lib/index.js", "types": "lib/index.d.ts", "jsii": { @@ -112,6 +112,7 @@ "props-physical-name:@aws-cdk/aws-rds.DatabaseInstanceReadReplicaProps", "props-physical-name:@aws-cdk/aws-rds.DatabaseSecretProps", "props-physical-name:@aws-cdk/aws-rds.OptionGroupProps", + "props-physical-name:@aws-cdk/aws-rds.SubnetGroupProps", "docs-public-apis:@aws-cdk/aws-rds.SecretRotationApplication.semanticVersion", "docs-public-apis:@aws-cdk/aws-rds.SecretRotationApplication.applicationId", "docs-public-apis:@aws-cdk/aws-rds.SecretRotationApplication.SQLSERVER_ROTATION_SINGLE_USER", 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 new file mode 100644 index 0000000000000..8b2b425303bec --- /dev/null +++ b/packages/@aws-cdk/aws-rds/test/integ.instance-s3.expected.json @@ -0,0 +1,616 @@ +{ + "Resources": { + "VPCB9E5F0B4": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-instance-s3-integ/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-cdk-rds-instance-s3-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1RouteTableFEE4B781": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-instance-s3-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1RouteTableAssociation0B0896DC": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + } + } + }, + "VPCPublicSubnet1DefaultRoute91CEF279": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet1EIP6AD938E8": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-instance-s3-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1NATGatewayE0556630": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet1EIP6AD938E8", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-instance-s3-integ/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-cdk-rds-instance-s3-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2RouteTable6F1A15F1": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-instance-s3-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2RouteTableAssociation5A808732": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + } + }, + "VPCPublicSubnet2DefaultRouteB7481BBA": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet2EIP4947BC00": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-instance-s3-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2NATGateway3C070193": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet2EIP4947BC00", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-instance-s3-integ/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-cdk-rds-instance-s3-integ/VPC/PrivateSubnet1" + } + ] + } + }, + "VPCPrivateSubnet1RouteTableBE8A6027": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-instance-s3-integ/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-cdk-rds-instance-s3-integ/VPC/PrivateSubnet2" + } + ] + } + }, + "VPCPrivateSubnet2RouteTable0A19E10E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-instance-s3-integ/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-cdk-rds-instance-s3-integ/VPC" + } + ] + } + }, + "VPCVPCGW99B986DC": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "InternetGatewayId": { + "Ref": "VPCIGWB7E252D3" + } + } + }, + "ImportBucketBAF3A8E9": { + "Type": "AWS::S3::Bucket", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ExportBucket4E99310E": { + "Type": "AWS::S3::Bucket", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "DatabaseSubnetGroup7D60F180": { + "Type": "AWS::RDS::DBSubnetGroup", + "Properties": { + "DBSubnetGroupDescription": "Subnet group for Database database", + "SubnetIds": [ + { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + }, + { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + ] + } + }, + "DatabaseSecurityGroup5C91FDCB": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "Security group for Database database", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "DatabaseS3ImportRole377BC9C0": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "rds.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "DatabaseS3ImportRoleDefaultPolicyA60A7342": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetObject*", + "s3:GetBucket*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "ImportBucketBAF3A8E9", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "ImportBucketBAF3A8E9", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": [ + "s3:GetObject*", + "s3:GetBucket*", + "s3:List*", + "s3:DeleteObject*", + "s3:PutObject*", + "s3:Abort*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "ExportBucket4E99310E", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "ExportBucket4E99310E", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "DatabaseS3ImportRoleDefaultPolicyA60A7342", + "Roles": [ + { + "Ref": "DatabaseS3ImportRole377BC9C0" + } + ] + } + }, + "DatabaseInstanceOptionGroupDA39E317": { + "Type": "AWS::RDS::OptionGroup", + "Properties": { + "EngineName": "sqlserver-se", + "MajorEngineVersion": "14.00", + "OptionConfigurations": [ + { + "OptionName": "SQLSERVER_BACKUP_RESTORE", + "OptionSettings": [ + { + "Name": "IAM_ROLE_ARN", + "Value": { + "Fn::GetAtt": [ + "DatabaseS3ImportRole377BC9C0", + "Arn" + ] + } + } + ] + } + ], + "OptionGroupDescription": "Option group for sqlserver-se 14.00" + } + }, + "DatabaseSecret3B817195": { + "Type": "AWS::SecretsManager::Secret", + "Properties": { + "Description": { + "Fn::Join": [ + "", + [ + "Generated by the CDK for stack: ", + { + "Ref": "AWS::StackName" + } + ] + ] + }, + "GenerateSecretString": { + "ExcludeCharacters": "\"@/\\", + "GenerateStringKey": "password", + "PasswordLength": 30, + "SecretStringTemplate": "{\"username\":\"admin\"}" + } + } + }, + "DatabaseSecretAttachmentE5D1B020": { + "Type": "AWS::SecretsManager::SecretTargetAttachment", + "Properties": { + "SecretId": { + "Ref": "DatabaseSecret3B817195" + }, + "TargetId": { + "Ref": "DatabaseB269D8BB" + }, + "TargetType": "AWS::RDS::DBInstance" + } + }, + "DatabaseB269D8BB": { + "Type": "AWS::RDS::DBInstance", + "Properties": { + "DBInstanceClass": "db.m5.large", + "AllocatedStorage": "100", + "AssociatedRoles": [ + { + "FeatureName": "S3_INTEGRATION", + "RoleArn": { + "Fn::GetAtt": [ + "DatabaseS3ImportRole377BC9C0", + "Arn" + ] + } + } + ], + "CopyTagsToSnapshot": true, + "DBSubnetGroupName": { + "Ref": "DatabaseSubnetGroup7D60F180" + }, + "Engine": "sqlserver-se", + "EngineVersion": "14.00.3192.2.v1", + "LicenseModel": "license-included", + "MasterUsername": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "DatabaseSecret3B817195" + }, + ":SecretString:username::}}" + ] + ] + }, + "MasterUserPassword": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "DatabaseSecret3B817195" + }, + ":SecretString:password::}}" + ] + ] + }, + "OptionGroupName": { + "Ref": "DatabaseInstanceOptionGroupDA39E317" + }, + "StorageType": "gp2", + "VPCSecurityGroups": [ + { + "Fn::GetAtt": [ + "DatabaseSecurityGroup5C91FDCB", + "GroupId" + ] + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + } +} diff --git a/packages/@aws-cdk/aws-rds/test/integ.instance-s3.ts b/packages/@aws-cdk/aws-rds/test/integ.instance-s3.ts new file mode 100644 index 0000000000000..d3503d5889404 --- /dev/null +++ b/packages/@aws-cdk/aws-rds/test/integ.instance-s3.ts @@ -0,0 +1,24 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as cdk from '@aws-cdk/core'; +import { DatabaseInstance, DatabaseInstanceEngine, LicenseModel, SqlServerEngineVersion } from '../lib'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-cdk-rds-instance-s3-integ'); + +const vpc = new ec2.Vpc(stack, 'VPC', { maxAzs: 2 }); + +const importBucket = new s3.Bucket(stack, 'ImportBucket', { removalPolicy: cdk.RemovalPolicy.DESTROY }); +const exportBucket = new s3.Bucket(stack, 'ExportBucket', { removalPolicy: cdk.RemovalPolicy.DESTROY }); + +new DatabaseInstance(stack, 'Database', { + engine: DatabaseInstanceEngine.sqlServerSe({ version: SqlServerEngineVersion.VER_14_00_3192_2_V1 }), + masterUsername: 'admin', + vpc, + licenseModel: LicenseModel.LICENSE_INCLUDED, + s3ImportBuckets: [importBucket], + s3ExportBuckets: [exportBucket], + removalPolicy: cdk.RemovalPolicy.DESTROY, +}); + +app.synth(); 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 478b874b4d079..ef71c890eaf4b 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 @@ -636,7 +636,6 @@ "DBSubnetGroupName": { "Ref": "InstanceSubnetGroupF2CBA54F" }, - "DeletionProtection": true, "EnableCloudwatchLogsExports": [ "trace", "audit", @@ -1122,4 +1121,4 @@ "Description": "Artifact hash for asset \"74a1cab76f5603c5e27101cb3809d8745c50f708b0f4b497ed0910eb533d437b\"" } } -} \ 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 10e7b2afb02f8..3a77314058702 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.proxy.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.proxy.expected.json @@ -428,7 +428,6 @@ "DBSubnetGroupName": { "Ref": "dbInstanceSubnetGroupD062EC9E" }, - "DeletionProtection": true, "Engine": "postgres", "MasterUsername": { "Fn::Join": [ diff --git a/packages/@aws-cdk/aws-rds/test/test.cluster.ts b/packages/@aws-cdk/aws-rds/test/test.cluster.ts index 8320b7a5e25c4..8915973a5938d 100644 --- a/packages/@aws-cdk/aws-rds/test/test.cluster.ts +++ b/packages/@aws-cdk/aws-rds/test/test.cluster.ts @@ -7,8 +7,8 @@ import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; import { - AuroraEngineVersion, AuroraMysqlEngineVersion, AuroraPostgresEngineVersion, DatabaseCluster, DatabaseClusterEngine, - DatabaseClusterFromSnapshot, ParameterGroup, PerformanceInsightRetention, + AuroraEngineVersion, AuroraMysqlEngineVersion, AuroraPostgresEngineVersion, CfnDBCluster, DatabaseCluster, DatabaseClusterEngine, + DatabaseClusterFromSnapshot, ParameterGroup, PerformanceInsightRetention, SubnetGroup, } from '../lib'; export = { @@ -839,6 +839,129 @@ export = { test.done(); }, + 'cluster with s3 import bucket adds supported feature name to IAM role'(test: Test) { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + const bucket = new s3.Bucket(stack, 'Bucket'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.auroraPostgres({ + version: AuroraPostgresEngineVersion.VER_10_12, + }), + instances: 1, + masterUser: { + username: 'admin', + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + }, + s3ImportBuckets: [bucket], + }); + + // THEN + expect(stack).to(haveResource('AWS::RDS::DBCluster', { + AssociatedRoles: [{ + RoleArn: { + 'Fn::GetAtt': [ + 'DatabaseS3ImportRole377BC9C0', + 'Arn', + ], + }, + FeatureName: 's3Import', + }], + })); + + test.done(); + }, + + 'throws when s3 import bucket or s3 export bucket is supplied for a Postgres version that does not support it'(test: Test) { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + const bucket = new s3.Bucket(stack, 'Bucket'); + + // WHEN / THEN + test.throws(() => { + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.auroraPostgres({ + version: AuroraPostgresEngineVersion.VER_10_4, + }), + instances: 1, + masterUser: { + username: 'admin', + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + }, + s3ImportBuckets: [bucket], + }); + }, /s3Import is not supported for Postgres version: 10.4. Use a version that supports the s3Import feature./); + + test.throws(() => { + new DatabaseCluster(stack, 'AnotherDatabase', { + engine: DatabaseClusterEngine.auroraPostgres({ + version: AuroraPostgresEngineVersion.VER_10_4, + }), + instances: 1, + masterUser: { + username: 'admin', + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + }, + s3ExportBuckets: [bucket], + }); + }, /s3Export is not supported for Postgres version: 10.4. Use a version that supports the s3Export feature./); + + test.done(); + }, + + 'cluster with s3 export bucket adds supported feature name to IAM role'(test: Test) { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + const bucket = new s3.Bucket(stack, 'Bucket'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.auroraPostgres({ + version: AuroraPostgresEngineVersion.VER_10_12, + }), + instances: 1, + masterUser: { + username: 'admin', + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + }, + s3ExportBuckets: [bucket], + }); + + // THEN + expect(stack).to(haveResource('AWS::RDS::DBCluster', { + AssociatedRoles: [{ + RoleArn: { + 'Fn::GetAtt': [ + 'DatabaseS3ExportRole9E328562', + 'Arn', + ], + }, + FeatureName: 's3Export', + }], + })); + + test.done(); + }, + 'create a cluster with s3 export role'(test: Test) { // GIVEN const stack = testStack(); @@ -1125,7 +1248,7 @@ export = { // WHEN new DatabaseCluster(stack, 'Database', { engine: DatabaseClusterEngine.auroraPostgres({ - version: AuroraPostgresEngineVersion.VER_11_4, + version: AuroraPostgresEngineVersion.VER_11_6, }), instances: 1, masterUser: { @@ -1157,6 +1280,56 @@ export = { test.done(); }, + 'unversioned PostgreSQL cluster can be used with s3 import and s3 export buckets'(test: Test) { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + const bucket = new s3.Bucket(stack, 'Bucket'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA_POSTGRESQL, + instances: 1, + masterUser: { + username: 'admin', + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + }, + parameterGroup: ParameterGroup.fromParameterGroupName(stack, 'ParameterGroup', 'default.aurora-postgresql11'), + s3ImportBuckets: [bucket], + s3ExportBuckets: [bucket], + }); + + // THEN + expect(stack).to(haveResource('AWS::RDS::DBCluster', { + AssociatedRoles: [ + { + FeatureName: 's3Import', + RoleArn: { + 'Fn::GetAtt': [ + 'DatabaseS3ImportRole377BC9C0', + 'Arn', + ], + }, + }, + { + FeatureName: 's3Export', + RoleArn: { + 'Fn::GetAtt': [ + 'DatabaseS3ExportRole9E328562', + 'Arn', + ], + }, + }, + ], + })); + + test.done(); + }, + 'MySQL cluster without S3 exports or imports references the correct default ParameterGroup'(test: Test) { // GIVEN const stack = testStack(); @@ -1422,6 +1595,54 @@ export = { test.done(); }, + + 'reuse an existing subnet group'(test: Test) { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.aurora({ version: AuroraEngineVersion.VER_1_22_2 }), + masterUser: { + username: 'admin', + }, + instanceProps: { + vpc, + }, + subnetGroup: SubnetGroup.fromSubnetGroupName(stack, 'SubnetGroup', 'my-subnet-group'), + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::RDS::DBCluster', { + DBSubnetGroupName: 'my-subnet-group', + })); + expect(stack).to(countResources('AWS::RDS::DBSubnetGroup', 0)); + + test.done(); + }, + + 'defaultChild returns the DB Cluster'(test: Test) { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + const cluster = new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.aurora({ version: AuroraEngineVersion.VER_1_22_2 }), + masterUser: { + username: 'admin', + }, + instanceProps: { + vpc, + }, + }); + + // THEN + test.ok(cluster.node.defaultChild instanceof CfnDBCluster); + + test.done(); + }, }; function testStack() { diff --git a/packages/@aws-cdk/aws-rds/test/test.instance-engine.ts b/packages/@aws-cdk/aws-rds/test/test.instance-engine.ts index 4668cfd683163..90d5a7a204eae 100644 --- a/packages/@aws-cdk/aws-rds/test/test.instance-engine.ts +++ b/packages/@aws-cdk/aws-rds/test/test.instance-engine.ts @@ -1,3 +1,6 @@ +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 * as rds from '../lib'; @@ -111,4 +114,174 @@ export = { test.done(); }, + + 'Oracle engine bindToInstance': { + + 'returns s3 integration feature'(test: Test) { + const engine = rds.DatabaseInstanceEngine.oracleSe2({ version: rds.OracleEngineVersion.VER_19_0_0_0_2020_04_R1 }); + + const engineConfig = engine.bindToInstance(new cdk.Stack(), {}); + test.equals(engineConfig.features?.s3Import, 'S3_INTEGRATION'); + test.equals(engineConfig.features?.s3Export, 'S3_INTEGRATION'); + + test.done(); + }, + + 's3 import/export - creates an option group if needed'(test: Test) { + const stack = new cdk.Stack(); + const engine = rds.DatabaseInstanceEngine.oracleSe2({ version: rds.OracleEngineVersion.VER_19_0_0_0_2020_04_R1 }); + + const engineConfig = engine.bindToInstance(stack, { + optionGroup: undefined, + s3ImportRole: new iam.Role(stack, 'ImportRole', { assumedBy: new iam.AccountRootPrincipal() }), + }); + + test.ok(engineConfig.optionGroup); + expect(stack).to(haveResourceLike('AWS::RDS::OptionGroup', { + EngineName: 'oracle-se2', + OptionConfigurations: [{ + OptionName: 'S3_INTEGRATION', + OptionVersion: '1.0', + }], + })); + + test.done(); + }, + + 's3 import/export - appends to an existing option group if it exists'(test: Test) { + const stack = new cdk.Stack(); + const engine = rds.DatabaseInstanceEngine.oracleSe2({ version: rds.OracleEngineVersion.VER_19_0_0_0_2020_04_R1 }); + const optionGroup = new rds.OptionGroup(stack, 'OptionGroup', { + engine, + configurations: [{ + name: 'MY_OPTION_CONFIG', + }], + }); + + const engineConfig = engine.bindToInstance(stack, { + optionGroup, + s3ImportRole: new iam.Role(stack, 'ImportRole', { assumedBy: new iam.AccountRootPrincipal() }), + }); + + test.equals(engineConfig.optionGroup, optionGroup); + expect(stack).to(haveResourceLike('AWS::RDS::OptionGroup', { + EngineName: 'oracle-se2', + OptionConfigurations: [{ + OptionName: 'MY_OPTION_CONFIG', + }, + { + OptionName: 'S3_INTEGRATION', + OptionVersion: '1.0', + }], + })); + + test.done(); + }, + }, + + 'SQL Server engine bindToInstance': { + 'returns s3 integration feature'(test: Test) { + const engine = rds.DatabaseInstanceEngine.sqlServerSe({ version: rds.SqlServerEngineVersion.VER_14_00_3192_2_V1 }); + + const engineConfig = engine.bindToInstance(new cdk.Stack(), {}); + test.equals(engineConfig.features?.s3Import, 'S3_INTEGRATION'); + test.equals(engineConfig.features?.s3Export, 'S3_INTEGRATION'); + + test.done(); + }, + + 's3 import/export - throws if roles are not equal'(test: Test) { + const stack = new cdk.Stack(); + const engine = rds.DatabaseInstanceEngine.sqlServerSe({ version: rds.SqlServerEngineVersion.VER_14_00_3192_2_V1 }); + + const s3ImportRole = new iam.Role(stack, 'ImportRole', { assumedBy: new iam.AccountRootPrincipal() }); + const s3ExportRole = new iam.Role(stack, 'ExportRole', { assumedBy: new iam.AccountRootPrincipal() }); + + test.throws(() => engine.bindToInstance(new cdk.Stack(), { s3ImportRole, s3ExportRole }), /S3 import and export roles must be the same/); + test.doesNotThrow(() => engine.bindToInstance(new cdk.Stack(), { s3ImportRole })); + test.doesNotThrow(() => engine.bindToInstance(new cdk.Stack(), { s3ExportRole })); + test.doesNotThrow(() => engine.bindToInstance(new cdk.Stack(), { s3ImportRole, s3ExportRole: s3ImportRole })); + + test.done(); + }, + + 's3 import/export - creates an option group if needed'(test: Test) { + const stack = new cdk.Stack(); + const engine = rds.DatabaseInstanceEngine.sqlServerSe({ version: rds.SqlServerEngineVersion.VER_14_00_3192_2_V1 }); + + const engineConfig = engine.bindToInstance(stack, { + optionGroup: undefined, + s3ImportRole: new iam.Role(stack, 'ImportRole', { assumedBy: new iam.AccountRootPrincipal() }), + }); + + test.ok(engineConfig.optionGroup); + expect(stack).to(haveResourceLike('AWS::RDS::OptionGroup', { + EngineName: 'sqlserver-se', + OptionConfigurations: [{ + OptionName: 'SQLSERVER_BACKUP_RESTORE', + OptionSettings: [{ + Name: 'IAM_ROLE_ARN', + Value: { 'Fn::GetAtt': ['ImportRole0C9E6F9A', 'Arn'] }, + }], + }], + })); + + test.done(); + }, + + 's3 import/export - appends to an existing option group if it exists'(test: Test) { + const stack = new cdk.Stack(); + const engine = rds.DatabaseInstanceEngine.sqlServerSe({ version: rds.SqlServerEngineVersion.VER_14_00_3192_2_V1 }); + const optionGroup = new rds.OptionGroup(stack, 'OptionGroup', { + engine, + configurations: [{ + name: 'MY_OPTION_CONFIG', + }], + }); + + const engineConfig = engine.bindToInstance(stack, { + optionGroup, + s3ImportRole: new iam.Role(stack, 'ImportRole', { assumedBy: new iam.AccountRootPrincipal() }), + }); + + test.equals(engineConfig.optionGroup, optionGroup); + expect(stack).to(haveResourceLike('AWS::RDS::OptionGroup', { + EngineName: 'sqlserver-se', + OptionConfigurations: [{ + OptionName: 'MY_OPTION_CONFIG', + }, + { + OptionName: 'SQLSERVER_BACKUP_RESTORE', + OptionSettings: [{ + Name: 'IAM_ROLE_ARN', + Value: { 'Fn::GetAtt': ['ImportRole0C9E6F9A', 'Arn'] }, + }], + }], + })); + + test.done(); + }, + }, + + 'PostgreSQL engine bindToInstance': { + 'returns no features for older versions'(test: Test) { + const engineNewerVersion = rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_10_6 }); + + const engineConfig = engineNewerVersion.bindToInstance(new cdk.Stack(), {}); + test.equals(engineConfig.features?.s3Import, undefined); + test.equals(engineConfig.features?.s3Export, undefined); + + test.done(); + }, + + 'returns s3 import feature if the version supports it'(test: Test) { + const engineNewerVersion = rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_12_3 }); + + const engineConfig = engineNewerVersion.bindToInstance(new cdk.Stack(), {}); + test.equals(engineConfig.features?.s3Import, 's3Import'); + test.equals(engineConfig.features?.s3Export, undefined); + + test.done(); + }, + }, }; diff --git a/packages/@aws-cdk/aws-rds/test/test.instance.ts b/packages/@aws-cdk/aws-rds/test/test.instance.ts index 074bb1438b3e2..2cd024ead7aab 100644 --- a/packages/@aws-cdk/aws-rds/test/test.instance.ts +++ b/packages/@aws-cdk/aws-rds/test/test.instance.ts @@ -5,6 +5,7 @@ import { ManagedPolicy, Role, ServicePrincipal, AccountPrincipal } from '@aws-cd import * as kms from '@aws-cdk/aws-kms'; 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 * as rds from '../lib'; @@ -56,7 +57,6 @@ export = { DBSubnetGroupName: { Ref: 'InstanceSubnetGroupF2CBA54F', }, - DeletionProtection: true, EnableCloudwatchLogsExports: [ 'trace', 'audit', @@ -688,7 +688,7 @@ export = { masterUsername: 'master', timezone: 'Europe/Zurich', vpc, - }), /timezone property can be configured only for Microsoft SQL Server/); + }), /timezone property can not be configured for/); }); test.done(); @@ -964,4 +964,161 @@ export = { test.done(); }, }, + + 'reuse an existing subnet group'(test: Test) { + new rds.DatabaseInstance(stack, 'Database', { + engine: rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_12_3 }), + masterUsername: 'admin', + vpc, + subnetGroup: rds.SubnetGroup.fromSubnetGroupName(stack, 'SubnetGroup', 'my-subnet-group'), + }); + + expect(stack).to(haveResourceLike('AWS::RDS::DBInstance', { + DBSubnetGroupName: 'my-subnet-group', + })); + expect(stack).to(countResources('AWS::RDS::DBSubnetGroup', 0)); + + test.done(); + }, + + 'defaultChild returns the DB Instance'(test: Test) { + const instance = new rds.DatabaseInstance(stack, 'Database', { + engine: rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_12_3 }), + masterUsername: 'admin', + vpc, + }); + + // THEN + test.ok(instance.node.defaultChild instanceof rds.CfnDBInstance); + + test.done(); + }, + 'S3 Import/Export': { + 'instance with s3 import and export buckets'(test: Test) { + new rds.DatabaseInstance(stack, 'DB', { + engine: rds.DatabaseInstanceEngine.sqlServerSe({ version: rds.SqlServerEngineVersion.VER_14_00_3192_2_V1 }), + masterUsername: 'admin', + vpc, + s3ImportBuckets: [new s3.Bucket(stack, 'S3Import')], + s3ExportBuckets: [new s3.Bucket(stack, 'S3Export')], + }); + + expect(stack).to(haveResource('AWS::RDS::DBInstance', { + AssociatedRoles: [ + { + FeatureName: 'S3_INTEGRATION', + RoleArn: { 'Fn::GetAtt': ['DBS3ImportRoleEF69B7D7', 'Arn'] }, + }, + ], + OptionGroupName: { Ref: 'DBInstanceOptionGroup46C68006' }, + })); + + // Can read from import bucket, and read/write from export bucket + expect(stack).to(haveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [{ + Action: [ + 's3:GetObject*', + 's3:GetBucket*', + 's3:List*', + ], + Effect: 'Allow', + Resource: [ + { 'Fn::GetAtt': ['S3ImportD5D5F2EB', 'Arn'] }, + { 'Fn::Join': ['', [{ 'Fn::GetAtt': ['S3ImportD5D5F2EB', 'Arn'] }, '/*']] }, + ], + }, + { + Action: [ + 's3:GetObject*', + 's3:GetBucket*', + 's3:List*', + 's3:DeleteObject*', + 's3:PutObject*', + 's3:Abort*', + ], + Effect: 'Allow', + Resource: [ + { 'Fn::GetAtt': ['S3Export390B8694', 'Arn'] }, + { 'Fn::Join': ['', [{ 'Fn::GetAtt': ['S3Export390B8694', 'Arn'] }, '/*']] }, + ], + }], + Version: '2012-10-17', + }, + })); + + test.done(); + }, + + 'throws if using s3 import on unsupported engine'(test: Test) { + const s3ImportRole = new Role(stack, 'S3ImportRole', { + assumedBy: new ServicePrincipal('rds.amazonaws.com'), + }); + + test.throws(() => { + new rds.DatabaseInstance(stack, 'DBWithImportBucket', { + engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19 }), + masterUsername: 'admin', + vpc, + s3ImportBuckets: [new s3.Bucket(stack, 'S3Import')], + }); + }, /Engine 'mysql-8.0.19' does not support S3 import/); + test.throws(() => { + new rds.DatabaseInstance(stack, 'DBWithImportRole', { + engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19 }), + masterUsername: 'admin', + vpc, + s3ImportRole, + }); + }, /Engine 'mysql-8.0.19' does not support S3 import/); + + test.done(); + }, + + 'throws if using s3 export on unsupported engine'(test: Test) { + const s3ExportRole = new Role(stack, 'S3ExportRole', { + assumedBy: new ServicePrincipal('rds.amazonaws.com'), + }); + + test.throws(() => { + new rds.DatabaseInstance(stack, 'DBWithExportBucket', { + engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19 }), + masterUsername: 'admin', + vpc, + s3ExportBuckets: [new s3.Bucket(stack, 'S3Export')], + }); + }, /Engine 'mysql-8.0.19' does not support S3 export/); + test.throws(() => { + new rds.DatabaseInstance(stack, 'DBWithExportRole', { + engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19 }), + masterUsername: 'admin', + vpc, + s3ExportRole: s3ExportRole, + }); + }, /Engine 'mysql-8.0.19' does not support S3 export/); + + test.done(); + }, + + 'throws if provided two different roles for import/export'(test: Test) { + const s3ImportRole = new Role(stack, 'S3ImportRole', { + assumedBy: new ServicePrincipal('rds.amazonaws.com'), + }); + const s3ExportRole = new Role(stack, 'S3ExportRole', { + assumedBy: new ServicePrincipal('rds.amazonaws.com'), + }); + + test.throws(() => { + new rds.DatabaseInstance(stack, 'DBWithExportBucket', { + engine: rds.DatabaseInstanceEngine.sqlServerEe({ version: rds.SqlServerEngineVersion.VER_14_00_3192_2_V1 }), + masterUsername: 'admin', + vpc, + s3ImportRole, + s3ExportRole, + }); + }, /S3 import and export roles must be the same/); + + test.done(); + }, + }, }; diff --git a/packages/@aws-cdk/aws-rds/test/test.subnet-group.ts b/packages/@aws-cdk/aws-rds/test/test.subnet-group.ts new file mode 100644 index 0000000000000..6d2a71e84bad7 --- /dev/null +++ b/packages/@aws-cdk/aws-rds/test/test.subnet-group.ts @@ -0,0 +1,98 @@ +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 * as rds from '../lib'; + +let stack: cdk.Stack; +let vpc: ec2.IVpc; + +export = { + 'setUp'(cb: () => void) { + stack = new cdk.Stack(); + vpc = new ec2.Vpc(stack, 'VPC'); + cb(); + }, + + 'creates a subnet group from minimal properties'(test: Test) { + new rds.SubnetGroup(stack, 'Group', { + description: 'MyGroup', + vpc, + }); + + expect(stack).to(haveResource('AWS::RDS::DBSubnetGroup', { + DBSubnetGroupDescription: 'MyGroup', + SubnetIds: [ + { Ref: 'VPCPrivateSubnet1Subnet8BCA10E0' }, + { Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A' }, + ], + })); + + test.done(); + }, + + 'creates a subnet group from all properties'(test: Test) { + new rds.SubnetGroup(stack, 'Group', { + description: 'My Shared Group', + subnetGroupName: 'SharedGroup', + vpc, + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE }, + }); + + expect(stack).to(haveResource('AWS::RDS::DBSubnetGroup', { + DBSubnetGroupDescription: 'My Shared Group', + DBSubnetGroupName: 'SharedGroup', + SubnetIds: [ + { Ref: 'VPCPrivateSubnet1Subnet8BCA10E0' }, + { Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A' }, + ], + })); + + test.done(); + }, + + 'subnet selection': { + 'defaults to private subnets'(test: Test) { + new rds.SubnetGroup(stack, 'Group', { + description: 'MyGroup', + vpc, + }); + + expect(stack).to(haveResource('AWS::RDS::DBSubnetGroup', { + DBSubnetGroupDescription: 'MyGroup', + SubnetIds: [ + { Ref: 'VPCPrivateSubnet1Subnet8BCA10E0' }, + { Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A' }, + ], + })); + + test.done(); + }, + + 'can specify subnet type'(test: Test) { + new rds.SubnetGroup(stack, 'Group', { + description: 'MyGroup', + vpc, + vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC }, + }); + + expect(stack).to(haveResource('AWS::RDS::DBSubnetGroup', { + DBSubnetGroupDescription: 'MyGroup', + SubnetIds: [ + { Ref: 'VPCPublicSubnet1SubnetB4246D30' }, + { Ref: 'VPCPublicSubnet2Subnet74179F39' }, + ], + })); + test.done(); + }, + }, + + 'import group by name'(test: Test) { + const subnetGroup = rds.SubnetGroup.fromSubnetGroupName(stack, 'Group', 'my-subnet-group'); + + test.equals(subnetGroup.subnetGroupName, 'my-subnet-group'); + + test.done(); + }, + +}; diff --git a/packages/@aws-cdk/aws-redshift/lib/cluster.ts b/packages/@aws-cdk/aws-redshift/lib/cluster.ts index d21dd186ed8d3..98a3257924863 100644 --- a/packages/@aws-cdk/aws-redshift/lib/cluster.ts +++ b/packages/@aws-cdk/aws-redshift/lib/cluster.ts @@ -7,7 +7,8 @@ import { Construct, Duration, IResource, RemovalPolicy, Resource, SecretValue, T import { DatabaseSecret } from './database-secret'; import { Endpoint } from './endpoint'; import { IClusterParameterGroup } from './parameter-group'; -import { CfnCluster, CfnClusterSubnetGroup } from './redshift.generated'; +import { CfnCluster } from './redshift.generated'; +import { ClusterSubnetGroup, IClusterSubnetGroup } from './subnet-group'; /** * Possible Node Types to use in the cluster @@ -245,17 +246,24 @@ export interface ClusterProps { /** * Where to place the instances within the VPC * - * @default private subnets + * @default - private subnets */ readonly vpcSubnets?: ec2.SubnetSelection; /** * Security group. * - * @default a new security group is created. + * @default - a new security group is created. */ readonly securityGroups?: ec2.ISecurityGroup[]; + /** + * A cluster subnet group to use with this cluster. + * + * @default - a new subnet group will be created. + */ + readonly subnetGroup?: IClusterSubnetGroup; + /** * Username and password for the administrative user */ @@ -396,15 +404,11 @@ export class Cluster extends ClusterBase { const removalPolicy = props.removalPolicy ? props.removalPolicy : RemovalPolicy.RETAIN; - const { subnetIds } = this.vpc.selectSubnets(this.vpcSubnets); - - const subnetGroup = new CfnClusterSubnetGroup(this, 'Subnets', { + const subnetGroup = props.subnetGroup ?? new ClusterSubnetGroup(this, 'Subnets', { description: `Subnets for ${id} Redshift cluster`, - subnetIds, - }); - - subnetGroup.applyRemovalPolicy(removalPolicy, { - applyToUpdateReplacePolicy: true, + vpc: this.vpc, + vpcSubnets: this.vpcSubnets, + removalPolicy: removalPolicy, }); const securityGroups = props.securityGroups !== undefined ? @@ -448,7 +452,7 @@ export class Cluster extends ClusterBase { automatedSnapshotRetentionPeriod: 1, clusterType, clusterIdentifier: props.clusterName, - clusterSubnetGroupName: subnetGroup.ref, + clusterSubnetGroupName: subnetGroup.clusterSubnetGroupName, vpcSecurityGroupIds: securityGroupIds, port: props.port, clusterParameterGroupName: props.parameterGroup && props.parameterGroup.clusterParameterGroupName, diff --git a/packages/@aws-cdk/aws-redshift/lib/index.ts b/packages/@aws-cdk/aws-redshift/lib/index.ts index 6d5e5d00bb134..8a8fc89428ce3 100644 --- a/packages/@aws-cdk/aws-redshift/lib/index.ts +++ b/packages/@aws-cdk/aws-redshift/lib/index.ts @@ -2,6 +2,7 @@ export * from './cluster'; export * from './parameter-group'; export * from './database-secret'; export * from './endpoint'; +export * from './subnet-group'; // AWS::Redshift CloudFormation Resources: export * from './redshift.generated'; diff --git a/packages/@aws-cdk/aws-redshift/lib/subnet-group.ts b/packages/@aws-cdk/aws-redshift/lib/subnet-group.ts new file mode 100644 index 0000000000000..b8ef551ad5834 --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/lib/subnet-group.ts @@ -0,0 +1,79 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; +import { Construct, IResource, RemovalPolicy, Resource } from '@aws-cdk/core'; +import { CfnClusterSubnetGroup } from './redshift.generated'; + +/** + * Interface for a cluster subnet group. + */ +export interface IClusterSubnetGroup extends IResource { + /** + * The name of the cluster subnet group. + * @attribute + */ + readonly clusterSubnetGroupName: string; +} + +/** + * Properties for creating a ClusterSubnetGroup. + */ +export interface ClusterSubnetGroupProps { + /** + * Description of the subnet group. + */ + readonly description: string; + + /** + * The VPC to place the subnet group in. + */ + readonly vpc: ec2.IVpc; + + /** + * Which subnets within the VPC to associate with this group. + * + * @default - private subnets + */ + readonly vpcSubnets?: ec2.SubnetSelection; + + /** + * The removal policy to apply when the subnet group are removed + * from the stack or replaced during an update. + * + * @default RemovalPolicy.RETAIN + */ + readonly removalPolicy?: RemovalPolicy +} + +/** + * Class for creating a Redshift cluster subnet group + * + * @resource AWS::Redshift::ClusterSubnetGroup + */ +export class ClusterSubnetGroup extends Resource implements IClusterSubnetGroup { + + /** + * Imports an existing subnet group by name. + */ + public static fromClusterSubnetGroupName(scope: Construct, id: string, clusterSubnetGroupName: string): IClusterSubnetGroup { + return new class extends Resource implements IClusterSubnetGroup { + public readonly clusterSubnetGroupName = clusterSubnetGroupName; + }(scope, id); + } + + public readonly clusterSubnetGroupName: string; + + constructor(scope: Construct, id: string, props: ClusterSubnetGroupProps) { + super(scope, id); + + const { subnetIds } = props.vpc.selectSubnets(props.vpcSubnets ?? { subnetType: ec2.SubnetType.PRIVATE }); + + const subnetGroup = new CfnClusterSubnetGroup(this, 'Default', { + description: props.description, + subnetIds, + }); + subnetGroup.applyRemovalPolicy(props.removalPolicy ?? RemovalPolicy.RETAIN, { + applyToUpdateReplacePolicy: true, + }); + + this.clusterSubnetGroupName = subnetGroup.ref; + } +} diff --git a/packages/@aws-cdk/aws-redshift/package.json b/packages/@aws-cdk/aws-redshift/package.json index 7c5bcf4a66b2a..ba6f6745d40f3 100644 --- a/packages/@aws-cdk/aws-redshift/package.json +++ b/packages/@aws-cdk/aws-redshift/package.json @@ -67,7 +67,7 @@ "@aws-cdk/assert": "0.0.0", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "jest": "^25.5.3", + "jest": "^26.4.2", "pkglint": "0.0.0" }, "dependencies": { @@ -98,6 +98,7 @@ "docs-public-apis:@aws-cdk/aws-redshift.ParameterGroupParameters.parameterName", "docs-public-apis:@aws-cdk/aws-redshift.ParameterGroupParameters.parameterValue", "props-physical-name:@aws-cdk/aws-redshift.ClusterParameterGroupProps", + "props-physical-name:@aws-cdk/aws-redshift.ClusterSubnetGroupProps", "props-physical-name:@aws-cdk/aws-redshift.DatabaseSecretProps" ] }, diff --git a/packages/@aws-cdk/aws-redshift/test/cluster.test.ts b/packages/@aws-cdk/aws-redshift/test/cluster.test.ts index d74a8bc2c9ad8..397777ec3ca40 100644 --- a/packages/@aws-cdk/aws-redshift/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-redshift/test/cluster.test.ts @@ -4,7 +4,7 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as kms from '@aws-cdk/aws-kms'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; -import { Cluster, ClusterParameterGroup, ClusterType } from '../lib'; +import { CfnCluster, Cluster, ClusterParameterGroup, ClusterSubnetGroup, ClusterType } from '../lib'; let stack: cdk.Stack; let vpc: ec2.IVpc; @@ -358,6 +358,33 @@ test('throws when trying to add single user rotation multiple times', () => { }).toThrowError(); }); +test('can use existing cluster subnet group', () => { + // GIVEN + new Cluster(stack, 'Redshift', { + masterUser: { + masterUsername: 'admin', + }, + vpc, + subnetGroup: ClusterSubnetGroup.fromClusterSubnetGroupName(stack, 'Group', 'my-existing-cluster-subnet-group'), + }); + + expect(stack).not.toHaveResource('AWS::Redshift::ClusterSubnetGroup'); + expect(stack).toHaveResourceLike('AWS::Redshift::Cluster', { + ClusterSubnetGroupName: 'my-existing-cluster-subnet-group', + }); +}); + +test('default child returns a CfnCluster', () => { + const cluster = new Cluster(stack, 'Redshift', { + masterUser: { + masterUsername: 'admin', + }, + vpc, + }); + + expect(cluster.node.defaultChild).toBeInstanceOf(CfnCluster); +}); + function testStack() { const newTestStack = new cdk.Stack(undefined, undefined, { env: { account: '12345', region: 'us-test-1' } }); newTestStack.node.setContext('availability-zones:12345:us-test-1', ['us-test-1a', 'us-test-1b']); diff --git a/packages/@aws-cdk/aws-redshift/test/subnet-group.test.ts b/packages/@aws-cdk/aws-redshift/test/subnet-group.test.ts new file mode 100644 index 0000000000000..f2e68491c635d --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/subnet-group.test.ts @@ -0,0 +1,66 @@ +import '@aws-cdk/assert/jest'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import { Stack } from '@aws-cdk/core'; +import { ClusterSubnetGroup } from '../lib'; + +let stack: Stack; +let vpc: ec2.IVpc; + +beforeEach(() => { + stack = new Stack(); + vpc = new ec2.Vpc(stack, 'VPC'); +}); + +test('creates a subnet group from minimal properties', () => { + new ClusterSubnetGroup(stack, 'Group', { + description: 'MyGroup', + vpc, + }); + + expect(stack).toHaveResource('AWS::Redshift::ClusterSubnetGroup', { + Description: 'MyGroup', + SubnetIds: [ + { Ref: 'VPCPrivateSubnet1Subnet8BCA10E0' }, + { Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A' }, + ], + }); +}); + +describe('subnet selection', () => { + test('defaults to private subnets', () => { + new ClusterSubnetGroup(stack, 'Group', { + description: 'MyGroup', + vpc, + }); + + expect(stack).toHaveResource('AWS::Redshift::ClusterSubnetGroup', { + Description: 'MyGroup', + SubnetIds: [ + { Ref: 'VPCPrivateSubnet1Subnet8BCA10E0' }, + { Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A' }, + ], + }); + }); + + test('can specify subnet type', () => { + new ClusterSubnetGroup(stack, 'Group', { + description: 'MyGroup', + vpc, + vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC }, + }); + + expect(stack).toHaveResource('AWS::Redshift::ClusterSubnetGroup', { + Description: 'MyGroup', + SubnetIds: [ + { Ref: 'VPCPublicSubnet1SubnetB4246D30' }, + { Ref: 'VPCPublicSubnet2Subnet74179F39' }, + ], + }); + }); +}); + +test('import group by name', () => { + const subnetGroup = ClusterSubnetGroup.fromClusterSubnetGroupName(stack, 'Group', 'my-subnet-group'); + + expect(subnetGroup.clusterSubnetGroupName).toBe('my-subnet-group'); +}); diff --git a/packages/@aws-cdk/aws-route53-patterns/package.json b/packages/@aws-cdk/aws-route53-patterns/package.json index cd67cc5729336..ef708106293ec 100644 --- a/packages/@aws-cdk/aws-route53-patterns/package.json +++ b/packages/@aws-cdk/aws-route53-patterns/package.json @@ -1,7 +1,7 @@ { "name": "@aws-cdk/aws-route53-patterns", "version": "0.0.0", - "description": "CDK Constructs for AWS Route53 patterns", + "description": "The CDK Construct Library for AWS Route53 patterns", "main": "lib/index.js", "types": "lib/index.d.ts", "jsii": { @@ -64,7 +64,7 @@ "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "pkglint": "0.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-route53-targets/package.json b/packages/@aws-cdk/aws-route53-targets/package.json index 4f98390aaaa3d..a877af56d17b8 100644 --- a/packages/@aws-cdk/aws-route53-targets/package.json +++ b/packages/@aws-cdk/aws-route53-targets/package.json @@ -1,7 +1,7 @@ { "name": "@aws-cdk/aws-route53-targets", "version": "0.0.0", - "description": "CDK Constructs for AWS Route53 Alias Targets", + "description": "The CDK Construct Library for AWS Route53 Alias Targets", "main": "lib/index.js", "types": "lib/index.d.ts", "jsii": { @@ -65,7 +65,7 @@ "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "pkglint": "0.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-route53/package.json b/packages/@aws-cdk/aws-route53/package.json index 7115f213f71d3..1c340eb48bf5a 100644 --- a/packages/@aws-cdk/aws-route53/package.json +++ b/packages/@aws-cdk/aws-route53/package.json @@ -1,7 +1,7 @@ { "name": "@aws-cdk/aws-route53", "version": "0.0.0", - "description": "CDK Constructs for AWS Route53", + "description": "The CDK Construct Library for AWS::Route53", "main": "lib/index.js", "types": "lib/index.d.ts", "jsii": { diff --git a/packages/@aws-cdk/aws-s3-deployment/package.json b/packages/@aws-cdk/aws-s3-deployment/package.json index 72a630108c040..90d443aa52769 100644 --- a/packages/@aws-cdk/aws-s3-deployment/package.json +++ b/packages/@aws-cdk/aws-s3-deployment/package.json @@ -79,10 +79,10 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/jest": "^26.0.10", + "@types/jest": "^26.0.14", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "pkglint": "0.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-s3-notifications/lib/lambda.ts b/packages/@aws-cdk/aws-s3-notifications/lib/lambda.ts index 6cc4560a89c1c..a0bd0acaeaee6 100644 --- a/packages/@aws-cdk/aws-s3-notifications/lib/lambda.ts +++ b/packages/@aws-cdk/aws-s3-notifications/lib/lambda.ts @@ -11,19 +11,28 @@ export class LambdaDestination implements s3.IBucketNotificationDestination { } public bind(_scope: Construct, bucket: s3.IBucket): s3.BucketNotificationDestinationConfig { - const permissionId = `AllowBucketNotificationsFrom${bucket.node.uniqueId}`; + const permissionId = `AllowBucketNotificationsTo${this.fn.permissionsNode.uniqueId}`; - if (this.fn.permissionsNode.tryFindChild(permissionId) === undefined) { + if (!Construct.isConstruct(bucket)) { + throw new Error(`LambdaDestination for function ${this.fn.permissionsNode.uniqueId} can only be configured on a + bucket construct (Bucket ${bucket.bucketName})`); + } + + if (bucket.node.tryFindChild(permissionId) === undefined) { this.fn.addPermission(permissionId, { sourceAccount: Stack.of(bucket).account, principal: new iam.ServicePrincipal('s3.amazonaws.com'), sourceArn: bucket.bucketArn, + // Placing the permissions node in the same scope as the s3 bucket. + // Otherwise, there is a circular dependency when the s3 bucket + // and lambda functions declared in different stacks. + scope: bucket, }); } // if we have a permission resource for this relationship, add it as a dependency // to the bucket notifications resource, so it will be created first. - const permission = this.fn.permissionsNode.tryFindChild(permissionId) as CfnResource | undefined; + const permission = bucket.node.tryFindChild(permissionId) as CfnResource | undefined; return { type: s3.BucketNotificationDestinationType.LAMBDA, diff --git a/packages/@aws-cdk/aws-s3-notifications/package.json b/packages/@aws-cdk/aws-s3-notifications/package.json index 928db63f094c2..d3748021e1ce9 100644 --- a/packages/@aws-cdk/aws-s3-notifications/package.json +++ b/packages/@aws-cdk/aws-s3-notifications/package.json @@ -62,7 +62,7 @@ "@aws-cdk/assert": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "pkglint": "0.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-s3-notifications/test/lambda/integ.bucket-notifications.expected.json b/packages/@aws-cdk/aws-s3-notifications/test/lambda/integ.bucket-notifications.expected.json index bb0b743ab2fdb..98ddf87498738 100644 --- a/packages/@aws-cdk/aws-s3-notifications/test/lambda/integ.bucket-notifications.expected.json +++ b/packages/@aws-cdk/aws-s3-notifications/test/lambda/integ.bucket-notifications.expected.json @@ -44,9 +44,31 @@ } }, "DependsOn": [ - "MyFunctionAllowBucketNotificationsFromlambdabucketnotificationsMyBucket0F0FC402189522F6" + "MyBucketAllowBucketNotificationsTolambdabucketnotificationsMyFunction4086861C1BF13476" ] }, + "MyBucketAllowBucketNotificationsTolambdabucketnotificationsMyFunction4086861C1BF13476": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "MyFunction3BAA72D1", + "Arn" + ] + }, + "Principal": "s3.amazonaws.com", + "SourceAccount": { + "Ref": "AWS::AccountId" + }, + "SourceArn": { + "Fn::GetAtt": [ + "MyBucketF68F3FF0", + "Arn" + ] + } + } + }, "MyFunctionServiceRole3C357FF2": { "Type": "AWS::IAM::Role", "Properties": { @@ -97,50 +119,6 @@ "MyFunctionServiceRole3C357FF2" ] }, - "MyFunctionAllowBucketNotificationsFromlambdabucketnotificationsMyBucket0F0FC402189522F6": { - "Type": "AWS::Lambda::Permission", - "Properties": { - "Action": "lambda:InvokeFunction", - "FunctionName": { - "Fn::GetAtt": [ - "MyFunction3BAA72D1", - "Arn" - ] - }, - "Principal": "s3.amazonaws.com", - "SourceAccount": { - "Ref": "AWS::AccountId" - }, - "SourceArn": { - "Fn::GetAtt": [ - "MyBucketF68F3FF0", - "Arn" - ] - } - } - }, - "MyFunctionAllowBucketNotificationsFromlambdabucketnotificationsYourBucket307F72F245F2C5AE": { - "Type": "AWS::Lambda::Permission", - "Properties": { - "Action": "lambda:InvokeFunction", - "FunctionName": { - "Fn::GetAtt": [ - "MyFunction3BAA72D1", - "Arn" - ] - }, - "Principal": "s3.amazonaws.com", - "SourceAccount": { - "Ref": "AWS::AccountId" - }, - "SourceArn": { - "Fn::GetAtt": [ - "YourBucketC6A57364", - "Arn" - ] - } - } - }, "YourBucketC6A57364": { "Type": "AWS::S3::Bucket", "UpdateReplacePolicy": "Delete", @@ -175,9 +153,31 @@ } }, "DependsOn": [ - "MyFunctionAllowBucketNotificationsFromlambdabucketnotificationsYourBucket307F72F245F2C5AE" + "YourBucketAllowBucketNotificationsTolambdabucketnotificationsMyFunction4086861C8FE2B89D" ] }, + "YourBucketAllowBucketNotificationsTolambdabucketnotificationsMyFunction4086861C8FE2B89D": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "MyFunction3BAA72D1", + "Arn" + ] + }, + "Principal": "s3.amazonaws.com", + "SourceAccount": { + "Ref": "AWS::AccountId" + }, + "SourceArn": { + "Fn::GetAtt": [ + "YourBucketC6A57364", + "Arn" + ] + } + } + }, "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleB6FB88EC": { "Type": "AWS::IAM::Role", "Properties": { diff --git a/packages/@aws-cdk/aws-s3-notifications/test/lambda/lambda.test.ts b/packages/@aws-cdk/aws-s3-notifications/test/lambda/lambda.test.ts index 923846852b20d..10de49b776d02 100644 --- a/packages/@aws-cdk/aws-s3-notifications/test/lambda/lambda.test.ts +++ b/packages/@aws-cdk/aws-s3-notifications/test/lambda/lambda.test.ts @@ -3,9 +3,105 @@ import { ResourcePart } from '@aws-cdk/assert'; import '@aws-cdk/assert/jest'; import * as lambda from '@aws-cdk/aws-lambda'; import * as s3 from '@aws-cdk/aws-s3'; -import { Stack } from '@aws-cdk/core'; +import { Stack, App } from '@aws-cdk/core'; import * as s3n from '../../lib'; +test('add notifications to multiple functions', () => { + + const stack = new Stack(); + const bucket = new s3.Bucket(stack, 'MyBucket'); + const fn1 = new lambda.Function(stack, 'MyFunction1', { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromInline('foo'), + }); + + const fn2 = new lambda.Function(stack, 'MyFunction2', { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromInline('foo'), + }); + + const lambdaDestination1 = new s3n.LambdaDestination(fn1); + const lambdaDestination2 = new s3n.LambdaDestination(fn2); + + bucket.addEventNotification(s3.EventType.OBJECT_CREATED, lambdaDestination1, { prefix: 'v1/' }); + bucket.addEventNotification(s3.EventType.OBJECT_CREATED, lambdaDestination2, { prefix: 'v2/' }); + + // expecting notification configuration to have both events + expect(stack).toHaveResourceLike('Custom::S3BucketNotifications', { + NotificationConfiguration: { + LambdaFunctionConfigurations: [ + { Filter: { Key: { FilterRules: [{ Name: 'prefix', Value: 'v1/' }] } } }, + { Filter: { Key: { FilterRules: [{ Name: 'prefix', Value: 'v2/' }] } } }, + ], + }, + }); + + // expecting one permission for each function + expect(stack).toCountResources('AWS::Lambda::Permission', 2); + + // make sure each permission points to the correct function + expect(stack).toHaveResourceLike('AWS::Lambda::Permission', { + FunctionName: { + 'Fn::GetAtt': [ + 'MyFunction12A744C2E', + 'Arn', + ], + }, + SourceArn: { + 'Fn::GetAtt': [ + 'MyBucketF68F3FF0', + 'Arn', + ], + }, + }); + expect(stack).toHaveResourceLike('AWS::Lambda::Permission', { + FunctionName: { + 'Fn::GetAtt': [ + 'MyFunction2F2A964CA', + 'Arn', + ], + }, + SourceArn: { + 'Fn::GetAtt': [ + 'MyBucketF68F3FF0', + 'Arn', + ], + }, + }); + +}); + +test('lambda in a different stack as notification target', () => { + + const app = new App(); + const lambdaStack = new Stack(app, 'stack1'); + const bucketStack = new Stack(app, 'stack2'); + + const lambdaFunction = new lambda.Function(lambdaStack, 'lambdaFunction', { + code: lambda.Code.fromInline('whatever'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + }); + + const bucket = new s3.Bucket(bucketStack, 'bucket'); + bucket.addObjectCreatedNotification(new s3n.LambdaDestination(lambdaFunction)); + + // permission should be in the bucket stack + expect(bucketStack).toHaveResourceLike('AWS::Lambda::Permission', { + FunctionName: { + 'Fn::ImportValue': 'stack1:ExportsOutputFnGetAttlambdaFunction940E68ADArn6B2878AF', + }, + SourceArn: { + 'Fn::GetAtt': [ + 'bucket43879C71', + 'Arn', + ], + }, + }); +}); + test('lambda as notification target', () => { // GIVEN const stack = new Stack(); @@ -88,7 +184,7 @@ test('permissions are added as a dependency to the notifications resource when u bucket.addEventNotification(s3.EventType.OBJECT_CREATED, lambdaDestination, { prefix: 'v1/' }); expect(stack).toHaveResource('Custom::S3BucketNotifications', { - DependsOn: ['SingletonLambdauuidAllowBucketNotificationsFromMyBucket1464DCBA'], + DependsOn: ['MyBucketAllowBucketNotificationsToSingletonLambdauuid28C96883'], }, ResourcePart.CompleteDefinition); }); diff --git a/packages/@aws-cdk/aws-s3/package.json b/packages/@aws-cdk/aws-s3/package.json index fa59007748c9b..e9673a87c4893 100644 --- a/packages/@aws-cdk/aws-s3/package.json +++ b/packages/@aws-cdk/aws-s3/package.json @@ -1,7 +1,7 @@ { "name": "@aws-cdk/aws-s3", "version": "0.0.0", - "description": "CDK Constructs for AWS S3", + "description": "The CDK Construct Library for AWS::S3", "main": "lib/index.js", "types": "lib/index.d.ts", "jsii": { diff --git a/packages/@aws-cdk/aws-sam/package.json b/packages/@aws-cdk/aws-sam/package.json index 7407ae6bc4725..dcf3da7c7209b 100644 --- a/packages/@aws-cdk/aws-sam/package.json +++ b/packages/@aws-cdk/aws-sam/package.json @@ -66,12 +66,12 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/jest": "^26.0.10", + "@types/jest": "^26.0.14", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "pkglint": "0.0.0", - "ts-jest": "^26.2.0" + "ts-jest": "^26.3.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts b/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts index 6399a55ed5988..c4539cca154ea 100644 --- a/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts +++ b/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts @@ -129,13 +129,6 @@ export interface SecretAttributes { * The ARN of the secret in SecretsManager. */ readonly secretArn: string; - - /** - * The name of the secret in SecretsManager. - * - * @default - the name is derived from the secretArn. - */ - readonly secretName?: string; } /** @@ -286,7 +279,7 @@ export class Secret extends SecretBase { class Import extends SecretBase { public readonly encryptionKey = attrs.encryptionKey; public readonly secretArn = attrs.secretArn; - public readonly secretName = parseSecretName(scope, attrs.secretArn, attrs.secretName); + public readonly secretName = parseSecretName(scope, attrs.secretArn); protected readonly autoCreatePolicy = false; } @@ -601,9 +594,8 @@ export interface SecretStringGenerator { readonly generateStringKey?: string; } -/** Returns the secret name if defined, otherwise attempts to parse it from the ARN. */ -export function parseSecretName(construct: IConstruct, secretArn: string, secretName?: string) { - if (secretName) { return secretName; } +/** Parses the secret name from the ARN. */ +function parseSecretName(construct: IConstruct, secretArn: string) { const resourceName = Stack.of(construct).parseArn(secretArn).resourceName; if (resourceName) { // Secret resource names are in the format `${secretName}-${SecretsManager suffix}` diff --git a/packages/@aws-cdk/aws-ses-actions/package.json b/packages/@aws-cdk/aws-ses-actions/package.json index f8b9b42302ca6..d03df20b359d7 100644 --- a/packages/@aws-cdk/aws-ses-actions/package.json +++ b/packages/@aws-cdk/aws-ses-actions/package.json @@ -64,7 +64,7 @@ "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "pkglint": "0.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-sns-subscriptions/package.json b/packages/@aws-cdk/aws-sns-subscriptions/package.json index ad794f978be1c..012deb7b5776e 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/package.json +++ b/packages/@aws-cdk/aws-sns-subscriptions/package.json @@ -63,7 +63,7 @@ "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "pkglint": "0.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-sns/package.json b/packages/@aws-cdk/aws-sns/package.json index b6d5a164ddbef..96bbf2ccee89f 100644 --- a/packages/@aws-cdk/aws-sns/package.json +++ b/packages/@aws-cdk/aws-sns/package.json @@ -1,7 +1,7 @@ { "name": "@aws-cdk/aws-sns", "version": "0.0.0", - "description": "CDK Constructs for AWS SNS", + "description": "The CDK Construct Library for AWS::SNS", "main": "lib/index.js", "types": "lib/index.d.ts", "jsii": { diff --git a/packages/@aws-cdk/aws-sqs/package.json b/packages/@aws-cdk/aws-sqs/package.json index 1d149cddc2150..4dbeb49535ea4 100644 --- a/packages/@aws-cdk/aws-sqs/package.json +++ b/packages/@aws-cdk/aws-sqs/package.json @@ -1,7 +1,7 @@ { "name": "@aws-cdk/aws-sqs", "version": "0.0.0", - "description": "CDK Constructs for AWS SQS", + "description": "The CDK Construct Library for AWS::SQS", "main": "lib/index.js", "types": "lib/index.d.ts", "jsii": { diff --git a/packages/@aws-cdk/aws-ssm/test/test.ssm-document.ts b/packages/@aws-cdk/aws-ssm/test/test.ssm-document.ts index 90641bef11a52..e37ee02c98121 100644 --- a/packages/@aws-cdk/aws-ssm/test/test.ssm-document.ts +++ b/packages/@aws-cdk/aws-ssm/test/test.ssm-document.ts @@ -11,11 +11,19 @@ export = { // WHEN new ssm.CfnAssociation(stack, 'Assoc', { name: 'document', + parameters: { + a: ['a'], + B: [], + }, }); // THEN expect(stack).to(haveResource('AWS::SSM::Association', { Name: 'document', + Parameters: { + a: ['a'], + B: [], + }, })); test.done(); }, diff --git a/packages/@aws-cdk/aws-sso/.eslintrc.js b/packages/@aws-cdk/aws-sso/.eslintrc.js new file mode 100644 index 0000000000000..61dd8dd001f63 --- /dev/null +++ b/packages/@aws-cdk/aws-sso/.eslintrc.js @@ -0,0 +1,3 @@ +const baseConfig = require('cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sso/.gitignore b/packages/@aws-cdk/aws-sso/.gitignore new file mode 100644 index 0000000000000..5b0f33aaa6d08 --- /dev/null +++ b/packages/@aws-cdk/aws-sso/.gitignore @@ -0,0 +1,19 @@ +*.js +*.js.map +*.d.ts +tsconfig.json +node_modules +*.generated.ts +dist +.jsii + +.LAST_BUILD +.nyc_output +coverage +.nycrc +.LAST_PACKAGE +*.snk +nyc.config.js +!.eslintrc.js +!jest.config.js +junit.xml \ No newline at end of file diff --git a/packages/@aws-cdk/aws-sso/.npmignore b/packages/@aws-cdk/aws-sso/.npmignore new file mode 100644 index 0000000000000..72b7fcab0a22a --- /dev/null +++ b/packages/@aws-cdk/aws-sso/.npmignore @@ -0,0 +1,26 @@ +# Don't include original .ts files when doing `npm pack` +*.ts +!*.d.ts +coverage +.nyc_output +*.tgz + +dist +.LAST_PACKAGE +.LAST_BUILD +!*.js + +# Include .jsii +!.jsii + +*.snk + +*.tsbuildinfo + +tsconfig.json + +.eslintrc.js +jest.config.js +# exclude cdk artifacts +**/cdk.out +junit.xml diff --git a/packages/@aws-cdk/aws-sso/LICENSE b/packages/@aws-cdk/aws-sso/LICENSE new file mode 100644 index 0000000000000..b71ec1688783a --- /dev/null +++ b/packages/@aws-cdk/aws-sso/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/@aws-cdk/aws-sso/NOTICE b/packages/@aws-cdk/aws-sso/NOTICE new file mode 100644 index 0000000000000..bfccac9a7f69c --- /dev/null +++ b/packages/@aws-cdk/aws-sso/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/aws-sso/README.md b/packages/@aws-cdk/aws-sso/README.md new file mode 100644 index 0000000000000..474dcd0d59dfa --- /dev/null +++ b/packages/@aws-cdk/aws-sso/README.md @@ -0,0 +1,16 @@ +## AWS::SSO Construct Library + +--- + +![cfn-resources: Stable](https://img.shields.io/badge/cfn--resources-stable-success.svg?style=for-the-badge) + +> All classes with the `Cfn` prefix in this module ([CFN Resources](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) are always stable and safe to use. + +--- + + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts +import sso = require('@aws-cdk/aws-sso'); +``` diff --git a/packages/@aws-cdk/aws-sso/jest.config.js b/packages/@aws-cdk/aws-sso/jest.config.js new file mode 100644 index 0000000000000..54e28beb9798b --- /dev/null +++ b/packages/@aws-cdk/aws-sso/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-sso/lib/index.ts b/packages/@aws-cdk/aws-sso/lib/index.ts new file mode 100644 index 0000000000000..3d6b1e14d0122 --- /dev/null +++ b/packages/@aws-cdk/aws-sso/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::SSO CloudFormation Resources: +export * from './sso.generated'; diff --git a/packages/@aws-cdk/aws-sso/package.json b/packages/@aws-cdk/aws-sso/package.json new file mode 100644 index 0000000000000..ca07479857ec2 --- /dev/null +++ b/packages/@aws-cdk/aws-sso/package.json @@ -0,0 +1,88 @@ +{ + "name": "@aws-cdk/aws-sso", + "version": "0.0.0", + "description": "The CDK Construct Library for AWS::SSO", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "projectReferences": true, + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.SSO", + "packageId": "Amazon.CDK.AWS.SSO", + "signAssembly": true, + "assemblyOriginatorKeyFile": "../../key.snk", + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png" + }, + "java": { + "package": "software.amazon.awscdk.services.sso", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "sso" + } + }, + "python": { + "distName": "aws-cdk.aws-sso", + "module": "aws_cdk.aws_sso" + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-sso" + }, + "homepage": "https://github.com/aws/aws-cdk", + "scripts": { + "build": "cdk-build", + "watch": "cdk-watch", + "lint": "cdk-lint", + "test": "cdk-test", + "integ": "cdk-integ", + "pkglint": "pkglint -f", + "package": "cdk-package", + "awslint": "cdk-awslint", + "cfn2ts": "cfn2ts", + "build+test+package": "npm run build+test && npm run package", + "build+test": "npm run build && npm test", + "compat": "cdk-compat" + }, + "cdk-build": { + "cloudformation": "AWS::SSO", + "jest": true + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::SSO", + "aws-sso" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/assert": "0.0.0", + "cdk-build-tools": "0.0.0", + "cfn2ts": "0.0.0", + "pkglint": "0.0.0" + }, + "dependencies": { + "@aws-cdk/core": "0.0.0" + }, + "peerDependencies": { + "@aws-cdk/core": "0.0.0" + }, + "engines": { + "node": ">= 10.13.0 <13 || >=13.7.0" + }, + "stability": "experimental", + "maturity": "cfn-only", + "awscdkio": { + "announce": false + } +} diff --git a/packages/@aws-cdk/aws-sso/test/sso.test.ts b/packages/@aws-cdk/aws-sso/test/sso.test.ts new file mode 100644 index 0000000000000..e394ef336bfb4 --- /dev/null +++ b/packages/@aws-cdk/aws-sso/test/sso.test.ts @@ -0,0 +1,6 @@ +import '@aws-cdk/assert/jest'; +import {} from '../lib'; + +test('No tests are specified for this package', () => { + expect(true).toBe(true); +}); diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/README.md b/packages/@aws-cdk/aws-stepfunctions-tasks/README.md index 600ee8fdd03af..5faf997549ed6 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/README.md +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/README.md @@ -701,6 +701,12 @@ new tasks.LambdaInvoke(stack, 'Invoke with callback', { call. Learn more about [Callback with the Task Token](https://docs.aws.amazon.com/step-functions/latest/dg/connect-to-resource.html#connect-wait-token). +AWS Lambda can occasionally experience transient service errors. In this case, invoking Lambda +results in a 500 error, such as `ServiceException`, `AWSLambdaException`, or `SdkClientException`. +As a best practive, the `LambdaInvoke` task will retry on those errors with an interval of 2 seconds, +a back-off rate of 2 and 6 maximum attempts. Set the `retryOnServiceExceptions` prop to `false` to +disable this behavior. + ## SageMaker Step Functions supports [AWS SageMaker](https://docs.aws.amazon.com/step-functions/latest/dg/connect-sagemaker.html) through the service integration pattern. diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/lambda/invoke.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/lambda/invoke.ts index 6c44c555f80a4..b11041190a723 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/lambda/invoke.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/lambda/invoke.ts @@ -57,6 +57,19 @@ export interface LambdaInvokeProps extends sfn.TaskStateBaseProps { * @default false */ readonly payloadResponseOnly?: boolean; + + /** + * Whether to retry on Lambda service exceptions. + * + * This handles `Lambda.ServiceException`, `Lambda.AWSLambdaException` and + * `Lambda.SdkClientException` with an interval of 2 seconds, a back-off rate + * of 2 and 6 maximum attempts. + * + * @see https://docs.aws.amazon.com/step-functions/latest/dg/bp-lambda-serviceexception.html + * + * @default true + */ + readonly retryOnServiceExceptions?: boolean; } /** @@ -109,6 +122,16 @@ export class LambdaInvoke extends sfn.TaskStateBase { actions: ['lambda:InvokeFunction'], }), ]; + + if (props.retryOnServiceExceptions ?? true) { + // Best practice from https://docs.aws.amazon.com/step-functions/latest/dg/bp-lambda-serviceexception.html + this.addRetry({ + errors: ['Lambda.ServiceException', 'Lambda.AWSLambdaException', 'Lambda.SdkClientException'], + interval: cdk.Duration.seconds(2), + maxAttempts: 6, + backoffRate: 2, + }); + } } /** diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json index 2758eb9ad530e..4cd9d02c114e4 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json @@ -65,7 +65,7 @@ "@aws-cdk/aws-sns-subscriptions": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "pkglint": "0.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-create-cluster.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-create-cluster.test.ts index 742f92ef02786..fce085651c0cf 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-create-cluster.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-create-cluster.test.ts @@ -30,7 +30,7 @@ beforeEach(() => { actions: [ 'sts:AssumeRole', ], - }) + }), ); }); @@ -986,4 +986,4 @@ test('Task throws if WAIT_FOR_TASK_TOKEN is supplied as service integration patt integrationPattern: sfn.IntegrationPattern.WAIT_FOR_TASK_TOKEN, }); }).toThrow(/Unsupported service integration pattern. Supported Patterns: REQUEST_RESPONSE,RUN_JOB. Received: WAIT_FOR_TASK_TOKEN/); -}); \ No newline at end of file +}); diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/integ.invoke.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/integ.invoke.expected.json index 4fb88c61bb6df..efa3aac3cf73a 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/integ.invoke.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/integ.invoke.expected.json @@ -167,11 +167,17 @@ "StateMachine2E01A3A5": { "Type": "AWS::StepFunctions::StateMachine", "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRoleB840431D", + "Arn" + ] + }, "DefinitionString": { "Fn::Join": [ "", [ - "{\"StartAt\":\"Invoke Handler\",\"States\":{\"Invoke Handler\":{\"Next\":\"Check the job state\",\"Type\":\"Task\",\"OutputPath\":\"$.Payload\",\"Resource\":\"arn:", + "{\"StartAt\":\"Invoke Handler\",\"States\":{\"Invoke Handler\":{\"Next\":\"Check the job state\",\"Retry\":[{\"ErrorEquals\":[\"Lambda.ServiceException\",\"Lambda.AWSLambdaException\",\"Lambda.SdkClientException\"],\"IntervalSeconds\":2,\"MaxAttempts\":6,\"BackoffRate\":2}],\"Type\":\"Task\",\"OutputPath\":\"$.Payload\",\"Resource\":\"arn:", { "Ref": "AWS::Partition" }, @@ -182,7 +188,7 @@ "Arn" ] }, - "\",\"Payload.$\":\"$\"}},\"Check the job state\":{\"Next\":\"Job Complete?\",\"Type\":\"Task\",\"OutputPath\":\"$.Payload\",\"Resource\":\"arn:", + "\",\"Payload.$\":\"$\"}},\"Check the job state\":{\"Next\":\"Job Complete?\",\"Retry\":[{\"ErrorEquals\":[\"Lambda.ServiceException\",\"Lambda.AWSLambdaException\",\"Lambda.SdkClientException\"],\"IntervalSeconds\":2,\"MaxAttempts\":6,\"BackoffRate\":2}],\"Type\":\"Task\",\"OutputPath\":\"$.Payload\",\"Resource\":\"arn:", { "Ref": "AWS::Partition" }, @@ -196,12 +202,6 @@ "\",\"Payload.$\":\"$\"}},\"Job Complete?\":{\"Type\":\"Choice\",\"Choices\":[{\"Variable\":\"$.status\",\"StringEquals\":\"FAILED\",\"Next\":\"Job Failed\"},{\"Variable\":\"$.status\",\"StringEquals\":\"SUCCEEDED\",\"Next\":\"Final step\"}]},\"Job Failed\":{\"Type\":\"Fail\",\"Error\":\"Received a status that was not 200\",\"Cause\":\"Job Failed\"},\"Final step\":{\"Type\":\"Pass\",\"End\":true}},\"TimeoutSeconds\":30}" ] ] - }, - "RoleArn": { - "Fn::GetAtt": [ - "StateMachineRoleB840431D", - "Arn" - ] } }, "DependsOn": [ diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/integ.invoke.payload.only.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/integ.invoke.payload.only.expected.json index b994f8b20cc5e..32bec4cb4a2fe 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/integ.invoke.payload.only.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/integ.invoke.payload.only.expected.json @@ -177,14 +177,14 @@ "Fn::Join": [ "", [ - "{\"StartAt\":\"Invoke Handler\",\"States\":{\"Invoke Handler\":{\"Next\":\"Check the job state\",\"Type\":\"Task\",\"Resource\":\"", + "{\"StartAt\":\"Invoke Handler\",\"States\":{\"Invoke Handler\":{\"Next\":\"Check the job state\",\"Retry\":[{\"ErrorEquals\":[\"Lambda.ServiceException\",\"Lambda.AWSLambdaException\",\"Lambda.SdkClientException\"],\"IntervalSeconds\":2,\"MaxAttempts\":6,\"BackoffRate\":2}],\"Type\":\"Task\",\"Resource\":\"", { "Fn::GetAtt": [ "submitJobLambdaEFB00F3C", "Arn" ] }, - "\"},\"Check the job state\":{\"Next\":\"Job Complete?\",\"Type\":\"Task\",\"Resource\":\"", + "\"},\"Check the job state\":{\"Next\":\"Job Complete?\",\"Retry\":[{\"ErrorEquals\":[\"Lambda.ServiceException\",\"Lambda.AWSLambdaException\",\"Lambda.SdkClientException\"],\"IntervalSeconds\":2,\"MaxAttempts\":6,\"BackoffRate\":2}],\"Type\":\"Task\",\"Resource\":\"", { "Fn::GetAtt": [ "checkJobStateLambda4618B7B7", diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/invoke.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/invoke.test.ts index dc2cf11ac367b..a6b8063ad38c2 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/invoke.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/invoke.test.ts @@ -52,6 +52,18 @@ describe('LambdaInvoke', () => { }, 'Payload.$': '$', }, + Retry: [ + { + ErrorEquals: [ + 'Lambda.ServiceException', + 'Lambda.AWSLambdaException', + 'Lambda.SdkClientException', + ], + IntervalSeconds: 2, + MaxAttempts: 6, + BackoffRate: 2, + }, + ], }); }); @@ -68,7 +80,7 @@ describe('LambdaInvoke', () => { }); // THEN - expect(stack.resolve(task.toStateJson())).toEqual({ + expect(stack.resolve(task.toStateJson())).toEqual(expect.objectContaining({ Type: 'Task', Resource: { 'Fn::Join': [ @@ -97,7 +109,7 @@ describe('LambdaInvoke', () => { ClientContext: 'eyJoZWxsbyI6IndvcmxkIn0=', Qualifier: '1', }, - }); + })); }); test('invoke Lambda function and wait for task token', () => { @@ -112,7 +124,7 @@ describe('LambdaInvoke', () => { }); // THEN - expect(stack.resolve(task.toStateJson())).toEqual({ + expect(stack.resolve(task.toStateJson())).toEqual(expect.objectContaining({ Type: 'Task', Resource: { 'Fn::Join': [ @@ -139,7 +151,7 @@ describe('LambdaInvoke', () => { }, Qualifier: 'my-alias', }, - }); + })); }); test('pass part of state input as input to Lambda function ', () => { @@ -150,7 +162,7 @@ describe('LambdaInvoke', () => { }); // THEN - expect(stack.resolve(task.toStateJson())).toEqual({ + expect(stack.resolve(task.toStateJson())).toEqual(expect.objectContaining({ Type: 'Task', Resource: { 'Fn::Join': [ @@ -174,7 +186,7 @@ describe('LambdaInvoke', () => { }, 'Payload.$': '$.foo', }, - }); + })); }); test('Invoke lambda with payloadResponseOnly', () => { @@ -185,7 +197,7 @@ describe('LambdaInvoke', () => { }); // THEN - expect(stack.resolve(task.toStateJson())).toEqual({ + expect(stack.resolve(task.toStateJson())).toEqual(expect.objectContaining({ End: true, Type: 'Task', Resource: { @@ -194,7 +206,7 @@ describe('LambdaInvoke', () => { 'Arn', ], }, - }); + })); }); test('Invoke lambda with payloadResponseOnly with payload', () => { @@ -208,7 +220,7 @@ describe('LambdaInvoke', () => { }); // THEN - expect(stack.resolve(task.toStateJson())).toEqual({ + expect(stack.resolve(task.toStateJson())).toEqual(expect.objectContaining({ End: true, Type: 'Task', Resource: { @@ -220,6 +232,41 @@ describe('LambdaInvoke', () => { Parameters: { foo: 'bar', }, + })); + }); + + test('with retryOnServiceExceptions set to false', () => { + // WHEN + const task = new LambdaInvoke(stack, 'Task', { + lambdaFunction, + retryOnServiceExceptions: false, + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toEqual({ + End: true, + Type: 'Task', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:::lambda:invoke', + ], + ], + }, + Parameters: { + FunctionName: { + 'Fn::GetAtt': [ + 'Fn9270CBC0', + 'Arn', + ], + }, + 'Payload.$': '$', + }, }); }); @@ -292,4 +339,4 @@ describe('LambdaInvoke', () => { }); }).toThrow(/Unsupported service integration pattern. Supported Patterns: REQUEST_RESPONSE,WAIT_FOR_TASK_TOKEN. Received: RUN_JOB/); }); -}); \ No newline at end of file +}); diff --git a/packages/@aws-cdk/aws-stepfunctions/README.md b/packages/@aws-cdk/aws-stepfunctions/README.md index fc1ee6b294dcd..a8d712400a2b5 100644 --- a/packages/@aws-cdk/aws-stepfunctions/README.md +++ b/packages/@aws-cdk/aws-stepfunctions/README.md @@ -154,7 +154,7 @@ and also injects a field called `otherData`. ```ts const pass = new stepfunctions.Pass(this, 'Filter input and inject data', { parameters: { // input to the pass state - input: stepfunctions.JsonPath.stringAt('$.input.greeting') + input: stepfunctions.JsonPath.stringAt('$.input.greeting'), otherData: 'some-extra-stuff' }, }); @@ -217,6 +217,54 @@ If your `Choice` doesn't have an `otherwise()` and none of the conditions match the JSON state, a `NoChoiceMatched` error will be thrown. Wrap the state machine in a `Parallel` state if you want to catch and recover from this. +#### Available Conditions: +see [step function comparison operators](https://docs.aws.amazon.com/step-functions/latest/dg/amazon-states-language-choice-state.html#amazon-states-language-choice-state-rules) +* `Condition.isPresent` - matches if a json path is present +* `Condition.isNotPresent` - matches if a json path is not present +* `Condition.isString` - matches if a json path contains a string +* `Condition.isNotString` - matches if a json path is not a string +* `Condition.isNumeric` - matches if a json path is numeric +* `Condition.isNotNumeric` - matches if a json path is not numeric +* `Condition.isBoolean` - matches if a json path is boolean +* `Condition.isNotBoolean` - matches if a json path is not boolean +* `Condition.isTimestamp` - matches if a json path is a timestamp +* `Condition.isNotTimestamp` - matches if a json path is not a timestamp +* `Condition.isNotNull` - matches if a json path is not null +* `Condition.isNull` - matches if a json path is null +* `Condition.booleanEquals` - matches if a boolean field has a given value +* `Condition.booleanEqualsJsonPath` - matches if a boolean field equals a value in a given mapping path +* `Condition.stringEqualsJsonPath` - matches if a string field equals a given mapping path +* `Condition.stringEquals` - matches if a field equals a string value +* `Condition.stringLessThan` - matches if a string field sorts before a given value +* `Condition.stringLessThanJsonPath` - matches if a string field sorts before a value at given mapping path +* `Condition.stringLessThanEquals` - matches if a string field sorts equal to or before a given value +* `Condition.stringLessThanEqualsJsonPath` - matches if a string field sorts equal to or before a given mapping +* `Condition.stringGreaterThan` - matches if a string field sorts after a given value +* `Condition.stringGreaterThanJsonPath` - matches if a string field sorts after a value at a given mapping path +* `Condition.stringGreaterThanEqualsJsonPath` - matches if a string field sorts after or equal to value at a given mapping path +* `Condition.stringGreaterThanEquals` - matches if a string field sorts after or equal to a given value +* `Condition.numberEquals` - matches if a numeric field has the given value +* `Condition.numberEqualsJsonPath` - matches if a numeric field has the value in a given mapping path +* `Condition.numberLessThan` - matches if a numeric field is less than the given value +* `Condition.numberLessThanJsonPath` - matches if a numeric field is less than the value at the given mapping path +* `Condition.numberLessThanEquals` - matches if a numeric field is less than or equal to the given value +* `Condition.numberLessThanEqualsJsonPath` - matches if a numeric field is less than or equal to the numeric value at given mapping path +* `Condition.numberGreaterThan` - matches if a numeric field is greater than the given value +* `Condition.numberGreaterThanJsonPath` - matches if a numeric field is greater than the value at a given mapping path +* `Condition.numberGreaterThanEquals` - matches if a numeric field is greater than or equal to the given value +* `Condition.numberGreaterThanEqualsJsonPath` - matches if a numeric field is greater than or equal to the value at a given mapping path +* `Condition.timestampEquals` - matches if a timestamp field is the same time as the given timestamp +* `Condition.timestampEqualsJsonPath` - matches if a timestamp field is the same time as the timestamp at a given mapping path +* `Condition.timestampLessThan` - matches if a timestamp field is before the given timestamp +* `Condition.timestampLessThanJsonPath` - matches if a timestamp field is before the timestamp at a given mapping path +* `Condition.timestampLessThanEquals` - matches if a timestamp field is before or equal to the given timestamp +* `Condition.timestampLessThanEqualsJsonPath` - matches if a timestamp field is before or equal to the timestamp at a given mapping path +* `Condition.timestampGreaterThan` - matches if a timestamp field is after the timestamp at a given mapping path +* `Condition.timestampGreaterThanJsonPath` - matches if a timestamp field is after the timestamp at a given mapping path +* `Condition.timestampGreaterThanEquals` - matches if a timestamp field is after or equal to the given timestamp +* `Condition.timestampGreaterThanEqualsJsonPath` - matches if a timestamp field is after or equal to the timestamp at a given mapping path +* `Condition.stringMatches` - matches if a field matches a string pattern that can contain a wild card (\*) e.g: log-\*.txt or \*LATEST\*. No other characters other than "\*" have any special meaning - \* can be escaped: \\\\* + ### Parallel A `Parallel` state executes one or more subworkflows in parallel. It can also @@ -520,6 +568,22 @@ new stepfunctions.StateMachine(stack, 'MyStateMachine', { }); ``` +## X-Ray tracing + +Enable X-Ray tracing for StateMachine: + +```ts +const logGroup = new logs.LogGroup(stack, 'MyLogGroup'); + +new stepfunctions.StateMachine(stack, 'MyStateMachine', { + definition: stepfunctions.Chain.start(new stepfunctions.Pass(stack, 'Pass')), + tracingEnabled: true +}); +``` + +See [the AWS documentation](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-xray-tracing.html) +to learn more about AWS Step Functions's X-Ray support. + ## State Machine Permission Grants IAM roles, users, or groups which need to be able to work with a State Machine should be granted IAM permissions. diff --git a/packages/@aws-cdk/aws-stepfunctions/lib/condition.ts b/packages/@aws-cdk/aws-stepfunctions/lib/condition.ts index 2f334af06190c..bc264874f8093 100644 --- a/packages/@aws-cdk/aws-stepfunctions/lib/condition.ts +++ b/packages/@aws-cdk/aws-stepfunctions/lib/condition.ts @@ -2,6 +2,89 @@ * A Condition for use in a Choice state branch */ export abstract class Condition { + + /** + * Matches if variable is present + */ + public static isPresent(variable: string): Condition { + return new VariableComparison(variable, ComparisonOperator.IsPresent, true); + } + + /** + * Matches if variable is not present + */ + public static isNotPresent(variable: string): Condition { + return new VariableComparison(variable, ComparisonOperator.IsPresent, false); + } + + /** + * Matches if variable is a string + */ + public static isString(variable: string): Condition { + return new VariableComparison(variable, ComparisonOperator.IsString, true); + } + + /** + * Matches if variable is not a string + */ + public static isNotString(variable: string): Condition { + return new VariableComparison(variable, ComparisonOperator.IsString, false); + } + + /** + * Matches if variable is numeric + */ + public static isNumeric(variable: string): Condition { + return new VariableComparison(variable, ComparisonOperator.IsNumeric, true); + } + + /** + * Matches if variable is not numeric + */ + public static isNotNumeric(variable: string): Condition { + return new VariableComparison(variable, ComparisonOperator.IsNumeric, false); + } + + /** + * Matches if variable is boolean + */ + public static isBoolean(variable: string): Condition { + return new VariableComparison(variable, ComparisonOperator.IsBoolean, true); + } + + /** + * Matches if variable is not boolean + */ + public static isNotBoolean(variable: string): Condition { + return new VariableComparison(variable, ComparisonOperator.IsBoolean, false); + } + + /** + * Matches if variable is a timestamp + */ + public static isTimestamp(variable: string): Condition { + return new VariableComparison(variable, ComparisonOperator.IsTimestamp, true); + } + + /** + * Matches if variable is not a timestamp + */ + public static isNotTimestamp(variable: string): Condition { + return new VariableComparison(variable, ComparisonOperator.IsTimestamp, false); + } + + /** + * Matches if variable is not null + */ + public static isNotNull(variable: string): Condition { + return new VariableComparison(variable, ComparisonOperator.IsNull, false); + } + /** + * Matches if variable is Null + */ + public static isNull(variable: string): Condition { + return new VariableComparison(variable, ComparisonOperator.IsNull, true); + } /** * Matches if a boolean field has the given value */ @@ -9,6 +92,20 @@ export abstract class Condition { return new VariableComparison(variable, ComparisonOperator.BooleanEquals, value); } + /** + * Matches if a boolean field equals to a value at a given mapping path + */ + public static booleanEqualsJsonPath(variable: string, value: string): Condition { + return new VariableComparison(variable, ComparisonOperator.BooleanEqualsPath, value); + } + + /** + * Matches if a string field equals to a value at a given mapping path + */ + public static stringEqualsJsonPath(variable: string, value: string): Condition { + return new VariableComparison(variable, ComparisonOperator.StringEqualsPath, value); + } + /** * Matches if a string field has the given value */ @@ -23,6 +120,13 @@ export abstract class Condition { return new VariableComparison(variable, ComparisonOperator.StringLessThan, value); } + /** + * Matches if a string field sorts before a given value at a particular mapping + */ + public static stringLessThanJsonPath(variable: string, value: string): Condition { + return new VariableComparison(variable, ComparisonOperator.StringLessThanPath, value); + } + /** * Matches if a string field sorts equal to or before a given value */ @@ -30,6 +134,13 @@ export abstract class Condition { return new VariableComparison(variable, ComparisonOperator.StringLessThanEquals, value); } + /** + * Matches if a string field sorts equal to or before a given mapping + */ + public static stringLessThanEqualsJsonPath(variable: string, value: string): Condition { + return new VariableComparison(variable, ComparisonOperator.StringLessThanEqualsPath, value); + } + /** * Matches if a string field sorts after a given value */ @@ -37,6 +148,20 @@ export abstract class Condition { return new VariableComparison(variable, ComparisonOperator.StringGreaterThan, value); } + /** + * Matches if a string field sorts after a value at a given mapping path + */ + public static stringGreaterThanJsonPath(variable: string, value: string): Condition { + return new VariableComparison(variable, ComparisonOperator.StringGreaterThanPath, value); + } + + /** + * Matches if a string field sorts after or equal to value at a given mapping path + */ + public static stringGreaterThanEqualsJsonPath(variable: string, value: string): Condition { + return new VariableComparison(variable, ComparisonOperator.StringGreaterThanEqualsPath, value); + } + /** * Matches if a string field sorts after or equal to a given value */ @@ -51,6 +176,13 @@ export abstract class Condition { return new VariableComparison(variable, ComparisonOperator.NumericEquals, value); } + /** + * Matches if a numeric field has the value in a given mapping path + */ + public static numberEqualsJsonPath(variable: string, value: string): Condition { + return new VariableComparison(variable, ComparisonOperator.NumericEqualsPath, value); + } + /** * Matches if a numeric field is less than the given value */ @@ -58,6 +190,13 @@ export abstract class Condition { return new VariableComparison(variable, ComparisonOperator.NumericLessThan, value); } + /** + * Matches if a numeric field is less than the value at the given mapping path + */ + public static numberLessThanJsonPath(variable: string, value: string): Condition { + return new VariableComparison(variable, ComparisonOperator.NumericLessThanPath, value); + } + /** * Matches if a numeric field is less than or equal to the given value */ @@ -65,6 +204,13 @@ export abstract class Condition { return new VariableComparison(variable, ComparisonOperator.NumericLessThanEquals, value); } + /** + * Matches if a numeric field is less than or equal to the numeric value at given mapping path + */ + public static numberLessThanEqualsJsonPath(variable: string, value: string): Condition { + return new VariableComparison(variable, ComparisonOperator.NumericLessThanEqualsPath, value); + } + /** * Matches if a numeric field is greater than the given value */ @@ -72,6 +218,13 @@ export abstract class Condition { return new VariableComparison(variable, ComparisonOperator.NumericGreaterThan, value); } + /** + * Matches if a numeric field is greater than the value at a given mapping path + */ + public static numberGreaterThanJsonPath(variable: string, value: string): Condition { + return new VariableComparison(variable, ComparisonOperator.NumericGreaterThanPath, value); + } + /** * Matches if a numeric field is greater than or equal to the given value */ @@ -79,6 +232,13 @@ export abstract class Condition { return new VariableComparison(variable, ComparisonOperator.NumericGreaterThanEquals, value); } + /** + * Matches if a numeric field is greater than or equal to the value at a given mapping path + */ + public static numberGreaterThanEqualsJsonPath(variable: string, value: string): Condition { + return new VariableComparison(variable, ComparisonOperator.NumericGreaterThanEqualsPath, value); + } + /** * Matches if a timestamp field is the same time as the given timestamp */ @@ -86,6 +246,13 @@ export abstract class Condition { return new VariableComparison(variable, ComparisonOperator.TimestampEquals, value); } + /** + * Matches if a timestamp field is the same time as the timestamp at a given mapping path + */ + public static timestampEqualsJsonPath(variable: string, value: string): Condition { + return new VariableComparison(variable, ComparisonOperator.TimestampEqualsPath, value); + } + /** * Matches if a timestamp field is before the given timestamp */ @@ -93,6 +260,13 @@ export abstract class Condition { return new VariableComparison(variable, ComparisonOperator.TimestampLessThan, value); } + /** + * Matches if a timestamp field is before the timestamp at a given mapping path + */ + public static timestampLessThanJsonPath(variable: string, value: string): Condition { + return new VariableComparison(variable, ComparisonOperator.TimestampLessThanPath, value); + } + /** * Matches if a timestamp field is before or equal to the given timestamp */ @@ -100,6 +274,13 @@ export abstract class Condition { return new VariableComparison(variable, ComparisonOperator.TimestampLessThanEquals, value); } + /** + * Matches if a timestamp field is before or equal to the timestamp at a given mapping path + */ + public static timestampLessThanEqualsJsonPath(variable: string, value: string): Condition { + return new VariableComparison(variable, ComparisonOperator.TimestampLessThanEqualsPath, value); + } + /** * Matches if a timestamp field is after the given timestamp */ @@ -107,6 +288,13 @@ export abstract class Condition { return new VariableComparison(variable, ComparisonOperator.TimestampGreaterThan, value); } + /** + * Matches if a timestamp field is after the timestamp at a given mapping path + */ + public static timestampGreaterThanJsonPath(variable: string, value: string): Condition { + return new VariableComparison(variable, ComparisonOperator.TimestampGreaterThanPath, value); + } + /** * Matches if a timestamp field is after or equal to the given timestamp */ @@ -114,6 +302,21 @@ export abstract class Condition { return new VariableComparison(variable, ComparisonOperator.TimestampGreaterThanEquals, value); } + /** + * Matches if a timestamp field is after or equal to the timestamp at a given mapping path + */ + public static timestampGreaterThanEqualsJsonPath(variable: string, value: string): Condition { + return new VariableComparison(variable, ComparisonOperator.TimestampGreaterThanEqualsPath, value); + } + + /** + * Matches if a field matches a string pattern that can contain a wild card (*) e.g: log-*.txt or *LATEST*. + * No other characters other than "*" have any special meaning - * can be escaped: \\* + */ + public static stringMatches(variable: string, value: string): Condition { + return new VariableComparison(variable, ComparisonOperator.StringMatches, value); + } + /** * Combine two or more conditions with a logical AND */ @@ -146,21 +349,45 @@ export abstract class Condition { */ enum ComparisonOperator { StringEquals, + StringEqualsPath, StringLessThan, + StringLessThanPath, StringGreaterThan, + StringGreaterThanPath, StringLessThanEquals, + StringLessThanEqualsPath, StringGreaterThanEquals, + StringGreaterThanEqualsPath, NumericEquals, + NumericEqualsPath, NumericLessThan, + NumericLessThanPath, NumericGreaterThan, + NumericGreaterThanPath, NumericLessThanEquals, + NumericLessThanEqualsPath, NumericGreaterThanEquals, + NumericGreaterThanEqualsPath, BooleanEquals, + BooleanEqualsPath, TimestampEquals, + TimestampEqualsPath, TimestampLessThan, + TimestampLessThanPath, TimestampGreaterThan, + TimestampGreaterThanPath, TimestampLessThanEquals, + TimestampLessThanEqualsPath, TimestampGreaterThanEquals, + TimestampGreaterThanEqualsPath, + IsNull, + IsBoolean, + IsNumeric, + IsString, + IsTimestamp, + IsPresent, + StringMatches, + } /** diff --git a/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts b/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts index a6632a7e5d35d..13a0b9ea5b7be 100644 --- a/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts +++ b/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts @@ -118,6 +118,13 @@ export interface StateMachineProps { * @default No logging */ readonly logs?: LogOptions; + + /** + * Specifies whether Amazon X-Ray tracing is enabled for this state machine. + * + * @default false + */ + readonly tracingEnabled?: boolean; } /** @@ -272,37 +279,13 @@ export class StateMachine extends StateMachineBase { this.stateMachineType = props.stateMachineType ? props.stateMachineType : StateMachineType.STANDARD; - let loggingConfiguration: CfnStateMachine.LoggingConfigurationProperty | undefined; - if (props.logs) { - const conf = props.logs; - loggingConfiguration = { - destinations: [{ cloudWatchLogsLogGroup: { logGroupArn: conf.destination.logGroupArn } }], - includeExecutionData: conf.includeExecutionData, - level: conf.level || 'ERROR', - }; - // https://docs.aws.amazon.com/step-functions/latest/dg/cw-logs.html#cloudwatch-iam-policy - this.addToRolePolicy(new iam.PolicyStatement({ - effect: iam.Effect.ALLOW, - actions: [ - 'logs:CreateLogDelivery', - 'logs:GetLogDelivery', - 'logs:UpdateLogDelivery', - 'logs:DeleteLogDelivery', - 'logs:ListLogDeliveries', - 'logs:PutResourcePolicy', - 'logs:DescribeResourcePolicies', - 'logs:DescribeLogGroups', - ], - resources: ['*'], - })); - } - const resource = new CfnStateMachine(this, 'Resource', { stateMachineName: this.physicalName, stateMachineType: props.stateMachineType ? props.stateMachineType : undefined, roleArn: this.role.roleArn, definitionString: Stack.of(this).toJsonString(graph.toGraphJson()), - loggingConfiguration, + loggingConfiguration: props.logs ? this.buildLoggingConfiguration(props.logs) : undefined, + tracingConfiguration: props.tracingEnabled ? this.buildTracingConfiguration() : undefined, }); resource.node.addDependency(this.role); @@ -324,7 +307,7 @@ export class StateMachine extends StateMachineBase { * Add the given statement to the role's policy */ public addToRolePolicy(statement: iam.PolicyStatement) { - this.role.addToPolicy(statement); + this.role.addToPrincipalPolicy(statement); } /** @@ -404,6 +387,44 @@ export class StateMachine extends StateMachineBase { public metricTime(props?: cloudwatch.MetricOptions): cloudwatch.Metric { return this.metric('ExecutionTime', props); } + + private buildLoggingConfiguration(logOptions: LogOptions): CfnStateMachine.LoggingConfigurationProperty { + // https://docs.aws.amazon.com/step-functions/latest/dg/cw-logs.html#cloudwatch-iam-policy + this.addToRolePolicy(new iam.PolicyStatement({ + effect: iam.Effect.ALLOW, + actions: [ + 'logs:CreateLogDelivery', + 'logs:GetLogDelivery', + 'logs:UpdateLogDelivery', + 'logs:DeleteLogDelivery', + 'logs:ListLogDeliveries', + 'logs:PutResourcePolicy', + 'logs:DescribeResourcePolicies', + 'logs:DescribeLogGroups', + ], + resources: ['*'], + })); + + return { + destinations: [{ + cloudWatchLogsLogGroup: { logGroupArn: logOptions.destination.logGroupArn }, + }], + includeExecutionData: logOptions.includeExecutionData, + level: logOptions.level || 'ERROR', + }; + } + + private buildTracingConfiguration(): CfnStateMachine.TracingConfigurationProperty { + this.addToRolePolicy(new iam.PolicyStatement({ + // https://docs.aws.amazon.com/xray/latest/devguide/security_iam_id-based-policy-examples.html#xray-permissions-resources + actions: ['xray:PutTraceSegments', 'xray:PutTelemetryRecords'], + resources: ['*'], + })); + + return { + enabled: true, + }; + } } /** diff --git a/packages/@aws-cdk/aws-stepfunctions/test/condition.test.ts b/packages/@aws-cdk/aws-stepfunctions/test/condition.test.ts index aef483b4583a5..55fa5a6d2c535 100644 --- a/packages/@aws-cdk/aws-stepfunctions/test/condition.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions/test/condition.test.ts @@ -37,6 +37,91 @@ describe('Condition Variables', () => { [stepfunctions.Condition.numberEquals('$.a', 5), { Variable: '$.a', NumericEquals: 5 }], ]; + for (const [cond, expected] of cases) { + assertRendersTo(cond, expected); + } + }), + test('Exercise string conditions', () => { + const cases: Array<[stepfunctions.Condition, object]> = [ + [stepfunctions.Condition.stringEquals('$.a', 'foo'), { Variable: '$.a', StringEquals: 'foo' }], + [stepfunctions.Condition.stringEqualsJsonPath('$.a', '$.b'), { Variable: '$.a', StringEqualsPath: '$.b' }], + [stepfunctions.Condition.stringLessThan('$.a', 'foo'), { Variable: '$.a', StringLessThan: 'foo' }], + [stepfunctions.Condition.stringLessThanJsonPath('$.a', '$.b'), { Variable: '$.a', StringLessThanPath: '$.b' }], + [stepfunctions.Condition.stringLessThanEquals('$.a', 'foo'), { Variable: '$.a', StringLessThanEquals: 'foo' }], + [stepfunctions.Condition.stringLessThanEqualsJsonPath('$.a', '$.b'), { Variable: '$.a', StringLessThanEqualsPath: '$.b' }], + [stepfunctions.Condition.stringGreaterThan('$.a', 'foo'), { Variable: '$.a', StringGreaterThan: 'foo' }], + [stepfunctions.Condition.stringGreaterThanJsonPath('$.a', '$.b'), { Variable: '$.a', StringGreaterThanPath: '$.b' }], + [stepfunctions.Condition.stringGreaterThanEquals('$.a', 'foo'), { Variable: '$.a', StringGreaterThanEquals: 'foo' }], + [stepfunctions.Condition.stringGreaterThanEqualsJsonPath('$.a', '$.b'), { Variable: '$.a', StringGreaterThanEqualsPath: '$.b' }], + ]; + + for (const [cond, expected] of cases) { + assertRendersTo(cond, expected); + } + }), + test('Exercise number conditions', () => { + const cases: Array<[stepfunctions.Condition, object]> = [ + [stepfunctions.Condition.numberEquals('$.a', 5), { Variable: '$.a', NumericEquals: 5 }], + [stepfunctions.Condition.numberEqualsJsonPath('$.a', '$.b'), { Variable: '$.a', NumericEqualsPath: '$.b' }], + [stepfunctions.Condition.numberLessThan('$.a', 5), { Variable: '$.a', NumericLessThan: 5 }], + [stepfunctions.Condition.numberLessThanJsonPath('$.a', '$.b'), { Variable: '$.a', NumericLessThanPath: '$.b' }], + [stepfunctions.Condition.numberGreaterThan('$.a', 5), { Variable: '$.a', NumericGreaterThan: 5 }], + [stepfunctions.Condition.numberGreaterThanJsonPath('$.a', '$.b'), { Variable: '$.a', NumericGreaterThanPath: '$.b' }], + [stepfunctions.Condition.numberLessThanEquals('$.a', 5), { Variable: '$.a', NumericLessThanEquals: 5 }], + [stepfunctions.Condition.numberLessThanEqualsJsonPath('$.a', '$.b'), { Variable: '$.a', NumericLessThanEqualsPath: '$.b' }], + [stepfunctions.Condition.numberGreaterThanEquals('$.a', 5), { Variable: '$.a', NumericGreaterThanEquals: 5 }], + [stepfunctions.Condition.numberGreaterThanEqualsJsonPath('$.a', '$.b'), { Variable: '$.a', NumericGreaterThanEqualsPath: '$.b' }], + ]; + + + for (const [cond, expected] of cases) { + assertRendersTo(cond, expected); + } + }), + test('Exercise type conditions', () => { + const cases: Array<[stepfunctions.Condition, object]> = [ + [stepfunctions.Condition.isString('$.a'), { Variable: '$.a', IsString: true }], + [stepfunctions.Condition.isNotString('$.a'), { Variable: '$.a', IsString: false }], + [stepfunctions.Condition.isNumeric('$.a'), { Variable: '$.a', IsNumeric: true }], + [stepfunctions.Condition.isNotNumeric('$.a'), { Variable: '$.a', IsNumeric: false }], + [stepfunctions.Condition.isBoolean('$.a'), { Variable: '$.a', IsBoolean: true }], + [stepfunctions.Condition.isNotBoolean('$.a'), { Variable: '$.a', IsBoolean: false }], + [stepfunctions.Condition.isTimestamp('$.a'), { Variable: '$.a', IsTimestamp: true }], + [stepfunctions.Condition.isNotTimestamp('$.a'), { Variable: '$.a', IsTimestamp: false }], + ]; + + for (const [cond, expected] of cases) { + assertRendersTo(cond, expected); + } + }), + test('Exercise timestamp conditions', () => { + const cases: Array<[stepfunctions.Condition, object]> = [ + [stepfunctions.Condition.timestampEquals('$.a', 'timestamp'), { Variable: '$.a', TimestampEquals: 'timestamp' }], + [stepfunctions.Condition.timestampEqualsJsonPath('$.a', '$.b'), { Variable: '$.a', TimestampEqualsPath: '$.b' }], + [stepfunctions.Condition.timestampLessThan('$.a', 'timestamp'), { Variable: '$.a', TimestampLessThan: 'timestamp' }], + [stepfunctions.Condition.timestampLessThanJsonPath('$.a', '$.b'), { Variable: '$.a', TimestampLessThanPath: '$.b' }], + [stepfunctions.Condition.timestampGreaterThan('$.a', 'timestamp'), { Variable: '$.a', TimestampGreaterThan: 'timestamp' }], + [stepfunctions.Condition.timestampGreaterThanJsonPath('$.a', '$.b'), { Variable: '$.a', TimestampGreaterThanPath: '$.b' }], + [stepfunctions.Condition.timestampLessThanEquals('$.a', 'timestamp'), { Variable: '$.a', TimestampLessThanEquals: 'timestamp' }], + [stepfunctions.Condition.timestampLessThanEqualsJsonPath('$.a', '$.b'), { Variable: '$.a', TimestampLessThanEqualsPath: '$.b' }], + [stepfunctions.Condition.timestampGreaterThanEquals('$.a', 'timestamp'), { Variable: '$.a', TimestampGreaterThanEquals: 'timestamp' }], + [stepfunctions.Condition.timestampGreaterThanEqualsJsonPath('$.a', '$.b'), { Variable: '$.a', TimestampGreaterThanEqualsPath: '$.b' }], + ]; + + for (const [cond, expected] of cases) { + assertRendersTo(cond, expected); + } + }), + + test('Exercise other conditions', () => { + const cases: Array<[stepfunctions.Condition, object]> = [ + [stepfunctions.Condition.booleanEqualsJsonPath('$.a', '$.b'), { Variable: '$.a', BooleanEqualsPath: '$.b' }], + [stepfunctions.Condition.booleanEquals('$.a', true), { Variable: '$.a', BooleanEquals: true }], + [stepfunctions.Condition.isPresent('$.a'), { Variable: '$.a', IsPresent: true }], + [stepfunctions.Condition.isNotPresent('$.a'), { Variable: '$.a', IsPresent: false }], + [stepfunctions.Condition.stringMatches('$.a', 'foo'), { Variable: '$.a', StringMatches: 'foo' }], + ]; + for (const [cond, expected] of cases) { assertRendersTo(cond, expected); } diff --git a/packages/@aws-cdk/aws-stepfunctions/test/state-machine.test.ts b/packages/@aws-cdk/aws-stepfunctions/test/state-machine.test.ts index 428fef3440066..86475be650276 100644 --- a/packages/@aws-cdk/aws-stepfunctions/test/state-machine.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions/test/state-machine.test.ts @@ -120,4 +120,42 @@ describe('State Machine', () => { }); }); -}); \ No newline at end of file + test('tracing configuration', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new stepfunctions.StateMachine(stack, 'MyStateMachine', { + definition: stepfunctions.Chain.start(new stepfunctions.Pass(stack, 'Pass')), + tracingEnabled: true, + }); + + // THEN + expect(stack).toHaveResource('AWS::StepFunctions::StateMachine', { + DefinitionString: '{"StartAt":"Pass","States":{"Pass":{"Type":"Pass","End":true}}}', + TracingConfiguration: { + Enabled: true, + }, + }); + + expect(stack).toHaveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [{ + Action: [ + 'xray:PutTraceSegments', + 'xray:PutTelemetryRecords', + ], + Effect: 'Allow', + Resource: '*', + }], + Version: '2012-10-17', + }, + PolicyName: 'MyStateMachineRoleDefaultPolicyE468EB18', + Roles: [ + { + Ref: 'MyStateMachineRoleD59FFEBC', + }, + ], + }); + }); +}); diff --git a/packages/@aws-cdk/cdk-assets-schema/package.json b/packages/@aws-cdk/cdk-assets-schema/package.json index 30c3b8705771a..94f2091e69426 100644 --- a/packages/@aws-cdk/cdk-assets-schema/package.json +++ b/packages/@aws-cdk/cdk-assets-schema/package.json @@ -47,9 +47,9 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.10", + "@types/jest": "^26.0.14", "cdk-build-tools": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "pkglint": "0.0.0" }, "repository": { diff --git a/packages/@aws-cdk/cfnspec/CHANGELOG.md b/packages/@aws-cdk/cfnspec/CHANGELOG.md index 168379fce3ccd..3d279634e1034 100644 --- a/packages/@aws-cdk/cfnspec/CHANGELOG.md +++ b/packages/@aws-cdk/cfnspec/CHANGELOG.md @@ -1,3 +1,155 @@ +# CloudFormation Resource Specification v18.3.0 + +## New Resource Types + +* AWS::ApplicationInsights::Application +* AWS::CloudFront::CachePolicy +* AWS::CloudFront::OriginRequestPolicy +* AWS::CloudFront::RealtimeLogConfig +* AWS::CodeGuruReviewer::RepositoryAssociation +* AWS::EC2::CarrierGateway +* AWS::EKS::FargateProfile +* AWS::GameLift::GameServerGroup +* AWS::IoT::Authorizer +* AWS::Kendra::DataSource +* AWS::Kendra::Faq +* AWS::Kendra::Index +* AWS::Route53Resolver::ResolverQueryLoggingConfig +* AWS::Route53Resolver::ResolverQueryLoggingConfigAssociation +* AWS::SSO::Assignment +* AWS::SSO::PermissionSet +* AWS::SageMaker::MonitoringSchedule + +## Attribute Changes + +* AWS::GameLift::Alias AliasId (__added__) +* AWS::IoT::Certificate Id (__added__) +* AWS::KMS::Key KeyId (__added__) +* AWS::Lambda::EventSourceMapping Id (__added__) +* AWS::OpsWorksCM::Server Id (__added__) +* AWS::Route53::HealthCheck HealthCheckId (__added__) +* AWS::StepFunctions::StateMachine Arn (__added__) + +## Property Changes + +* AWS::ApiGatewayV2::Authorizer AuthorizerPayloadFormatVersion (__added__) +* AWS::ApiGatewayV2::Authorizer EnableSimpleResponses (__added__) +* AWS::ApiGatewayV2::Integration IntegrationSubtype (__added__) +* AWS::Cognito::UserPoolClient AccessTokenValidity (__added__) +* AWS::Cognito::UserPoolClient IdTokenValidity (__added__) +* AWS::Cognito::UserPoolClient TokenValidityUnits (__added__) +* AWS::EC2::NetworkInterface Ipv6Addresses.DuplicatesAllowed (__added__) +* AWS::EC2::NetworkInterface Ipv6Addresses.ItemType (__added__) +* AWS::EC2::NetworkInterface Ipv6Addresses.Type (__changed__) + * Old: InstanceIpv6Address + * New: List +* AWS::EC2::TransitGateway MulticastSupport (__added__) +* AWS::ECR::Repository ImageScanningConfiguration (__added__) +* AWS::ECR::Repository ImageTagMutability (__added__) +* AWS::ECR::Repository RepositoryPolicyText.PrimitiveType (__deleted__) +* AWS::ECR::Repository Tags.DuplicatesAllowed (__changed__) + * Old: true + * New: false +* AWS::ECS::TaskDefinition TaskDefinitionStatus (__deleted__) +* AWS::EKS::Nodegroup LaunchTemplate (__added__) +* AWS::GuardDuty::Detector DataSources (__added__) +* AWS::IoT::Certificate CACertificatePem (__added__) +* AWS::IoT::Certificate CertificateMode (__added__) +* AWS::IoT::Certificate CertificatePem (__added__) +* AWS::IoT::Certificate CertificateSigningRequest.Required (__changed__) + * Old: true + * New: false +* AWS::KMS::Key KeyPolicy.PrimitiveType (__deleted__) +* AWS::KMS::Key Tags.DuplicatesAllowed (__changed__) + * Old: true + * New: false +* AWS::Lambda::EventSourceMapping Topics (__added__) +* AWS::Neptune::DBCluster AssociatedRoles (__added__) +* AWS::OpsWorksCM::Server EngineAttributes.DuplicatesAllowed (__added__) +* AWS::OpsWorksCM::Server SecurityGroupIds.DuplicatesAllowed (__added__) +* AWS::OpsWorksCM::Server SubnetIds.DuplicatesAllowed (__added__) +* AWS::OpsWorksCM::Server Tags.DuplicatesAllowed (__added__) +* AWS::Route53::HealthCheck HealthCheckConfig.Type (__deleted__) +* AWS::Route53::HealthCheck HealthCheckConfig.PrimitiveType (__added__) +* AWS::Route53::HealthCheck HealthCheckConfig.UpdateType (__changed__) + * Old: Conditional + * New: Mutable +* AWS::Route53::HealthCheck HealthCheckTags.DuplicatesAllowed (__changed__) + * Old: true + * New: false +* AWS::SNS::Topic FifoTopic (__deleted__) +* AWS::SageMaker::Model EnableNetworkIsolation (__added__) +* AWS::ServiceCatalog::CloudFormationProvisionedProduct PathName (__added__) +* AWS::StepFunctions::StateMachine StateMachineType.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::StepFunctions::StateMachine Tags.DuplicatesAllowed (__added__) +* AWS::Transfer::Server SecurityPolicyName (__added__) + +## Property Type Changes + +* AWS::ECS::TaskDefinition.EfsVolumeConfiguration (__removed__) +* AWS::ECS::TaskDefinition.Options (__removed__) +* AWS::Route53::HealthCheck.AlarmIdentifier (__removed__) +* AWS::Route53::HealthCheck.HealthCheckConfig (__removed__) +* AWS::Cognito::UserPoolClient.TokenValidityUnits (__added__) +* AWS::ECS::TaskDefinition.EFSVolumeConfiguration (__added__) +* AWS::ECS::TaskDefinition.EnvironmentFile (__added__) +* AWS::EKS::Nodegroup.LaunchTemplateSpecification (__added__) +* AWS::GuardDuty::Detector.CFNDataSourceConfigurations (__added__) +* AWS::GuardDuty::Detector.CFNS3LogsConfiguration (__added__) +* AWS::MSK::Cluster.Sasl (__added__) +* AWS::MSK::Cluster.Scram (__added__) +* AWS::Macie::FindingsFilter.FindingsFilterListItem (__added__) +* AWS::Neptune::DBCluster.DBClusterRole (__added__) +* AWS::SSM::Association.ParameterValues (__added__) +* AWS::CloudFront::Distribution.CacheBehavior RealtimeLogConfigArn (__added__) +* AWS::CloudFront::Distribution.DefaultCacheBehavior RealtimeLogConfigArn (__added__) +* AWS::CodeCommit::Repository.Code BranchName (__added__) +* AWS::ECS::TaskDefinition.ContainerDefinition EnvironmentFiles (__added__) +* AWS::ECS::TaskDefinition.AuthorizationConfig Iam (__deleted__) +* AWS::ECS::TaskDefinition.AuthorizationConfig IAM (__added__) +* AWS::ECS::TaskDefinition.AuthorizationConfig AccessPointId.Documentation (__changed__) + * Old: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/efs-volumes.html#specify-efs-config + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-authorizationconfig.html#cfn-ecs-taskdefinition-authorizationconfig-accesspointid +* AWS::ECS::TaskDefinition.FirelensConfiguration Options.PrimitiveItemType (__added__) +* AWS::ECS::TaskDefinition.FirelensConfiguration Options.Type (__changed__) + * Old: Options + * New: Map +* AWS::ECS::TaskDefinition.LogConfiguration Options.PrimitiveItemType (__added__) +* AWS::ECS::TaskDefinition.LogConfiguration Options.Type (__changed__) + * Old: Options + * New: Map +* AWS::ECS::TaskDefinition.Volume EfsVolumeConfiguration (__deleted__) +* AWS::ECS::TaskDefinition.Volume EFSVolumeConfiguration (__added__) +* AWS::FSx::FileSystem.LustreConfiguration DriveCacheType (__added__) +* AWS::GameLift::Alias.RoutingStrategy Type.Required (__changed__) + * Old: true + * New: false +* AWS::Lambda::EventSourceMapping.DestinationConfig OnFailure.Required (__changed__) + * Old: true + * New: false +* AWS::Lambda::EventSourceMapping.OnFailure Destination.Required (__changed__) + * Old: true + * New: false +* AWS::MSK::Cluster.ClientAuthentication Sasl (__added__) +* AWS::Route53::HealthCheck.HealthCheckTag Key.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthchecktag.html#cfn-route53-healthchecktags-key + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthchecktag.html#cfn-route53-healthcheck-healthchecktag-key +* AWS::Route53::HealthCheck.HealthCheckTag Value.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthchecktag.html#cfn-route53-healthchecktags-value + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthchecktag.html#cfn-route53-healthcheck-healthchecktag-value +* AWS::StepFunctions::StateMachine.CloudWatchLogsLogGroup LogGroupArn.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-stepfunctions-statemachine-logdestination-cloudwatchlogsloggroup.html#cfn-stepfunctions-statemachine-logdestination-cloudwatchlogsloggroup-loggrouparn + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-stepfunctions-statemachine-cloudwatchlogsloggroup.html#cfn-stepfunctions-statemachine-cloudwatchlogsloggroup-loggrouparn +* AWS::StepFunctions::StateMachine.CloudWatchLogsLogGroup LogGroupArn.Required (__changed__) + * Old: true + * New: false +* AWS::StepFunctions::StateMachine.TracingConfiguration Enabled.Required (__changed__) + * Old: true + * New: false + + # CloudFormation Resource Specification v16.3.0 ## New Resource Types diff --git a/packages/@aws-cdk/cfnspec/cfn.version b/packages/@aws-cdk/cfnspec/cfn.version index d9a8a35788584..ef9129a61aca3 100644 --- a/packages/@aws-cdk/cfnspec/cfn.version +++ b/packages/@aws-cdk/cfnspec/cfn.version @@ -1 +1 @@ -16.3.0 +18.3.0 diff --git a/packages/@aws-cdk/cfnspec/lib/schema/property.ts b/packages/@aws-cdk/cfnspec/lib/schema/property.ts index a5d8bc602347f..d901ab3045bd9 100644 --- a/packages/@aws-cdk/cfnspec/lib/schema/property.ts +++ b/packages/@aws-cdk/cfnspec/lib/schema/property.ts @@ -5,6 +5,7 @@ export type ScalarProperty = PrimitiveProperty | ComplexProperty | UnionProperty export type CollectionProperty = ListProperty | MapProperty | UnionProperty; export type ListProperty = PrimitiveListProperty | ComplexListProperty; export type MapProperty = PrimitiveMapProperty | ComplexMapProperty; +export type ComplexMapProperty = MapOfStructs | MapOfListsOfPrimitives; export type TagProperty = TagPropertyStandard | TagPropertyAutoScalingGroup | TagPropertyJson | TagPropertyStringMap; export interface PropertyBase extends Documented { @@ -81,11 +82,19 @@ export interface PrimitiveMapProperty extends MapPropertyBase { PrimitiveItemType: PrimitiveType; } -export interface ComplexMapProperty extends MapPropertyBase { +export interface MapOfStructs extends MapPropertyBase { /** Valid values for the property */ ItemType: string; } +export interface MapOfListsOfPrimitives extends MapPropertyBase { + /** The type of the map values, which in this case is always 'List'. */ + ItemType: string; + + /** The valid primitive type for the lists that are the values of this map. */ + PrimitiveItemItemType: PrimitiveType; +} + export interface TagPropertyStandard extends PropertyBase { ItemType: 'Tag' | 'TagsEntry' | 'TagRef' | 'ElasticFileSystemTag' | 'HostedZoneTag'; Type: 'Tags'; @@ -177,8 +186,17 @@ export function isPrimitiveMapProperty(prop: Property): prop is PrimitiveMapProp return isMapProperty(prop) && !!(prop as PrimitiveMapProperty).PrimitiveItemType; } -export function isComplexMapProperty(prop: Property): prop is ComplexMapProperty { - return isMapProperty(prop) && !!(prop as ComplexMapProperty).ItemType; +export function isMapOfStructsProperty(prop: Property): prop is MapOfStructs { + return isMapProperty(prop) && + !isPrimitiveMapProperty(prop) && + !isMapOfListsOfPrimitivesProperty(prop); +} + +// note: this (and the MapOfListsOfPrimitives type) are not actually valid in the CFN spec! +// they are only here to support our patch of the CFN spec +// to alleviate https://github.com/aws/aws-cdk/issues/3092 +export function isMapOfListsOfPrimitivesProperty(prop: Property): prop is MapOfListsOfPrimitives { + return isMapProperty(prop) && (prop as ComplexMapProperty).ItemType === 'List'; } export function isUnionProperty(prop: Property): prop is UnionProperty { diff --git a/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json b/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json index 85f9b4bfb03b9..7842a5b81996b 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json +++ b/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json @@ -4274,6 +4274,293 @@ } } }, + "AWS::ApplicationInsights::Application.Alarm": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-alarm.html", + "Properties": { + "AlarmName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-alarm.html#cfn-applicationinsights-application-alarm-alarmname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Severity": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-alarm.html#cfn-applicationinsights-application-alarm-severity", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::ApplicationInsights::Application.AlarmMetric": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-alarmmetric.html", + "Properties": { + "AlarmMetricName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-alarmmetric.html#cfn-applicationinsights-application-alarmmetric-alarmmetricname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::ApplicationInsights::Application.ComponentConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-componentconfiguration.html", + "Properties": { + "ConfigurationDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-componentconfiguration.html#cfn-applicationinsights-application-componentconfiguration-configurationdetails", + "Required": false, + "Type": "ConfigurationDetails", + "UpdateType": "Mutable" + }, + "SubComponentTypeConfigurations": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-componentconfiguration.html#cfn-applicationinsights-application-componentconfiguration-subcomponenttypeconfigurations", + "ItemType": "SubComponentTypeConfiguration", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::ApplicationInsights::Application.ComponentMonitoringSetting": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-componentmonitoringsetting.html", + "Properties": { + "ComponentARN": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-componentmonitoringsetting.html#cfn-applicationinsights-application-componentmonitoringsetting-componentarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ComponentConfigurationMode": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-componentmonitoringsetting.html#cfn-applicationinsights-application-componentmonitoringsetting-componentconfigurationmode", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ComponentName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-componentmonitoringsetting.html#cfn-applicationinsights-application-componentmonitoringsetting-componentname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "CustomComponentConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-componentmonitoringsetting.html#cfn-applicationinsights-application-componentmonitoringsetting-customcomponentconfiguration", + "Required": false, + "Type": "ComponentConfiguration", + "UpdateType": "Mutable" + }, + "DefaultOverwriteComponentConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-componentmonitoringsetting.html#cfn-applicationinsights-application-componentmonitoringsetting-defaultoverwritecomponentconfiguration", + "Required": false, + "Type": "ComponentConfiguration", + "UpdateType": "Mutable" + }, + "Tier": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-componentmonitoringsetting.html#cfn-applicationinsights-application-componentmonitoringsetting-tier", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::ApplicationInsights::Application.ConfigurationDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-configurationdetails.html", + "Properties": { + "AlarmMetrics": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-configurationdetails.html#cfn-applicationinsights-application-configurationdetails-alarmmetrics", + "ItemType": "AlarmMetric", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Alarms": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-configurationdetails.html#cfn-applicationinsights-application-configurationdetails-alarms", + "ItemType": "Alarm", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Logs": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-configurationdetails.html#cfn-applicationinsights-application-configurationdetails-logs", + "ItemType": "Log", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "WindowsEvents": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-configurationdetails.html#cfn-applicationinsights-application-configurationdetails-windowsevents", + "ItemType": "WindowsEvent", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::ApplicationInsights::Application.CustomComponent": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-customcomponent.html", + "Properties": { + "ComponentName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-customcomponent.html#cfn-applicationinsights-application-customcomponent-componentname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ResourceList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-customcomponent.html#cfn-applicationinsights-application-customcomponent-resourcelist", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::ApplicationInsights::Application.Log": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-log.html", + "Properties": { + "Encoding": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-log.html#cfn-applicationinsights-application-log-encoding", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "LogGroupName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-log.html#cfn-applicationinsights-application-log-loggroupname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "LogPath": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-log.html#cfn-applicationinsights-application-log-logpath", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "LogType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-log.html#cfn-applicationinsights-application-log-logtype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "PatternSet": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-log.html#cfn-applicationinsights-application-log-patternset", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::ApplicationInsights::Application.LogPattern": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-logpattern.html", + "Properties": { + "Pattern": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-logpattern.html#cfn-applicationinsights-application-logpattern-pattern", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "PatternName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-logpattern.html#cfn-applicationinsights-application-logpattern-patternname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Rank": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-logpattern.html#cfn-applicationinsights-application-logpattern-rank", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::ApplicationInsights::Application.LogPatternSet": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-logpatternset.html", + "Properties": { + "LogPatterns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-logpatternset.html#cfn-applicationinsights-application-logpatternset-logpatterns", + "ItemType": "LogPattern", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "PatternSetName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-logpatternset.html#cfn-applicationinsights-application-logpatternset-patternsetname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::ApplicationInsights::Application.SubComponentConfigurationDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-subcomponentconfigurationdetails.html", + "Properties": { + "AlarmMetrics": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-subcomponentconfigurationdetails.html#cfn-applicationinsights-application-subcomponentconfigurationdetails-alarmmetrics", + "ItemType": "AlarmMetric", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Logs": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-subcomponentconfigurationdetails.html#cfn-applicationinsights-application-subcomponentconfigurationdetails-logs", + "ItemType": "Log", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "WindowsEvents": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-subcomponentconfigurationdetails.html#cfn-applicationinsights-application-subcomponentconfigurationdetails-windowsevents", + "ItemType": "WindowsEvent", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::ApplicationInsights::Application.SubComponentTypeConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-subcomponenttypeconfiguration.html", + "Properties": { + "SubComponentConfigurationDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-subcomponenttypeconfiguration.html#cfn-applicationinsights-application-subcomponenttypeconfiguration-subcomponentconfigurationdetails", + "Required": true, + "Type": "SubComponentConfigurationDetails", + "UpdateType": "Mutable" + }, + "SubComponentType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-subcomponenttypeconfiguration.html#cfn-applicationinsights-application-subcomponenttypeconfiguration-subcomponenttype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::ApplicationInsights::Application.WindowsEvent": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-windowsevent.html", + "Properties": { + "EventLevels": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-windowsevent.html#cfn-applicationinsights-application-windowsevent-eventlevels", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "EventName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-windowsevent.html#cfn-applicationinsights-application-windowsevent-eventname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "LogGroupName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-windowsevent.html#cfn-applicationinsights-application-windowsevent-loggroupname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "PatternSet": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationinsights-application-windowsevent.html#cfn-applicationinsights-application-windowsevent-patternset", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::Athena::DataCatalog.Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-athena-datacatalog-tags.html", "Properties": { @@ -6111,6 +6398,133 @@ } } }, + "AWS::CloudFront::CachePolicy.CachePolicyConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-cachepolicy-cachepolicyconfig.html", + "Properties": { + "Comment": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-cachepolicy-cachepolicyconfig.html#cfn-cloudfront-cachepolicy-cachepolicyconfig-comment", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "DefaultTTL": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-cachepolicy-cachepolicyconfig.html#cfn-cloudfront-cachepolicy-cachepolicyconfig-defaultttl", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + }, + "MaxTTL": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-cachepolicy-cachepolicyconfig.html#cfn-cloudfront-cachepolicy-cachepolicyconfig-maxttl", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + }, + "MinTTL": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-cachepolicy-cachepolicyconfig.html#cfn-cloudfront-cachepolicy-cachepolicyconfig-minttl", + "PrimitiveType": "Double", + "Required": true, + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-cachepolicy-cachepolicyconfig.html#cfn-cloudfront-cachepolicy-cachepolicyconfig-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ParametersInCacheKeyAndForwardedToOrigin": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-cachepolicy-cachepolicyconfig.html#cfn-cloudfront-cachepolicy-cachepolicyconfig-parametersincachekeyandforwardedtoorigin", + "Required": false, + "Type": "ParametersInCacheKeyAndForwardedToOrigin", + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::CachePolicy.CookiesConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-cachepolicy-cookiesconfig.html", + "Properties": { + "CookieBehavior": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-cachepolicy-cookiesconfig.html#cfn-cloudfront-cachepolicy-cookiesconfig-cookiebehavior", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Cookies": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-cachepolicy-cookiesconfig.html#cfn-cloudfront-cachepolicy-cookiesconfig-cookies", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::CachePolicy.HeadersConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-cachepolicy-headersconfig.html", + "Properties": { + "HeaderBehavior": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-cachepolicy-headersconfig.html#cfn-cloudfront-cachepolicy-headersconfig-headerbehavior", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Headers": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-cachepolicy-headersconfig.html#cfn-cloudfront-cachepolicy-headersconfig-headers", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::CachePolicy.ParametersInCacheKeyAndForwardedToOrigin": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-cachepolicy-parametersincachekeyandforwardedtoorigin.html", + "Properties": { + "CookiesConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-cachepolicy-parametersincachekeyandforwardedtoorigin.html#cfn-cloudfront-cachepolicy-parametersincachekeyandforwardedtoorigin-cookiesconfig", + "Required": true, + "Type": "CookiesConfig", + "UpdateType": "Mutable" + }, + "EnableAcceptEncodingGzip": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-cachepolicy-parametersincachekeyandforwardedtoorigin.html#cfn-cloudfront-cachepolicy-parametersincachekeyandforwardedtoorigin-enableacceptencodinggzip", + "PrimitiveType": "Boolean", + "Required": true, + "UpdateType": "Mutable" + }, + "HeadersConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-cachepolicy-parametersincachekeyandforwardedtoorigin.html#cfn-cloudfront-cachepolicy-parametersincachekeyandforwardedtoorigin-headersconfig", + "Required": true, + "Type": "HeadersConfig", + "UpdateType": "Mutable" + }, + "QueryStringsConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-cachepolicy-parametersincachekeyandforwardedtoorigin.html#cfn-cloudfront-cachepolicy-parametersincachekeyandforwardedtoorigin-querystringsconfig", + "Required": true, + "Type": "QueryStringsConfig", + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::CachePolicy.QueryStringsConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-cachepolicy-querystringsconfig.html", + "Properties": { + "QueryStringBehavior": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-cachepolicy-querystringsconfig.html#cfn-cloudfront-cachepolicy-querystringsconfig-querystringbehavior", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "QueryStrings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-cachepolicy-querystringsconfig.html#cfn-cloudfront-cachepolicy-querystringsconfig-querystrings", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::CloudFront::CloudFrontOriginAccessIdentity.CloudFrontOriginAccessIdentityConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-cloudfrontoriginaccessidentity-cloudfrontoriginaccessidentityconfig.html", "Properties": { @@ -6200,6 +6614,12 @@ "Required": true, "UpdateType": "Mutable" }, + "RealtimeLogConfigArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-cachebehavior.html#cfn-cloudfront-distribution-cachebehavior-realtimelogconfigarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "SmoothStreaming": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-cachebehavior.html#cfn-cloudfront-distribution-cachebehavior-smoothstreaming", "PrimitiveType": "Boolean", @@ -6388,6 +6808,12 @@ "Required": false, "UpdateType": "Mutable" }, + "RealtimeLogConfigArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-defaultcachebehavior.html#cfn-cloudfront-distribution-defaultcachebehavior-realtimelogconfigarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "SmoothStreaming": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-defaultcachebehavior.html#cfn-cloudfront-distribution-defaultcachebehavior-smoothstreaming", "PrimitiveType": "Boolean", @@ -6842,6 +7268,132 @@ } } }, + "AWS::CloudFront::OriginRequestPolicy.CookiesConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-originrequestpolicy-cookiesconfig.html", + "Properties": { + "CookieBehavior": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-originrequestpolicy-cookiesconfig.html#cfn-cloudfront-originrequestpolicy-cookiesconfig-cookiebehavior", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Cookies": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-originrequestpolicy-cookiesconfig.html#cfn-cloudfront-originrequestpolicy-cookiesconfig-cookies", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::OriginRequestPolicy.HeadersConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-originrequestpolicy-headersconfig.html", + "Properties": { + "HeaderBehavior": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-originrequestpolicy-headersconfig.html#cfn-cloudfront-originrequestpolicy-headersconfig-headerbehavior", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Headers": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-originrequestpolicy-headersconfig.html#cfn-cloudfront-originrequestpolicy-headersconfig-headers", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::OriginRequestPolicy.OriginRequestPolicyConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-originrequestpolicy-originrequestpolicyconfig.html", + "Properties": { + "Comment": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-originrequestpolicy-originrequestpolicyconfig.html#cfn-cloudfront-originrequestpolicy-originrequestpolicyconfig-comment", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "CookiesConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-originrequestpolicy-originrequestpolicyconfig.html#cfn-cloudfront-originrequestpolicy-originrequestpolicyconfig-cookiesconfig", + "Required": true, + "Type": "CookiesConfig", + "UpdateType": "Mutable" + }, + "HeadersConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-originrequestpolicy-originrequestpolicyconfig.html#cfn-cloudfront-originrequestpolicy-originrequestpolicyconfig-headersconfig", + "Required": true, + "Type": "HeadersConfig", + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-originrequestpolicy-originrequestpolicyconfig.html#cfn-cloudfront-originrequestpolicy-originrequestpolicyconfig-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "QueryStringsConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-originrequestpolicy-originrequestpolicyconfig.html#cfn-cloudfront-originrequestpolicy-originrequestpolicyconfig-querystringsconfig", + "Required": true, + "Type": "QueryStringsConfig", + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::OriginRequestPolicy.QueryStringsConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-originrequestpolicy-querystringsconfig.html", + "Properties": { + "QueryStringBehavior": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-originrequestpolicy-querystringsconfig.html#cfn-cloudfront-originrequestpolicy-querystringsconfig-querystringbehavior", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "QueryStrings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-originrequestpolicy-querystringsconfig.html#cfn-cloudfront-originrequestpolicy-querystringsconfig-querystrings", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::RealtimeLogConfig.EndPoint": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-realtimelogconfig-endpoint.html", + "Properties": { + "KinesisStreamConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-realtimelogconfig-endpoint.html#cfn-cloudfront-realtimelogconfig-endpoint-kinesisstreamconfig", + "Required": true, + "Type": "KinesisStreamConfig", + "UpdateType": "Mutable" + }, + "StreamType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-realtimelogconfig-endpoint.html#cfn-cloudfront-realtimelogconfig-endpoint-streamtype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::RealtimeLogConfig.KinesisStreamConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-realtimelogconfig-kinesisstreamconfig.html", + "Properties": { + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-realtimelogconfig-kinesisstreamconfig.html#cfn-cloudfront-realtimelogconfig-kinesisstreamconfig-rolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "StreamArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-realtimelogconfig-kinesisstreamconfig.html#cfn-cloudfront-realtimelogconfig-kinesisstreamconfig-streamarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::CloudFront::StreamingDistribution.Logging": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-streamingdistribution-logging.html", "Properties": { @@ -7740,6 +8292,12 @@ "AWS::CodeCommit::Repository.Code": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codecommit-repository-code.html", "Properties": { + "BranchName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codecommit-repository-code.html#cfn-codecommit-repository-code-branchname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, "S3": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codecommit-repository-code.html#cfn-codecommit-repository-code-s3", "Required": true, @@ -9156,6 +9714,29 @@ } } }, + "AWS::Cognito::UserPoolClient.TokenValidityUnits": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cognito-userpoolclient-tokenvalidityunits.html", + "Properties": { + "AccessToken": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cognito-userpoolclient-tokenvalidityunits.html#cfn-cognito-userpoolclient-tokenvalidityunits-accesstoken", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "IdToken": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cognito-userpoolclient-tokenvalidityunits.html#cfn-cognito-userpoolclient-tokenvalidityunits-idtoken", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "RefreshToken": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cognito-userpoolclient-tokenvalidityunits.html#cfn-cognito-userpoolclient-tokenvalidityunits-refreshtoken", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::Cognito::UserPoolDomain.CustomDomainConfigType": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cognito-userpooldomain-customdomainconfigtype.html", "Properties": { @@ -10609,6 +11190,19 @@ } } }, + "AWS::EC2::CarrierGateway.Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-carriergateway-tags.html", + "Properties": { + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-carriergateway-tags.html#cfn-ec2-carriergateway-tags-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::EC2::ClientVpnEndpoint.CertificateAuthenticationRequest": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-clientvpnendpoint-certificateauthenticationrequest.html", "Properties": { @@ -13096,6 +13690,23 @@ } } }, + "AWS::ECS::TaskDefinition.AuthorizationConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-authorizationconfig.html", + "Properties": { + "AccessPointId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-authorizationconfig.html#cfn-ecs-taskdefinition-authorizationconfig-accesspointid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "IAM": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-authorizationconfig.html#cfn-ecs-taskdefinition-authorizationconfig-iam", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, "AWS::ECS::TaskDefinition.ContainerDefinition": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-containerdefinitions.html", "Properties": { @@ -13168,6 +13779,13 @@ "Type": "List", "UpdateType": "Immutable" }, + "EnvironmentFiles": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-containerdefinitions.html#cfn-ecs-taskdefinition-containerdefinition-environmentfiles", + "ItemType": "EnvironmentFile", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, "Essential": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-containerdefinitions.html#cfn-ecs-taskdefinition-containerdefinition-essential", "PrimitiveType": "Boolean", @@ -13430,52 +14048,53 @@ } } }, - "AWS::ECS::TaskDefinition.EfsVolumeConfiguration": { - "Documentation": "https://docs.aws.amazon.com/AmazonECS/latest/developerguide/efs-volumes.html#specify-efs-config", + "AWS::ECS::TaskDefinition.EFSVolumeConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-efsvolumeconfiguration.html", "Properties": { - "FileSystemId": { - "Documentation": "https://docs.aws.amazon.com/AmazonECS/latest/developerguide/efs-volumes.html#specify-efs-config", + "AuthorizationConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-efsvolumeconfiguration.html#cfn-ecs-taskdefinition-efsvolumeconfiguration-authorizationconfig", + "PrimitiveType": "Json", + "Required": false, + "Type": "AuthorizationConfig", + "UpdateType": "Immutable" + }, + "FilesystemId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-efsvolumeconfiguration.html#cfn-ecs-taskdefinition-efsvolumeconfiguration-filesystemid", "PrimitiveType": "String", "Required": true, "UpdateType": "Immutable" }, "RootDirectory": { - "Documentation": "https://docs.aws.amazon.com/AmazonECS/latest/developerguide/efs-volumes.html#specify-efs-config", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-efsvolumeconfiguration.html#cfn-ecs-taskdefinition-efsvolumeconfiguration-rootdirectory", "PrimitiveType": "String", "Required": false, "UpdateType": "Immutable" }, "TransitEncryption": { - "Documentation": "https://docs.aws.amazon.com/AmazonECS/latest/developerguide/efs-volumes.html#specify-efs-config", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-efsvolumeconfiguration.html#cfn-ecs-taskdefinition-efsvolumeconfiguration-transitencryption", "PrimitiveType": "String", "Required": false, "UpdateType": "Immutable" }, "TransitEncryptionPort": { - "Documentation": "https://docs.aws.amazon.com/AmazonECS/latest/developerguide/efs-volumes.html#specify-efs-config", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-efsvolumeconfiguration.html#cfn-ecs-taskdefinition-efsvolumeconfiguration-transitencryptionport", "PrimitiveType": "Integer", "Required": false, "UpdateType": "Immutable" - }, - "AuthorizationConfig": { - "Documentation": "https://docs.aws.amazon.com/AmazonECS/latest/developerguide/efs-volumes.html#specify-efs-config", - "Type": "AuthorizationConfig", - "Required": false, - "UpdateType": "Immutable" } } }, - "AWS::ECS::TaskDefinition.AuthorizationConfig": { - "Documentation": "https://docs.aws.amazon.com/AmazonECS/latest/developerguide/efs-volumes.html#specify-efs-config", + "AWS::ECS::TaskDefinition.EnvironmentFile": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-environmentfile.html", "Properties": { - "AccessPointId": { - "Documentation": "https://docs.aws.amazon.com/AmazonECS/latest/developerguide/efs-volumes.html#specify-efs-config", + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-environmentfile.html#cfn-ecs-taskdefinition-environmentfile-type", "PrimitiveType": "String", "Required": false, "UpdateType": "Immutable" }, - "Iam": { - "Documentation": "https://docs.aws.amazon.com/AmazonECS/latest/developerguide/efs-volumes.html#specify-efs-config", + "Value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-environmentfile.html#cfn-ecs-taskdefinition-environmentfile-value", "PrimitiveType": "String", "Required": false, "UpdateType": "Immutable" @@ -13487,8 +14106,9 @@ "Properties": { "Options": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-firelensconfiguration.html#cfn-ecs-taskdefinition-firelensconfiguration-options", + "PrimitiveItemType": "String", "Required": false, - "Type": "Options", + "Type": "Map", "UpdateType": "Immutable" }, "Type": { @@ -13676,8 +14296,9 @@ }, "Options": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-containerdefinitions-logconfiguration.html#cfn-ecs-taskdefinition-containerdefinition-logconfiguration-options", + "PrimitiveItemType": "String", "Required": false, - "Type": "Options", + "Type": "Map", "UpdateType": "Immutable" }, "SecretOptions": { @@ -13712,9 +14333,6 @@ } } }, - "AWS::ECS::TaskDefinition.Options": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-options.html" - }, "AWS::ECS::TaskDefinition.PortMapping": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-containerdefinitions-portmappings.html", "Properties": { @@ -13898,6 +14516,12 @@ "Type": "DockerVolumeConfiguration", "UpdateType": "Immutable" }, + "EFSVolumeConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-volumes.html#cfn-ecs-taskdefinition-volume-efsvolumeconfiguration", + "Required": false, + "Type": "EFSVolumeConfiguration", + "UpdateType": "Immutable" + }, "Host": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-volumes.html#cfn-ecs-taskdefinition-volumes-host", "Required": false, @@ -13909,12 +14533,6 @@ "PrimitiveType": "String", "Required": false, "UpdateType": "Immutable" - }, - "EfsVolumeConfiguration": { - "Documentation": "https://docs.aws.amazon.com/AmazonECS/latest/developerguide/efs-volumes.html#specify-efs-config", - "Required": false, - "Type": "EfsVolumeConfiguration", - "UpdateType": "Immutable" } } }, @@ -14214,6 +14832,64 @@ } } }, + "AWS::EKS::FargateProfile.Label": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-fargateprofile-label.html", + "Properties": { + "Key": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-fargateprofile-label.html#cfn-eks-fargateprofile-label-key", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-fargateprofile-label.html#cfn-eks-fargateprofile-label-value", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, + "AWS::EKS::FargateProfile.Selector": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-fargateprofile-selector.html", + "Properties": { + "Labels": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-fargateprofile-selector.html#cfn-eks-fargateprofile-selector-labels", + "ItemType": "Label", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "Namespace": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-fargateprofile-selector.html#cfn-eks-fargateprofile-selector-namespace", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, + "AWS::EKS::Nodegroup.LaunchTemplateSpecification": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-nodegroup-launchtemplatespecification.html", + "Properties": { + "Id": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-nodegroup-launchtemplatespecification.html#cfn-eks-nodegroup-launchtemplatespecification-id", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-nodegroup-launchtemplatespecification.html#cfn-eks-nodegroup-launchtemplatespecification-name", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Version": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-nodegroup-launchtemplatespecification.html#cfn-eks-nodegroup-launchtemplatespecification-version", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::EKS::Nodegroup.RemoteAccess": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-nodegroup-remoteaccess.html", "Properties": { @@ -17524,6 +18200,12 @@ "Required": false, "UpdateType": "Immutable" }, + "DriveCacheType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-filesystem-lustreconfiguration.html#cfn-fsx-filesystem-lustreconfiguration-drivecachetype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, "ExportPath": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-filesystem-lustreconfiguration.html#cfn-fsx-filesystem-lustreconfiguration-exportpath", "PrimitiveType": "String", @@ -17675,7 +18357,7 @@ "Type": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-alias-routingstrategy.html#cfn-gamelift-alias-routingstrategy-type", "PrimitiveType": "String", - "Required": true, + "Required": false, "UpdateType": "Mutable" } } @@ -17814,6 +18496,110 @@ } } }, + "AWS::GameLift::GameServerGroup.AutoScalingPolicy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-gameservergroup-autoscalingpolicy.html", + "Properties": { + "EstimatedInstanceWarmup": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-gameservergroup-autoscalingpolicy.html#cfn-gamelift-gameservergroup-autoscalingpolicy-estimatedinstancewarmup", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + }, + "TargetTrackingConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-gameservergroup-autoscalingpolicy.html#cfn-gamelift-gameservergroup-autoscalingpolicy-targettrackingconfiguration", + "Required": true, + "Type": "TargetTrackingConfiguration", + "UpdateType": "Mutable" + } + } + }, + "AWS::GameLift::GameServerGroup.InstanceDefinition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-gameservergroup-instancedefinition.html", + "Properties": { + "InstanceType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-gameservergroup-instancedefinition.html#cfn-gamelift-gameservergroup-instancedefinition-instancetype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "WeightedCapacity": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-gameservergroup-instancedefinition.html#cfn-gamelift-gameservergroup-instancedefinition-weightedcapacity", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::GameLift::GameServerGroup.InstanceDefinitions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-gameservergroup-instancedefinitions.html", + "Properties": { + "InstanceDefinitions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-gameservergroup-instancedefinitions.html#cfn-gamelift-gameservergroup-instancedefinitions-instancedefinitions", + "ItemType": "InstanceDefinition", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::GameLift::GameServerGroup.LaunchTemplate": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-gameservergroup-launchtemplate.html", + "Properties": { + "LaunchTemplateId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-gameservergroup-launchtemplate.html#cfn-gamelift-gameservergroup-launchtemplate-launchtemplateid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "LaunchTemplateName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-gameservergroup-launchtemplate.html#cfn-gamelift-gameservergroup-launchtemplate-launchtemplatename", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Version": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-gameservergroup-launchtemplate.html#cfn-gamelift-gameservergroup-launchtemplate-version", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::GameLift::GameServerGroup.Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-gameservergroup-tags.html", + "Properties": { + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-gameservergroup-tags.html#cfn-gamelift-gameservergroup-tags-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::GameLift::GameServerGroup.TargetTrackingConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-gameservergroup-targettrackingconfiguration.html", + "Properties": { + "TargetValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-gameservergroup-targettrackingconfiguration.html#cfn-gamelift-gameservergroup-targettrackingconfiguration-targetvalue", + "PrimitiveType": "Double", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::GameLift::GameServerGroup.VpcSubnets": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-gameservergroup-vpcsubnets.html", + "Properties": { + "VpcSubnets": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-gameservergroup-vpcsubnets.html#cfn-gamelift-gameservergroup-vpcsubnets-vpcsubnets", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::GameLift::GameSessionQueue.Destination": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-gamesessionqueue-destination.html", "Properties": { @@ -20222,6 +21008,28 @@ } } }, + "AWS::GuardDuty::Detector.CFNDataSourceConfigurations": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-guardduty-detector-cfndatasourceconfigurations.html", + "Properties": { + "S3Logs": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-guardduty-detector-cfndatasourceconfigurations.html#cfn-guardduty-detector-cfndatasourceconfigurations-s3logs", + "Required": false, + "Type": "CFNS3LogsConfiguration", + "UpdateType": "Mutable" + } + } + }, + "AWS::GuardDuty::Detector.CFNS3LogsConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-guardduty-detector-cfns3logsconfiguration.html", + "Properties": { + "Enable": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-guardduty-detector-cfns3logsconfiguration.html#cfn-guardduty-detector-cfns3logsconfiguration-enable", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::GuardDuty::Filter.Condition": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-guardduty-filter-condition.html", "Properties": { @@ -20568,6 +21376,21 @@ } } }, + "AWS::IoT::Authorizer.Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-authorizer-tags.html", + "Properties": { + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-authorizer-tags.html#cfn-iot-authorizer-tags-tags", + "ItemType": "Json", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::IoT::Authorizer.TokenSigningPublicKeys": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-authorizer-tokensigningpublickeys.html" + }, "AWS::IoT::ProvisioningTemplate.ProvisioningHook": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-provisioningtemplate-provisioninghook.html", "Properties": { @@ -22809,6 +23632,1057 @@ } } }, + "AWS::Kendra::DataSource.AccessControlListConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-accesscontrollistconfiguration.html", + "Properties": { + "KeyPath": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-accesscontrollistconfiguration.html#cfn-kendra-datasource-accesscontrollistconfiguration-keypath", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.AclConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-aclconfiguration.html", + "Properties": { + "AllowedGroupsColumnName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-aclconfiguration.html#cfn-kendra-datasource-aclconfiguration-allowedgroupscolumnname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.ChangeDetectingColumns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-changedetectingcolumns.html", + "Properties": { + "ChangeDetectingColumns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-changedetectingcolumns.html#cfn-kendra-datasource-changedetectingcolumns-changedetectingcolumns", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.ColumnConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-columnconfiguration.html", + "Properties": { + "ChangeDetectingColumns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-columnconfiguration.html#cfn-kendra-datasource-columnconfiguration-changedetectingcolumns", + "Required": true, + "Type": "ChangeDetectingColumns", + "UpdateType": "Mutable" + }, + "DocumentDataColumnName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-columnconfiguration.html#cfn-kendra-datasource-columnconfiguration-documentdatacolumnname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "DocumentIdColumnName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-columnconfiguration.html#cfn-kendra-datasource-columnconfiguration-documentidcolumnname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "DocumentTitleColumnName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-columnconfiguration.html#cfn-kendra-datasource-columnconfiguration-documenttitlecolumnname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "FieldMappings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-columnconfiguration.html#cfn-kendra-datasource-columnconfiguration-fieldmappings", + "Required": false, + "Type": "DataSourceToIndexFieldMappingList", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.ConnectionConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-connectionconfiguration.html", + "Properties": { + "DatabaseHost": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-connectionconfiguration.html#cfn-kendra-datasource-connectionconfiguration-databasehost", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "DatabaseName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-connectionconfiguration.html#cfn-kendra-datasource-connectionconfiguration-databasename", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "DatabasePort": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-connectionconfiguration.html#cfn-kendra-datasource-connectionconfiguration-databaseport", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + }, + "SecretArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-connectionconfiguration.html#cfn-kendra-datasource-connectionconfiguration-secretarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "TableName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-connectionconfiguration.html#cfn-kendra-datasource-connectionconfiguration-tablename", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.DataSourceConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-datasourceconfiguration.html", + "Properties": { + "DatabaseConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-datasourceconfiguration.html#cfn-kendra-datasource-datasourceconfiguration-databaseconfiguration", + "Required": false, + "Type": "DatabaseConfiguration", + "UpdateType": "Mutable" + }, + "OneDriveConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-datasourceconfiguration.html#cfn-kendra-datasource-datasourceconfiguration-onedriveconfiguration", + "Required": false, + "Type": "OneDriveConfiguration", + "UpdateType": "Mutable" + }, + "S3Configuration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-datasourceconfiguration.html#cfn-kendra-datasource-datasourceconfiguration-s3configuration", + "Required": false, + "Type": "S3DataSourceConfiguration", + "UpdateType": "Mutable" + }, + "SalesforceConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-datasourceconfiguration.html#cfn-kendra-datasource-datasourceconfiguration-salesforceconfiguration", + "Required": false, + "Type": "SalesforceConfiguration", + "UpdateType": "Mutable" + }, + "ServiceNowConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-datasourceconfiguration.html#cfn-kendra-datasource-datasourceconfiguration-servicenowconfiguration", + "Required": false, + "Type": "ServiceNowConfiguration", + "UpdateType": "Mutable" + }, + "SharePointConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-datasourceconfiguration.html#cfn-kendra-datasource-datasourceconfiguration-sharepointconfiguration", + "Required": false, + "Type": "SharePointConfiguration", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.DataSourceInclusionsExclusionsStrings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-datasourceinclusionsexclusionsstrings.html", + "Properties": { + "DataSourceInclusionsExclusionsStrings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-datasourceinclusionsexclusionsstrings.html#cfn-kendra-datasource-datasourceinclusionsexclusionsstrings-datasourceinclusionsexclusionsstrings", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.DataSourceToIndexFieldMapping": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-datasourcetoindexfieldmapping.html", + "Properties": { + "DataSourceFieldName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-datasourcetoindexfieldmapping.html#cfn-kendra-datasource-datasourcetoindexfieldmapping-datasourcefieldname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "DateFieldFormat": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-datasourcetoindexfieldmapping.html#cfn-kendra-datasource-datasourcetoindexfieldmapping-datefieldformat", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "IndexFieldName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-datasourcetoindexfieldmapping.html#cfn-kendra-datasource-datasourcetoindexfieldmapping-indexfieldname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.DataSourceToIndexFieldMappingList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-datasourcetoindexfieldmappinglist.html", + "Properties": { + "DataSourceToIndexFieldMappingList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-datasourcetoindexfieldmappinglist.html#cfn-kendra-datasource-datasourcetoindexfieldmappinglist-datasourcetoindexfieldmappinglist", + "ItemType": "DataSourceToIndexFieldMapping", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.DataSourceVpcConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-datasourcevpcconfiguration.html", + "Properties": { + "SecurityGroupIds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-datasourcevpcconfiguration.html#cfn-kendra-datasource-datasourcevpcconfiguration-securitygroupids", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "SubnetIds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-datasourcevpcconfiguration.html#cfn-kendra-datasource-datasourcevpcconfiguration-subnetids", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.DatabaseConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-databaseconfiguration.html", + "Properties": { + "AclConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-databaseconfiguration.html#cfn-kendra-datasource-databaseconfiguration-aclconfiguration", + "Required": false, + "Type": "AclConfiguration", + "UpdateType": "Mutable" + }, + "ColumnConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-databaseconfiguration.html#cfn-kendra-datasource-databaseconfiguration-columnconfiguration", + "Required": true, + "Type": "ColumnConfiguration", + "UpdateType": "Mutable" + }, + "ConnectionConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-databaseconfiguration.html#cfn-kendra-datasource-databaseconfiguration-connectionconfiguration", + "Required": true, + "Type": "ConnectionConfiguration", + "UpdateType": "Mutable" + }, + "DatabaseEngineType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-databaseconfiguration.html#cfn-kendra-datasource-databaseconfiguration-databaseenginetype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "SqlConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-databaseconfiguration.html#cfn-kendra-datasource-databaseconfiguration-sqlconfiguration", + "Required": false, + "Type": "SqlConfiguration", + "UpdateType": "Mutable" + }, + "VpcConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-databaseconfiguration.html#cfn-kendra-datasource-databaseconfiguration-vpcconfiguration", + "Required": false, + "Type": "DataSourceVpcConfiguration", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.DocumentsMetadataConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-documentsmetadataconfiguration.html", + "Properties": { + "S3Prefix": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-documentsmetadataconfiguration.html#cfn-kendra-datasource-documentsmetadataconfiguration-s3prefix", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.OneDriveConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-onedriveconfiguration.html", + "Properties": { + "ExclusionPatterns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-onedriveconfiguration.html#cfn-kendra-datasource-onedriveconfiguration-exclusionpatterns", + "Required": false, + "Type": "DataSourceInclusionsExclusionsStrings", + "UpdateType": "Mutable" + }, + "FieldMappings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-onedriveconfiguration.html#cfn-kendra-datasource-onedriveconfiguration-fieldmappings", + "Required": false, + "Type": "DataSourceToIndexFieldMappingList", + "UpdateType": "Mutable" + }, + "InclusionPatterns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-onedriveconfiguration.html#cfn-kendra-datasource-onedriveconfiguration-inclusionpatterns", + "Required": false, + "Type": "DataSourceInclusionsExclusionsStrings", + "UpdateType": "Mutable" + }, + "OneDriveUsers": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-onedriveconfiguration.html#cfn-kendra-datasource-onedriveconfiguration-onedriveusers", + "Required": true, + "Type": "OneDriveUsers", + "UpdateType": "Mutable" + }, + "SecretArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-onedriveconfiguration.html#cfn-kendra-datasource-onedriveconfiguration-secretarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "TenantDomain": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-onedriveconfiguration.html#cfn-kendra-datasource-onedriveconfiguration-tenantdomain", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.OneDriveUserList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-onedriveuserlist.html", + "Properties": { + "OneDriveUserList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-onedriveuserlist.html#cfn-kendra-datasource-onedriveuserlist-onedriveuserlist", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.OneDriveUsers": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-onedriveusers.html", + "Properties": { + "OneDriveUserList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-onedriveusers.html#cfn-kendra-datasource-onedriveusers-onedriveuserlist", + "Required": false, + "Type": "OneDriveUserList", + "UpdateType": "Mutable" + }, + "OneDriveUserS3Path": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-onedriveusers.html#cfn-kendra-datasource-onedriveusers-onedriveusers3path", + "Required": false, + "Type": "S3Path", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.S3DataSourceConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-s3datasourceconfiguration.html", + "Properties": { + "AccessControlListConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-s3datasourceconfiguration.html#cfn-kendra-datasource-s3datasourceconfiguration-accesscontrollistconfiguration", + "Required": false, + "Type": "AccessControlListConfiguration", + "UpdateType": "Mutable" + }, + "BucketName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-s3datasourceconfiguration.html#cfn-kendra-datasource-s3datasourceconfiguration-bucketname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "DocumentsMetadataConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-s3datasourceconfiguration.html#cfn-kendra-datasource-s3datasourceconfiguration-documentsmetadataconfiguration", + "Required": false, + "Type": "DocumentsMetadataConfiguration", + "UpdateType": "Mutable" + }, + "ExclusionPatterns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-s3datasourceconfiguration.html#cfn-kendra-datasource-s3datasourceconfiguration-exclusionpatterns", + "Required": false, + "Type": "DataSourceInclusionsExclusionsStrings", + "UpdateType": "Mutable" + }, + "InclusionPrefixes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-s3datasourceconfiguration.html#cfn-kendra-datasource-s3datasourceconfiguration-inclusionprefixes", + "Required": false, + "Type": "DataSourceInclusionsExclusionsStrings", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.S3Path": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-s3path.html", + "Properties": { + "Bucket": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-s3path.html#cfn-kendra-datasource-s3path-bucket", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Key": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-s3path.html#cfn-kendra-datasource-s3path-key", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.SalesforceChatterFeedConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcechatterfeedconfiguration.html", + "Properties": { + "DocumentDataFieldName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcechatterfeedconfiguration.html#cfn-kendra-datasource-salesforcechatterfeedconfiguration-documentdatafieldname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "DocumentTitleFieldName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcechatterfeedconfiguration.html#cfn-kendra-datasource-salesforcechatterfeedconfiguration-documenttitlefieldname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "FieldMappings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcechatterfeedconfiguration.html#cfn-kendra-datasource-salesforcechatterfeedconfiguration-fieldmappings", + "Required": false, + "Type": "DataSourceToIndexFieldMappingList", + "UpdateType": "Mutable" + }, + "IncludeFilterTypes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcechatterfeedconfiguration.html#cfn-kendra-datasource-salesforcechatterfeedconfiguration-includefiltertypes", + "Required": false, + "Type": "SalesforceChatterFeedIncludeFilterTypes", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.SalesforceChatterFeedIncludeFilterTypes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcechatterfeedincludefiltertypes.html", + "Properties": { + "SalesforceChatterFeedIncludeFilterTypes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcechatterfeedincludefiltertypes.html#cfn-kendra-datasource-salesforcechatterfeedincludefiltertypes-salesforcechatterfeedincludefiltertypes", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.SalesforceConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforceconfiguration.html", + "Properties": { + "ChatterFeedConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforceconfiguration.html#cfn-kendra-datasource-salesforceconfiguration-chatterfeedconfiguration", + "Required": false, + "Type": "SalesforceChatterFeedConfiguration", + "UpdateType": "Mutable" + }, + "CrawlAttachments": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforceconfiguration.html#cfn-kendra-datasource-salesforceconfiguration-crawlattachments", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "ExcludeAttachmentFilePatterns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforceconfiguration.html#cfn-kendra-datasource-salesforceconfiguration-excludeattachmentfilepatterns", + "Required": false, + "Type": "DataSourceInclusionsExclusionsStrings", + "UpdateType": "Mutable" + }, + "IncludeAttachmentFilePatterns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforceconfiguration.html#cfn-kendra-datasource-salesforceconfiguration-includeattachmentfilepatterns", + "Required": false, + "Type": "DataSourceInclusionsExclusionsStrings", + "UpdateType": "Mutable" + }, + "KnowledgeArticleConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforceconfiguration.html#cfn-kendra-datasource-salesforceconfiguration-knowledgearticleconfiguration", + "Required": false, + "Type": "SalesforceKnowledgeArticleConfiguration", + "UpdateType": "Mutable" + }, + "SecretArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforceconfiguration.html#cfn-kendra-datasource-salesforceconfiguration-secretarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ServerUrl": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforceconfiguration.html#cfn-kendra-datasource-salesforceconfiguration-serverurl", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "StandardObjectAttachmentConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforceconfiguration.html#cfn-kendra-datasource-salesforceconfiguration-standardobjectattachmentconfiguration", + "Required": false, + "Type": "SalesforceStandardObjectAttachmentConfiguration", + "UpdateType": "Mutable" + }, + "StandardObjectConfigurations": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforceconfiguration.html#cfn-kendra-datasource-salesforceconfiguration-standardobjectconfigurations", + "Required": false, + "Type": "SalesforceStandardObjectConfigurationList", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.SalesforceCustomKnowledgeArticleTypeConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcecustomknowledgearticletypeconfiguration.html", + "Properties": { + "DocumentDataFieldName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcecustomknowledgearticletypeconfiguration.html#cfn-kendra-datasource-salesforcecustomknowledgearticletypeconfiguration-documentdatafieldname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "DocumentTitleFieldName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcecustomknowledgearticletypeconfiguration.html#cfn-kendra-datasource-salesforcecustomknowledgearticletypeconfiguration-documenttitlefieldname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "FieldMappings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcecustomknowledgearticletypeconfiguration.html#cfn-kendra-datasource-salesforcecustomknowledgearticletypeconfiguration-fieldmappings", + "Required": false, + "Type": "DataSourceToIndexFieldMappingList", + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcecustomknowledgearticletypeconfiguration.html#cfn-kendra-datasource-salesforcecustomknowledgearticletypeconfiguration-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.SalesforceCustomKnowledgeArticleTypeConfigurationList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcecustomknowledgearticletypeconfigurationlist.html", + "Properties": { + "SalesforceCustomKnowledgeArticleTypeConfigurationList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcecustomknowledgearticletypeconfigurationlist.html#cfn-kendra-datasource-salesforcecustomknowledgearticletypeconfigurationlist-salesforcecustomknowledgearticletypeconfigurationlist", + "ItemType": "SalesforceCustomKnowledgeArticleTypeConfiguration", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.SalesforceKnowledgeArticleConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforceknowledgearticleconfiguration.html", + "Properties": { + "CustomKnowledgeArticleTypeConfigurations": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforceknowledgearticleconfiguration.html#cfn-kendra-datasource-salesforceknowledgearticleconfiguration-customknowledgearticletypeconfigurations", + "Required": false, + "Type": "SalesforceCustomKnowledgeArticleTypeConfigurationList", + "UpdateType": "Mutable" + }, + "IncludedStates": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforceknowledgearticleconfiguration.html#cfn-kendra-datasource-salesforceknowledgearticleconfiguration-includedstates", + "Required": true, + "Type": "SalesforceKnowledgeArticleStateList", + "UpdateType": "Mutable" + }, + "StandardKnowledgeArticleTypeConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforceknowledgearticleconfiguration.html#cfn-kendra-datasource-salesforceknowledgearticleconfiguration-standardknowledgearticletypeconfiguration", + "Required": false, + "Type": "SalesforceStandardKnowledgeArticleTypeConfiguration", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.SalesforceKnowledgeArticleStateList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforceknowledgearticlestatelist.html", + "Properties": { + "SalesforceKnowledgeArticleStateList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforceknowledgearticlestatelist.html#cfn-kendra-datasource-salesforceknowledgearticlestatelist-salesforceknowledgearticlestatelist", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.SalesforceStandardKnowledgeArticleTypeConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcestandardknowledgearticletypeconfiguration.html", + "Properties": { + "DocumentDataFieldName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcestandardknowledgearticletypeconfiguration.html#cfn-kendra-datasource-salesforcestandardknowledgearticletypeconfiguration-documentdatafieldname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "DocumentTitleFieldName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcestandardknowledgearticletypeconfiguration.html#cfn-kendra-datasource-salesforcestandardknowledgearticletypeconfiguration-documenttitlefieldname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "FieldMappings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcestandardknowledgearticletypeconfiguration.html#cfn-kendra-datasource-salesforcestandardknowledgearticletypeconfiguration-fieldmappings", + "Required": false, + "Type": "DataSourceToIndexFieldMappingList", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.SalesforceStandardObjectAttachmentConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcestandardobjectattachmentconfiguration.html", + "Properties": { + "DocumentTitleFieldName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcestandardobjectattachmentconfiguration.html#cfn-kendra-datasource-salesforcestandardobjectattachmentconfiguration-documenttitlefieldname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "FieldMappings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcestandardobjectattachmentconfiguration.html#cfn-kendra-datasource-salesforcestandardobjectattachmentconfiguration-fieldmappings", + "Required": false, + "Type": "DataSourceToIndexFieldMappingList", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.SalesforceStandardObjectConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcestandardobjectconfiguration.html", + "Properties": { + "DocumentDataFieldName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcestandardobjectconfiguration.html#cfn-kendra-datasource-salesforcestandardobjectconfiguration-documentdatafieldname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "DocumentTitleFieldName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcestandardobjectconfiguration.html#cfn-kendra-datasource-salesforcestandardobjectconfiguration-documenttitlefieldname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "FieldMappings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcestandardobjectconfiguration.html#cfn-kendra-datasource-salesforcestandardobjectconfiguration-fieldmappings", + "Required": false, + "Type": "DataSourceToIndexFieldMappingList", + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcestandardobjectconfiguration.html#cfn-kendra-datasource-salesforcestandardobjectconfiguration-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.SalesforceStandardObjectConfigurationList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcestandardobjectconfigurationlist.html", + "Properties": { + "SalesforceStandardObjectConfigurationList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcestandardobjectconfigurationlist.html#cfn-kendra-datasource-salesforcestandardobjectconfigurationlist-salesforcestandardobjectconfigurationlist", + "ItemType": "SalesforceStandardObjectConfiguration", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.ServiceNowConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowconfiguration.html", + "Properties": { + "HostUrl": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowconfiguration.html#cfn-kendra-datasource-servicenowconfiguration-hosturl", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "KnowledgeArticleConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowconfiguration.html#cfn-kendra-datasource-servicenowconfiguration-knowledgearticleconfiguration", + "Required": false, + "Type": "ServiceNowKnowledgeArticleConfiguration", + "UpdateType": "Mutable" + }, + "SecretArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowconfiguration.html#cfn-kendra-datasource-servicenowconfiguration-secretarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ServiceCatalogConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowconfiguration.html#cfn-kendra-datasource-servicenowconfiguration-servicecatalogconfiguration", + "Required": false, + "Type": "ServiceNowServiceCatalogConfiguration", + "UpdateType": "Mutable" + }, + "ServiceNowBuildVersion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowconfiguration.html#cfn-kendra-datasource-servicenowconfiguration-servicenowbuildversion", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.ServiceNowKnowledgeArticleConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowknowledgearticleconfiguration.html", + "Properties": { + "CrawlAttachments": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowknowledgearticleconfiguration.html#cfn-kendra-datasource-servicenowknowledgearticleconfiguration-crawlattachments", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "DocumentDataFieldName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowknowledgearticleconfiguration.html#cfn-kendra-datasource-servicenowknowledgearticleconfiguration-documentdatafieldname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "DocumentTitleFieldName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowknowledgearticleconfiguration.html#cfn-kendra-datasource-servicenowknowledgearticleconfiguration-documenttitlefieldname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ExcludeAttachmentFilePatterns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowknowledgearticleconfiguration.html#cfn-kendra-datasource-servicenowknowledgearticleconfiguration-excludeattachmentfilepatterns", + "Required": false, + "Type": "DataSourceInclusionsExclusionsStrings", + "UpdateType": "Mutable" + }, + "FieldMappings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowknowledgearticleconfiguration.html#cfn-kendra-datasource-servicenowknowledgearticleconfiguration-fieldmappings", + "Required": false, + "Type": "DataSourceToIndexFieldMappingList", + "UpdateType": "Mutable" + }, + "IncludeAttachmentFilePatterns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowknowledgearticleconfiguration.html#cfn-kendra-datasource-servicenowknowledgearticleconfiguration-includeattachmentfilepatterns", + "Required": false, + "Type": "DataSourceInclusionsExclusionsStrings", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.ServiceNowServiceCatalogConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowservicecatalogconfiguration.html", + "Properties": { + "CrawlAttachments": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowservicecatalogconfiguration.html#cfn-kendra-datasource-servicenowservicecatalogconfiguration-crawlattachments", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "DocumentDataFieldName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowservicecatalogconfiguration.html#cfn-kendra-datasource-servicenowservicecatalogconfiguration-documentdatafieldname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "DocumentTitleFieldName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowservicecatalogconfiguration.html#cfn-kendra-datasource-servicenowservicecatalogconfiguration-documenttitlefieldname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ExcludeAttachmentFilePatterns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowservicecatalogconfiguration.html#cfn-kendra-datasource-servicenowservicecatalogconfiguration-excludeattachmentfilepatterns", + "Required": false, + "Type": "DataSourceInclusionsExclusionsStrings", + "UpdateType": "Mutable" + }, + "FieldMappings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowservicecatalogconfiguration.html#cfn-kendra-datasource-servicenowservicecatalogconfiguration-fieldmappings", + "Required": false, + "Type": "DataSourceToIndexFieldMappingList", + "UpdateType": "Mutable" + }, + "IncludeAttachmentFilePatterns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowservicecatalogconfiguration.html#cfn-kendra-datasource-servicenowservicecatalogconfiguration-includeattachmentfilepatterns", + "Required": false, + "Type": "DataSourceInclusionsExclusionsStrings", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.SharePointConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-sharepointconfiguration.html", + "Properties": { + "CrawlAttachments": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-sharepointconfiguration.html#cfn-kendra-datasource-sharepointconfiguration-crawlattachments", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "DocumentTitleFieldName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-sharepointconfiguration.html#cfn-kendra-datasource-sharepointconfiguration-documenttitlefieldname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ExclusionPatterns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-sharepointconfiguration.html#cfn-kendra-datasource-sharepointconfiguration-exclusionpatterns", + "Required": false, + "Type": "DataSourceInclusionsExclusionsStrings", + "UpdateType": "Mutable" + }, + "FieldMappings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-sharepointconfiguration.html#cfn-kendra-datasource-sharepointconfiguration-fieldmappings", + "Required": false, + "Type": "DataSourceToIndexFieldMappingList", + "UpdateType": "Mutable" + }, + "InclusionPatterns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-sharepointconfiguration.html#cfn-kendra-datasource-sharepointconfiguration-inclusionpatterns", + "Required": false, + "Type": "DataSourceInclusionsExclusionsStrings", + "UpdateType": "Mutable" + }, + "SecretArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-sharepointconfiguration.html#cfn-kendra-datasource-sharepointconfiguration-secretarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "SharePointVersion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-sharepointconfiguration.html#cfn-kendra-datasource-sharepointconfiguration-sharepointversion", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Urls": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-sharepointconfiguration.html#cfn-kendra-datasource-sharepointconfiguration-urls", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "UseChangeLog": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-sharepointconfiguration.html#cfn-kendra-datasource-sharepointconfiguration-usechangelog", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "VpcConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-sharepointconfiguration.html#cfn-kendra-datasource-sharepointconfiguration-vpcconfiguration", + "Required": false, + "Type": "DataSourceVpcConfiguration", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.SqlConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-sqlconfiguration.html", + "Properties": { + "QueryIdentifiersEnclosingOption": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-sqlconfiguration.html#cfn-kendra-datasource-sqlconfiguration-queryidentifiersenclosingoption", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.TagList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-taglist.html", + "Properties": { + "TagList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-taglist.html#cfn-kendra-datasource-taglist-taglist", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::Faq.S3Path": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-faq-s3path.html", + "Properties": { + "Bucket": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-faq-s3path.html#cfn-kendra-faq-s3path-bucket", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Key": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-faq-s3path.html#cfn-kendra-faq-s3path-key", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, + "AWS::Kendra::Faq.TagList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-faq-taglist.html", + "Properties": { + "TagList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-faq-taglist.html#cfn-kendra-faq-taglist-taglist", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::Index.CapacityUnitsConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-capacityunitsconfiguration.html", + "Properties": { + "QueryCapacityUnits": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-capacityunitsconfiguration.html#cfn-kendra-index-capacityunitsconfiguration-querycapacityunits", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + }, + "StorageCapacityUnits": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-capacityunitsconfiguration.html#cfn-kendra-index-capacityunitsconfiguration-storagecapacityunits", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::Index.DocumentMetadataConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-documentmetadataconfiguration.html", + "Properties": { + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-documentmetadataconfiguration.html#cfn-kendra-index-documentmetadataconfiguration-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Relevance": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-documentmetadataconfiguration.html#cfn-kendra-index-documentmetadataconfiguration-relevance", + "Required": false, + "Type": "Relevance", + "UpdateType": "Mutable" + }, + "Search": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-documentmetadataconfiguration.html#cfn-kendra-index-documentmetadataconfiguration-search", + "Required": false, + "Type": "Search", + "UpdateType": "Mutable" + }, + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-documentmetadataconfiguration.html#cfn-kendra-index-documentmetadataconfiguration-type", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::Index.DocumentMetadataConfigurationList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-documentmetadataconfigurationlist.html", + "Properties": { + "DocumentMetadataConfigurationList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-documentmetadataconfigurationlist.html#cfn-kendra-index-documentmetadataconfigurationlist-documentmetadataconfigurationlist", + "ItemType": "DocumentMetadataConfiguration", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::Index.Relevance": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-relevance.html", + "Properties": { + "Duration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-relevance.html#cfn-kendra-index-relevance-duration", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Freshness": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-relevance.html#cfn-kendra-index-relevance-freshness", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "Importance": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-relevance.html#cfn-kendra-index-relevance-importance", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "RankOrder": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-relevance.html#cfn-kendra-index-relevance-rankorder", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ValueImportanceItems": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-relevance.html#cfn-kendra-index-relevance-valueimportanceitems", + "Required": false, + "Type": "ValueImportanceItems", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::Index.Search": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-search.html", + "Properties": { + "Displayable": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-search.html#cfn-kendra-index-search-displayable", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "Facetable": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-search.html#cfn-kendra-index-search-facetable", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "Searchable": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-search.html#cfn-kendra-index-search-searchable", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "Sortable": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-search.html#cfn-kendra-index-search-sortable", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::Index.ServerSideEncryptionConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-serversideencryptionconfiguration.html", + "Properties": { + "KmsKeyId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-serversideencryptionconfiguration.html#cfn-kendra-index-serversideencryptionconfiguration-kmskeyid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::Kendra::Index.TagList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-taglist.html", + "Properties": { + "TagList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-taglist.html#cfn-kendra-index-taglist-taglist", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::Index.ValueImportanceItem": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-valueimportanceitem.html", + "Properties": { + "Key": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-valueimportanceitem.html#cfn-kendra-index-valueimportanceitem-key", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-valueimportanceitem.html#cfn-kendra-index-valueimportanceitem-value", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::Index.ValueImportanceItems": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-valueimportanceitems.html", + "Properties": { + "ValueImportanceItems": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-valueimportanceitems.html#cfn-kendra-index-valueimportanceitems-valueimportanceitems", + "ItemType": "ValueImportanceItem", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::Kinesis::Stream.StreamEncryption": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesis-stream-streamencryption.html", "Properties": { @@ -25206,7 +27080,7 @@ "Properties": { "OnFailure": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-eventsourcemapping-destinationconfig.html#cfn-lambda-eventsourcemapping-destinationconfig-onfailure", - "Required": true, + "Required": false, "Type": "OnFailure", "UpdateType": "Mutable" } @@ -25218,7 +27092,7 @@ "Destination": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-eventsourcemapping-onfailure.html#cfn-lambda-eventsourcemapping-onfailure-destination", "PrimitiveType": "String", - "Required": true, + "Required": false, "UpdateType": "Mutable" } } @@ -25451,6 +27325,12 @@ "AWS::MSK::Cluster.ClientAuthentication": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-clientauthentication.html", "Properties": { + "Sasl": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-clientauthentication.html#cfn-msk-cluster-clientauthentication-sasl", + "Required": false, + "Type": "Sasl", + "UpdateType": "Immutable" + }, "Tls": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-clientauthentication.html#cfn-msk-cluster-clientauthentication-tls", "Required": false, @@ -25650,6 +27530,28 @@ } } }, + "AWS::MSK::Cluster.Sasl": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-sasl.html", + "Properties": { + "Scram": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-sasl.html#cfn-msk-cluster-sasl-scram", + "Required": true, + "Type": "Scram", + "UpdateType": "Immutable" + } + } + }, + "AWS::MSK::Cluster.Scram": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-scram.html", + "Properties": { + "Enabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-scram.html#cfn-msk-cluster-scram-enabled", + "PrimitiveType": "Boolean", + "Required": true, + "UpdateType": "Immutable" + } + } + }, "AWS::MSK::Cluster.StorageInfo": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-storageinfo.html", "Properties": { @@ -25687,6 +27589,23 @@ } } }, + "AWS::Macie::FindingsFilter.FindingsFilterListItem": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-macie-findingsfilter-findingsfilterlistitem.html", + "Properties": { + "Id": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-macie-findingsfilter-findingsfilterlistitem.html#cfn-macie-findingsfilter-findingsfilterlistitem-id", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-macie-findingsfilter-findingsfilterlistitem.html#cfn-macie-findingsfilter-findingsfilterlistitem-name", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::ManagedBlockchain::Member.ApprovalThresholdPolicy": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-managedblockchain-member-approvalthresholdpolicy.html", "Properties": { @@ -26547,6 +28466,23 @@ } } }, + "AWS::Neptune::DBCluster.DBClusterRole": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-neptune-dbcluster-dbclusterrole.html", + "Properties": { + "FeatureName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-neptune-dbcluster-dbclusterrole.html#cfn-neptune-dbcluster-dbclusterrole-featurename", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-neptune-dbcluster-dbclusterrole.html#cfn-neptune-dbcluster-dbclusterrole-rolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::NetworkManager::Device.Location": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkmanager-device-location.html", "Properties": { @@ -28756,139 +30692,17 @@ } } }, - "AWS::Route53::HealthCheck.AlarmIdentifier": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-alarmidentifier.html", - "Properties": { - "Name": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-alarmidentifier.html#cfn-route53-healthcheck-alarmidentifier-name", - "PrimitiveType": "String", - "Required": true, - "UpdateType": "Mutable" - }, - "Region": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-alarmidentifier.html#cfn-route53-healthcheck-alarmidentifier-region", - "PrimitiveType": "String", - "Required": true, - "UpdateType": "Mutable" - } - } - }, - "AWS::Route53::HealthCheck.HealthCheckConfig": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthcheckconfig.html", - "Properties": { - "AlarmIdentifier": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthcheckconfig.html#cfn-route53-healthcheck-healthcheckconfig-alarmidentifier", - "Required": false, - "Type": "AlarmIdentifier", - "UpdateType": "Mutable" - }, - "ChildHealthChecks": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthcheckconfig.html#cfn-route53-healthcheck-healthcheckconfig-childhealthchecks", - "DuplicatesAllowed": false, - "PrimitiveItemType": "String", - "Required": false, - "Type": "List", - "UpdateType": "Mutable" - }, - "EnableSNI": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthcheckconfig.html#cfn-route53-healthcheck-healthcheckconfig-enablesni", - "PrimitiveType": "Boolean", - "Required": false, - "UpdateType": "Mutable" - }, - "FailureThreshold": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthcheckconfig.html#cfn-route53-healthcheck-healthcheckconfig-failurethreshold", - "PrimitiveType": "Integer", - "Required": false, - "UpdateType": "Mutable" - }, - "FullyQualifiedDomainName": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthcheckconfig.html#cfn-route53-healthcheck-healthcheckconfig-fullyqualifieddomainname", - "PrimitiveType": "String", - "Required": false, - "UpdateType": "Mutable" - }, - "HealthThreshold": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthcheckconfig.html#cfn-route53-healthcheck-healthcheckconfig-healththreshold", - "PrimitiveType": "Integer", - "Required": false, - "UpdateType": "Mutable" - }, - "IPAddress": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthcheckconfig.html#cfn-route53-healthcheck-healthcheckconfig-ipaddress", - "PrimitiveType": "String", - "Required": false, - "UpdateType": "Mutable" - }, - "InsufficientDataHealthStatus": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthcheckconfig.html#cfn-route53-healthcheck-healthcheckconfig-insufficientdatahealthstatus", - "PrimitiveType": "String", - "Required": false, - "UpdateType": "Mutable" - }, - "Inverted": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthcheckconfig.html#cfn-route53-healthcheck-healthcheckconfig-inverted", - "PrimitiveType": "Boolean", - "Required": false, - "UpdateType": "Mutable" - }, - "MeasureLatency": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthcheckconfig.html#cfn-route53-healthcheck-healthcheckconfig-measurelatency", - "PrimitiveType": "Boolean", - "Required": false, - "UpdateType": "Immutable" - }, - "Port": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthcheckconfig.html#cfn-route53-healthcheck-healthcheckconfig-port", - "PrimitiveType": "Integer", - "Required": false, - "UpdateType": "Mutable" - }, - "Regions": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthcheckconfig.html#cfn-route53-healthcheck-healthcheckconfig-regions", - "DuplicatesAllowed": false, - "PrimitiveItemType": "String", - "Required": false, - "Type": "List", - "UpdateType": "Mutable" - }, - "RequestInterval": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthcheckconfig.html#cfn-route53-healthcheck-healthcheckconfig-requestinterval", - "PrimitiveType": "Integer", - "Required": false, - "UpdateType": "Immutable" - }, - "ResourcePath": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthcheckconfig.html#cfn-route53-healthcheck-healthcheckconfig-resourcepath", - "PrimitiveType": "String", - "Required": false, - "UpdateType": "Mutable" - }, - "SearchString": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthcheckconfig.html#cfn-route53-healthcheck-healthcheckconfig-searchstring", - "PrimitiveType": "String", - "Required": false, - "UpdateType": "Mutable" - }, - "Type": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthcheckconfig.html#cfn-route53-healthcheck-healthcheckconfig-type", - "PrimitiveType": "String", - "Required": true, - "UpdateType": "Immutable" - } - } - }, "AWS::Route53::HealthCheck.HealthCheckTag": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthchecktag.html", "Properties": { "Key": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthchecktag.html#cfn-route53-healthchecktags-key", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthchecktag.html#cfn-route53-healthcheck-healthchecktag-key", "PrimitiveType": "String", "Required": true, "UpdateType": "Mutable" }, "Value": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthchecktag.html#cfn-route53-healthchecktags-value", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-healthcheck-healthchecktag.html#cfn-route53-healthcheck-healthchecktag-value", "PrimitiveType": "String", "Required": true, "UpdateType": "Mutable" @@ -30703,6 +32517,18 @@ } } }, + "AWS::SSM::Association.ParameterValues": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ssm-association-parametervalues.html", + "Properties": { + "ParameterValues": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ssm-association-parametervalues.html#cfn-ssm-association-parametervalues-parametervalues", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::SSM::Association.S3OutputLocation": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ssm-association-s3outputlocation.html", "Properties": { @@ -31366,6 +33192,422 @@ } } }, + "AWS::SageMaker::MonitoringSchedule.BaselineConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-baselineconfig.html", + "Properties": { + "ConstraintsResource": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-baselineconfig.html#cfn-sagemaker-monitoringschedule-baselineconfig-constraintsresource", + "Required": false, + "Type": "ConstraintsResource", + "UpdateType": "Mutable" + }, + "StatisticsResource": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-baselineconfig.html#cfn-sagemaker-monitoringschedule-baselineconfig-statisticsresource", + "Required": false, + "Type": "StatisticsResource", + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::MonitoringSchedule.ClusterConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-clusterconfig.html", + "Properties": { + "InstanceCount": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-clusterconfig.html#cfn-sagemaker-monitoringschedule-clusterconfig-instancecount", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + }, + "InstanceType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-clusterconfig.html#cfn-sagemaker-monitoringschedule-clusterconfig-instancetype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "VolumeKmsKeyId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-clusterconfig.html#cfn-sagemaker-monitoringschedule-clusterconfig-volumekmskeyid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "VolumeSizeInGB": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-clusterconfig.html#cfn-sagemaker-monitoringschedule-clusterconfig-volumesizeingb", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::MonitoringSchedule.ConstraintsResource": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-constraintsresource.html", + "Properties": { + "S3Uri": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-constraintsresource.html#cfn-sagemaker-monitoringschedule-constraintsresource-s3uri", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::MonitoringSchedule.EndpointInput": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-endpointinput.html", + "Properties": { + "EndpointName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-endpointinput.html#cfn-sagemaker-monitoringschedule-endpointinput-endpointname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "LocalPath": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-endpointinput.html#cfn-sagemaker-monitoringschedule-endpointinput-localpath", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "S3DataDistributionType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-endpointinput.html#cfn-sagemaker-monitoringschedule-endpointinput-s3datadistributiontype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "S3InputMode": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-endpointinput.html#cfn-sagemaker-monitoringschedule-endpointinput-s3inputmode", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::MonitoringSchedule.Environment": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-environment.html" + }, + "AWS::SageMaker::MonitoringSchedule.MonitoringAppSpecification": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringappspecification.html", + "Properties": { + "ContainerArguments": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringappspecification.html#cfn-sagemaker-monitoringschedule-monitoringappspecification-containerarguments", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "ContainerEntrypoint": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringappspecification.html#cfn-sagemaker-monitoringschedule-monitoringappspecification-containerentrypoint", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "ImageUri": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringappspecification.html#cfn-sagemaker-monitoringschedule-monitoringappspecification-imageuri", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "PostAnalyticsProcessorSourceUri": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringappspecification.html#cfn-sagemaker-monitoringschedule-monitoringappspecification-postanalyticsprocessorsourceuri", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "RecordPreprocessorSourceUri": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringappspecification.html#cfn-sagemaker-monitoringschedule-monitoringappspecification-recordpreprocessorsourceuri", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::MonitoringSchedule.MonitoringExecutionSummary": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringexecutionsummary.html", + "Properties": { + "CreationTime": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringexecutionsummary.html#cfn-sagemaker-monitoringschedule-monitoringexecutionsummary-creationtime", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "EndpointName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringexecutionsummary.html#cfn-sagemaker-monitoringschedule-monitoringexecutionsummary-endpointname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "FailureReason": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringexecutionsummary.html#cfn-sagemaker-monitoringschedule-monitoringexecutionsummary-failurereason", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "LastModifiedTime": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringexecutionsummary.html#cfn-sagemaker-monitoringschedule-monitoringexecutionsummary-lastmodifiedtime", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "MonitoringExecutionStatus": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringexecutionsummary.html#cfn-sagemaker-monitoringschedule-monitoringexecutionsummary-monitoringexecutionstatus", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "MonitoringScheduleName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringexecutionsummary.html#cfn-sagemaker-monitoringschedule-monitoringexecutionsummary-monitoringschedulename", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ProcessingJobArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringexecutionsummary.html#cfn-sagemaker-monitoringschedule-monitoringexecutionsummary-processingjobarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ScheduledTime": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringexecutionsummary.html#cfn-sagemaker-monitoringschedule-monitoringexecutionsummary-scheduledtime", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::MonitoringSchedule.MonitoringInput": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringinput.html", + "Properties": { + "EndpointInput": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringinput.html#cfn-sagemaker-monitoringschedule-monitoringinput-endpointinput", + "Required": true, + "Type": "EndpointInput", + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::MonitoringSchedule.MonitoringInputs": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringinputs.html", + "Properties": { + "MonitoringInputs": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringinputs.html#cfn-sagemaker-monitoringschedule-monitoringinputs-monitoringinputs", + "ItemType": "MonitoringInput", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::MonitoringSchedule.MonitoringJobDefinition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringjobdefinition.html", + "Properties": { + "BaselineConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringjobdefinition.html#cfn-sagemaker-monitoringschedule-monitoringjobdefinition-baselineconfig", + "Required": false, + "Type": "BaselineConfig", + "UpdateType": "Mutable" + }, + "Environment": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringjobdefinition.html#cfn-sagemaker-monitoringschedule-monitoringjobdefinition-environment", + "Required": false, + "Type": "Environment", + "UpdateType": "Mutable" + }, + "MonitoringAppSpecification": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringjobdefinition.html#cfn-sagemaker-monitoringschedule-monitoringjobdefinition-monitoringappspecification", + "Required": true, + "Type": "MonitoringAppSpecification", + "UpdateType": "Mutable" + }, + "MonitoringInputs": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringjobdefinition.html#cfn-sagemaker-monitoringschedule-monitoringjobdefinition-monitoringinputs", + "Required": true, + "Type": "MonitoringInputs", + "UpdateType": "Mutable" + }, + "MonitoringOutputConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringjobdefinition.html#cfn-sagemaker-monitoringschedule-monitoringjobdefinition-monitoringoutputconfig", + "Required": true, + "Type": "MonitoringOutputConfig", + "UpdateType": "Mutable" + }, + "MonitoringResources": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringjobdefinition.html#cfn-sagemaker-monitoringschedule-monitoringjobdefinition-monitoringresources", + "Required": true, + "Type": "MonitoringResources", + "UpdateType": "Mutable" + }, + "NetworkConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringjobdefinition.html#cfn-sagemaker-monitoringschedule-monitoringjobdefinition-networkconfig", + "Required": false, + "Type": "NetworkConfig", + "UpdateType": "Mutable" + }, + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringjobdefinition.html#cfn-sagemaker-monitoringschedule-monitoringjobdefinition-rolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "StoppingCondition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringjobdefinition.html#cfn-sagemaker-monitoringschedule-monitoringjobdefinition-stoppingcondition", + "Required": false, + "Type": "StoppingCondition", + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::MonitoringSchedule.MonitoringOutput": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringoutput.html", + "Properties": { + "S3Output": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringoutput.html#cfn-sagemaker-monitoringschedule-monitoringoutput-s3output", + "Required": true, + "Type": "S3Output", + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::MonitoringSchedule.MonitoringOutputConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringoutputconfig.html", + "Properties": { + "KmsKeyId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringoutputconfig.html#cfn-sagemaker-monitoringschedule-monitoringoutputconfig-kmskeyid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "MonitoringOutputs": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringoutputconfig.html#cfn-sagemaker-monitoringschedule-monitoringoutputconfig-monitoringoutputs", + "ItemType": "MonitoringOutput", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::MonitoringSchedule.MonitoringResources": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringresources.html", + "Properties": { + "ClusterConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringresources.html#cfn-sagemaker-monitoringschedule-monitoringresources-clusterconfig", + "Required": true, + "Type": "ClusterConfig", + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::MonitoringSchedule.MonitoringScheduleConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringscheduleconfig.html", + "Properties": { + "MonitoringJobDefinition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringscheduleconfig.html#cfn-sagemaker-monitoringschedule-monitoringscheduleconfig-monitoringjobdefinition", + "Required": true, + "Type": "MonitoringJobDefinition", + "UpdateType": "Mutable" + }, + "ScheduleConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringscheduleconfig.html#cfn-sagemaker-monitoringschedule-monitoringscheduleconfig-scheduleconfig", + "Required": false, + "Type": "ScheduleConfig", + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::MonitoringSchedule.NetworkConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-networkconfig.html", + "Properties": { + "EnableInterContainerTrafficEncryption": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-networkconfig.html#cfn-sagemaker-monitoringschedule-networkconfig-enableintercontainertrafficencryption", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "EnableNetworkIsolation": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-networkconfig.html#cfn-sagemaker-monitoringschedule-networkconfig-enablenetworkisolation", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "VpcConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-networkconfig.html#cfn-sagemaker-monitoringschedule-networkconfig-vpcconfig", + "Required": false, + "Type": "VpcConfig", + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::MonitoringSchedule.S3Output": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-s3output.html", + "Properties": { + "LocalPath": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-s3output.html#cfn-sagemaker-monitoringschedule-s3output-localpath", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "S3UploadMode": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-s3output.html#cfn-sagemaker-monitoringschedule-s3output-s3uploadmode", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "S3Uri": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-s3output.html#cfn-sagemaker-monitoringschedule-s3output-s3uri", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::MonitoringSchedule.ScheduleConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-scheduleconfig.html", + "Properties": { + "ScheduleExpression": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-scheduleconfig.html#cfn-sagemaker-monitoringschedule-scheduleconfig-scheduleexpression", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::MonitoringSchedule.StatisticsResource": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-statisticsresource.html", + "Properties": { + "S3Uri": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-statisticsresource.html#cfn-sagemaker-monitoringschedule-statisticsresource-s3uri", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::MonitoringSchedule.StoppingCondition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-stoppingcondition.html", + "Properties": { + "MaxRuntimeInSeconds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-stoppingcondition.html#cfn-sagemaker-monitoringschedule-stoppingcondition-maxruntimeinseconds", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::SageMaker::MonitoringSchedule.VpcConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-vpcconfig.html", + "Properties": { + "SecurityGroupIds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-vpcconfig.html#cfn-sagemaker-monitoringschedule-vpcconfig-securitygroupids", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "Subnets": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-vpcconfig.html#cfn-sagemaker-monitoringschedule-vpcconfig-subnets", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::SageMaker::NotebookInstanceLifecycleConfig.NotebookInstanceLifecycleHook": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-notebookinstancelifecycleconfig-notebookinstancelifecyclehook.html", "Properties": { @@ -31735,18 +33977,18 @@ } }, "AWS::StepFunctions::StateMachine.CloudWatchLogsLogGroup": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-stepfunctions-statemachine-logdestination-cloudwatchlogsloggroup.html", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-stepfunctions-statemachine-cloudwatchlogsloggroup.html", "Properties": { "LogGroupArn": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-stepfunctions-statemachine-logdestination-cloudwatchlogsloggroup.html#cfn-stepfunctions-statemachine-logdestination-cloudwatchlogsloggroup-loggrouparn", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-stepfunctions-statemachine-cloudwatchlogsloggroup.html#cfn-stepfunctions-statemachine-cloudwatchlogsloggroup-loggrouparn", "PrimitiveType": "String", - "Required": true, + "Required": false, "UpdateType": "Mutable" } } }, "AWS::StepFunctions::StateMachine.DefinitionSubstitutions": { - "PrimitiveType": "Json" + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-stepfunctions-statemachine-definitionsubstitutions.html" }, "AWS::StepFunctions::StateMachine.LogDestination": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-stepfunctions-statemachine-logdestination.html", @@ -31829,7 +34071,7 @@ "Enabled": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-stepfunctions-statemachine-tracingconfiguration.html#cfn-stepfunctions-statemachine-tracingconfiguration-enabled", "PrimitiveType": "Boolean", - "Required": true, + "Required": false, "UpdateType": "Mutable" } } @@ -34096,7 +36338,7 @@ } } }, - "ResourceSpecificationVersion": "16.3.0", + "ResourceSpecificationVersion": "18.3.0", "ResourceTypes": { "AWS::ACMPCA::Certificate": { "Attributes": { @@ -35733,6 +37975,12 @@ "Required": false, "UpdateType": "Mutable" }, + "AuthorizerPayloadFormatVersion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-authorizer.html#cfn-apigatewayv2-authorizer-authorizerpayloadformatversion", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "AuthorizerResultTtlInSeconds": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-authorizer.html#cfn-apigatewayv2-authorizer-authorizerresultttlinseconds", "PrimitiveType": "Integer", @@ -35751,6 +37999,12 @@ "Required": false, "UpdateType": "Mutable" }, + "EnableSimpleResponses": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-authorizer.html#cfn-apigatewayv2-authorizer-enablesimpleresponses", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, "IdentitySource": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-authorizer.html#cfn-apigatewayv2-authorizer-identitysource", "PrimitiveItemType": "String", @@ -35878,6 +38132,12 @@ "Required": false, "UpdateType": "Mutable" }, + "IntegrationSubtype": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-integration.html#cfn-apigatewayv2-integration-integrationsubtype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "IntegrationType": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-integration.html#cfn-apigatewayv2-integration-integrationtype", "PrimitiveType": "String", @@ -37760,6 +40020,74 @@ } } }, + "AWS::ApplicationInsights::Application": { + "Attributes": { + "ApplicationARN": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-applicationinsights-application.html", + "Properties": { + "AutoConfigurationEnabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-applicationinsights-application.html#cfn-applicationinsights-application-autoconfigurationenabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "CWEMonitorEnabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-applicationinsights-application.html#cfn-applicationinsights-application-cwemonitorenabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "ComponentMonitoringSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-applicationinsights-application.html#cfn-applicationinsights-application-componentmonitoringsettings", + "ItemType": "ComponentMonitoringSetting", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "CustomComponents": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-applicationinsights-application.html#cfn-applicationinsights-application-customcomponents", + "ItemType": "CustomComponent", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "LogPatternSets": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-applicationinsights-application.html#cfn-applicationinsights-application-logpatternsets", + "ItemType": "LogPatternSet", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "OpsCenterEnabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-applicationinsights-application.html#cfn-applicationinsights-application-opscenterenabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "OpsItemSNSTopicArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-applicationinsights-application.html#cfn-applicationinsights-application-opsitemsnstopicarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ResourceGroupName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-applicationinsights-application.html#cfn-applicationinsights-application-resourcegroupname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-applicationinsights-application.html#cfn-applicationinsights-application-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::Athena::DataCatalog": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-athena-datacatalog.html", "Properties": { @@ -38965,6 +41293,25 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-waitconditionhandle.html", "Properties": {} }, + "AWS::CloudFront::CachePolicy": { + "Attributes": { + "Id": { + "PrimitiveType": "String" + }, + "LastModifiedTime": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-cachepolicy.html", + "Properties": { + "CachePolicyConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-cachepolicy.html#cfn-cloudfront-cachepolicy-cachepolicyconfig", + "Required": true, + "Type": "CachePolicyConfig", + "UpdateType": "Mutable" + } + } + }, "AWS::CloudFront::CloudFrontOriginAccessIdentity": { "Attributes": { "S3CanonicalUserId": { @@ -39004,6 +41351,63 @@ } } }, + "AWS::CloudFront::OriginRequestPolicy": { + "Attributes": { + "Id": { + "PrimitiveType": "String" + }, + "LastModifiedTime": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-originrequestpolicy.html", + "Properties": { + "OriginRequestPolicyConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-originrequestpolicy.html#cfn-cloudfront-originrequestpolicy-originrequestpolicyconfig", + "Required": true, + "Type": "OriginRequestPolicyConfig", + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::RealtimeLogConfig": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-realtimelogconfig.html", + "Properties": { + "EndPoints": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-realtimelogconfig.html#cfn-cloudfront-realtimelogconfig-endpoints", + "DuplicatesAllowed": true, + "ItemType": "EndPoint", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "Fields": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-realtimelogconfig.html#cfn-cloudfront-realtimelogconfig-fields", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-realtimelogconfig.html#cfn-cloudfront-realtimelogconfig-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "SamplingRate": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-realtimelogconfig.html#cfn-cloudfront-realtimelogconfig-samplingrate", + "PrimitiveType": "Double", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::CloudFront::StreamingDistribution": { "Attributes": { "DomainName": { @@ -39849,6 +42253,40 @@ } } }, + "AWS::CodeGuruReviewer::RepositoryAssociation": { + "Attributes": { + "AssociationArn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codegurureviewer-repositoryassociation.html", + "Properties": { + "ConnectionArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codegurureviewer-repositoryassociation.html#cfn-codegurureviewer-repositoryassociation-connectionarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codegurureviewer-repositoryassociation.html#cfn-codegurureviewer-repositoryassociation-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Owner": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codegurureviewer-repositoryassociation.html#cfn-codegurureviewer-repositoryassociation-owner", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codegurureviewer-repositoryassociation.html#cfn-codegurureviewer-repositoryassociation-type", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, "AWS::CodePipeline::CustomActionType": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codepipeline-customactiontype.html", "Properties": { @@ -40434,6 +42872,12 @@ }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cognito-userpoolclient.html", "Properties": { + "AccessTokenValidity": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cognito-userpoolclient.html#cfn-cognito-userpoolclient-accesstokenvalidity", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, "AllowedOAuthFlows": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cognito-userpoolclient.html#cfn-cognito-userpoolclient-allowedoauthflows", "PrimitiveItemType": "String", @@ -40492,6 +42936,12 @@ "Required": false, "UpdateType": "Immutable" }, + "IdTokenValidity": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cognito-userpoolclient.html#cfn-cognito-userpoolclient-idtokenvalidity", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, "LogoutURLs": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cognito-userpoolclient.html#cfn-cognito-userpoolclient-logouturls", "PrimitiveItemType": "String", @@ -40525,6 +42975,12 @@ "Type": "List", "UpdateType": "Mutable" }, + "TokenValidityUnits": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cognito-userpoolclient.html#cfn-cognito-userpoolclient-tokenvalidityunits", + "Required": false, + "Type": "TokenValidityUnits", + "UpdateType": "Mutable" + }, "UserPoolId": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cognito-userpoolclient.html#cfn-cognito-userpoolclient-userpoolid", "PrimitiveType": "String", @@ -42395,6 +44851,34 @@ } } }, + "AWS::EC2::CarrierGateway": { + "Attributes": { + "CarrierGatewayId": { + "PrimitiveType": "String" + }, + "OwnerId": { + "PrimitiveType": "String" + }, + "State": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-carriergateway.html", + "Properties": { + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-carriergateway.html#cfn-ec2-carriergateway-tags", + "Required": false, + "Type": "Tags", + "UpdateType": "Mutable" + }, + "VpcId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-carriergateway.html#cfn-ec2-carriergateway-vpcid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, "AWS::EC2::ClientVpnAuthorizationRule": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-clientvpnauthorizationrule.html", "Properties": { @@ -43427,8 +45911,10 @@ }, "Ipv6Addresses": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html#cfn-ec2-networkinterface-ipv6addresses", + "DuplicatesAllowed": false, + "ItemType": "InstanceIpv6Address", "Required": false, - "Type": "InstanceIpv6Address", + "Type": "List", "UpdateType": "Mutable" }, "PrivateIpAddress": { @@ -44206,6 +46692,12 @@ "Required": false, "UpdateType": "Immutable" }, + "MulticastSupport": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgateway.html#cfn-ec2-transitgateway-multicastsupport", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgateway.html#cfn-ec2-transitgateway-tags", "ItemType": "Tag", @@ -44849,6 +47341,18 @@ }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecr-repository.html", "Properties": { + "ImageScanningConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecr-repository.html#cfn-ecr-repository-imagescanningconfiguration", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Mutable" + }, + "ImageTagMutability": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecr-repository.html#cfn-ecr-repository-imagetagmutability", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "LifecyclePolicy": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecr-repository.html#cfn-ecr-repository-lifecyclepolicy", "Required": false, @@ -44863,13 +47367,12 @@ }, "RepositoryPolicyText": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecr-repository.html#cfn-ecr-repository-repositorypolicytext", - "PrimitiveType": "Json", "Required": false, "UpdateType": "Mutable" }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecr-repository.html#cfn-ecr-repository-tags", - "DuplicatesAllowed": true, + "DuplicatesAllowed": false, "ItemType": "Tag", "Required": false, "Type": "List", @@ -45197,12 +47700,6 @@ "Type": "List", "UpdateType": "Mutable" }, - "TaskDefinitionStatus": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-taskdefinition.html#cfn-ecs-taskdefinition-taskdefinitionstatus", - "PrimitiveType": "String", - "Required": false, - "UpdateType": "Mutable" - }, "TaskRoleArn": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-taskdefinition.html#cfn-ecs-taskdefinition-taskrolearn", "PrimitiveType": "String", @@ -45496,6 +47993,56 @@ } } }, + "AWS::EKS::FargateProfile": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-fargateprofile.html", + "Properties": { + "ClusterName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-fargateprofile.html#cfn-eks-fargateprofile-clustername", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "FargateProfileName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-fargateprofile.html#cfn-eks-fargateprofile-fargateprofilename", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "PodExecutionRoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-fargateprofile.html#cfn-eks-fargateprofile-podexecutionrolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Selectors": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-fargateprofile.html#cfn-eks-fargateprofile-selectors", + "ItemType": "Selector", + "Required": true, + "Type": "List", + "UpdateType": "Immutable" + }, + "Subnets": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-fargateprofile.html#cfn-eks-fargateprofile-subnets", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-fargateprofile.html#cfn-eks-fargateprofile-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::EKS::Nodegroup": { "Attributes": { "Arn": { @@ -45547,6 +48094,12 @@ "Required": false, "UpdateType": "Mutable" }, + "LaunchTemplate": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-nodegroup.html#cfn-eks-nodegroup-launchtemplate", + "Required": false, + "Type": "LaunchTemplateSpecification", + "UpdateType": "Mutable" + }, "NodeRole": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-nodegroup.html#cfn-eks-nodegroup-noderole", "PrimitiveType": "String", @@ -47551,6 +50104,11 @@ } }, "AWS::GameLift::Alias": { + "Attributes": { + "AliasId": { + "PrimitiveType": "String" + } + }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-alias.html", "Properties": { "Description": { @@ -47739,6 +50297,91 @@ } } }, + "AWS::GameLift::GameServerGroup": { + "Attributes": { + "AutoScalingGroupArn": { + "PrimitiveType": "String" + }, + "GameServerGroupArn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-gameservergroup.html", + "Properties": { + "AutoScalingPolicy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-gameservergroup.html#cfn-gamelift-gameservergroup-autoscalingpolicy", + "Required": false, + "Type": "AutoScalingPolicy", + "UpdateType": "Mutable" + }, + "BalancingStrategy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-gameservergroup.html#cfn-gamelift-gameservergroup-balancingstrategy", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "DeleteOption": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-gameservergroup.html#cfn-gamelift-gameservergroup-deleteoption", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "GameServerGroupName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-gameservergroup.html#cfn-gamelift-gameservergroup-gameservergroupname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "GameServerProtectionPolicy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-gameservergroup.html#cfn-gamelift-gameservergroup-gameserverprotectionpolicy", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "InstanceDefinitions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-gameservergroup.html#cfn-gamelift-gameservergroup-instancedefinitions", + "Required": true, + "Type": "InstanceDefinitions", + "UpdateType": "Mutable" + }, + "LaunchTemplate": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-gameservergroup.html#cfn-gamelift-gameservergroup-launchtemplate", + "Required": true, + "Type": "LaunchTemplate", + "UpdateType": "Mutable" + }, + "MaxSize": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-gameservergroup.html#cfn-gamelift-gameservergroup-maxsize", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + }, + "MinSize": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-gameservergroup.html#cfn-gamelift-gameservergroup-minsize", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + }, + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-gameservergroup.html#cfn-gamelift-gameservergroup-rolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-gameservergroup.html#cfn-gamelift-gameservergroup-tags", + "Required": false, + "Type": "Tags", + "UpdateType": "Mutable" + }, + "VpcSubnets": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-gameservergroup.html#cfn-gamelift-gameservergroup-vpcsubnets", + "Required": false, + "Type": "VpcSubnets", + "UpdateType": "Mutable" + } + } + }, "AWS::GameLift::GameSessionQueue": { "Attributes": { "Arn": { @@ -49171,6 +51814,12 @@ "AWS::GuardDuty::Detector": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-guardduty-detector.html", "Properties": { + "DataSources": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-guardduty-detector.html#cfn-guardduty-detector-datasources", + "Required": false, + "Type": "CFNDataSourceConfigurations", + "UpdateType": "Mutable" + }, "Enable": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-guardduty-detector.html#cfn-guardduty-detector-enable", "PrimitiveType": "Boolean", @@ -50291,18 +52940,91 @@ } } }, + "AWS::IoT::Authorizer": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-authorizer.html", + "Properties": { + "AuthorizerFunctionArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-authorizer.html#cfn-iot-authorizer-authorizerfunctionarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "AuthorizerName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-authorizer.html#cfn-iot-authorizer-authorizername", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "SigningDisabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-authorizer.html#cfn-iot-authorizer-signingdisabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Immutable" + }, + "Status": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-authorizer.html#cfn-iot-authorizer-status", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-authorizer.html#cfn-iot-authorizer-tags", + "Required": false, + "Type": "Tags", + "UpdateType": "Mutable" + }, + "TokenKeyName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-authorizer.html#cfn-iot-authorizer-tokenkeyname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "TokenSigningPublicKeys": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-authorizer.html#cfn-iot-authorizer-tokensigningpublickeys", + "Required": false, + "Type": "TokenSigningPublicKeys", + "UpdateType": "Mutable" + } + } + }, "AWS::IoT::Certificate": { "Attributes": { "Arn": { "PrimitiveType": "String" + }, + "Id": { + "PrimitiveType": "String" } }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-certificate.html", "Properties": { + "CACertificatePem": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-certificate.html#cfn-iot-certificate-cacertificatepem", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "CertificateMode": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-certificate.html#cfn-iot-certificate-certificatemode", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "CertificatePem": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-certificate.html#cfn-iot-certificate-certificatepem", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, "CertificateSigningRequest": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-certificate.html#cfn-iot-certificate-certificatesigningrequest", "PrimitiveType": "String", - "Required": true, + "Required": false, "UpdateType": "Immutable" }, "Status": { @@ -50712,6 +53434,9 @@ "Attributes": { "Arn": { "PrimitiveType": "String" + }, + "KeyId": { + "PrimitiveType": "String" } }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kms-key.html", @@ -50736,7 +53461,6 @@ }, "KeyPolicy": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kms-key.html#cfn-kms-key-keypolicy", - "PrimitiveType": "Json", "Required": true, "UpdateType": "Mutable" }, @@ -50754,7 +53478,7 @@ }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kms-key.html#cfn-kms-key-tags", - "DuplicatesAllowed": true, + "DuplicatesAllowed": false, "ItemType": "Tag", "Required": false, "Type": "List", @@ -50762,6 +53486,177 @@ } } }, + "AWS::Kendra::DataSource": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "Id": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-datasource.html", + "Properties": { + "DataSourceConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-datasource.html#cfn-kendra-datasource-datasourceconfiguration", + "Required": true, + "Type": "DataSourceConfiguration", + "UpdateType": "Mutable" + }, + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-datasource.html#cfn-kendra-datasource-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "IndexId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-datasource.html#cfn-kendra-datasource-indexid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-datasource.html#cfn-kendra-datasource-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-datasource.html#cfn-kendra-datasource-rolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Schedule": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-datasource.html#cfn-kendra-datasource-schedule", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-datasource.html#cfn-kendra-datasource-tags", + "Required": false, + "Type": "TagList", + "UpdateType": "Mutable" + }, + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-datasource.html#cfn-kendra-datasource-type", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, + "AWS::Kendra::Faq": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "Id": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-faq.html", + "Properties": { + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-faq.html#cfn-kendra-faq-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "IndexId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-faq.html#cfn-kendra-faq-indexid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-faq.html#cfn-kendra-faq-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-faq.html#cfn-kendra-faq-rolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "S3Path": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-faq.html#cfn-kendra-faq-s3path", + "Required": true, + "Type": "S3Path", + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-faq.html#cfn-kendra-faq-tags", + "Required": false, + "Type": "TagList", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::Index": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "Id": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-index.html", + "Properties": { + "CapacityUnits": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-index.html#cfn-kendra-index-capacityunits", + "Required": false, + "Type": "CapacityUnitsConfiguration", + "UpdateType": "Mutable" + }, + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-index.html#cfn-kendra-index-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "DocumentMetadataConfigurations": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-index.html#cfn-kendra-index-documentmetadataconfigurations", + "Required": false, + "Type": "DocumentMetadataConfigurationList", + "UpdateType": "Mutable" + }, + "Edition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-index.html#cfn-kendra-index-edition", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-index.html#cfn-kendra-index-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-index.html#cfn-kendra-index-rolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ServerSideEncryptionConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-index.html#cfn-kendra-index-serversideencryptionconfiguration", + "Required": false, + "Type": "ServerSideEncryptionConfiguration", + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kendra-index.html#cfn-kendra-index-tags", + "Required": false, + "Type": "TagList", + "UpdateType": "Mutable" + } + } + }, "AWS::Kinesis::Stream": { "Attributes": { "Arn": { @@ -51201,6 +54096,11 @@ } }, "AWS::Lambda::EventSourceMapping": { + "Attributes": { + "Id": { + "PrimitiveType": "String" + } + }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-eventsourcemapping.html", "Properties": { "BatchSize": { @@ -51268,6 +54168,14 @@ "PrimitiveType": "String", "Required": false, "UpdateType": "Immutable" + }, + "Topics": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-eventsourcemapping.html#cfn-lambda-eventsourcemapping-topics", + "DuplicatesAllowed": false, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" } } }, @@ -52330,6 +55238,13 @@ }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-neptune-dbcluster.html", "Properties": { + "AssociatedRoles": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-neptune-dbcluster.html#cfn-neptune-dbcluster-associatedroles", + "ItemType": "DBClusterRole", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, "AvailabilityZones": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-neptune-dbcluster.html#cfn-neptune-dbcluster-availabilityzones", "PrimitiveItemType": "String", @@ -53524,6 +56439,9 @@ }, "Endpoint": { "PrimitiveType": "String" + }, + "Id": { + "PrimitiveType": "String" } }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opsworkscm-server.html", @@ -53578,6 +56496,7 @@ }, "EngineAttributes": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opsworkscm-server.html#cfn-opsworkscm-server-engineattributes", + "DuplicatesAllowed": true, "ItemType": "EngineAttribute", "Required": false, "Type": "List", @@ -53627,6 +56546,7 @@ }, "SecurityGroupIds": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opsworkscm-server.html#cfn-opsworkscm-server-securitygroupids", + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": false, "Type": "List", @@ -53646,6 +56566,7 @@ }, "SubnetIds": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opsworkscm-server.html#cfn-opsworkscm-server-subnetids", + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": false, "Type": "List", @@ -53653,6 +56574,7 @@ }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opsworkscm-server.html#cfn-opsworkscm-server-tags", + "DuplicatesAllowed": true, "ItemType": "Tag", "Required": false, "Type": "List", @@ -56157,17 +59079,22 @@ } }, "AWS::Route53::HealthCheck": { + "Attributes": { + "HealthCheckId": { + "PrimitiveType": "String" + } + }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53-healthcheck.html", "Properties": { "HealthCheckConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53-healthcheck.html#cfn-route53-healthcheck-healthcheckconfig", + "PrimitiveType": "Json", "Required": true, - "Type": "HealthCheckConfig", - "UpdateType": "Conditional" + "UpdateType": "Mutable" }, "HealthCheckTags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53-healthcheck.html#cfn-route53-healthcheck-healthchecktags", - "DuplicatesAllowed": true, + "DuplicatesAllowed": false, "ItemType": "HealthCheckTag", "Required": false, "Type": "List", @@ -56406,6 +59333,83 @@ } } }, + "AWS::Route53Resolver::ResolverQueryLoggingConfig": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "AssociationCount": { + "PrimitiveType": "Integer" + }, + "CreationTime": { + "PrimitiveType": "String" + }, + "CreatorRequestId": { + "PrimitiveType": "String" + }, + "Id": { + "PrimitiveType": "String" + }, + "OwnerId": { + "PrimitiveType": "String" + }, + "ShareStatus": { + "PrimitiveType": "String" + }, + "Status": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-resolverqueryloggingconfig.html", + "Properties": { + "DestinationArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-resolverqueryloggingconfig.html#cfn-route53resolver-resolverqueryloggingconfig-destinationarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-resolverqueryloggingconfig.html#cfn-route53resolver-resolverqueryloggingconfig-name", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::Route53Resolver::ResolverQueryLoggingConfigAssociation": { + "Attributes": { + "CreationTime": { + "PrimitiveType": "String" + }, + "Error": { + "PrimitiveType": "String" + }, + "ErrorMessage": { + "PrimitiveType": "String" + }, + "Id": { + "PrimitiveType": "String" + }, + "Status": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-resolverqueryloggingconfigassociation.html", + "Properties": { + "ResolverQueryLogConfigId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-resolverqueryloggingconfigassociation.html#cfn-route53resolver-resolverqueryloggingconfigassociation-resolverquerylogconfigid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "ResourceId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-resolverqueryloggingconfigassociation.html#cfn-route53resolver-resolverqueryloggingconfigassociation-resourceid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, "AWS::Route53Resolver::ResolverRule": { "Attributes": { "Arn": { @@ -56882,12 +59886,6 @@ "Required": false, "UpdateType": "Mutable" }, - "FifoTopic": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sns-topic.html#cfn-sns-topic-fifotopic", - "PrimitiveType": "Boolean", - "Required": false, - "UpdateType": "Immutable" - }, "KmsMasterKeyId": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sns-topic.html#cfn-sns-topic-kmsmasterkeyid", "PrimitiveType": "String", @@ -57588,6 +60586,107 @@ } } }, + "AWS::SSO::Assignment": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sso-assignment.html", + "Properties": { + "InstanceArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sso-assignment.html#cfn-sso-assignment-instancearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "PermissionSetArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sso-assignment.html#cfn-sso-assignment-permissionsetarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "PrincipalId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sso-assignment.html#cfn-sso-assignment-principalid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "PrincipalType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sso-assignment.html#cfn-sso-assignment-principaltype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "TargetId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sso-assignment.html#cfn-sso-assignment-targetid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "TargetType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sso-assignment.html#cfn-sso-assignment-targettype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, + "AWS::SSO::PermissionSet": { + "Attributes": { + "PermissionSetArn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sso-permissionset.html", + "Properties": { + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sso-permissionset.html#cfn-sso-permissionset-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "InlinePolicy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sso-permissionset.html#cfn-sso-permissionset-inlinepolicy", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "InstanceArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sso-permissionset.html#cfn-sso-permissionset-instancearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "ManagedPolicies": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sso-permissionset.html#cfn-sso-permissionset-managedpolicies", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sso-permissionset.html#cfn-sso-permissionset-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "RelayStateType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sso-permissionset.html#cfn-sso-permissionset-relaystatetype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SessionDuration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sso-permissionset.html#cfn-sso-permissionset-sessionduration", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sso-permissionset.html#cfn-sso-permissionset-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::SageMaker::CodeRepository": { "Attributes": { "CodeRepositoryName": { @@ -57709,6 +60808,12 @@ "Type": "List", "UpdateType": "Immutable" }, + "EnableNetworkIsolation": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-model.html#cfn-sagemaker-model-enablenetworkisolation", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Immutable" + }, "ExecutionRoleArn": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-model.html#cfn-sagemaker-model-executionrolearn", "PrimitiveType": "String", @@ -57742,6 +60847,72 @@ } } }, + "AWS::SageMaker::MonitoringSchedule": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-monitoringschedule.html", + "Properties": { + "CreationTime": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-monitoringschedule.html#cfn-sagemaker-monitoringschedule-creationtime", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "EndpointName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-monitoringschedule.html#cfn-sagemaker-monitoringschedule-endpointname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "FailureReason": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-monitoringschedule.html#cfn-sagemaker-monitoringschedule-failurereason", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "LastModifiedTime": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-monitoringschedule.html#cfn-sagemaker-monitoringschedule-lastmodifiedtime", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "LastMonitoringExecutionSummary": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-monitoringschedule.html#cfn-sagemaker-monitoringschedule-lastmonitoringexecutionsummary", + "Required": false, + "Type": "MonitoringExecutionSummary", + "UpdateType": "Mutable" + }, + "MonitoringScheduleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-monitoringschedule.html#cfn-sagemaker-monitoringschedule-monitoringschedulearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "MonitoringScheduleConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-monitoringschedule.html#cfn-sagemaker-monitoringschedule-monitoringscheduleconfig", + "Required": true, + "Type": "MonitoringScheduleConfig", + "UpdateType": "Mutable" + }, + "MonitoringScheduleName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-monitoringschedule.html#cfn-sagemaker-monitoringschedule-monitoringschedulename", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "MonitoringScheduleStatus": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-monitoringschedule.html#cfn-sagemaker-monitoringschedule-monitoringschedulestatus", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-monitoringschedule.html#cfn-sagemaker-monitoringschedule-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::SageMaker::NotebookInstance": { "Attributes": { "NotebookInstanceName": { @@ -58173,6 +61344,12 @@ "Required": false, "UpdateType": "Mutable" }, + "PathName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-servicecatalog-cloudformationprovisionedproduct.html#cfn-servicecatalog-cloudformationprovisionedproduct-pathname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "ProductId": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-servicecatalog-cloudformationprovisionedproduct.html#cfn-servicecatalog-cloudformationprovisionedproduct-productid", "PrimitiveType": "String", @@ -58804,6 +61981,9 @@ }, "AWS::StepFunctions::StateMachine": { "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, "Name": { "PrimitiveType": "String" } @@ -58850,10 +62030,11 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-statemachinetype", "PrimitiveType": "String", "Required": false, - "UpdateType": "Immutable" + "UpdateType": "Mutable" }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html#cfn-stepfunctions-statemachine-tags", + "DuplicatesAllowed": true, "ItemType": "TagsEntry", "Required": false, "Type": "List", @@ -59008,6 +62189,12 @@ "Type": "List", "UpdateType": "Mutable" }, + "SecurityPolicyName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-transfer-server.html#cfn-transfer-server-securitypolicyname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-transfer-server.html#cfn-transfer-server-tags", "ItemType": "Tag", diff --git a/packages/@aws-cdk/cfnspec/spec-source/540_SSM_Association_Parameters_patch.json b/packages/@aws-cdk/cfnspec/spec-source/540_SSM_Association_Parameters_patch.json index 0059cd2577767..815f593a3cfb4 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/540_SSM_Association_Parameters_patch.json +++ b/packages/@aws-cdk/cfnspec/spec-source/540_SSM_Association_Parameters_patch.json @@ -5,12 +5,13 @@ "description": "Removes 'ItemType' property since 'ParameterValues' is (currently) not defined in the spec and the documentation states it to be a list of String", "operations": [ { - "op": "remove", - "path": "/Properties/Parameters/ItemType" + "op": "replace", + "path": "/Properties/Parameters/ItemType", + "value": "List" }, { "op": "add", - "path": "/Properties/Parameters/PrimitiveItemType", + "path": "/Properties/Parameters/PrimitiveItemItemType", "value": "String" } ] diff --git a/packages/@aws-cdk/cfnspec/spec-source/580_Kms_Key_KeyPolicy_patch.json b/packages/@aws-cdk/cfnspec/spec-source/580_Kms_Key_KeyPolicy_patch.json new file mode 100644 index 0000000000000..d32271df45689 --- /dev/null +++ b/packages/@aws-cdk/cfnspec/spec-source/580_Kms_Key_KeyPolicy_patch.json @@ -0,0 +1,16 @@ +{ + "ResourceTypes": { + "AWS::KMS::Key": { + "patch": { + "description": "Primitive type does not exist at all for some reason and it should be Json", + "operations": [ + { + "path": "/Properties/KeyPolicy/PrimitiveType", + "op": "add", + "value": "Json" + } + ] + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/cfnspec/spec-source/590_Ecr_RepositoryPolicyText_patch.json b/packages/@aws-cdk/cfnspec/spec-source/590_Ecr_RepositoryPolicyText_patch.json new file mode 100644 index 0000000000000..933859092983a --- /dev/null +++ b/packages/@aws-cdk/cfnspec/spec-source/590_Ecr_RepositoryPolicyText_patch.json @@ -0,0 +1,16 @@ +{ + "ResourceTypes": { + "AWS::ECR::Repository": { + "patch": { + "description": "Primitive type does not exist at all for some reason and it should be Json", + "operations": [ + { + "path": "/Properties/RepositoryPolicyText/PrimitiveType", + "op": "add", + "value": "Json" + } + ] + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/cfnspec/spec-source/600_Ecs_TaskDefinition_EFSVolumeConfiguration_AuthorizationConfig_patch.json b/packages/@aws-cdk/cfnspec/spec-source/600_Ecs_TaskDefinition_EFSVolumeConfiguration_AuthorizationConfig_patch.json new file mode 100644 index 0000000000000..e1f7e1c0375d1 --- /dev/null +++ b/packages/@aws-cdk/cfnspec/spec-source/600_Ecs_TaskDefinition_EFSVolumeConfiguration_AuthorizationConfig_patch.json @@ -0,0 +1,15 @@ +{ + "PropertyTypes": { + "AWS::ECS::TaskDefinition.EFSVolumeConfiguration": { + "patch": { + "description": "Primitive type should not exist because it already has a complext type of AuthorizationConfig", + "operations": [ + { + "path": "/Properties/AuthorizationConfig/PrimitiveType", + "op": "remove" + } + ] + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/cfnspec/spec-source/610_IoT_Authorizer_Tags_patch.json b/packages/@aws-cdk/cfnspec/spec-source/610_IoT_Authorizer_Tags_patch.json new file mode 100644 index 0000000000000..45e189299b113 --- /dev/null +++ b/packages/@aws-cdk/cfnspec/spec-source/610_IoT_Authorizer_Tags_patch.json @@ -0,0 +1,16 @@ +{ + "PropertyTypes": { + "AWS::IoT::Authorizer.Tags": { + "patch": { + "description": "Tags is defined as a List whereas it should he List", + "operations": [ + { + "path": "/Properties/Tags/ItemType", + "op": "replace", + "value": "Tag" + } + ] + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/cfnspec/test/spec-validators.ts b/packages/@aws-cdk/cfnspec/test/spec-validators.ts index 521a61be55682..c09fb7dc0e27f 100644 --- a/packages/@aws-cdk/cfnspec/test/spec-validators.ts +++ b/packages/@aws-cdk/cfnspec/test/spec-validators.ts @@ -68,7 +68,7 @@ function validateProperties( test.ok(resolvedType, `${typeName}.Properties.${name} ItemType (${fqn}) resolves`); } - } else if (schema.isComplexMapProperty(property)) { + } else if (schema.isMapOfStructsProperty(property)) { expectedKeys.push('Type', 'DuplicatesAllowed', 'ItemType', 'Type'); test.ok(property.ItemType, `${typeName}.Properties.${name} has a valid ItemType`); const fqn = `${typeName.split('.')[0]}.${property.ItemType}`; @@ -76,6 +76,11 @@ function validateProperties( test.ok(resolvedType, `${typeName}.Properties.${name} ItemType (${fqn}) resolves`); test.ok(!property.DuplicatesAllowed, `${typeName}.Properties.${name} does not allow duplicates`); + } else if (schema.isMapOfListsOfPrimitivesProperty(property)) { + expectedKeys.push('Type', 'DuplicatesAllowed', 'ItemType', 'PrimitiveItemItemType', 'Type'); + test.ok(schema.isPrimitiveType(property.PrimitiveItemItemType), `${typeName}.Properties.${name} has a valid PrimitiveItemItemType`); + test.ok(!property.DuplicatesAllowed, `${typeName}.Properties.${name} does not allow duplicates`); + } else if (schema.isComplexProperty(property)) { expectedKeys.push('Type'); test.ok(property.Type, `${typeName}.Properties.${name} has a valid type`); diff --git a/packages/@aws-cdk/cloud-assembly-schema/package.json b/packages/@aws-cdk/cloud-assembly-schema/package.json index 89ba9b9bdbdcd..41be3a4faa4fa 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/package.json +++ b/packages/@aws-cdk/cloud-assembly-schema/package.json @@ -48,13 +48,13 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.10", + "@types/jest": "^26.0.14", "@types/mock-fs": "^4.10.0", "cdk-build-tools": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "mock-fs": "^4.13.0", "pkglint": "0.0.0", - "typescript-json-schema": "^0.42.0" + "typescript-json-schema": "^0.43.0" }, "repository": { "url": "https://github.com/aws/aws-cdk.git", @@ -78,8 +78,8 @@ "exclude": [] }, "dependencies": { - "jsonschema": "^1.2.5", - "semver": "^7.2.2" + "jsonschema": "^1.2.6", + "semver": "^7.3.2" }, "awscdkio": { "announce": false diff --git a/packages/@aws-cdk/cloudformation-diff/lib/diff/util.ts b/packages/@aws-cdk/cloudformation-diff/lib/diff/util.ts index 02858f802647c..763afbecaf79e 100644 --- a/packages/@aws-cdk/cloudformation-diff/lib/diff/util.ts +++ b/packages/@aws-cdk/cloudformation-diff/lib/diff/util.ts @@ -15,6 +15,12 @@ */ export function deepEqual(lvalue: any, rvalue: any): boolean { if (lvalue === rvalue) { return true; } + // CloudFormation allows passing strings into boolean-typed fields + if (((typeof lvalue === 'string' && typeof rvalue === 'boolean') || + (typeof lvalue === 'boolean' && typeof rvalue === 'string')) && + lvalue.toString() === rvalue.toString()) { + return true; + } // 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))) { @@ -38,7 +44,11 @@ export function deepEqual(lvalue: any, rvalue: any): boolean { if (keys.length !== Object.keys(rvalue).length) { return false; } for (const key of keys) { if (!rvalue.hasOwnProperty(key)) { return false; } - if (key === 'DependsOn') { return dependsOnEqual(lvalue[key], rvalue[key]); } + if (key === 'DependsOn') { + if (!dependsOnEqual(lvalue[key], rvalue[key])) { return false; }; + // check differences other than `DependsOn` + continue; + } if (!deepEqual(lvalue[key], rvalue[key])) { return false; } } return true; diff --git a/packages/@aws-cdk/cloudformation-diff/lib/format-table.ts b/packages/@aws-cdk/cloudformation-diff/lib/format-table.ts index 6bff9f3709234..51ed503a30b91 100644 --- a/packages/@aws-cdk/cloudformation-diff/lib/format-table.ts +++ b/packages/@aws-cdk/cloudformation-diff/lib/format-table.ts @@ -27,10 +27,10 @@ function lineBetween(rowA: string[], rowB: string[]) { return rowA[1] !== rowB[1]; } -function buildColumnConfig(widths: number[] | undefined): { [index: number]: table.ColumnConfig } | undefined { +function buildColumnConfig(widths: number[] | undefined): { [index: number]: table.TableColumns } | undefined { if (widths === undefined) { return undefined; } - const ret: { [index: number]: table.ColumnConfig } = {}; + const ret: { [index: number]: table.TableColumns } = {}; widths.forEach((width, i) => { ret[i] = { width, useWordWrap: true } as any; // 'useWordWrap' is not in @types/table if (width === undefined) { diff --git a/packages/@aws-cdk/cloudformation-diff/package.json b/packages/@aws-cdk/cloudformation-diff/package.json index aa9882ffa31de..7e36bc1200638 100644 --- a/packages/@aws-cdk/cloudformation-diff/package.json +++ b/packages/@aws-cdk/cloudformation-diff/package.json @@ -26,17 +26,17 @@ "diff": "^4.0.2", "fast-deep-equal": "^3.1.3", "string-width": "^4.2.0", - "table": "^5.4.6" + "table": "^6.0.3" }, "devDependencies": { - "@types/jest": "^26.0.10", + "@types/jest": "^26.0.14", "@types/string-width": "^4.0.1", - "@types/table": "^4.0.7", + "@types/table": "^5.0.0", "cdk-build-tools": "0.0.0", - "fast-check": "^1.26.0", - "jest": "^25.5.4", + "fast-check": "^2.3.0", + "jest": "^26.4.2", "pkglint": "0.0.0", - "ts-jest": "^26.2.0" + "ts-jest": "^26.3.0" }, "repository": { "url": "https://github.com/aws/aws-cdk.git", 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 9aff935252717..8110922a41790 100644 --- a/packages/@aws-cdk/cloudformation-diff/test/diff-template.test.ts +++ b/packages/@aws-cdk/cloudformation-diff/test/diff-template.test.ts @@ -403,7 +403,6 @@ test('single element arrays are equivalent to the single element in DependsOn ex expect(differences.resources.differenceCount).toBe(0); }); - test('array equivalence is independent of element order in DependsOn expressions', () => { // GIVEN const currentTemplate = { @@ -487,3 +486,70 @@ test('arrays that differ only in element order are considered unequal outside of differences = diffTemplate(newTemplate, currentTemplate); expect(differences.resources.differenceCount).toBe(1); }); + +test('boolean properties are considered equal with their stringified counterparts', () => { + // GIVEN + const currentTemplate = { + Resources: { + Bucket: { + Type: 'AWS::S3::Bucket', + Properties: { + PublicAccessBlockConfiguration: { + BlockPublicAcls: 'true', + }, + }, + }, + }, + }; + const newTemplate = { + Resources: { + Bucket: { + Type: 'AWS::S3::Bucket', + Properties: { + PublicAccessBlockConfiguration: { + BlockPublicAcls: true, + }, + }, + }, + }, + }; + + // WHEN + const differences = diffTemplate(currentTemplate, newTemplate); + + // THEN + expect(differences.differenceCount).toBe(0); +}); + +test('when a property changes including equivalent DependsOn', () => { + // GIVEN + const bucketName = 'ShineyBucketName'; + const currentTemplate = { + Resources: { + BucketResource: { + Type: 'AWS::S3::Bucket', + DependsOn: ['SomeResource'], + BucketName: bucketName, + }, + }, + }; + + // WHEN + const newBucketName = `${bucketName}-v2`; + const newTemplate = { + Resources: { + BucketResource: { + Type: 'AWS::S3::Bucket', + DependsOn: ['SomeResource'], + BucketName: newBucketName, + }, + }, + }; + + // THEN + let differences = diffTemplate(currentTemplate, newTemplate); + expect(differences.resources.differenceCount).toBe(1); + + differences = diffTemplate(newTemplate, currentTemplate); + expect(differences.resources.differenceCount).toBe(1); +}); diff --git a/packages/@aws-cdk/cloudformation-include/README.md b/packages/@aws-cdk/cloudformation-include/README.md index 52da55a585b02..0e2324128c2c3 100644 --- a/packages/@aws-cdk/cloudformation-include/README.md +++ b/packages/@aws-cdk/cloudformation-include/README.md @@ -3,9 +3,9 @@ --- -![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge) +![cdk-constructs: Developer Preview](https://img.shields.io/badge/cdk--constructs-developer--preview-informational.svg?style=for-the-badge) -> The APIs of higher level constructs in this module are experimental and under active development. They are subject to non-backward compatible changes or removal in any future version. These are not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be announced in the release notes. This means that while you may use them, you may need to update your source code when upgrading to a newer version of this package. +> The APIs of higher level constructs in this module are in **developer preview** before they become stable. We will only make breaking changes to address unforeseen API issues. Therefore, these APIs are not subject to [Semantic Versioning](https://semver.org/), and breaking changes will be announced in release notes. This means that while you may use them, you may need to update your source code when upgrading to a newer version of this package. --- @@ -254,7 +254,7 @@ and the nested stack in your CDK application as follows: ```typescript const parentTemplate = new inc.CfnInclude(this, 'ParentStack', { templateFile: 'path/to/my-parent-template.json', - nestedStacks: { + loadNestedStacks: { 'ChildStack': { templateFile: 'path/to/my-nested-template.json', }, @@ -299,6 +299,15 @@ role.addToPolicy(new iam.PolicyStatement({ })); ``` +You can also include the nested stack after the `CfnInclude` object was created, +instead of doing it on construction: + +```ts +const includedChildStack = parentTemplate.loadNestedStack('ChildTemplate', { + templateFile: 'path/to/my-nested-template.json', +}); +``` + ## Vending CloudFormation templates as Constructs In many cases, there are existing CloudFormation templates that are not entire applications, diff --git a/packages/@aws-cdk/cloudformation-include/lib/cfn-include.ts b/packages/@aws-cdk/cloudformation-include/lib/cfn-include.ts index 14549f452eccb..aad5c653c3693 100644 --- a/packages/@aws-cdk/cloudformation-include/lib/cfn-include.ts +++ b/packages/@aws-cdk/cloudformation-include/lib/cfn-include.ts @@ -32,7 +32,8 @@ export interface CfnIncludeProps { * Specifies the template files that define nested stacks that should be included. * * If your template specifies a stack that isn't included here, it won't be created as a NestedStack - * resource, and it won't be accessible from {@link CfnInclude.getNestedStack}. + * resource, and it won't be accessible from the {@link CfnInclude.getNestedStack} method + * (but will still be accessible from the {@link CfnInclude.getResource} method). * * If you include a stack here with an ID that isn't in the template, * or is in the template but is not a nested stack, @@ -40,7 +41,7 @@ export interface CfnIncludeProps { * * @default - no nested stacks will be included */ - readonly nestedStacks?: { [stackName: string]: CfnIncludeProps }; + readonly loadNestedStacks?: { [stackName: string]: CfnIncludeProps }; /** * Specifies parameters to be replaced by the values in this mapping. @@ -134,13 +135,13 @@ export class CfnInclude extends core.CfnElement { this.createRule(ruleName); } - this.nestedStacksToInclude = props.nestedStacks || {}; + this.nestedStacksToInclude = props.loadNestedStacks || {}; // instantiate all resources as CDK L1 objects for (const logicalId of Object.keys(this.template.Resources || {})) { this.getOrCreateResource(logicalId); } // verify that all nestedStacks have been instantiated - for (const nestedStackId of Object.keys(props.nestedStacks || {})) { + for (const nestedStackId of Object.keys(props.loadNestedStacks || {})) { if (!(nestedStackId in this.resources)) { throw new Error(`Nested Stack with logical ID '${nestedStackId}' was not found in the template`); } @@ -290,9 +291,10 @@ export class CfnInclude extends core.CfnElement { } /** - * Returns the NestedStack with name logicalId. - * For a nested stack to be returned by this method, it must be specified in the {@link CfnIncludeProps.nestedStacks} - * property. + * Returns a loaded NestedStack with name logicalId. + * For a nested stack to be returned by this method, + * it must be specified either in the {@link CfnIncludeProps.loadNestedStacks} property, + * or through the {@link loadNestedStack} method. * * @param logicalId the ID of the stack to retrieve, as it appears in the template */ @@ -303,12 +305,47 @@ export class CfnInclude extends core.CfnElement { } else if (this.template.Resources[logicalId].Type !== 'AWS::CloudFormation::Stack') { throw new Error(`Resource with logical ID '${logicalId}' is not a CloudFormation Stack`); } else { - throw new Error(`Nested Stack '${logicalId}' was not included in the nestedStacks property when including the parent template`); + throw new Error(`Nested Stack '${logicalId}' was not included in the parent template. ` + + 'To retrieve an included nested stack, it must be specified either in the `loadNestedStacks` property, or through the `loadNestedStack` method'); } } return this.nestedStacks[logicalId]; } + /** + * Includes a template for a child stack inside of this parent template. + * A child with this logical ID must exist in the template, + * and be of type AWS::CloudFormation::Stack. + * This is equivalent to specifying the value in the {@link CfnIncludeProps.loadNestedStacks} + * property on object construction. + * + * @param logicalId the ID of the stack to retrieve, as it appears in the template + * @param nestedStackProps the properties of the included child Stack + * @returns the same {@link IncludedNestedStack} object that {@link getNestedStack} returns for this logical ID + */ + public loadNestedStack(logicalId: string, nestedStackProps: CfnIncludeProps): IncludedNestedStack { + if (logicalId in this.nestedStacks) { + throw new Error(`Nested Stack '${logicalId}' was already included in its parent template`); + } + const cfnStack = this.resources[logicalId]; + if (!cfnStack) { + throw new Error(`Nested Stack with logical ID '${logicalId}' was not found in the template`); + } + if (cfnStack instanceof core.CfnStack) { + // delete the old CfnStack child - one will be created by the NestedStack object + this.node.tryRemoveChild(logicalId); + // remove the previously created CfnStack resource from the resources map + delete this.resources[logicalId]; + // createNestedStack() (called by getOrCreateResource()) expects this to be filled + this.nestedStacksToInclude[logicalId] = nestedStackProps; + + this.getOrCreateResource(logicalId); + return this.nestedStacks[logicalId]; + } else { + throw new Error(`Nested Stack with logical ID '${logicalId}' is not an AWS::CloudFormation::Stack resource`); + } + } + /** @internal */ public _toCloudFormation(): object { const ret: { [section: string]: any } = {}; @@ -410,7 +447,9 @@ export class CfnInclude extends core.CfnElement { return self.parameters[refTarget]; }, findResource() { throw new Error('Using GetAtt expressions in Rule definitions is not allowed'); }, - findCondition() { throw new Error('Referring to Conditions in Rule definitions is not allowed'); }, + findCondition(conditionName: string): core.CfnCondition | undefined { + return self.conditions[conditionName]; + }, findMapping(mappingName: string): core.CfnMapping | undefined { return self.mappings[mappingName]; }, @@ -477,8 +516,8 @@ export class CfnInclude extends core.CfnElement { findRefTarget(elementName: string): core.CfnElement | undefined { return self.resources[elementName] ?? self.parameters[elementName]; }, - findCondition(): undefined { - return undefined; + findCondition(conditionName: string): core.CfnCondition | undefined { + return self.conditions[conditionName]; }, findMapping(mappingName): core.CfnMapping | undefined { return self.mappings[mappingName]; @@ -550,12 +589,12 @@ export class CfnInclude extends core.CfnElement { // fail early for resource attributes we don't support yet const knownAttributes = [ - 'Type', 'Properties', 'Condition', 'DependsOn', 'Metadata', + 'Type', 'Properties', 'Condition', 'DependsOn', 'Metadata', 'Version', 'CreationPolicy', 'UpdatePolicy', 'DeletionPolicy', 'UpdateReplacePolicy', ]; for (const attribute of Object.keys(resourceAttributes)) { if (!knownAttributes.includes(attribute)) { - throw new Error(`The ${attribute} resource attribute is not supported by cloudformation-include yet. ` + + throw new Error(`The '${attribute}' resource attribute is not supported by cloudformation-include yet. ` + 'Either remove it from the template, or use the CdkInclude class from the core package instead.'); } } @@ -595,7 +634,11 @@ export class CfnInclude extends core.CfnElement { l1Instance = this.createNestedStack(logicalId, cfnParser); } else { const l1ClassFqn = cfn_type_to_l1_mapping.lookup(resourceAttributes.Type); - if (l1ClassFqn) { + // The AWS::CloudFormation::CustomResource type corresponds to the CfnCustomResource class. + // Unfortunately, it's quite useless; it only has a single property, ServiceToken. + // For that reason, even the CustomResource class from @core doesn't use it! + // So, special-case the handling of this one resource type + if (l1ClassFqn && resourceAttributes.Type !== 'AWS::CloudFormation::CustomResource') { const options: cfn_parse.FromCloudFormationOptions = { parser: cfnParser, }; diff --git a/packages/@aws-cdk/cloudformation-include/lib/file-utils.ts b/packages/@aws-cdk/cloudformation-include/lib/file-utils.ts index e78a6e46bde8a..2eb24e7013d93 100644 --- a/packages/@aws-cdk/cloudformation-include/lib/file-utils.ts +++ b/packages/@aws-cdk/cloudformation-include/lib/file-utils.ts @@ -1,7 +1,5 @@ import * as fs from 'fs'; -import * as yaml from 'yaml'; -import * as yaml_cst from 'yaml/parse-cst'; -import * as yaml_types from 'yaml/types'; +import * as yaml_cfn from '@aws-cdk/yaml-cfn'; export function readJsonSync(filePath: string): any { const fileContents = fs.readFileSync(filePath); @@ -10,62 +8,5 @@ export function readJsonSync(filePath: string): any { export function readYamlSync(filePath: string): any { const fileContents = fs.readFileSync(filePath); - return parseYamlStrWithCfnTags(fileContents.toString()); -} - -function makeTagForCfnIntrinsic( - intrinsicName: string, addFnPrefix: boolean = true, - resolveFun?: (_doc: yaml.Document, cstNode: yaml_cst.CST.Node) => any): yaml_types.Schema.CustomTag { - - return { - identify(value: any) { return typeof value === 'string'; }, - tag: `!${intrinsicName}`, - resolve: resolveFun || ((_doc: yaml.Document, cstNode: yaml_cst.CST.Node) => { - const ret: any = {}; - ret[addFnPrefix ? `Fn::${intrinsicName}` : intrinsicName] = - // the +1 is to account for the ! the short form begins with - parseYamlStrWithCfnTags(cstNode.toString().substring(intrinsicName.length + 1)); - return ret; - }), - }; -} - -const shortForms: yaml_types.Schema.CustomTag[] = [ - 'Base64', 'Cidr', 'FindInMap', 'GetAZs', 'ImportValue', 'Join', 'Sub', - 'Select', 'Split', 'Transform', 'And', 'Equals', 'If', 'Not', 'Or', -].map(name => makeTagForCfnIntrinsic(name)).concat( - makeTagForCfnIntrinsic('Ref', false), - makeTagForCfnIntrinsic('Condition', false), - makeTagForCfnIntrinsic('GetAtt', true, (_doc: yaml.Document, cstNode: yaml_cst.CST.Node): any => { - const parsedArguments = parseYamlStrWithCfnTags(cstNode.toString().substring('!GetAtt'.length)); - - let value: any; - if (typeof parsedArguments === 'string') { - // if the arguments to !GetAtt are a string, - // the part before the first '.' is the logical ID, - // and the rest is the attribute name - // (which can contain '.') - const firstDot = parsedArguments.indexOf('.'); - if (firstDot === -1) { - throw new Error(`Short-form Fn::GetAtt must contain a '.' in its string argument, got: '${parsedArguments}'`); - } - value = [ - parsedArguments.substring(0, firstDot), - parsedArguments.substring(firstDot + 1), // the + 1 is to skip the actual '.' - ]; - } else { - // this is the form where the arguments to Fn::GetAtt are already an array - - // in this case, nothing more to do - value = parsedArguments; - } - - return { 'Fn::GetAtt': value }; - }), -); - -function parseYamlStrWithCfnTags(text: string): any { - return yaml.parse(text, { - customTags: shortForms, - schema: 'yaml-1.1', - }); + return yaml_cfn.deserialize(fileContents.toString()); } diff --git a/packages/@aws-cdk/cloudformation-include/package.json b/packages/@aws-cdk/cloudformation-include/package.json index 8383cae076334..6aaf21ef1ff8d 100644 --- a/packages/@aws-cdk/cloudformation-include/package.json +++ b/packages/@aws-cdk/cloudformation-include/package.json @@ -68,6 +68,7 @@ "@aws-cdk/aws-apigatewayv2": "0.0.0", "@aws-cdk/aws-appconfig": "0.0.0", "@aws-cdk/aws-applicationautoscaling": "0.0.0", + "@aws-cdk/aws-applicationinsights": "0.0.0", "@aws-cdk/aws-appmesh": "0.0.0", "@aws-cdk/aws-appstream": "0.0.0", "@aws-cdk/aws-appsync": "0.0.0", @@ -89,6 +90,7 @@ "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-codedeploy": "0.0.0", "@aws-cdk/aws-codeguruprofiler": "0.0.0", + "@aws-cdk/aws-codegurureviewer": "0.0.0", "@aws-cdk/aws-codepipeline": "0.0.0", "@aws-cdk/aws-codestar": "0.0.0", "@aws-cdk/aws-codestarconnections": "0.0.0", @@ -134,6 +136,7 @@ "@aws-cdk/aws-kinesis": "0.0.0", "@aws-cdk/aws-kinesisanalytics": "0.0.0", "@aws-cdk/aws-kinesisfirehose": "0.0.0", + "@aws-cdk/aws-kendra": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-lakeformation": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", @@ -170,6 +173,7 @@ "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", + "@aws-cdk/aws-sso": "0.0.0", "@aws-cdk/aws-stepfunctions": "0.0.0", "@aws-cdk/aws-synthetics": "0.0.0", "@aws-cdk/aws-transfer": "0.0.0", @@ -178,7 +182,7 @@ "@aws-cdk/aws-wafv2": "0.0.0", "@aws-cdk/aws-workspaces": "0.0.0", "@aws-cdk/core": "0.0.0", - "yaml": "1.10.0" + "@aws-cdk/yaml-cfn": "0.0.0" }, "peerDependencies": { "@aws-cdk/alexa-ask": "0.0.0", @@ -190,6 +194,7 @@ "@aws-cdk/aws-apigatewayv2": "0.0.0", "@aws-cdk/aws-appconfig": "0.0.0", "@aws-cdk/aws-applicationautoscaling": "0.0.0", + "@aws-cdk/aws-applicationinsights": "0.0.0", "@aws-cdk/aws-appmesh": "0.0.0", "@aws-cdk/aws-appstream": "0.0.0", "@aws-cdk/aws-appsync": "0.0.0", @@ -211,6 +216,7 @@ "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-codedeploy": "0.0.0", "@aws-cdk/aws-codeguruprofiler": "0.0.0", + "@aws-cdk/aws-codegurureviewer": "0.0.0", "@aws-cdk/aws-codepipeline": "0.0.0", "@aws-cdk/aws-codestar": "0.0.0", "@aws-cdk/aws-codestarconnections": "0.0.0", @@ -253,6 +259,7 @@ "@aws-cdk/aws-iotanalytics": "0.0.0", "@aws-cdk/aws-iotevents": "0.0.0", "@aws-cdk/aws-iotthingsgraph": "0.0.0", + "@aws-cdk/aws-kendra": "0.0.0", "@aws-cdk/aws-kinesis": "0.0.0", "@aws-cdk/aws-kinesisanalytics": "0.0.0", "@aws-cdk/aws-kinesisfirehose": "0.0.0", @@ -292,6 +299,7 @@ "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", + "@aws-cdk/aws-sso": "0.0.0", "@aws-cdk/aws-stepfunctions": "0.0.0", "@aws-cdk/aws-synthetics": "0.0.0", "@aws-cdk/aws-transfer": "0.0.0", @@ -300,21 +308,18 @@ "@aws-cdk/aws-wafv2": "0.0.0", "@aws-cdk/aws-workspaces": "0.0.0", "@aws-cdk/core": "0.0.0", + "@aws-cdk/yaml-cfn": "0.0.0", "constructs": "^3.0.4" }, "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/jest": "^26.0.10", - "@types/yaml": "1.2.0", + "@types/jest": "^26.0.14", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", - "jest": "^25.4.0", + "jest": "^26.4.2", "pkglint": "0.0.0", - "ts-jest": "^26.2.0" + "ts-jest": "^26.3.0" }, - "bundledDependencies": [ - "yaml" - ], "keywords": [ "aws", "cdk", @@ -332,11 +337,11 @@ }, "awslint": { "exclude": [ - "props-no-cfn-types:@aws-cdk/cloudformation-include.CfnIncludeProps.nestedStacks" + "props-no-cfn-types:@aws-cdk/cloudformation-include.CfnIncludeProps.loadNestedStacks" ] }, "stability": "experimental", - "maturity": "experimental", + "maturity": "developer-preview", "awscdkio": { "announce": false } diff --git a/packages/@aws-cdk/cloudformation-include/test/integ.nested-stacks.ts b/packages/@aws-cdk/cloudformation-include/test/integ.nested-stacks.ts index 5ccd876c328db..11d2391e06582 100644 --- a/packages/@aws-cdk/cloudformation-include/test/integ.nested-stacks.ts +++ b/packages/@aws-cdk/cloudformation-include/test/integ.nested-stacks.ts @@ -7,7 +7,7 @@ const stack = new core.Stack(app, 'ParentStack'); new inc.CfnInclude(stack, 'ParentStack', { templateFile: 'test-templates/nested/parent-one-child.json', - nestedStacks: { + loadNestedStacks: { ChildStack: { templateFile: 'test-templates/nested/grandchild-import-stack.json', }, diff --git a/packages/@aws-cdk/cloudformation-include/test/invalid-templates.test.ts b/packages/@aws-cdk/cloudformation-include/test/invalid-templates.test.ts index 17bf6b9a3261e..5c901dc3f1bf2 100644 --- a/packages/@aws-cdk/cloudformation-include/test/invalid-templates.test.ts +++ b/packages/@aws-cdk/cloudformation-include/test/invalid-templates.test.ts @@ -80,7 +80,7 @@ describe('CDK Include', () => { test('throws a validation exception when encountering an unrecognized resource attribute', () => { expect(() => { includeTestTemplate(stack, 'non-existent-resource-attribute.json'); - }).toThrow(/The NonExistentResourceAttribute resource attribute is not supported by cloudformation-include yet/); + }).toThrow(/The 'NonExistentResourceAttribute' resource attribute is not supported by cloudformation-include yet/); }); test("throws a validation exception when encountering a Ref-erence to a template element that doesn't exist", () => { diff --git a/packages/@aws-cdk/cloudformation-include/test/nested-stacks.test.ts b/packages/@aws-cdk/cloudformation-include/test/nested-stacks.test.ts index 69ce97dcca07d..bf729dcedd38b 100644 --- a/packages/@aws-cdk/cloudformation-include/test/nested-stacks.test.ts +++ b/packages/@aws-cdk/cloudformation-include/test/nested-stacks.test.ts @@ -19,7 +19,7 @@ describe('CDK Include for nested stacks', () => { test('can ingest a template with one child', () => { const parentTemplate = new inc.CfnInclude(stack, 'ParentStack', { templateFile: testTemplateFilePath('parent-one-child.json'), - nestedStacks: { + loadNestedStacks: { 'ChildStack': { templateFile: testTemplateFilePath('grandchild-import-stack.json'), }, @@ -35,7 +35,7 @@ describe('CDK Include for nested stacks', () => { test('can ingest a template with two children', () => { const parentTemplate = new inc.CfnInclude(stack, 'ParentStack', { templateFile: testTemplateFilePath('parent-two-children.json'), - nestedStacks: { + loadNestedStacks: { 'ChildStack': { templateFile: testTemplateFilePath('grandchild-import-stack.json'), }, @@ -59,10 +59,10 @@ describe('CDK Include for nested stacks', () => { test('can ingest a template with one child and one grandchild', () => { const parentTemplate = new inc.CfnInclude(stack, 'ParentStack', { templateFile: testTemplateFilePath('parent-two-children.json'), - nestedStacks: { + loadNestedStacks: { 'ChildStack': { templateFile: testTemplateFilePath('child-import-stack.json'), - nestedStacks: { + loadNestedStacks: { 'GrandChildStack': { templateFile: testTemplateFilePath('grandchild-import-stack.json'), }, @@ -86,7 +86,7 @@ describe('CDK Include for nested stacks', () => { expect(() => { new inc.CfnInclude(stack, 'ParentStack', { templateFile: testTemplateFilePath('parent-two-children.json'), - nestedStacks: { + loadNestedStacks: { 'FakeStack': { templateFile: testTemplateFilePath('child-import-stack.json'), }, @@ -99,7 +99,7 @@ describe('CDK Include for nested stacks', () => { expect(() => { new inc.CfnInclude(stack, 'ParentStack', { templateFile: testTemplateFilePath('child-import-stack.json'), - nestedStacks: { + loadNestedStacks: { 'BucketImport': { templateFile: testTemplateFilePath('grandchild-import-stack.json'), }, @@ -112,7 +112,7 @@ describe('CDK Include for nested stacks', () => { expect(() => { new inc.CfnInclude(stack, 'ParentStack', { templateFile: testTemplateFilePath('parent-creation-policy.json'), - nestedStacks: { + loadNestedStacks: { 'ChildStack': { templateFile: testTemplateFilePath('grandchild-import-stack.json'), }, @@ -125,7 +125,7 @@ describe('CDK Include for nested stacks', () => { expect(() => { new inc.CfnInclude(stack, 'ParentStack', { templateFile: testTemplateFilePath('parent-update-policy.json'), - nestedStacks: { + loadNestedStacks: { 'ChildStack': { templateFile: testTemplateFilePath('grandchild-import-stack.json'), }, @@ -138,7 +138,7 @@ describe('CDK Include for nested stacks', () => { expect(() => { new inc.CfnInclude(stack, 'ParentStack', { templateFile: testTemplateFilePath('parent-invalid-condition.json'), - nestedStacks: { + loadNestedStacks: { 'ChildStack': { templateFile: testTemplateFilePath('grandchild-import-stack.json'), }, @@ -151,7 +151,7 @@ describe('CDK Include for nested stacks', () => { expect(() => { new inc.CfnInclude(stack, 'ParentStack', { templateFile: testTemplateFilePath('parent-bad-depends-on.json'), - nestedStacks: { + loadNestedStacks: { 'ChildStack': { templateFile: testTemplateFilePath('child-import-stack.json'), }, @@ -160,11 +160,11 @@ describe('CDK Include for nested stacks', () => { }).toThrow(/Resource 'ChildStack' depends on 'AFakeResource' that doesn't exist/); }); - test('throws an exception when an ID was passed in nestedStacks that is a resource type not in the CloudFormation schema', () => { + test('throws an exception when an ID was passed in loadNestedStacks that is a resource type not in the CloudFormation schema', () => { expect(() => { new inc.CfnInclude(stack, 'Template', { templateFile: testTemplateFilePath('custom-resource.json'), - nestedStacks: { + loadNestedStacks: { 'CustomResource': { templateFile: testTemplateFilePath('whatever.json'), }, @@ -176,7 +176,7 @@ describe('CDK Include for nested stacks', () => { test('can modify resources in nested stacks', () => { const parent = new inc.CfnInclude(stack, 'ParentStack', { templateFile: testTemplateFilePath('child-import-stack.json'), - nestedStacks: { + loadNestedStacks: { 'GrandChildStack': { templateFile: testTemplateFilePath('grandchild-import-stack.json'), }, @@ -194,7 +194,7 @@ describe('CDK Include for nested stacks', () => { test('can use a condition', () => { const parent = new inc.CfnInclude(stack, 'ParentStack', { templateFile: testTemplateFilePath('parent-valid-condition.json'), - nestedStacks: { + loadNestedStacks: { 'ChildStack': { templateFile: testTemplateFilePath('grandchild-import-stack.json'), }, @@ -209,7 +209,7 @@ describe('CDK Include for nested stacks', () => { test('asset parameters generated in parent and child are identical', () => { new inc.CfnInclude(stack, 'ParentStack', { templateFile: testTemplateFilePath('parent-one-child.json'), - nestedStacks: { + loadNestedStacks: { 'ChildStack': { templateFile: testTemplateFilePath('grandchild-import-stack.json'), }, @@ -279,7 +279,7 @@ describe('CDK Include for nested stacks', () => { }); }); - test('templates with nested stacks that were not provided in the nestedStacks property are left unmodified', () => { + test('templates with nested stacks that were not provided in the loadNestedStacks property are left unmodified', () => { new inc.CfnInclude(stack, 'ParentStack', { templateFile: testTemplateFilePath('parent-two-children.json'), }); @@ -290,7 +290,7 @@ describe('CDK Include for nested stacks', () => { test('getNestedStack() throws an exception when getting a resource that does not exist in the template', () => { const parentTemplate = new inc.CfnInclude(stack, 'ParentStack', { templateFile: testTemplateFilePath('parent-two-children.json'), - nestedStacks: { + loadNestedStacks: { 'ChildStack': { templateFile: testTemplateFilePath('child-import-stack.json'), }, @@ -305,7 +305,7 @@ describe('CDK Include for nested stacks', () => { test('getNestedStack() throws an exception when getting a resource that exists in the template, but is not a Stack', () => { const parentTemplate = new inc.CfnInclude(stack, 'ParentStack', { templateFile: testTemplateFilePath('parent-two-children.json'), - nestedStacks: { + loadNestedStacks: { 'ChildStack': { templateFile: testTemplateFilePath('child-import-stack.json'), }, @@ -319,10 +319,10 @@ describe('CDK Include for nested stacks', () => { }).toThrow(/Resource with logical ID 'BucketImport' is not a CloudFormation Stack/); }); - test('getNestedStack() throws an exception when getting a resource that exists in the template, but was not specified in the props', () => { + test('getNestedStack() throws an exception when getting a nested stack that exists in the template, but was not specified in the props', () => { const parentTemplate = new inc.CfnInclude(stack, 'ParentStack', { templateFile: testTemplateFilePath('parent-two-children.json'), - nestedStacks: { + loadNestedStacks: { 'ChildStack': { templateFile: testTemplateFilePath('child-import-stack.json'), }, @@ -331,13 +331,13 @@ describe('CDK Include for nested stacks', () => { expect(() => { parentTemplate.getNestedStack('AnotherChildStack'); - }).toThrow(/Nested Stack 'AnotherChildStack' was not included in the nestedStacks property when including the parent template/); + }).toThrow(/Nested Stack 'AnotherChildStack' was not included in the parent template/); }); test('correctly handles renaming of references across nested stacks', () => { const parentTemplate = new inc.CfnInclude(stack, 'ParentStack', { templateFile: testTemplateFilePath('cross-stack-refs.json'), - nestedStacks: { + loadNestedStacks: { 'ChildStack': { templateFile: testTemplateFilePath('child-import-stack.json'), }, @@ -360,7 +360,7 @@ describe('CDK Include for nested stacks', () => { }); }); - test('returns the CfnStack object from getResource() for a nested stack that was not in the nestedStacks property', () => { + test('returns the CfnStack object from getResource() for a nested stack that was not in the loadNestedStacks property', () => { const cfnTemplate = new inc.CfnInclude(stack, 'ParentStack', { templateFile: testTemplateFilePath('parent-two-children.json'), }); @@ -370,10 +370,10 @@ describe('CDK Include for nested stacks', () => { expect(childStack1).toBeInstanceOf(core.CfnStack); }); - test('returns the CfnStack object from getResource() for a nested stack that was in the nestedStacks property', () => { + test('returns the CfnStack object from getResource() for a nested stack that was in the loadNestedStacks property', () => { const cfnTemplate = new inc.CfnInclude(stack, 'ParentStack', { templateFile: testTemplateFilePath('parent-one-child.json'), - nestedStacks: { + loadNestedStacks: { 'ChildStack': { templateFile: testTemplateFilePath('child-import-stack.json'), }, @@ -388,7 +388,7 @@ describe('CDK Include for nested stacks', () => { test("handles Metadata, DeletionPolicy, and UpdateReplacePolicy attributes of the nested stack's resource", () => { const cfnTemplate = new inc.CfnInclude(stack, 'ParentStack', { templateFile: testTemplateFilePath('parent-with-attributes.json'), - nestedStacks: { + loadNestedStacks: { 'ChildStack': { templateFile: testTemplateFilePath('child-import-stack.json'), }, @@ -424,6 +424,20 @@ describe('CDK Include for nested stacks', () => { }); }); + test('can lazily include a single child nested stack', () => { + const parentTemplate = new inc.CfnInclude(stack, 'ParentStack', { + templateFile: testTemplateFilePath('parent-one-child.json'), + }); + const includedChild = parentTemplate.loadNestedStack('ChildStack', { + templateFile: testTemplateFilePath('child-no-bucket.json'), + }); + + expect(includedChild.stack).toMatchTemplate( + loadTestFileToJsObject('child-no-bucket.json'), + ); + expect(includedChild.includedTemplate.getResource('GrandChildStack')).toBeDefined(); + }); + describe('for a parent stack with children and grandchildren', () => { let assetStack: core.Stack; let parentTemplate: inc.CfnInclude; @@ -442,10 +456,10 @@ describe('CDK Include for nested stacks', () => { assetStack = new core.Stack(); parentTemplate = new inc.CfnInclude(assetStack, 'ParentStack', { templateFile: testTemplateFilePath('parent-one-child.json'), - nestedStacks: { + loadNestedStacks: { 'ChildStack': { templateFile: testTemplateFilePath('child-no-bucket.json'), - nestedStacks: { + loadNestedStacks: { 'GrandChildStack': { templateFile: testTemplateFilePath('grandchild-import-stack.json'), }, @@ -621,7 +635,7 @@ describe('CDK Include for nested stacks', () => { parentStack = new core.Stack(); const parentTemplate = new inc.CfnInclude(parentStack, 'ParentStack', { templateFile: testTemplateFilePath('parent-two-parameters.json'), - nestedStacks: { + loadNestedStacks: { 'ChildStack': { templateFile: testTemplateFilePath('child-two-parameters.json'), parameters: { diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/custom-resource-with-attributes.json b/packages/@aws-cdk/cloudformation-include/test/test-templates/custom-resource-with-attributes.json index b99e4cc2c0eea..c490a16515944 100644 --- a/packages/@aws-cdk/cloudformation-include/test/test-templates/custom-resource-with-attributes.json +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/custom-resource-with-attributes.json @@ -13,6 +13,7 @@ "CustomBucket": { "Type": "AWS::MyService::Custom", "Condition": "AlwaysFalseCond", + "Version": "1.0", "Metadata": { "Object1": "Value1", "Object2": "Value2" @@ -26,9 +27,9 @@ "DependsOn": [ "CustomResource" ] }, "CustomResource": { - "Type": "AWS::MyService::AnotherCustom", + "Type": "AWS::CloudFormation::CustomResource", "Properties": { - "CustomProp": "CustomValue", + "ServiceToken": "CustomValue", "CustomFuncProp": { "Ref": "AWS::NoValue" } diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/fn-sub-map-dotted-attributes.json b/packages/@aws-cdk/cloudformation-include/test/test-templates/fn-sub-map-dotted-attributes.json index 5bc772b8f5860..c53229d2844d8 100644 --- a/packages/@aws-cdk/cloudformation-include/test/test-templates/fn-sub-map-dotted-attributes.json +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/fn-sub-map-dotted-attributes.json @@ -14,6 +14,7 @@ "AvailabilityZones": [ "us-east-1a" ], + "CrossZone": "true", "Listeners": [{ "LoadBalancerPort": "80", "InstancePort": "80", diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/only-empty-bucket-with-parameters.json b/packages/@aws-cdk/cloudformation-include/test/test-templates/only-empty-bucket-with-parameters.json index 66c92f4e4de41..efab5517fdbff 100644 --- a/packages/@aws-cdk/cloudformation-include/test/test-templates/only-empty-bucket-with-parameters.json +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/only-empty-bucket-with-parameters.json @@ -16,7 +16,11 @@ "Outputs": { "Output1": { "Value": { - "Fn::Base64": "Output1Value" + "Fn::If": [ + "Cond1", + { "Fn::Base64": "Output1Value" }, + { "Fn::GetAtt": ["Bucket", "DualStackDomainName"] } + ] } } }, diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/only-parameters-and-rule.json b/packages/@aws-cdk/cloudformation-include/test/test-templates/only-parameters-and-rule.json index 1cd9abf797acc..d1d15650f5113 100644 --- a/packages/@aws-cdk/cloudformation-include/test/test-templates/only-parameters-and-rule.json +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/only-parameters-and-rule.json @@ -7,12 +7,26 @@ "Type": "List" } }, + "Conditions": { + "IsProduction": { + "Fn::Equals": [ + { "Ref": "Env" }, + "prod" + ] + } + }, "Rules": { "TestVpcRule": { "RuleCondition": { - "Fn::Contains": [ - ["test", "pre-prod", "preprod"], - { "Ref": "Env" } + "Fn::If": [ + "IsProduction", + true, + { + "Fn::Contains": [ + ["test", "pre-prod", "preprod"], + { "Ref": "Env" } + ] + } ] }, "Assertions": [ diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/resource-attribute-update-policy.json b/packages/@aws-cdk/cloudformation-include/test/test-templates/resource-attribute-update-policy.json index e1440a46193be..fb1f6f2aab1b2 100644 --- a/packages/@aws-cdk/cloudformation-include/test/test-templates/resource-attribute-update-policy.json +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/resource-attribute-update-policy.json @@ -53,7 +53,7 @@ "BeforeAllowTrafficHook" : "Lambda2", "DeploymentGroupName" : { "Ref": "CodeDeployDg" } }, - "EnableVersionUpgrade": true, + "EnableVersionUpgrade": "true", "UseOnlineResharding": false } } diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/ssm-association.json b/packages/@aws-cdk/cloudformation-include/test/test-templates/ssm-association.json new file mode 100644 index 0000000000000..5b115bff34b5b --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/ssm-association.json @@ -0,0 +1,14 @@ +{ + "Resources": { + "Association": { + "Type": "AWS::SSM::Association", + "Properties": { + "Name": "association", + "Parameters": { + "P1": ["a", "b"], + "p2": [] + } + } + } + } +} diff --git a/packages/@aws-cdk/cloudformation-include/test/valid-templates.test.ts b/packages/@aws-cdk/cloudformation-include/test/valid-templates.test.ts index 9e9d41284d8b7..7394ada485266 100644 --- a/packages/@aws-cdk/cloudformation-include/test/valid-templates.test.ts +++ b/packages/@aws-cdk/cloudformation-include/test/valid-templates.test.ts @@ -3,6 +3,7 @@ import { ResourcePart } from '@aws-cdk/assert'; import '@aws-cdk/assert/jest'; import * as iam from '@aws-cdk/aws-iam'; import * as s3 from '@aws-cdk/aws-s3'; +import * as ssm from '@aws-cdk/aws-ssm'; import * as core from '@aws-cdk/core'; import * as inc from '../lib'; import * as futils from '../lib/file-utils'; @@ -213,6 +214,16 @@ describe('CDK Include', () => { ); }); + test('can correctly ingest a resource with a property of type: Map of Lists of primitive types', () => { + const cfnTemplate = includeTestTemplate(stack, 'ssm-association.json'); + + expect(stack).toMatchTemplate( + loadTestFileToJsObject('ssm-association.json'), + ); + const association = cfnTemplate.getResource('Association') as ssm.CfnAssociation; + expect(Object.keys(association.parameters as any)).toHaveLength(2); + }); + test('can ingest a template with intrinsic functions and conditions, and output it unchanged', () => { includeTestTemplate(stack, 'functions-and-conditions.json'); diff --git a/packages/@aws-cdk/core/lib/asset-staging.ts b/packages/@aws-cdk/core/lib/asset-staging.ts index 6ab46cb987f1d..e5878c2a31365 100644 --- a/packages/@aws-cdk/core/lib/asset-staging.ts +++ b/packages/@aws-cdk/core/lib/asset-staging.ts @@ -7,6 +7,7 @@ import { AssetHashType, AssetOptions } from './assets'; import { BundlingOptions } from './bundling'; import { Construct } from './construct-compat'; import { FileSystem, FingerprintOptions } from './fs'; +import { Stack } from './stack'; import { Stage } from './stage'; /** @@ -97,16 +98,26 @@ export class AssetStaging extends Construct { const hashType = determineHashType(props.assetHashType, props.assetHash); if (props.bundling) { - // Determine the source hash in advance of bundling if the asset hash type - // is SOURCE so that the bundler can opt to re-use its previous output. - const sourceHash = hashType === AssetHashType.SOURCE - ? this.calculateHash(hashType, props.assetHash, props.bundling) - : undefined; - - this.bundleDir = this.bundle(props.bundling, outdir, sourceHash); - this.assetHash = sourceHash ?? this.calculateHash(hashType, props.assetHash, props.bundling); - this.relativePath = renderAssetFilename(this.assetHash); - this.stagedPath = this.relativePath; + // Check if we actually have to bundle for this stack + const bundlingStacks: string[] = this.node.tryGetContext(cxapi.BUNDLING_STACKS) ?? ['*']; + const runBundling = bundlingStacks.includes(Stack.of(this).stackName) || bundlingStacks.includes('*'); + if (runBundling) { + // Determine the source hash in advance of bundling if the asset hash type + // is SOURCE so that the bundler can opt to re-use its previous output. + const sourceHash = hashType === AssetHashType.SOURCE + ? this.calculateHash(hashType, props.assetHash, props.bundling) + : undefined; + + this.bundleDir = this.bundle(props.bundling, outdir, sourceHash); + this.assetHash = sourceHash ?? this.calculateHash(hashType, props.assetHash, props.bundling); + this.relativePath = renderAssetFilename(this.assetHash); + this.stagedPath = this.relativePath; + } else { // Bundling is skipped + this.assetHash = props.assetHashType === AssetHashType.BUNDLE || props.assetHashType === AssetHashType.OUTPUT + ? this.calculateHash(AssetHashType.CUSTOM, this.node.path) // Use node path as dummy hash because we're not bundling + : this.calculateHash(hashType, props.assetHash); + this.stagedPath = this.sourcePath; + } } else { this.assetHash = this.calculateHash(hashType, props.assetHash); @@ -284,8 +295,9 @@ export class AssetStaging extends Construct { case AssetHashType.SOURCE: return FileSystem.fingerprint(this.sourcePath, this.fingerprintOptions); case AssetHashType.BUNDLE: + case AssetHashType.OUTPUT: if (!this.bundleDir) { - throw new Error('Cannot use `AssetHashType.BUNDLE` when `bundling` is not specified.'); + throw new Error(`Cannot use \`${hashType}\` hash type when \`bundling\` is not specified.`); } return FileSystem.fingerprint(this.bundleDir, this.fingerprintOptions); default: diff --git a/packages/@aws-cdk/core/lib/assets.ts b/packages/@aws-cdk/core/lib/assets.ts index 012b7da4d489c..17d3b9d93e53f 100644 --- a/packages/@aws-cdk/core/lib/assets.ts +++ b/packages/@aws-cdk/core/lib/assets.ts @@ -60,18 +60,35 @@ export interface AssetOptions { /** * The type of asset hash + * + * NOTE: the hash is used in order to identify a specific revision of the asset, and + * used for optimizing and caching deployment activities related to this asset such as + * packaging, uploading to Amazon S3, etc. */ export enum AssetHashType { /** * Based on the content of the source path + * + * When bundling, use `SOURCE` when the content of the bundling output is not + * stable across repeated bundling operations. */ SOURCE = 'source', /** * Based on the content of the bundled path + * + * @deprecated use `OUTPUT` instead */ BUNDLE = 'bundle', + /** + * Based on the content of the bundling output + * + * Use `OUTPUT` when the source of the asset is a top level folder containing + * code and/or dependencies that are not directly linked to the asset. + */ + OUTPUT = 'output', + /** * Use a custom hash */ diff --git a/packages/@aws-cdk/core/lib/cfn-fn.ts b/packages/@aws-cdk/core/lib/cfn-fn.ts index d2967779b08b3..b05d41968a909 100644 --- a/packages/@aws-cdk/core/lib/cfn-fn.ts +++ b/packages/@aws-cdk/core/lib/cfn-fn.ts @@ -134,6 +134,15 @@ export class Fn { return Token.asList(new FnCidr(ipBlock, count, sizeMask)); } + /** + * Given an url, parse the domain name + * @param url the url to parse + */ + public static parseDomainName(url: string): string { + const noHttps = Fn.select(1, Fn.split('//', url)); + return Fn.select(0, Fn.split('/', noHttps)); + } + /** * The intrinsic function ``Fn::GetAZs`` returns an array that lists * Availability Zones for a specified region. Because customers have access to diff --git a/packages/@aws-cdk/core/lib/cfn-parameter.ts b/packages/@aws-cdk/core/lib/cfn-parameter.ts index 6226f451c2fb8..c9f219d17ae72 100644 --- a/packages/@aws-cdk/core/lib/cfn-parameter.ts +++ b/packages/@aws-cdk/core/lib/cfn-parameter.ts @@ -289,8 +289,8 @@ export class CfnParameter extends CfnElement { * The parameter value, if it represents a string. */ public get valueAsString(): string { - if (!isStringType(this.type)) { - throw new Error(`Parameter type (${this.type}) is not a string type`); + if (!isStringType(this.type) && !isNumberType(this.type)) { + throw new Error(`Parameter type (${this.type}) is not a string or number type`); } return Token.asString(this.value); } diff --git a/packages/@aws-cdk/core/lib/cfn-parse.ts b/packages/@aws-cdk/core/lib/cfn-parse.ts index 742880f615e1b..7a18378556b9d 100644 --- a/packages/@aws-cdk/core/lib/cfn-parse.ts +++ b/packages/@aws-cdk/core/lib/cfn-parse.ts @@ -32,9 +32,20 @@ export class FromCloudFormation { // nothing to for any but return it public static getAny(value: any) { return value; } - // nothing to do - if 'value' is not a boolean or a Token, - // a validator should report that at runtime - public static getBoolean(value: any): boolean | IResolvable { return value; } + public static getBoolean(value: any): boolean | IResolvable { + if (typeof value === 'string') { + // CloudFormation allows passing strings as boolean + switch (value) { + case 'true': return true; + case 'false': return false; + default: throw new Error(`Expected 'true' or 'false' for boolean value, got: '${value}'`); + } + } + + // in all other cases, just return the value, + // and let a validator handle if it's not a boolean + return value; + } public static getDate(value: any): Date | IResolvable { // if the date is a deploy-time value, just return it @@ -80,9 +91,8 @@ export class FromCloudFormation { } // return a number, if the input can be parsed as one - let parsedValue; if (typeof value === 'string') { - parsedValue = parseFloat(value); + const parsedValue = parseFloat(value); if (!isNaN(parsedValue)) { return parsedValue; } @@ -274,6 +284,7 @@ export class CfnParser { cfnOptions.updatePolicy = this.parseUpdatePolicy(resourceAttributes.UpdatePolicy); cfnOptions.deletionPolicy = this.parseDeletionPolicy(resourceAttributes.DeletionPolicy); cfnOptions.updateReplacePolicy = this.parseDeletionPolicy(resourceAttributes.UpdateReplacePolicy); + cfnOptions.version = this.parseValue(resourceAttributes.Version); cfnOptions.metadata = this.parseValue(resourceAttributes.Metadata); // handle Condition @@ -338,8 +349,8 @@ export class CfnParser { autoScalingRollingUpdate: parseAutoScalingRollingUpdate(policy.AutoScalingRollingUpdate), autoScalingScheduledAction: parseAutoScalingScheduledAction(policy.AutoScalingScheduledAction), codeDeployLambdaAliasUpdate: parseCodeDeployLambdaAliasUpdate(policy.CodeDeployLambdaAliasUpdate), - enableVersionUpgrade: policy.EnableVersionUpgrade, - useOnlineResharding: policy.UseOnlineResharding, + enableVersionUpgrade: FromCloudFormation.getBoolean(policy.EnableVersionUpgrade), + useOnlineResharding: FromCloudFormation.getBoolean(policy.UseOnlineResharding), }); function parseAutoScalingReplacingUpdate(p: any): CfnAutoScalingReplacingUpdate | undefined { @@ -359,7 +370,7 @@ export class CfnParser { minSuccessfulInstancesPercent: FromCloudFormation.getNumber(p.MinSuccessfulInstancesPercent), pauseTime: FromCloudFormation.getString(p.PauseTime), suspendProcesses: FromCloudFormation.getStringArray(p.SuspendProcesses), - waitOnResourceSignals: p.WaitOnResourceSignals, + waitOnResourceSignals: FromCloudFormation.getBoolean(p.WaitOnResourceSignals), }); } diff --git a/packages/@aws-cdk/core/lib/cfn-resource.ts b/packages/@aws-cdk/core/lib/cfn-resource.ts index 9af3aa5c16a21..fcb1c95eaf5bb 100644 --- a/packages/@aws-cdk/core/lib/cfn-resource.ts +++ b/packages/@aws-cdk/core/lib/cfn-resource.ts @@ -300,6 +300,7 @@ export class CfnResource extends CfnRefElement { UpdatePolicy: capitalizePropertyNames(this, this.cfnOptions.updatePolicy), UpdateReplacePolicy: capitalizePropertyNames(this, this.cfnOptions.updateReplacePolicy), DeletionPolicy: capitalizePropertyNames(this, this.cfnOptions.deletionPolicy), + Version: this.cfnOptions.version, Metadata: ignoreEmpty(this.cfnOptions.metadata), Condition: this.cfnOptions.condition && this.cfnOptions.condition.logicalId, }, props => { @@ -429,6 +430,14 @@ export interface ICfnResourceOptions { */ updateReplacePolicy?: CfnDeletionPolicy; + /** + * The version of this resource. + * Used only for custom CloudFormation resources. + * + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cfn-customresource.html + */ + version?: string; + /** * Metadata associated with the CloudFormation resource. This is not the same as the construct metadata which can be added * using construct.addMetadata(), but would not appear in the CloudFormation template automatically. diff --git a/packages/@aws-cdk/core/lib/private/intrinsic.ts b/packages/@aws-cdk/core/lib/private/intrinsic.ts index f880162fa9015..88cbe6ee02af7 100644 --- a/packages/@aws-cdk/core/lib/private/intrinsic.ts +++ b/packages/@aws-cdk/core/lib/private/intrinsic.ts @@ -2,6 +2,20 @@ import { IResolvable, IResolveContext } from '../resolvable'; import { captureStackTrace } from '../stack-trace'; import { Token } from '../token'; +/** + * Customization properties for an Intrinsic token + * + * @experimental + */ +export interface IntrinsicProps { + /** + * Capture the stack trace of where this token is created + * + * @default true + */ + readonly stackTrace?: boolean; +} + /** * Token subclass that represents values intrinsic to the target document language * @@ -20,12 +34,12 @@ export class Intrinsic implements IResolvable { private readonly value: any; - constructor(value: any) { + constructor(value: any, options: IntrinsicProps = {}) { if (isFunction(value)) { throw new Error(`Argument to Intrinsic must be a plain value object, got ${value}`); } - this.creationStack = captureStackTrace(); + this.creationStack = options.stackTrace ?? true ? captureStackTrace() : []; this.value = value; } diff --git a/packages/@aws-cdk/core/lib/private/runtime-info.ts b/packages/@aws-cdk/core/lib/private/runtime-info.ts index 25fc3ccaf1818..0cc74d3c9f8f3 100644 --- a/packages/@aws-cdk/core/lib/private/runtime-info.ts +++ b/packages/@aws-cdk/core/lib/private/runtime-info.ts @@ -3,7 +3,7 @@ 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-solutions-konstruk', '@aws-solutions-constructs']; +const WHITELIST_SCOPES = ['@aws-cdk', '@aws-solutions-konstruk', '@aws-solutions-constructs', '@amzn']; // list of NPM packages included in version reporting const WHITELIST_PACKAGES = ['aws-rfdk']; diff --git a/packages/@aws-cdk/core/lib/util.ts b/packages/@aws-cdk/core/lib/util.ts index 7416189a33360..6924b197667af 100644 --- a/packages/@aws-cdk/core/lib/util.ts +++ b/packages/@aws-cdk/core/lib/util.ts @@ -80,7 +80,7 @@ export function filterUndefined(obj: any): any { */ export class PostResolveToken extends Intrinsic implements IPostProcessor { constructor(value: any, private readonly processor: (x: any) => any) { - super(value); + super(value, { stackTrace: false }); } public resolve(context: IResolveContext) { diff --git a/packages/@aws-cdk/core/package.json b/packages/@aws-cdk/core/package.json index 2b4572467a42d..3d64a2d8f03fd 100644 --- a/packages/@aws-cdk/core/package.json +++ b/packages/@aws-cdk/core/package.json @@ -156,14 +156,14 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/lodash": "^4.14.160", + "@types/lodash": "^4.14.161", "@types/minimatch": "^3.0.3", - "@types/node": "^10.17.28", + "@types/node": "^10.17.35", "@types/nodeunit": "^0.0.31", "@types/sinon": "^9.0.5", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "fast-check": "^1.26.0", + "fast-check": "^2.3.0", "lodash": "^4.17.20", "nodeunit": "^0.11.3", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/core/test/test.cfn-parameter.ts b/packages/@aws-cdk/core/test/test.cfn-parameter.ts new file mode 100644 index 0000000000000..a370b3948d401 --- /dev/null +++ b/packages/@aws-cdk/core/test/test.cfn-parameter.ts @@ -0,0 +1,32 @@ +import { Test } from 'nodeunit'; +import { CfnParameter, Stack } from '../lib'; + +export = { + 'valueAsString supports both string and number types'(test: Test) { + // GIVEN + const stack = new Stack(); + const numberParam = new CfnParameter(stack, 'numberParam', { type: 'Number', default: 10 }); + const stringParam = new CfnParameter(stack, 'stringParam', { type: 'String', default: 'a-default' }); + + // WHEN + const numVal = numberParam.valueAsString; + const strVal = stringParam.valueAsString; + + // THEN + test.deepEqual(stack.resolve(numVal), { Ref: 'numberParam' }); + test.deepEqual(stack.resolve(strVal), { Ref: 'stringParam' }); + + test.done(); + }, + + 'valueAsString fails for unsupported types'(test: Test) { + // GIVEN + const stack = new Stack(); + const listParam = new CfnParameter(stack, 'listParam', { type: 'List', default: 10 }); + + // WHEN - THEN + test.throws(() => listParam.valueAsList, /Parameter type \(List\)/); + + test.done(); + }, +} \ No newline at end of file diff --git a/packages/@aws-cdk/core/test/test.fn.ts b/packages/@aws-cdk/core/test/test.fn.ts index 8b5c7d7d68348..ec3f537ba0945 100644 --- a/packages/@aws-cdk/core/test/test.fn.ts +++ b/packages/@aws-cdk/core/test/test.fn.ts @@ -35,6 +35,24 @@ export = nodeunit.testCase({ test.done(); }, }, + 'FnParseDomainName': { + 'parse domain name from resolved url'(test: nodeunit.Test) { + test.deepEqual(Fn.parseDomainName('https://test.com/'), 'test.com'); + test.done(); + }, + 'parse domain name on token'(test: nodeunit.Test) { + const stack = new Stack(); + const url = Fn.join('//', [ + 'https:', + Fn.join('/', [ + 'test.com', + 'graphql', + ]), + ]); + test.deepEqual(Fn.parseDomainName(stack.resolve(url)), 'test.com'); + test.done(); + }, + }, 'FnJoin': { 'rejects empty list of arguments to join'(test: nodeunit.Test) { test.throws(() => Fn.join('.', [])); diff --git a/packages/@aws-cdk/core/test/test.staging.ts b/packages/@aws-cdk/core/test/test.staging.ts index 8b6c831231d8a..e652c884935f4 100644 --- a/packages/@aws-cdk/core/test/test.staging.ts +++ b/packages/@aws-cdk/core/test/test.staging.ts @@ -425,6 +425,28 @@ export = { test.done(); }, + 'bundling with OUTPUT asset hash type'(test: Test) { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'stack'); + const directory = path.join(__dirname, 'fs', 'fixtures', 'test1'); + + // WHEN + const asset = new AssetStaging(stack, 'Asset', { + sourcePath: directory, + bundling: { + image: BundlingDockerImage.fromRegistry('alpine'), + command: [DockerStubCommand.SUCCESS], + }, + assetHashType: AssetHashType.OUTPUT, + }); + + // THEN + test.equal(asset.assetHash, '33cbf2cae5432438e0f046bc45ba8c3cef7b6afcf47b59d1c183775c1918fb1f'); + + test.done(); + }, + 'custom hash'(test: Test) { // GIVEN const app = new App(); @@ -474,7 +496,23 @@ export = { test.throws(() => new AssetStaging(stack, 'Asset', { sourcePath: directory, assetHashType: AssetHashType.BUNDLE, - }), /Cannot use `AssetHashType.BUNDLE` when `bundling` is not specified/); + }), /Cannot use `bundle` hash type when `bundling` is not specified/); + test.equal(fs.existsSync(STUB_INPUT_FILE), false); + + test.done(); + }, + + 'throws with OUTPUT hash type and no bundling'(test: Test) { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'stack'); + const directory = path.join(__dirname, 'fs', 'fixtures', 'test1'); + + // THEN + test.throws(() => new AssetStaging(stack, 'Asset', { + sourcePath: directory, + assetHashType: AssetHashType.OUTPUT, + }), /Cannot use `output` hash type when `bundling` is not specified/); test.equal(fs.existsSync(STUB_INPUT_FILE), false); test.done(); @@ -580,6 +618,31 @@ export = { test.done(); }, + + 'bundling looks at bundling stacks in context'(test: Test) { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'MyStack'); + stack.node.setContext(cxapi.BUNDLING_STACKS, ['OtherStack']); + const directory = path.join(__dirname, 'fs', 'fixtures', 'test1'); + + // WHEN + const asset = new AssetStaging(stack, 'Asset', { + sourcePath: directory, + assetHashType: AssetHashType.BUNDLE, + bundling: { + image: BundlingDockerImage.fromRegistry('alpine'), + command: [DockerStubCommand.SUCCESS], + }, + }); + + test.throws(() => readDockerStubInput()); // Bundling did not run + test.equal(asset.assetHash, '3d96e735e26b857743a7c44523c9160c285c2d3ccf273d80fa38a1e674c32cb3'); // hash of MyStack/Asset + test.equal(asset.sourcePath, directory); + test.equal(stack.resolve(asset.stagedPath), directory); + + test.done(); + }, }; // Reads a docker stub and cleans the volume paths out of the stub. diff --git a/packages/@aws-cdk/custom-resources/README.md b/packages/@aws-cdk/custom-resources/README.md index 27356889bb848..44f9e01bef5e3 100644 --- a/packages/@aws-cdk/custom-resources/README.md +++ b/packages/@aws-cdk/custom-resources/README.md @@ -371,6 +371,31 @@ const awsCustom2 = new AwsCustomResource(this, 'API2', { }) ``` +### Physical Resource Id Parameter +Some AWS APIs may require passing the physical resource id in as a parameter for doing updates and deletes. You can pass it by using `PhysicalResourceIdReference`. + +``` +const awsCustom = new AwsCustomResource(this, '...', { + onCreate: { + service: '...', + action: '...' + parameters: { + text: '...' + }, + physicalResourceId: PhysicalResourceId.of('...') + }, + onUpdate: { + service: '...', + action: '...'. + parameters: { + text: '...', + resourceId: new PhysicalResourceIdReference() + } + }, + policy: AwsCustomResourcePolicy.fromSdkCalls({resources: AwsCustomResourcePolicy.ANY_RESOURCE}) +}) +``` + ### Error Handling Every error produced by the API call is treated as is and will cause a "FAILED" response to be submitted to CloudFormation. diff --git a/packages/@aws-cdk/custom-resources/lib/aws-custom-resource/aws-custom-resource.ts b/packages/@aws-cdk/custom-resources/lib/aws-custom-resource/aws-custom-resource.ts index db40e3269ca17..5169a85839800 100644 --- a/packages/@aws-cdk/custom-resources/lib/aws-custom-resource/aws-custom-resource.ts +++ b/packages/@aws-cdk/custom-resources/lib/aws-custom-resource/aws-custom-resource.ts @@ -4,6 +4,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as lambda from '@aws-cdk/aws-lambda'; import * as logs from '@aws-cdk/aws-logs'; import * as cdk from '@aws-cdk/core'; +import { PHYSICAL_RESOURCE_ID_REFERENCE, flatten } from './runtime'; // don't use "require" since the typescript compiler emits errors since this // file is not listed in tsconfig.json. @@ -16,6 +17,18 @@ export type AwsSdkMetadata = {[key: string]: any}; const awsSdkMetadata: AwsSdkMetadata = metadata; +/** + * Reference to the physical resource id that can be passed to the AWS operation as a parameter. + */ +export class PhysicalResourceIdReference { + /** + * toJSON serialization to replace `PhysicalResourceIdReference` with a magic string. + */ + public toJSON() { + return PHYSICAL_RESOURCE_ID_REFERENCE; + } +} + /** * Physical ID of the custom resource. */ @@ -309,6 +322,15 @@ export class AwsCustomResource extends cdk.Construct implements iam.IGrantable { } } + if (props.onCreate?.parameters) { + const flattenedOnCreateParams = flatten(JSON.parse(JSON.stringify(props.onCreate.parameters))); + for (const param in flattenedOnCreateParams) { + if (flattenedOnCreateParams[param] === PHYSICAL_RESOURCE_ID_REFERENCE) { + throw new Error('`PhysicalResourceIdReference` must not be specified in `onCreate` parameters.'); + } + } + } + this.props = props; const provider = new lambda.SingletonFunction(this, 'Provider', { diff --git a/packages/@aws-cdk/custom-resources/lib/aws-custom-resource/runtime/index.ts b/packages/@aws-cdk/custom-resources/lib/aws-custom-resource/runtime/index.ts index 9b311a5b84403..9f90c8f629f74 100644 --- a/packages/@aws-cdk/custom-resources/lib/aws-custom-resource/runtime/index.ts +++ b/packages/@aws-cdk/custom-resources/lib/aws-custom-resource/runtime/index.ts @@ -2,6 +2,11 @@ import { execSync } from 'child_process'; import { AwsSdkCall } from '../aws-custom-resource'; +/** + * Serialized form of the physical resource id for use in the operation parameters + */ +export const PHYSICAL_RESOURCE_ID_REFERENCE = 'PHYSICAL:RESOURCEID:'; + /** * Flattens a nested object * @@ -24,15 +29,17 @@ export function flatten(object: object): { [key: string]: string } { } /** - * Decodes encoded true/false values + * Decodes encoded special values (booleans and physicalResourceId) */ -function decodeBooleans(object: object) { +function decodeSpecialValues(object: object, physicalResourceId: string) { return JSON.parse(JSON.stringify(object), (_k, v) => { switch (v) { case 'TRUE:BOOLEAN': return true; case 'FALSE:BOOLEAN': return false; + case PHYSICAL_RESOURCE_ID_REFERENCE: + return physicalResourceId; default: return v; } @@ -115,7 +122,8 @@ export async function handler(event: AWSLambda.CloudFormationCustomResourceEvent }); try { - const response = await awsService[call.action](call.parameters && decodeBooleans(call.parameters)).promise(); + const response = await awsService[call.action]( + call.parameters && decodeSpecialValues(call.parameters, physicalResourceId)).promise(); flatData = { apiVersion: awsService.config.apiVersion, // For test purposes: check if apiVersion was correctly passed. region: awsService.config.region, // For test purposes: check if region was correctly passed. diff --git a/packages/@aws-cdk/custom-resources/lib/provider-framework/runtime/framework.ts b/packages/@aws-cdk/custom-resources/lib/provider-framework/runtime/framework.ts index fa5b42b3ac1c0..eda70ea7efb4f 100644 --- a/packages/@aws-cdk/custom-resources/lib/provider-framework/runtime/framework.ts +++ b/packages/@aws-cdk/custom-resources/lib/provider-framework/runtime/framework.ts @@ -39,7 +39,7 @@ async function onEvent(cfnRequest: AWSLambda.CloudFormationCustomResourceEvent) // determine if this is an async provider based on whether we have an isComplete handler defined. // if it is not defined, then we are basically ready to return a positive response. if (!process.env[consts.USER_IS_COMPLETE_FUNCTION_ARN_ENV]) { - return await cfnResponse.submitResponse('SUCCESS', resourceEvent); + return cfnResponse.submitResponse('SUCCESS', resourceEvent); } // ok, we are not complete, so kick off the waiter workflow diff --git a/packages/@aws-cdk/custom-resources/lib/provider-framework/runtime/outbound.ts b/packages/@aws-cdk/custom-resources/lib/provider-framework/runtime/outbound.ts index f3cb16ebd6f05..527868e8d3f94 100644 --- a/packages/@aws-cdk/custom-resources/lib/provider-framework/runtime/outbound.ts +++ b/packages/@aws-cdk/custom-resources/lib/provider-framework/runtime/outbound.ts @@ -35,7 +35,7 @@ async function defaultStartExecution(req: AWS.StepFunctions.StartExecutionInput) sfn = new AWS.StepFunctions(awsSdkConfig); } - return await sfn.startExecution(req).promise(); + return sfn.startExecution(req).promise(); } async function defaultInvokeFunction(req: AWS.Lambda.InvocationRequest): Promise { @@ -43,7 +43,7 @@ async function defaultInvokeFunction(req: AWS.Lambda.InvocationRequest): Promise lambda = new AWS.Lambda(awsSdkConfig); } - return await lambda.invoke(req).promise(); + return lambda.invoke(req).promise(); } export let startExecution = defaultStartExecution; diff --git a/packages/@aws-cdk/custom-resources/package.json b/packages/@aws-cdk/custom-resources/package.json index e4590c7a01183..98b961ab86b95 100644 --- a/packages/@aws-cdk/custom-resources/package.json +++ b/packages/@aws-cdk/custom-resources/package.json @@ -71,7 +71,7 @@ "@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.61", + "@types/aws-lambda": "^8.10.62", "@types/fs-extra": "^8.1.1", "@types/sinon": "^9.0.5", "aws-sdk": "^2.739.0", diff --git a/packages/@aws-cdk/custom-resources/test/aws-custom-resource/aws-custom-resource.test.ts b/packages/@aws-cdk/custom-resources/test/aws-custom-resource/aws-custom-resource.test.ts index 76d7ec9fa585d..8bf6a667f5c83 100644 --- a/packages/@aws-cdk/custom-resources/test/aws-custom-resource/aws-custom-resource.test.ts +++ b/packages/@aws-cdk/custom-resources/test/aws-custom-resource/aws-custom-resource.test.ts @@ -2,7 +2,7 @@ import '@aws-cdk/assert/jest'; import * as iam from '@aws-cdk/aws-iam'; import * as logs from '@aws-cdk/aws-logs'; import * as cdk from '@aws-cdk/core'; -import { AwsCustomResource, AwsCustomResourcePolicy, PhysicalResourceId } from '../../lib'; +import { AwsCustomResource, AwsCustomResourcePolicy, PhysicalResourceId, PhysicalResourceIdReference } from '../../lib'; /* eslint-disable quote-props */ @@ -224,6 +224,63 @@ test('encodes booleans', () => { }); }); +test('fails PhysicalResourceIdReference is passed to onCreate parameters', () => { + const stack = new cdk.Stack(); + expect(() => new AwsCustomResource(stack, 'AwsSdk', { + resourceType: 'Custom::ServiceAction', + onCreate: { + service: 'service', + action: 'action', + parameters: { + physicalResourceIdReference: new PhysicalResourceIdReference(), + }, + physicalResourceId: PhysicalResourceId.of('id'), + }, + policy: AwsCustomResourcePolicy.fromSdkCalls({ resources: AwsCustomResourcePolicy.ANY_RESOURCE }), + })).toThrow('`PhysicalResourceIdReference` must not be specified in `onCreate` parameters.'); +}); + +test('encodes physical resource id reference', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new AwsCustomResource(stack, 'AwsSdk', { + resourceType: 'Custom::ServiceAction', + onUpdate: { + service: 'service', + action: 'action', + parameters: { + trueBoolean: true, + trueString: 'true', + falseBoolean: false, + falseString: 'false', + physicalResourceIdReference: new PhysicalResourceIdReference(), + }, + physicalResourceId: PhysicalResourceId.of('id'), + }, + policy: AwsCustomResourcePolicy.fromSdkCalls({ resources: AwsCustomResourcePolicy.ANY_RESOURCE }), + }); + + // THEN + expect(stack).toHaveResource('Custom::ServiceAction', { + 'Create': { + 'service': 'service', + 'action': 'action', + 'parameters': { + 'trueBoolean': 'TRUE:BOOLEAN', + 'trueString': 'true', + 'falseBoolean': 'FALSE:BOOLEAN', + 'falseString': 'false', + 'physicalResourceIdReference': 'PHYSICAL:RESOURCEID:', + }, + 'physicalResourceId': { + 'id': 'id', + }, + }, + }); +}); + test('timeout defaults to 2 minutes', () => { // GIVEN const stack = new cdk.Stack(); diff --git a/packages/@aws-cdk/custom-resources/test/provider-framework/integration-test-fixtures/s3-file-handler/index.ts b/packages/@aws-cdk/custom-resources/test/provider-framework/integration-test-fixtures/s3-file-handler/index.ts index 7495b72cbd157..0e52b4ad66e3f 100644 --- a/packages/@aws-cdk/custom-resources/test/provider-framework/integration-test-fixtures/s3-file-handler/index.ts +++ b/packages/@aws-cdk/custom-resources/test/provider-framework/integration-test-fixtures/s3-file-handler/index.ts @@ -8,10 +8,10 @@ export async function onEvent(event: AWSCDKAsyncCustomResource.OnEventRequest) { switch (event.RequestType) { case 'Create': case 'Update': - return await putObject(event); + return putObject(event); case 'Delete': - return await deleteObject(event); + return deleteObject(event); } } diff --git a/packages/@aws-cdk/cx-api/lib/app.ts b/packages/@aws-cdk/cx-api/lib/app.ts index d135e9cf40f07..41283679f0db2 100644 --- a/packages/@aws-cdk/cx-api/lib/app.ts +++ b/packages/@aws-cdk/cx-api/lib/app.ts @@ -27,3 +27,8 @@ export const DISABLE_ASSET_STAGING_CONTEXT = 'aws:cdk:disable-asset-staging'; * Omits stack traces from construct metadata entries. */ export const DISABLE_METADATA_STACK_TRACE = 'aws:cdk:disable-stack-trace'; + +/** + * Run bundling for stacks specified in this context key + */ +export const BUNDLING_STACKS = 'aws:cdk:bundling-stacks'; diff --git a/packages/@aws-cdk/cx-api/package.json b/packages/@aws-cdk/cx-api/package.json index 5d9c131435aed..ed513afa55cd6 100644 --- a/packages/@aws-cdk/cx-api/package.json +++ b/packages/@aws-cdk/cx-api/package.json @@ -47,18 +47,18 @@ }, "dependencies": { "@aws-cdk/cloud-assembly-schema": "0.0.0", - "semver": "^7.2.2" + "semver": "^7.3.2" }, "peerDependencies": { "@aws-cdk/cloud-assembly-schema": "0.0.0" }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.10", + "@types/jest": "^26.0.14", "@types/mock-fs": "^4.10.0", - "@types/semver": "^7.3.3", + "@types/semver": "^7.3.4", "cdk-build-tools": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "mock-fs": "^4.13.0", "pkglint": "0.0.0" }, diff --git a/packages/@aws-cdk/example-construct-library/package.json b/packages/@aws-cdk/example-construct-library/package.json index 2dc201596864e..4768ce70bb5c9 100644 --- a/packages/@aws-cdk/example-construct-library/package.json +++ b/packages/@aws-cdk/example-construct-library/package.json @@ -64,7 +64,7 @@ "@aws-cdk/assert": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", - "jest": "^25.5.3", + "jest": "^26.4.2", "pkglint": "0.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk/pipelines/README.md b/packages/@aws-cdk/pipelines/README.md index 0fe49601d145a..350c99386d429 100644 --- a/packages/@aws-cdk/pipelines/README.md +++ b/packages/@aws-cdk/pipelines/README.md @@ -135,6 +135,9 @@ class MyPipelineStack extends Stack { sourceArtifact, cloudAssemblyArtifact, + // Optionally specify a VPC in which the action runs + vpc: new ec2.Vpc(this, 'NpmSynthVpc'), + // Use this if you need a build step (if you're not using ts-node // or if you have TypeScript Lambdas that need to be compiled). buildCommand: 'npm run build', @@ -328,6 +331,8 @@ const stage = pipeline.addApplicationStage(new MyApplication(/* ... */)); stage.addActions(new ShellScriptAction({ actionName: 'MyValidation', commands: ['curl -Ssf https://my.webservice.com/'], + // Optionally specify a VPC if, for example, the service is deployed with a private load balancer + vpc, // ... more configuration ... })); ``` diff --git a/packages/@aws-cdk/pipelines/lib/actions/publish-assets-action.ts b/packages/@aws-cdk/pipelines/lib/actions/publish-assets-action.ts index a16862c20d014..ca2bb7221ce87 100644 --- a/packages/@aws-cdk/pipelines/lib/actions/publish-assets-action.ts +++ b/packages/@aws-cdk/pipelines/lib/actions/publish-assets-action.ts @@ -1,6 +1,7 @@ import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as codepipeline_actions from '@aws-cdk/aws-codepipeline-actions'; +import * as ec2 from '@aws-cdk/aws-ec2'; import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; import { Construct, Lazy } from '@aws-cdk/core'; @@ -59,6 +60,22 @@ export interface PublishAssetsActionProps { * @default - Automatically generated */ readonly role?: iam.IRole; + + /** + * The VPC where to execute the PublishAssetsAction. + * + * @default - No VPC + */ + readonly vpc?: ec2.IVpc; + + /** + * Which subnets to use. + * + * Only used if 'vpc' is supplied. + * + * @default - All private subnets. + */ + readonly subnetSelection?: ec2.SubnetSelection; } /** @@ -85,6 +102,8 @@ export class PublishAssetsAction extends Construct implements codepipeline.IActi buildImage: codebuild.LinuxBuildImage.STANDARD_4_0, privileged: (props.assetType === AssetType.DOCKER_IMAGE) ? true : undefined, }, + vpc: props.vpc, + subnetSelection: props.subnetSelection, buildSpec: codebuild.BuildSpec.fromObject({ version: '0.2', phases: { diff --git a/packages/@aws-cdk/pipelines/lib/pipeline.ts b/packages/@aws-cdk/pipelines/lib/pipeline.ts index 9777bcdd4af4d..9643b413eef08 100644 --- a/packages/@aws-cdk/pipelines/lib/pipeline.ts +++ b/packages/@aws-cdk/pipelines/lib/pipeline.ts @@ -1,5 +1,6 @@ import * as path from 'path'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; +import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import { Annotations, App, CfnOutput, Construct, PhysicalName, Stack, Stage, Aspects } from '@aws-cdk/core'; import { AssetType, DeployCdkStackAction, PublishAssetsAction, UpdatePipelineAction } from './actions'; @@ -63,6 +64,22 @@ export interface CdkPipelineProps { * @default - Latest version */ readonly cdkCliVersion?: string; + + /** + * The VPC where to execute the CdkPipeline actions. + * + * @default - No VPC + */ + readonly vpc?: ec2.IVpc; + + /** + * Which subnets to use. + * + * Only used if 'vpc' is supplied. + * + * @default - All private subnets. + */ + readonly subnetSelection?: ec2.SubnetSelection; } /** @@ -117,12 +134,6 @@ export class CdkPipeline extends Construct { if (!props.sourceAction && (!props.codePipeline || props.codePipeline.stages.length < 1)) { throw new Error('You must pass a \'sourceAction\' (or a \'codePipeline\' that already has a Source stage)'); } - if (!props.synthAction && (!props.codePipeline || props.codePipeline.stages.length < 2)) { - // This looks like a weirdly specific requirement, but actually the underlying CodePipeline - // requires that a Pipeline has at least 2 stages. We're just hitching onto upstream - // requirements to do this check. - throw new Error('You must pass a \'synthAction\' (or a \'codePipeline\' that already has a Build stage)'); - } if (props.sourceAction) { this._pipeline.addStage({ @@ -153,6 +164,8 @@ export class CdkPipeline extends Construct { cdkCliVersion: props.cdkCliVersion, pipeline: this._pipeline, projectName: maybeSuffix(props.pipelineName, '-publish'), + vpc: props.vpc, + subnetSelection: props.subnetSelection, }); Aspects.of(this).add({ visit: () => this._assets.removeAssetsStageIfEmpty() }); @@ -300,6 +313,8 @@ interface AssetPublishingProps { readonly pipeline: codepipeline.Pipeline; readonly cdkCliVersion?: string; readonly projectName?: string; + readonly vpc?: ec2.IVpc; + readonly subnetSelection?: ec2.SubnetSelection; } /** @@ -367,6 +382,8 @@ class AssetPublishing extends Construct { cdkCliVersion: this.props.cdkCliVersion, assetType: command.assetType, role: this.assetRoles[command.assetType], + vpc: this.props.vpc, + subnetSelection: this.props.subnetSelection, }); this.stage.addAction(action); } diff --git a/packages/@aws-cdk/pipelines/lib/synths/simple-synth-action.ts b/packages/@aws-cdk/pipelines/lib/synths/simple-synth-action.ts index 88d36ae81d3eb..785ef9cc46bc7 100644 --- a/packages/@aws-cdk/pipelines/lib/synths/simple-synth-action.ts +++ b/packages/@aws-cdk/pipelines/lib/synths/simple-synth-action.ts @@ -3,6 +3,7 @@ import * as path from 'path'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as codepipeline_actions from '@aws-cdk/aws-codepipeline-actions'; +import * as ec2 from '@aws-cdk/aws-ec2'; import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; import { Construct, Stack } from '@aws-cdk/core'; @@ -88,6 +89,22 @@ export interface SimpleSynthOptions { * @default - No policy statements added to CodeBuild Project Role */ readonly rolePolicyStatements?: iam.PolicyStatement[]; + + /** + * The VPC where to execute the SimpleSynth. + * + * @default - No VPC + */ + readonly vpc?: ec2.IVpc; + + /** + * Which subnets to use. + * + * Only used if 'vpc' is supplied. + * + * @default - All private subnets. + */ + readonly subnetSelection?: ec2.SubnetSelection; } /** @@ -186,6 +203,8 @@ export class SimpleSynthAction implements codepipeline.IAction, iam.IGrantable { ...options, installCommand: options.installCommand ?? 'npm ci', synthCommand: options.synthCommand ?? 'npx cdk synth', + vpc: options.vpc, + subnetSelection: options.subnetSelection, }); } @@ -201,6 +220,8 @@ export class SimpleSynthAction implements codepipeline.IAction, iam.IGrantable { ...options, installCommand: options.installCommand ?? 'yarn install --frozen-lockfile', synthCommand: options.synthCommand ?? 'npx cdk synth', + vpc: options.vpc, + subnetSelection: options.subnetSelection, }); } @@ -314,6 +335,8 @@ export class SimpleSynthAction implements codepipeline.IAction, iam.IGrantable { const project = new codebuild.PipelineProject(scope, 'CdkBuildProject', { projectName: this.props.projectName, environment, + vpc: this.props.vpc, + subnetSelection: this.props.subnetSelection, buildSpec, environmentVariables, }); diff --git a/packages/@aws-cdk/pipelines/lib/validation/shell-script-action.ts b/packages/@aws-cdk/pipelines/lib/validation/shell-script-action.ts index ae4f8367f90eb..528cece1d0700 100644 --- a/packages/@aws-cdk/pipelines/lib/validation/shell-script-action.ts +++ b/packages/@aws-cdk/pipelines/lib/validation/shell-script-action.ts @@ -1,13 +1,14 @@ import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as codepipeline_actions from '@aws-cdk/aws-codepipeline-actions'; +import * as ec2 from '@aws-cdk/aws-ec2'; import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; import { Construct } from '@aws-cdk/core'; import { StackOutput } from '../stage'; /** - * Properties for ShellScriptValidation + * Properties for ShellScriptAction */ export interface ShellScriptActionProps { /** @@ -72,6 +73,22 @@ export interface ShellScriptActionProps { * @default - No policy statements */ readonly rolePolicyStatements?: iam.PolicyStatement[]; + + /** + * The VPC where to execute the specified script. + * + * @default - No VPC + */ + readonly vpc?: ec2.IVpc; + + /** + * Which subnets to use. + * + * Only used if 'vpc' is supplied. + * + * @default - All private subnets. + */ + readonly subnetSelection?: ec2.SubnetSelection } /** @@ -150,6 +167,8 @@ export class ShellScriptAction implements codepipeline.IAction, iam.IGrantable { this._project = new codebuild.PipelineProject(scope, 'Project', { environment: { buildImage: codebuild.LinuxBuildImage.STANDARD_4_0 }, + vpc: this.props.vpc, + subnetSelection: this.props.subnetSelection, buildSpec: codebuild.BuildSpec.fromObject({ version: '0.2', phases: { diff --git a/packages/@aws-cdk/pipelines/package.json b/packages/@aws-cdk/pipelines/package.json index 73ccb9fc14063..86301e67b0a0b 100644 --- a/packages/@aws-cdk/pipelines/package.json +++ b/packages/@aws-cdk/pipelines/package.json @@ -47,6 +47,7 @@ "@aws-cdk/aws-codepipeline-actions": "0.0.0", "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/cx-api": "0.0.0", @@ -61,6 +62,7 @@ "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/aws-cloudformation": "0.0.0" diff --git a/packages/@aws-cdk/pipelines/test/builds.test.ts b/packages/@aws-cdk/pipelines/test/builds.test.ts index 41c1187105700..fdb9171aedc73 100644 --- a/packages/@aws-cdk/pipelines/test/builds.test.ts +++ b/packages/@aws-cdk/pipelines/test/builds.test.ts @@ -2,6 +2,7 @@ import { arrayWith, deepObjectLike, encodedJson, objectLike, Capture } from '@aw import '@aws-cdk/assert/jest'; import * as cbuild from '@aws-cdk/aws-codebuild'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; +import * as ec2 from '@aws-cdk/aws-ec2'; import * as s3 from '@aws-cdk/aws-s3'; import { Stack } from '@aws-cdk/core'; import * as cdkp from '../lib'; @@ -218,6 +219,88 @@ test('Standard (NPM) synth can output additional artifacts', () => { }); }); +test('Standard (NPM) synth can run in a VPC', () => { + // WHEN + new TestGitHubNpmPipeline(pipelineStack, 'Cdk', { + sourceArtifact, + cloudAssemblyArtifact, + synthAction: cdkp.SimpleSynthAction.standardNpmSynth({ + vpc: new ec2.Vpc(pipelineStack, 'NpmSynthTestVpc'), + sourceArtifact, + cloudAssemblyArtifact, + }), + }); + + // THEN + expect(pipelineStack).toHaveResourceLike('AWS::CodeBuild::Project', { + VpcConfig: { + SecurityGroupIds: [ + { + 'Fn::GetAtt': [ + 'CdkPipelineBuildSynthCdkBuildProjectSecurityGroupEA44D7C2', + 'GroupId', + ], + }, + ], + Subnets: [ + { + Ref: 'NpmSynthTestVpcPrivateSubnet1Subnet81E3AA56', + }, + { + Ref: 'NpmSynthTestVpcPrivateSubnet2SubnetC1CA3EF0', + }, + { + Ref: 'NpmSynthTestVpcPrivateSubnet3SubnetA04163EE', + }, + ], + VpcId: { + Ref: 'NpmSynthTestVpc5E703F25', + }, + }, + }); +}); + +test('Standard (Yarn) synth can run in a VPC', () => { + // WHEN + new TestGitHubNpmPipeline(pipelineStack, 'Cdk', { + sourceArtifact, + cloudAssemblyArtifact, + synthAction: cdkp.SimpleSynthAction.standardYarnSynth({ + vpc: new ec2.Vpc(pipelineStack, 'YarnSynthTestVpc'), + sourceArtifact, + cloudAssemblyArtifact, + }), + }); + + // THEN + expect(pipelineStack).toHaveResourceLike('AWS::CodeBuild::Project', { + VpcConfig: { + SecurityGroupIds: [ + { + 'Fn::GetAtt': [ + 'CdkPipelineBuildSynthCdkBuildProjectSecurityGroupEA44D7C2', + 'GroupId', + ], + }, + ], + Subnets: [ + { + Ref: 'YarnSynthTestVpcPrivateSubnet1Subnet2805334B', + }, + { + Ref: 'YarnSynthTestVpcPrivateSubnet2SubnetDCFBF596', + }, + { + Ref: 'YarnSynthTestVpcPrivateSubnet3SubnetE11E0C86', + }, + ], + VpcId: { + Ref: 'YarnSynthTestVpc5F654735', + }, + }, + }); +}); + test('Pipeline action contains a hash that changes as the buildspec changes', () => { const hash1 = synthWithAction((sa, cxa) => cdkp.SimpleSynthAction.standardNpmSynth({ sourceArtifact: sa, diff --git a/packages/@aws-cdk/pipelines/test/existing-pipeline.test.ts b/packages/@aws-cdk/pipelines/test/existing-pipeline.test.ts index e9e6ed833e680..1c280ec2fe1a6 100644 --- a/packages/@aws-cdk/pipelines/test/existing-pipeline.test.ts +++ b/packages/@aws-cdk/pipelines/test/existing-pipeline.test.ts @@ -66,13 +66,6 @@ describe('with custom Source stage in existing Pipeline', () => { }); }); - test('synth action is required', () => { - // WHEN - expect(() => { - new cdkp.CdkPipeline(pipelineStack, 'Cdk', { cloudAssemblyArtifact, codePipeline }); - }).toThrow(/You must pass a 'synthAction'/); - }); - test('Work with synthAction', () => { // WHEN new cdkp.CdkPipeline(pipelineStack, 'Cdk', { diff --git a/packages/@aws-cdk/pipelines/test/pipeline-assets.test.ts b/packages/@aws-cdk/pipelines/test/pipeline-assets.test.ts index 499c0834e16b7..13ae9fcceda87 100644 --- a/packages/@aws-cdk/pipelines/test/pipeline-assets.test.ts +++ b/packages/@aws-cdk/pipelines/test/pipeline-assets.test.ts @@ -1,9 +1,9 @@ +import * as path from 'path'; import { arrayWith, deepObjectLike, encodedJson, notMatching, objectLike, stringLike } from '@aws-cdk/assert'; import '@aws-cdk/assert/jest'; import * as ecr_assets from '@aws-cdk/aws-ecr-assets'; import * as s3_assets from '@aws-cdk/aws-s3-assets'; import { Construct, Stack, Stage, StageProps } from '@aws-cdk/core'; -import * as path from 'path'; import * as cdkp from '../lib'; import { BucketStack, PIPELINE_ENV, TestApp, TestGitHubNpmPipeline } from './testutil'; @@ -156,6 +156,39 @@ test('docker image asset publishers use privilegedmode, have right AssumeRole', }); }); +test('docker image asset can use a VPC', () => { + // WHEN + pipeline.addApplicationStage(new DockerAssetApp(app, 'DockerAssetApp')); + + // THEN + expect(pipelineStack).toHaveResourceLike('AWS::CodeBuild::Project', { + VpcConfig: objectLike({ + SecurityGroupIds: [ + { + 'Fn::GetAtt': [ + 'CdkAssetsDockerAsset1SecurityGroup078F5C66', + 'GroupId', + ], + }, + ], + Subnets: [ + { + Ref: 'TestVpcPrivateSubnet1SubnetCC65D771', + }, + { + Ref: 'TestVpcPrivateSubnet2SubnetDE0C64A2', + }, + { + Ref: 'TestVpcPrivateSubnet3Subnet2311D32F', + }, + ], + VpcId: { + Ref: 'TestVpcE77CE678', + }, + }), + }); +}); + test('can control fix/CLI version used in pipeline selfupdate', () => { // WHEN const stack2 = new Stack(app, 'Stack2', { env: PIPELINE_ENV }); diff --git a/packages/@aws-cdk/pipelines/test/testutil.ts b/packages/@aws-cdk/pipelines/test/testutil.ts index beb6e0180fa87..821b795105365 100644 --- a/packages/@aws-cdk/pipelines/test/testutil.ts +++ b/packages/@aws-cdk/pipelines/test/testutil.ts @@ -2,6 +2,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as codepipeline_actions from '@aws-cdk/aws-codepipeline-actions'; +import * as ec2 from '@aws-cdk/aws-ec2'; import * as s3 from '@aws-cdk/aws-s3'; import { App, AppProps, Construct, Environment, SecretValue, Stack, StackProps, Stage } from '@aws-cdk/core'; import * as cdkp from '../lib'; @@ -45,6 +46,7 @@ export class TestGitHubNpmPipeline extends cdkp.CdkPipeline { sourceArtifact, cloudAssemblyArtifact, }), + vpc: new ec2.Vpc(scope, 'TestVpc'), cloudAssemblyArtifact, ...props, }); diff --git a/packages/@aws-cdk/pipelines/test/validation.test.ts b/packages/@aws-cdk/pipelines/test/validation.test.ts index ae1b44f2671f2..6dc5247b22452 100644 --- a/packages/@aws-cdk/pipelines/test/validation.test.ts +++ b/packages/@aws-cdk/pipelines/test/validation.test.ts @@ -1,6 +1,7 @@ import { anything, arrayWith, deepObjectLike, encodedJson } from '@aws-cdk/assert'; import '@aws-cdk/assert/jest'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; +import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as s3 from '@aws-cdk/aws-s3'; import { CfnOutput, Construct, Stack, Stage, StageProps } from '@aws-cdk/core'; @@ -223,6 +224,71 @@ test('ShellScriptAction is IGrantable', () => { }); }); +test('run ShellScriptAction in a VPC', () => { + // WHEN + const vpc = new ec2.Vpc(pipelineStack, 'VPC'); + pipeline.addStage('Test').addActions(new cdkp.ShellScriptAction({ + vpc, + actionName: 'VpcAction', + additionalArtifacts: [integTestArtifact], + commands: ['true'], + })); + + // THEN + expect(pipelineStack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Stages: arrayWith({ + Name: 'Test', + Actions: [ + deepObjectLike({ + Name: 'VpcAction', + InputArtifacts: [{ Name: 'IntegTests' }], + }), + ], + }), + }); + expect(pipelineStack).toHaveResourceLike('AWS::CodeBuild::Project', { + Environment: { + Image: 'aws/codebuild/standard:4.0', + }, + VpcConfig: { + SecurityGroupIds: [ + { + 'Fn::GetAtt': [ + 'CdkPipelineTestVpcActionProjectSecurityGroupBA94D315', + 'GroupId', + ], + }, + ], + Subnets: [ + { + Ref: 'VPCPrivateSubnet1Subnet8BCA10E0', + }, + { + Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A', + }, + { + Ref: 'VPCPrivateSubnet3Subnet3EDCD457', + }, + ], + VpcId: { + Ref: 'VPCB9E5F0B4', + }, + }, + Source: { + BuildSpec: encodedJson(deepObjectLike({ + phases: { + build: { + commands: [ + 'set -eu', + 'true', + ], + }, + }, + })), + }, + }); +}); + class AppWithStackOutput extends Stage { public readonly output: CfnOutput; diff --git a/packages/@aws-cdk/yaml-cfn/.eslintrc.js b/packages/@aws-cdk/yaml-cfn/.eslintrc.js new file mode 100644 index 0000000000000..61dd8dd001f63 --- /dev/null +++ b/packages/@aws-cdk/yaml-cfn/.eslintrc.js @@ -0,0 +1,3 @@ +const baseConfig = require('cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; +module.exports = baseConfig; diff --git a/packages/@aws-cdk/yaml-cfn/.gitignore b/packages/@aws-cdk/yaml-cfn/.gitignore new file mode 100644 index 0000000000000..bb785cfb74f08 --- /dev/null +++ b/packages/@aws-cdk/yaml-cfn/.gitignore @@ -0,0 +1,18 @@ +*.js +*.js.map +*.d.ts +node_modules +dist +tsconfig.json +.jsii + +.LAST_BUILD +.LAST_PACKAGE +*.snk +.nyc_output +coverage +nyc.config.js +!.eslintrc.js +!jest.config.js + +junit.xml \ No newline at end of file diff --git a/packages/@aws-cdk/yaml-cfn/.npmignore b/packages/@aws-cdk/yaml-cfn/.npmignore new file mode 100644 index 0000000000000..bca0ae2513f1e --- /dev/null +++ b/packages/@aws-cdk/yaml-cfn/.npmignore @@ -0,0 +1,26 @@ +# Don't include original .ts files when doing `npm pack` +*.ts +!*.d.ts +coverage +.nyc_output +*.tgz + +dist +.LAST_PACKAGE +.LAST_BUILD +!*.js + +# Include .jsii +!.jsii + +*.snk + +*.tsbuildinfo + +tsconfig.json +.eslintrc.js +jest.config.js + +# exclude cdk artifacts +**/cdk.out +junit.xml \ No newline at end of file diff --git a/packages/@aws-cdk/yaml-cfn/LICENSE b/packages/@aws-cdk/yaml-cfn/LICENSE new file mode 100644 index 0000000000000..b71ec1688783a --- /dev/null +++ b/packages/@aws-cdk/yaml-cfn/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/@aws-cdk/yaml-cfn/NOTICE b/packages/@aws-cdk/yaml-cfn/NOTICE new file mode 100644 index 0000000000000..bfccac9a7f69c --- /dev/null +++ b/packages/@aws-cdk/yaml-cfn/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/yaml-cfn/README.md b/packages/@aws-cdk/yaml-cfn/README.md new file mode 100644 index 0000000000000..b4dcb167f1e58 --- /dev/null +++ b/packages/@aws-cdk/yaml-cfn/README.md @@ -0,0 +1,16 @@ +## CloudFormation YAML utilities + + +--- + +![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge) + +> The APIs of higher level constructs in this module are experimental and under active development. They are subject to non-backward compatible changes or removal in any future version. These are not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be announced in the release notes. This means that while you may use them, you may need to update your source code when upgrading to a newer version of this package. + +--- + + +This module contains utilities for parsing and emitting +YAML that is used by [AWS CloudFormation](https://aws.amazon.com/cloudformation). + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. diff --git a/packages/@aws-cdk/yaml-cfn/jest.config.js b/packages/@aws-cdk/yaml-cfn/jest.config.js new file mode 100644 index 0000000000000..19fd4653b47af --- /dev/null +++ b/packages/@aws-cdk/yaml-cfn/jest.config.js @@ -0,0 +1,4 @@ +const baseConfig = require('cdk-build-tools/config/jest.config'); +module.exports = { + ...baseConfig, +}; diff --git a/packages/@aws-cdk/yaml-cfn/lib/index.ts b/packages/@aws-cdk/yaml-cfn/lib/index.ts new file mode 100644 index 0000000000000..8acac13029169 --- /dev/null +++ b/packages/@aws-cdk/yaml-cfn/lib/index.ts @@ -0,0 +1 @@ +export * from './yaml'; diff --git a/packages/@aws-cdk/yaml-cfn/lib/yaml.ts b/packages/@aws-cdk/yaml-cfn/lib/yaml.ts new file mode 100644 index 0000000000000..0a613f5aa7e14 --- /dev/null +++ b/packages/@aws-cdk/yaml-cfn/lib/yaml.ts @@ -0,0 +1,87 @@ +import * as yaml from 'yaml'; +import * as yaml_cst from 'yaml/parse-cst'; +import * as yaml_types from 'yaml/types'; + +/** + * Serializes the given data structure into valid YAML. + * + * @param obj the data structure to serialize + * @returns a string containing the YAML representation of {@param obj} + */ +export function serialize(obj: any): string { + const oldFold = yaml_types.strOptions.fold.lineWidth; + try { + yaml_types.strOptions.fold.lineWidth = 0; + return yaml.stringify(obj, { schema: 'yaml-1.1' }); + } finally { + yaml_types.strOptions.fold.lineWidth = oldFold; + } +} + +/** + * Deserialize the YAML into the appropriate data structure. + * + * @param str the string containing YAML + * @returns the data structure the YAML represents + * (most often in case of CloudFormation, an object) + */ +export function deserialize(str: string): any { + return parseYamlStrWithCfnTags(str); +} + +function makeTagForCfnIntrinsic( + intrinsicName: string, addFnPrefix: boolean = true, + resolveFun?: (_doc: yaml.Document, cstNode: yaml_cst.CST.Node) => any): yaml_types.Schema.CustomTag { + + return { + identify(value: any) { return typeof value === 'string'; }, + tag: `!${intrinsicName}`, + resolve: resolveFun || ((_doc: yaml.Document, cstNode: yaml_cst.CST.Node) => { + const ret: any = {}; + ret[addFnPrefix ? `Fn::${intrinsicName}` : intrinsicName] = + // the +1 is to account for the ! the short form begins with + parseYamlStrWithCfnTags(cstNode.toString().substring(intrinsicName.length + 1)); + return ret; + }), + }; +} + +const shortForms: yaml_types.Schema.CustomTag[] = [ + 'Base64', 'Cidr', 'FindInMap', 'GetAZs', 'ImportValue', 'Join', 'Sub', + 'Select', 'Split', 'Transform', 'And', 'Equals', 'If', 'Not', 'Or', +].map(name => makeTagForCfnIntrinsic(name)).concat( + makeTagForCfnIntrinsic('Ref', false), + makeTagForCfnIntrinsic('Condition', false), + makeTagForCfnIntrinsic('GetAtt', true, (_doc: yaml.Document, cstNode: yaml_cst.CST.Node): any => { + const parsedArguments = parseYamlStrWithCfnTags(cstNode.toString().substring('!GetAtt'.length)); + + let value: any; + if (typeof parsedArguments === 'string') { + // if the arguments to !GetAtt are a string, + // the part before the first '.' is the logical ID, + // and the rest is the attribute name + // (which can contain '.') + const firstDot = parsedArguments.indexOf('.'); + if (firstDot === -1) { + throw new Error(`Short-form Fn::GetAtt must contain a '.' in its string argument, got: '${parsedArguments}'`); + } + value = [ + parsedArguments.substring(0, firstDot), + parsedArguments.substring(firstDot + 1), // the + 1 is to skip the actual '.' + ]; + } else { + // this is the form where the arguments to Fn::GetAtt are already an array - + // in this case, nothing more to do + value = parsedArguments; + } + + return { 'Fn::GetAtt': value }; + }), +); + +function parseYamlStrWithCfnTags(text: string): any { + return yaml.parse(text, { + customTags: shortForms, + schema: 'yaml-1.1', + }); +} diff --git a/packages/@aws-cdk/yaml-cfn/package.json b/packages/@aws-cdk/yaml-cfn/package.json new file mode 100644 index 0000000000000..86fbed1f10197 --- /dev/null +++ b/packages/@aws-cdk/yaml-cfn/package.json @@ -0,0 +1,87 @@ +{ + "name": "@aws-cdk/yaml-cfn", + "version": "0.0.0", + "description": "Utilities for handling CloudFormation-flavored YAML", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "repository": { + "url": "https://github.com/aws/aws-cdk.git", + "type": "git", + "directory": "packages/@aws-cdk/yaml-cfn" + }, + "homepage": "https://github.com/aws/aws-cdk", + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "keywords": [ + "aws", + "cdk", + "cfn", + "cloudformation", + "yaml" + ], + "jsii": { + "outdir": "dist", + "targets": { + "java": { + "package": "software.amazon.awscdk.yaml.cfn", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "cdk-yaml-cfn" + } + }, + "dotnet": { + "namespace": "Amazon.CDK.Yaml.Cfn", + "packageId": "Amazon.CDK.Yaml.Cfn", + "signAssembly": true, + "assemblyOriginatorKeyFile": "../../key.snk", + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png" + }, + "python": { + "distName": "aws-cdk.yaml-cfn", + "module": "aws_cdk.yaml_cfn" + } + }, + "projectReferences": true + }, + "scripts": { + "build": "cdk-build", + "watch": "cdk-watch", + "lint": "cdk-lint", + "test": "cdk-test", + "pkglint": "pkglint -f", + "package": "cdk-package", + "awslint": "cdk-awslint", + "build+test+package": "npm run build+test && npm run package", + "build+test": "npm run build && npm test", + "compat": "cdk-compat" + }, + "dependencies": { + "yaml": "1.10.0" + }, + "devDependencies": { + "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.10", + "@types/yaml": "^1.9.7", + "cdk-build-tools": "0.0.0", + "jest": "^25.5.4", + "pkglint": "0.0.0" + }, + "bundledDependencies": [ + "yaml" + ], + "cdk-build": { + "jest": true + }, + "engines": { + "node": ">= 10.13.0 <13 || >=13.7.0" + }, + "stability": "experimental", + "maturity": "experimental", + "awscdkio": { + "announce": false + } +} diff --git a/packages/@aws-cdk/yaml-cfn/test/yaml.test.ts b/packages/@aws-cdk/yaml-cfn/test/yaml.test.ts new file mode 100644 index 0000000000000..f8ce8131c4de7 --- /dev/null +++ b/packages/@aws-cdk/yaml-cfn/test/yaml.test.ts @@ -0,0 +1,5 @@ +import '@aws-cdk/assert/jest'; + +test('No tests are specified for this package', () => { + expect(true).toBe(true); +}); diff --git a/packages/@monocdk-experiment/assert/package.json b/packages/@monocdk-experiment/assert/package.json index 25dd458b0f190..a1e3296b4f3d0 100644 --- a/packages/@monocdk-experiment/assert/package.json +++ b/packages/@monocdk-experiment/assert/package.json @@ -34,21 +34,21 @@ "license": "Apache-2.0", "devDependencies": { "@monocdk-experiment/rewrite-imports": "0.0.0", - "@types/jest": "^26.0.10", - "@types/node": "^10.17.28", + "@types/jest": "^26.0.14", + "@types/node": "^10.17.35", "cdk-build-tools": "0.0.0", "constructs": "^3.0.4", - "jest": "^25.5.4", + "jest": "^26.4.2", "monocdk-experiment": "0.0.0", "pkglint": "0.0.0", - "ts-jest": "^26.2.0" + "ts-jest": "^26.3.0" }, "dependencies": { "@aws-cdk/cloudformation-diff": "0.0.0" }, "peerDependencies": { "constructs": "^3.0.4", - "jest": "^25.5.4", + "jest": "^26.4.2", "monocdk-experiment": "^0.0.0" }, "repository": { diff --git a/packages/@monocdk-experiment/rewrite-imports/package.json b/packages/@monocdk-experiment/rewrite-imports/package.json index 1c2835f2ec164..ed39eee4544bd 100644 --- a/packages/@monocdk-experiment/rewrite-imports/package.json +++ b/packages/@monocdk-experiment/rewrite-imports/package.json @@ -36,8 +36,8 @@ }, "devDependencies": { "@types/glob": "^7.1.3", - "@types/jest": "^26.0.10", - "@types/node": "^10.17.28", + "@types/jest": "^26.0.14", + "@types/node": "^10.17.35", "cdk-build-tools": "0.0.0", "pkglint": "0.0.0" }, diff --git a/packages/aws-cdk-lib/package.json b/packages/aws-cdk-lib/package.json index 17d3ce816c69a..e60a75e06db76 100644 --- a/packages/aws-cdk-lib/package.json +++ b/packages/aws-cdk-lib/package.json @@ -91,13 +91,12 @@ "dependencies": { "case": "1.6.3", "fs-extra": "^9.0.1", - "jsonschema": "^1.2.5", + "jsonschema": "^1.2.6", "minimatch": "^3.0.4", - "semver": "^7.2.2", + "semver": "^7.3.2", "yaml": "1.10.0" }, "devDependencies": { - "constructs": "^3.0.4", "@aws-cdk/alexa-ask": "0.0.0", "@aws-cdk/app-delivery": "0.0.0", "@aws-cdk/assets": "0.0.0", @@ -109,6 +108,7 @@ "@aws-cdk/aws-apigatewayv2": "0.0.0", "@aws-cdk/aws-appconfig": "0.0.0", "@aws-cdk/aws-applicationautoscaling": "0.0.0", + "@aws-cdk/aws-applicationinsights": "0.0.0", "@aws-cdk/aws-appmesh": "0.0.0", "@aws-cdk/aws-appstream": "0.0.0", "@aws-cdk/aws-appsync": "0.0.0", @@ -135,6 +135,7 @@ "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-codedeploy": "0.0.0", "@aws-cdk/aws-codeguruprofiler": "0.0.0", + "@aws-cdk/aws-codegurureviewer": "0.0.0", "@aws-cdk/aws-codepipeline": "0.0.0", "@aws-cdk/aws-codepipeline-actions": "0.0.0", "@aws-cdk/aws-codestar": "0.0.0", @@ -187,6 +188,7 @@ "@aws-cdk/aws-kinesis": "0.0.0", "@aws-cdk/aws-kinesisanalytics": "0.0.0", "@aws-cdk/aws-kinesisfirehose": "0.0.0", + "@aws-cdk/aws-kendra": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-lakeformation": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", @@ -235,6 +237,7 @@ "@aws-cdk/aws-sns-subscriptions": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", + "@aws-cdk/aws-sso": "0.0.0", "@aws-cdk/aws-stepfunctions": "0.0.0", "@aws-cdk/aws-stepfunctions-tasks": "0.0.0", "@aws-cdk/aws-synthetics": "0.0.0", @@ -250,12 +253,14 @@ "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/pipelines": "0.0.0", "@aws-cdk/region-info": "0.0.0", + "@aws-cdk/yaml-cfn": "0.0.0", "@types/fs-extra": "^8.1.1", - "@types/node": "^10.17.28", + "@types/node": "^10.17.35", "cdk-build-tools": "0.0.0", + "constructs": "^3.0.4", "fs-extra": "^9.0.1", "pkglint": "0.0.0", - "ts-node": "^8.10.2", + "ts-node": "^9.0.0", "typescript": "~3.8.3", "ubergen": "0.0.0" }, diff --git a/packages/aws-cdk/README.md b/packages/aws-cdk/README.md index af536d6f184dc..4bb1c4eb6d3d6 100644 --- a/packages/aws-cdk/README.md +++ b/packages/aws-cdk/README.md @@ -307,6 +307,11 @@ $ cdk doctor - AWS_SDK_LOAD_CONFIG = 1 ``` +#### Bundling +By default asset bundling is skipped for `cdk list` and `cdk destroy`. For `cdk deploy`, `cdk diff` +and `cdk synthesize` the default is to bundle assets for all stacks unless `exclusively` is specified. +In this case, only the listed stacks will have their assets bundled. + ### MFA support If `mfa_serial` is found in the active profile of the shared ini file AWS CDK diff --git a/packages/aws-cdk/bin/cdk.ts b/packages/aws-cdk/bin/cdk.ts index bbd100df02ff1..5ae3896e2bec4 100644 --- a/packages/aws-cdk/bin/cdk.ts +++ b/packages/aws-cdk/bin/cdk.ts @@ -17,11 +17,11 @@ import { availableInitLanguages, cliInit, printAvailableTemplates } from '../lib import { data, debug, error, print, setLogLevel } from '../lib/logging'; import { PluginHost } from '../lib/plugin'; import { serializeStructure } from '../lib/serialize'; -import { Configuration, Settings } from '../lib/settings'; +import { Command, Configuration, Settings } from '../lib/settings'; import * as version from '../lib/version'; /* eslint-disable max-len */ -/* eslint-disable no-shadow */ // yargs +/* eslint-disable @typescript-eslint/no-shadow */ // yargs async function parseCommandLineArguments() { // Use the following configuration for array arguments: @@ -69,7 +69,8 @@ async function parseCommandLineArguments() { .option('exclusively', { type: 'boolean', alias: 'e', desc: 'Only synthesize requested stacks, don\'t include dependencies' })) .command('bootstrap [ENVIRONMENTS..]', 'Deploys the CDK toolkit stack into an AWS environment', yargs => yargs .option('bootstrap-bucket-name', { type: 'string', alias: ['b', 'toolkit-bucket-name'], desc: 'The name of the CDK toolkit bucket; bucket will be created and must not exist', default: undefined }) - .option('bootstrap-kms-key-id', { type: 'string', desc: 'AWS KMS master key ID used for the SSE-KMS encryption', default: undefined }) + .option('bootstrap-kms-key-id', { type: 'string', desc: 'AWS KMS master key ID used for the SSE-KMS encryption', default: undefined, conflicts: 'bootstrap-customer-key' }) + .option('bootstrap-customer-key', { type: 'boolean', desc: 'Create a Customer Master Key (CMK) for the bootstrap bucket (you will be charged but can customize permissions, modern bootstrapping only)', default: undefined, conflicts: 'bootstrap-kms-key-id' }) .option('qualifier', { type: 'string', desc: 'Unique string to distinguish multiple bootstrap stacks', default: undefined }) .option('public-access-block-configuration', { type: 'boolean', desc: 'Block public access configuration on CDK toolkit bucket (enabled by default) ', default: undefined }) .option('tags', { type: 'array', alias: 't', desc: 'Tags to add for the stack (KEY=VALUE)', nargs: 1, requiresArg: true, default: [] }) @@ -136,7 +137,10 @@ async function initCommandLine() { debug('CDK toolkit version:', version.DISPLAY_VERSION); debug('Command line arguments:', argv); - const configuration = new Configuration(argv); + const configuration = new Configuration({ + ...argv, + _: argv._ as [Command, ...string[]], // TypeScript at its best + }); await configuration.load(); const sdkProvider = await SdkProvider.withAwsCliCompatibleDefaults({ @@ -222,11 +226,11 @@ async function initCommandLine() { switch (command) { case 'ls': case 'list': - return await cli.list(args.STACKS, { long: args.long }); + return cli.list(args.STACKS, { long: args.long }); case 'diff': const enableDiffNoFail = isFeatureEnabled(configuration, cxapi.ENABLE_DIFF_NO_FAIL); - return await cli.diff({ + return cli.diff({ stackNames: args.STACKS, exclusively: args.exclusively, templatePath: args.template, @@ -258,10 +262,10 @@ async function initCommandLine() { const bootstrapper = new Bootstrapper(source); if (args.showTemplate) { - return await bootstrapper.showTemplate(); + return bootstrapper.showTemplate(); } - return await cli.bootstrap(args.ENVIRONMENTS, bootstrapper, { + return cli.bootstrap(args.ENVIRONMENTS, bootstrapper, { roleArn: args.roleArn, force: argv.force, toolkitStackName: toolkitStackName, @@ -271,6 +275,7 @@ async function initCommandLine() { parameters: { bucketName: configuration.settings.get(['toolkitBucket', 'bucketName']), kmsKeyId: configuration.settings.get(['toolkitBucket', 'kmsKeyId']), + createCustomerMasterKey: args.bootstrapCustomerKey, qualifier: args.qualifier, publicAccessBlockConfiguration: args.publicAccessBlockConfiguration, trustedAccounts: arrayFromYargs(args.trust), @@ -286,7 +291,7 @@ async function initCommandLine() { parameterMap[keyValue[0]] = keyValue.slice(1).join('='); } } - return await cli.deploy({ + return cli.deploy({ stackNames: args.STACKS, exclusively: args.exclusively, toolkitStackName, @@ -305,7 +310,7 @@ async function initCommandLine() { }); case 'destroy': - return await cli.destroy({ + return cli.destroy({ stackNames: args.STACKS, exclusively: args.exclusively, force: args.force, @@ -314,17 +319,17 @@ async function initCommandLine() { case 'synthesize': case 'synth': - return await cli.synth(args.STACKS, args.exclusively); + return cli.synth(args.STACKS, args.exclusively); case 'metadata': - return await cli.metadata(args.STACK); + return cli.metadata(args.STACK); case 'init': const language = configuration.settings.get(['language']); if (args.list) { - return await printAvailableTemplates(language); + return printAvailableTemplates(language); } else { - return await cliInit(args.TEMPLATE, language, undefined, args.generateOnly); + return cliInit(args.TEMPLATE, language, undefined, args.generateOnly); } case 'version': return data(version.DISPLAY_VERSION); diff --git a/packages/aws-cdk/lib/api/aws-auth/awscli-compatible.ts b/packages/aws-cdk/lib/api/aws-auth/awscli-compatible.ts index 515c0a548643a..12e2cfd375268 100644 --- a/packages/aws-cdk/lib/api/aws-auth/awscli-compatible.ts +++ b/packages/aws-cdk/lib/api/aws-auth/awscli-compatible.ts @@ -34,7 +34,16 @@ export class AwsCliCompatible { */ public static async credentialChain(options: CredentialChainOptions = {}) { - const profile = options.profile || process.env.AWS_PROFILE || process.env.AWS_DEFAULT_PROFILE || 'default'; + // To match AWS CLI behavior, if a profile is explicitly given using --profile, + // we use that to the exclusion of everything else (note: this does not apply + // to AWS_PROFILE, environment credentials still take precedence over AWS_PROFILE) + if (options.profile) { + await forceSdkToReadConfigIfPresent(); + const theProfile = options.profile; + return new AWS.CredentialProviderChain([() => profileCredentials(theProfile)]); + } + + const implicitProfile = process.env.AWS_PROFILE || process.env.AWS_DEFAULT_PROFILE || 'default'; const sources = [ () => new AWS.EnvironmentCredentials('AWS'), @@ -45,12 +54,7 @@ export class AwsCliCompatible { // Force reading the `config` file if it exists by setting the appropriate // environment variable. await forceSdkToReadConfigIfPresent(); - sources.push(() => new PatchedSharedIniFileCredentials({ - profile, - filename: credentialsFileName(), - httpOptions: options.httpOptions, - tokenCodeFn, - })); + sources.push(() => profileCredentials(implicitProfile)); } if (options.containerCreds ?? hasEcsCredentials()) { @@ -63,6 +67,15 @@ export class AwsCliCompatible { } return new AWS.CredentialProviderChain(sources); + + function profileCredentials(profileName: string) { + return new PatchedSharedIniFileCredentials({ + profile: profileName, + filename: credentialsFileName(), + httpOptions: options.httpOptions, + tokenCodeFn, + }); + } } /** diff --git a/packages/aws-cdk/lib/api/aws-auth/credential-plugins.ts b/packages/aws-cdk/lib/api/aws-auth/credential-plugins.ts index 7a66ec438ac6c..94cdfa052feb4 100644 --- a/packages/aws-cdk/lib/api/aws-auth/credential-plugins.ts +++ b/packages/aws-cdk/lib/api/aws-auth/credential-plugins.ts @@ -45,7 +45,7 @@ export class CredentialPlugins { // Backwards compatibility: if the plugin returns a ProviderChain, resolve that chain. // Otherwise it must have returned credentials. if ((providerOrCreds as any).resolvePromise) { - return await (providerOrCreds as any).resolvePromise(); + return (providerOrCreds as any).resolvePromise(); } return providerOrCreds; } diff --git a/packages/aws-cdk/lib/api/aws-auth/sdk-provider.ts b/packages/aws-cdk/lib/api/aws-auth/sdk-provider.ts index 6b7522e4e09f2..d88d69406ca65 100644 --- a/packages/aws-cdk/lib/api/aws-auth/sdk-provider.ts +++ b/packages/aws-cdk/lib/api/aws-auth/sdk-provider.ts @@ -148,7 +148,7 @@ export class SdkProvider { params: { RoleArn: roleArn, ...externalId ? { ExternalId: externalId } : {}, - RoleSessionName: `aws-cdk-${os.userInfo().username}`, + RoleSessionName: `aws-cdk-${safeUsername()}`, }, stsConfig: { region, @@ -362,4 +362,13 @@ function readIfPossible(filename: string): string | undefined { debug(e); return undefined; } +} + +/** + * Return the username with characters invalid for a RoleSessionName removed + * + * @see https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html#API_AssumeRole_RequestParameters + */ +function safeUsername() { + return os.userInfo().username.replace(/[^\w+=,.@-]/g, '@'); } \ No newline at end of file diff --git a/packages/aws-cdk/lib/api/aws-auth/sdk.ts b/packages/aws-cdk/lib/api/aws-auth/sdk.ts index d735231836e27..28e24f19e988c 100644 --- a/packages/aws-cdk/lib/api/aws-auth/sdk.ts +++ b/packages/aws-cdk/lib/api/aws-auth/sdk.ts @@ -106,6 +106,16 @@ export class SDK implements ISDK { return { accountId, partition }; })); } + + /** + * Return the current credentials + * + * Don't use -- only used to write tests around assuming roles. + */ + public async currentCredentials(): Promise { + await this.credentials.getPromise(); + return this.credentials; + } } /** diff --git a/packages/aws-cdk/lib/api/bootstrap/bootstrap-environment.ts b/packages/aws-cdk/lib/api/bootstrap/bootstrap-environment.ts index f160df6a6f2e7..c8b2e74138ecb 100644 --- a/packages/aws-cdk/lib/api/bootstrap/bootstrap-environment.ts +++ b/packages/aws-cdk/lib/api/bootstrap/bootstrap-environment.ts @@ -25,7 +25,7 @@ export class Bootstrapper { case 'legacy': return this.legacyBootstrap(environment, sdkProvider, options); case 'default': - return this.defaultBootstrap(environment, sdkProvider, options); + return this.modernBootstrap(environment, sdkProvider, options); case 'custom': return this.customBootstrap(environment, sdkProvider, options); } @@ -45,13 +45,16 @@ export class Bootstrapper { const params = options.parameters ?? {}; if (params.trustedAccounts?.length) { - throw new Error('--trust can only be passed for the new bootstrap experience.'); + throw new Error('--trust can only be passed for the modern bootstrap experience.'); } if (params.cloudFormationExecutionPolicies?.length) { - throw new Error('--cloudformation-execution-policies can only be passed for the new bootstrap experience.'); + throw new Error('--cloudformation-execution-policies can only be passed for the modern bootstrap experience.'); + } + if (params.createCustomerMasterKey !== undefined) { + throw new Error('--bootstrap-customer-key can only be passed for the modern bootstrap experience.'); } if (params.qualifier) { - throw new Error('--qualifier can only be passed for the new bootstrap experience.'); + throw new Error('--qualifier can only be passed for the modern bootstrap experience.'); } const current = await BootstrapStack.lookup(sdkProvider, environment, options.toolkitStackName); @@ -66,7 +69,7 @@ export class Bootstrapper { * * @experimental */ - private async defaultBootstrap( + private async modernBootstrap( environment: cxapi.Environment, sdkProvider: SdkProvider, options: BootstrapEnvironmentOptions = {}): Promise { @@ -77,6 +80,10 @@ export class Bootstrapper { const current = await BootstrapStack.lookup(sdkProvider, environment, options.toolkitStackName); + if (params.createCustomerMasterKey !== undefined && params.kmsKeyId) { + throw new Error('You cannot pass \'--bootstrap-kms-key-id\' and \'--bootstrap-customer-key\' together. Specify one or the other'); + } + // If people re-bootstrap, existing parameter values are reused so that people don't accidentally change the configuration // on their bootstrap stack (this happens automatically in deployStack). However, to do proper validation on the // combined arguments (such that if --trust has been given, --cloudformation-execution-policies is necessary as well) @@ -93,7 +100,20 @@ export class Bootstrapper { if (cloudFormationExecutionPolicies.length === 0) { throw new Error('Please pass \'--cloudformation-execution-policies\' to specify deployment permissions. Try a managed policy of the form \'arn:aws:iam::aws:policy/\'.'); } - // Remind people what the current settings are + + // * If an ARN is given, that ARN. Otherwise: + // * '-' if customerKey = false + // * '' if customerKey = true + // * if customerKey is also not given + // * undefined if we already had a value in place (reusing what we had) + // * '-' if this is the first time we're deploying this stack (or upgrading from old to new bootstrap) + const currentKmsKeyId = current.parameters.FileAssetsBucketKmsKeyId; + const kmsKeyId = params.kmsKeyId ?? + (params.createCustomerMasterKey === true ? CREATE_NEW_KEY : + params.createCustomerMasterKey === false || currentKmsKeyId === undefined ? USE_AWS_MANAGED_KEY : + undefined); + + // Remind people what we settled on info(`Trusted accounts: ${trustedAccounts.length > 0 ? trustedAccounts.join(', ') : '(none)'}`); info(`Execution policies: ${cloudFormationExecutionPolicies.join(', ')}`); @@ -101,7 +121,7 @@ export class Bootstrapper { bootstrapTemplate, { FileAssetsBucketName: params.bucketName, - FileAssetsBucketKmsKeyId: params.kmsKeyId, + FileAssetsBucketKmsKeyId: kmsKeyId, // Empty array becomes empty string TrustedAccounts: trustedAccounts.join(','), CloudFormationExecutionPolicies: cloudFormationExecutionPolicies.join(','), @@ -124,7 +144,7 @@ export class Bootstrapper { if (version === 0) { return this.legacyBootstrap(environment, sdkProvider, options); } else { - return this.defaultBootstrap(environment, sdkProvider, options); + return this.modernBootstrap(environment, sdkProvider, options); } } @@ -139,3 +159,13 @@ export class Bootstrapper { } } } + +/** + * Magic parameter value that will cause the bootstrap-template.yml to NOT create a CMK but use the default keyo + */ +const USE_AWS_MANAGED_KEY = 'AWS_MANAGED_KEY'; + +/** + * Magic parameter value that will cause the bootstrap-template.yml to create a CMK + */ +const CREATE_NEW_KEY = ''; \ No newline at end of file diff --git a/packages/aws-cdk/lib/api/bootstrap/bootstrap-props.ts b/packages/aws-cdk/lib/api/bootstrap/bootstrap-props.ts index f1d00107d1421..010e5603f1400 100644 --- a/packages/aws-cdk/lib/api/bootstrap/bootstrap-props.ts +++ b/packages/aws-cdk/lib/api/bootstrap/bootstrap-props.ts @@ -55,10 +55,20 @@ export interface BootstrappingParameters { /** * The ID of an existing KMS key to be used for encrypting items in the bucket. * - * @default - the default KMS key for S3 will be used. + * @default - use the default KMS key or create a custom one */ readonly kmsKeyId?: string; + /** + * Whether or not to create a new customer master key (CMK) + * + * Only applies to modern bootstrapping. Legacy bootstrapping will never create + * a CMK, only use the default S3 key. + * + * @default false + */ + readonly createCustomerMasterKey?: boolean; + /** * The list of AWS account IDs that are trusted to deploy into the environment being bootstrapped. * diff --git a/packages/aws-cdk/lib/api/bootstrap/bootstrap-template.yaml b/packages/aws-cdk/lib/api/bootstrap/bootstrap-template.yaml index feeee078030d6..0a5a19c0cb271 100644 --- a/packages/aws-cdk/lib/api/bootstrap/bootstrap-template.yaml +++ b/packages/aws-cdk/lib/api/bootstrap/bootstrap-template.yaml @@ -16,8 +16,8 @@ Parameters: Default: '' Type: String FileAssetsBucketKmsKeyId: - Description: Custom KMS key ID to use for encrypting file assets (by default a - KMS key will be automatically defined) + Description: Empty to create a new key (default), 'AWS_MANAGED_KEY' to use a managed + S3 key, or the ID/ARN of an existing key. Default: '' Type: String ContainerAssetsRepositoryName: @@ -61,6 +61,10 @@ Conditions: Fn::Equals: - '' - Ref: FileAssetsBucketKmsKeyId + UseAwsManagedKey: + Fn::Equals: + - 'AWS_MANAGED_KEY' + - Ref: FileAssetsBucketKmsKeyId HasCustomContainerAssetsRepositoryName: Fn::Not: - Fn::Equals: @@ -150,7 +154,10 @@ Resources: Fn::If: - CreateNewKey - Fn::Sub: "${FileAssetsBucketEncryptionKey.Arn}" - - Fn::Sub: "${FileAssetsBucketKmsKeyId}" + - Fn::If: + - UseAwsManagedKey + - Ref: AWS::NoValue + - Fn::Sub: "${FileAssetsBucketKmsKeyId}" PublicAccessBlockConfiguration: Fn::If: - UsePublicAccessBlockConfiguration diff --git a/packages/aws-cdk/lib/api/cxapp/exec.ts b/packages/aws-cdk/lib/api/cxapp/exec.ts index 597a236ec1b3c..735e9a7622e19 100644 --- a/packages/aws-cdk/lib/api/cxapp/exec.ts +++ b/packages/aws-cdk/lib/api/cxapp/exec.ts @@ -39,6 +39,9 @@ export async function execProgram(aws: SdkProvider, config: Configuration): Prom context[cxapi.DISABLE_ASSET_STAGING_CONTEXT] = true; } + const bundlingStacks = config.settings.get(['bundlingStacks']) ?? ['*']; + context[cxapi.BUNDLING_STACKS] = bundlingStacks; + debug('context:', context); env[cxapi.CONTEXT_ENV] = JSON.stringify(context); diff --git a/packages/aws-cdk/lib/api/util/cloudformation.ts b/packages/aws-cdk/lib/api/util/cloudformation.ts index 54c8fe8055045..4c75b88c445c0 100644 --- a/packages/aws-cdk/lib/api/util/cloudformation.ts +++ b/packages/aws-cdk/lib/api/util/cloudformation.ts @@ -377,7 +377,7 @@ export class StackParameters { this._changes = true; } - if (key in updates && updates[key]) { + if (key in updates && updates[key] !== undefined) { this.apiParameters.push({ ParameterKey: key, ParameterValue: updates[key] }); // If the updated value is different than the current value, this will lead to a change diff --git a/packages/aws-cdk/lib/assets.ts b/packages/aws-cdk/lib/assets.ts index b6a8b6b0dfeb8..1bc390ee4b969 100644 --- a/packages/aws-cdk/lib/assets.ts +++ b/packages/aws-cdk/lib/assets.ts @@ -61,7 +61,7 @@ async function prepareAsset(asset: cxschema.AssetMetadataEntry, assetManifest: A toolkitInfo, asset.packaging === 'zip' ? cxschema.FileAssetPackaging.ZIP_DIRECTORY : cxschema.FileAssetPackaging.FILE); case 'container-image': - return await prepareDockerImageAsset(asset, assetManifest, toolkitInfo); + return prepareDockerImageAsset(asset, assetManifest, toolkitInfo); default: // eslint-disable-next-line max-len throw new Error(`Unsupported packaging type: ${(asset as any).packaging}. You might need to upgrade your aws-cdk toolkit to support this asset type.`); diff --git a/packages/aws-cdk/lib/cdk-toolkit.ts b/packages/aws-cdk/lib/cdk-toolkit.ts index e14dab633c45c..62cd54f1d2068 100644 --- a/packages/aws-cdk/lib/cdk-toolkit.ts +++ b/packages/aws-cdk/lib/cdk-toolkit.ts @@ -206,7 +206,7 @@ export class CdkToolkit { stackOutputs[stack.stackName] = result.outputs; } - for (const name of Object.keys(result.outputs)) { + for (const name of Object.keys(result.outputs).sort()) { const value = result.outputs[name]; print('%s.%s = %s', colors.cyan(stack.id), colors.cyan(name), colors.underline(colors.cyan(value))); } diff --git a/packages/aws-cdk/lib/context-providers/vpcs.ts b/packages/aws-cdk/lib/context-providers/vpcs.ts index f91e829b4147c..33e2e09ff9499 100644 --- a/packages/aws-cdk/lib/context-providers/vpcs.ts +++ b/packages/aws-cdk/lib/context-providers/vpcs.ts @@ -18,7 +18,7 @@ export class VpcNetworkContextProviderPlugin implements ContextProviderPlugin { const vpcId = await this.findVpc(ec2, args); - return await this.readVpcProps(ec2, vpcId, args); + return this.readVpcProps(ec2, vpcId, args); } private async findVpc(ec2: AWS.EC2, args: cxschema.VpcContextQuery): Promise { diff --git a/packages/aws-cdk/lib/init-templates/app/csharp/src/%name.PascalCased%/%name.PascalCased%.template.csproj b/packages/aws-cdk/lib/init-templates/app/csharp/src/%name.PascalCased%/%name.PascalCased%.template.csproj index 3f22f0caa7370..4572e92eafed1 100644 --- a/packages/aws-cdk/lib/init-templates/app/csharp/src/%name.PascalCased%/%name.PascalCased%.template.csproj +++ b/packages/aws-cdk/lib/init-templates/app/csharp/src/%name.PascalCased%/%name.PascalCased%.template.csproj @@ -3,6 +3,8 @@ Exe netcoreapp3.1 + + Major diff --git a/packages/aws-cdk/lib/init-templates/app/fsharp/src/%name.PascalCased%/%name.PascalCased%.template.fsproj b/packages/aws-cdk/lib/init-templates/app/fsharp/src/%name.PascalCased%/%name.PascalCased%.template.fsproj index f194d13c5f4f1..1ecb568dddb47 100644 --- a/packages/aws-cdk/lib/init-templates/app/fsharp/src/%name.PascalCased%/%name.PascalCased%.template.fsproj +++ b/packages/aws-cdk/lib/init-templates/app/fsharp/src/%name.PascalCased%/%name.PascalCased%.template.fsproj @@ -3,6 +3,8 @@ Exe netcoreapp3.1 + + Major diff --git a/packages/aws-cdk/lib/init-templates/sample-app/csharp/src/%name.PascalCased%/%name.PascalCased%.template.csproj b/packages/aws-cdk/lib/init-templates/sample-app/csharp/src/%name.PascalCased%/%name.PascalCased%.template.csproj index 028e9039eea3d..859978ce84abb 100644 --- a/packages/aws-cdk/lib/init-templates/sample-app/csharp/src/%name.PascalCased%/%name.PascalCased%.template.csproj +++ b/packages/aws-cdk/lib/init-templates/sample-app/csharp/src/%name.PascalCased%/%name.PascalCased%.template.csproj @@ -3,6 +3,8 @@ Exe netcoreapp3.1 + + Major diff --git a/packages/aws-cdk/lib/init-templates/sample-app/fsharp/src/%name.PascalCased%/%name.PascalCased%.template.fsproj b/packages/aws-cdk/lib/init-templates/sample-app/fsharp/src/%name.PascalCased%/%name.PascalCased%.template.fsproj index 5a4a779c70e38..4edb9ddfe2e66 100644 --- a/packages/aws-cdk/lib/init-templates/sample-app/fsharp/src/%name.PascalCased%/%name.PascalCased%.template.fsproj +++ b/packages/aws-cdk/lib/init-templates/sample-app/fsharp/src/%name.PascalCased%/%name.PascalCased%.template.fsproj @@ -3,6 +3,8 @@ Exe netcoreapp3.1 + + Major diff --git a/packages/aws-cdk/lib/init.ts b/packages/aws-cdk/lib/init.ts index 61c5118477b8f..f955354659312 100644 --- a/packages/aws-cdk/lib/init.ts +++ b/packages/aws-cdk/lib/init.ts @@ -274,13 +274,13 @@ async function initializeGitRepository(workDir: string) { async function postInstall(language: string, canUseNetwork: boolean, workDir: string) { switch (language) { case 'javascript': - return await postInstallJavascript(canUseNetwork, workDir); + return postInstallJavascript(canUseNetwork, workDir); case 'typescript': - return await postInstallTypescript(canUseNetwork, workDir); + return postInstallTypescript(canUseNetwork, workDir); case 'java': - return await postInstallJava(canUseNetwork, workDir); + return postInstallJava(canUseNetwork, workDir); case 'python': - return await postInstallPython(workDir); + return postInstallPython(workDir); } } diff --git a/packages/aws-cdk/lib/serialize.ts b/packages/aws-cdk/lib/serialize.ts index 638c4f6314d9a..36b99b3e1be64 100644 --- a/packages/aws-cdk/lib/serialize.ts +++ b/packages/aws-cdk/lib/serialize.ts @@ -1,36 +1,19 @@ +import * as yaml_cfn from '@aws-cdk/yaml-cfn'; import * as fs from 'fs-extra'; -import * as YAML from 'yaml'; - -/* eslint-disable @typescript-eslint/no-require-imports */ -const yamlTypes = require('yaml/types'); -/* eslint-enable */ /** * Stringify to YAML */ export function toYAML(obj: any): string { - const oldFold = yamlTypes.strOptions.fold.lineWidth; - try { - yamlTypes.strOptions.fold.lineWidth = 0; - return YAML.stringify(obj, { schema: 'yaml-1.1' }); - } finally { - yamlTypes.strOptions.fold.lineWidth = oldFold; - } -} - -/** - * Parse YAML - */ -export function fromYAML(str: string): any { - return YAML.parse(str, { schema: 'yaml-1.1' }); + return yaml_cfn.serialize(obj); } /** * Parse either YAML or JSON */ -export function deserializeStructure(str: string) { +export function deserializeStructure(str: string): any { try { - return fromYAML(str); + return yaml_cfn.deserialize(str); } catch (e) { // This shouldn't really ever happen I think, but it's the code we had so I'm leaving it. return JSON.parse(str); @@ -54,4 +37,4 @@ export function serializeStructure(object: any, json: boolean) { export async function loadStructuredFile(fileName: string) { const contents = await fs.readFile(fileName, { encoding: 'utf-8' }); return deserializeStructure(contents); -} \ No newline at end of file +} diff --git a/packages/aws-cdk/lib/settings.ts b/packages/aws-cdk/lib/settings.ts index 1cd74d42e858c..af9193d9a6456 100644 --- a/packages/aws-cdk/lib/settings.ts +++ b/packages/aws-cdk/lib/settings.ts @@ -18,7 +18,33 @@ export const TRANSIENT_CONTEXT_KEY = '$dontSaveContext'; const CONTEXT_KEY = 'context'; -export type Arguments = { readonly [name: string]: unknown }; +export enum Command { + LS = 'ls', + LIST = 'list', + DIFF = 'diff', + BOOTSTRAP = 'bootstrap', + DEPLOY = 'deploy', + DESTROY = 'destroy', + SYNTHESIZE = 'synthesize', + SYNTH = 'synth', + METADATA = 'metadata', + INIT = 'init', + VERSION = 'version', +} + +const BUNDLING_COMMANDS = [ + Command.DEPLOY, + Command.DIFF, + Command.SYNTH, + Command.SYNTHESIZE, +]; + +export type Arguments = { + readonly _: [Command, ...string[]]; + readonly exclusively?: boolean; + readonly STACKS?: string[]; + readonly [name: string]: unknown; +}; /** * All sources of settings combined @@ -185,6 +211,18 @@ export class Settings { const context = this.parseStringContextListToObject(argv); const tags = this.parseStringTagsListToObject(expectStringList(argv.tags)); + // Determine bundling stacks + let bundlingStacks: string[]; + if (BUNDLING_COMMANDS.includes(argv._[0])) { + // If we deploy, diff or synth a list of stacks exclusively we skip + // bundling for all other stacks. + bundlingStacks = argv.exclusively + ? argv.STACKS ?? ['*'] + : ['*']; + } else { // Skip bundling for all stacks + bundlingStacks = []; + } + return new Settings({ app: argv.app, browser: argv.browser, @@ -205,6 +243,7 @@ export class Settings { staging: argv.staging, output: argv.output, progress: argv.progress, + bundlingStacks, }); } @@ -396,4 +435,4 @@ function expectStringList(x: unknown): string[] | undefined { throw new Error(`Expected list of strings, found ${nonStrings}`); } return x; -} \ No newline at end of file +} diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index 20e667f4ad0fc..0e1d20d1512d2 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -44,33 +44,33 @@ "@types/archiver": "^3.1.0", "@types/fs-extra": "^8.1.1", "@types/glob": "^7.1.3", - "@types/jest": "^26.0.10", + "@types/jest": "^26.0.14", "@types/minimatch": "^3.0.3", "@types/mockery": "^1.4.29", - "@types/node": "^10.17.28", + "@types/node": "^10.17.35", "@types/promptly": "^3.0.0", - "@types/semver": "^7.3.3", + "@types/semver": "^7.3.4", "@types/sinon": "^9.0.5", - "@types/table": "^4.0.7", + "@types/table": "^5.0.0", "@types/uuid": "^8.3.0", "@types/wrap-ansi": "^3.0.0", - "@types/yaml": "^1.9.7", "@types/yargs": "^15.0.5", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "mockery": "^2.1.0", "pkglint": "0.0.0", "sinon": "^9.0.3", - "ts-jest": "^26.2.0", - "ts-mock-imports": "^1.2.6" + "ts-jest": "^26.3.0", + "ts-mock-imports": "^1.3.0" }, "dependencies": { "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/cloudformation-diff": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/region-info": "0.0.0", - "archiver": "^4.0.2", + "@aws-cdk/yaml-cfn": "0.0.0", + "archiver": "^5.0.2", "aws-sdk": "^2.739.0", "camelcase": "^6.0.0", "cdk-assets": "0.0.0", @@ -82,13 +82,12 @@ "minimatch": ">=3.0", "promptly": "^3.0.3", "proxy-agent": "^3.1.1", - "semver": "^7.2.2", + "semver": "^7.3.2", "source-map-support": "^0.5.19", - "table": "^5.4.6", + "table": "^6.0.3", "uuid": "^8.3.0", "wrap-ansi": "^7.0.0", - "yaml": "^1.10.0", - "yargs": "^15.4.1" + "yargs": "^16.0.3" }, "repository": { "url": "https://github.com/aws/aws-cdk.git", diff --git a/packages/aws-cdk/test/api/bootstrap.test.ts b/packages/aws-cdk/test/api/bootstrap.test.ts index bda570d3cbe05..d04a49ec11472 100644 --- a/packages/aws-cdk/test/api/bootstrap.test.ts +++ b/packages/aws-cdk/test/api/bootstrap.test.ts @@ -1,6 +1,6 @@ import { CreateChangeSetInput } from 'aws-sdk/clients/cloudformation'; import { Bootstrapper } from '../../lib/api/bootstrap'; -import { fromYAML } from '../../lib/serialize'; +import { deserializeStructure } from '../../lib/serialize'; import { MockSdkProvider, SyncHandlerSubsetOf } from '../util/mock-sdk'; const env = { @@ -38,7 +38,7 @@ beforeEach(() => { ], })), createChangeSet: jest.fn((info: CreateChangeSetInput) => { - changeSetTemplate = fromYAML(info.TemplateBody as string); + changeSetTemplate = deserializeStructure(info.TemplateBody as string); return {}; }), describeChangeSet: jest.fn(() => ({ @@ -158,7 +158,7 @@ test('passing trusted accounts to the old bootstrapping results in an error', as }, })) .rejects - .toThrow('--trust can only be passed for the new bootstrap experience.'); + .toThrow('--trust can only be passed for the modern bootstrap experience.'); }); test('passing CFN execution policies to the old bootstrapping results in an error', async () => { @@ -169,7 +169,7 @@ test('passing CFN execution policies to the old bootstrapping results in an erro }, })) .rejects - .toThrow('--cloudformation-execution-policies can only be passed for the new bootstrap experience.'); + .toThrow('--cloudformation-execution-policies can only be passed for the modern bootstrap experience.'); }); test('even if the bootstrap stack is in a rollback state, can still retry bootstrapping it', async () => { @@ -295,4 +295,4 @@ test('stack is termination protected when set', async () => { // THEN expect(executed).toBeTruthy(); expect(protectedTermination).toBeTruthy(); -}); \ No newline at end of file +}); diff --git a/packages/aws-cdk/test/api/bootstrap2.test.ts b/packages/aws-cdk/test/api/bootstrap2.test.ts index 99edb18f5d033..77ec30243fe1f 100644 --- a/packages/aws-cdk/test/api/bootstrap2.test.ts +++ b/packages/aws-cdk/test/api/bootstrap2.test.ts @@ -28,6 +28,10 @@ describe('Bootstrapping v2', () => { mockTheToolkitInfo = undefined; }); + afterEach(() => { + mockDeployStack.mockClear(); + }); + test('passes the bucket name as a CFN parameter', async () => { await bootstrapper.bootstrapEnvironment(env, sdk, { parameters: { @@ -137,73 +141,130 @@ describe('Bootstrapping v2', () => { ]); }); - test('stack is not termination protected by default', async () => { - await bootstrapper.bootstrapEnvironment(env, sdk, { - parameters: { - cloudFormationExecutionPolicies: ['arn:policy'], - }, + describe('termination protection', () => { + test('stack is not termination protected by default', async () => { + await bootstrapper.bootstrapEnvironment(env, sdk, { + parameters: { + cloudFormationExecutionPolicies: ['arn:policy'], + }, + }); + + expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({ + stack: expect.objectContaining({ + terminationProtection: false, + }), + })); }); - expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({ - stack: expect.objectContaining({ - terminationProtection: false, - }), - })); - }); - - test('stack is termination protected when option is set', async () => { - await bootstrapper.bootstrapEnvironment(env, sdk, { - terminationProtection: true, - parameters: { - cloudFormationExecutionPolicies: ['arn:policy'], - }, - }); - - expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({ - stack: expect.objectContaining({ + test('stack is termination protected when option is set', async () => { + await bootstrapper.bootstrapEnvironment(env, sdk, { terminationProtection: true, - }), - })); - }); - - test('termination protection is left alone when option is not given', async () => { - mockTheToolkitInfo = mockToolkitInfo({ - EnableTerminationProtection: true, + parameters: { + cloudFormationExecutionPolicies: ['arn:policy'], + }, + }); + + expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({ + stack: expect.objectContaining({ + terminationProtection: true, + }), + })); }); - await bootstrapper.bootstrapEnvironment(env, sdk, { - parameters: { - cloudFormationExecutionPolicies: ['arn:policy'], - }, + test('termination protection is left alone when option is not given', async () => { + mockTheToolkitInfo = mockToolkitInfo({ + EnableTerminationProtection: true, + }); + + await bootstrapper.bootstrapEnvironment(env, sdk, { + parameters: { + cloudFormationExecutionPolicies: ['arn:policy'], + }, + }); + + expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({ + stack: expect.objectContaining({ + terminationProtection: true, + }), + })); }); - expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({ - stack: expect.objectContaining({ - terminationProtection: true, - }), - })); - }); + test('termination protection can be switched off', async () => { + mockTheToolkitInfo = mockToolkitInfo({ + EnableTerminationProtection: true, + }); - test('termination protection can be switched off', async () => { - mockTheToolkitInfo = mockToolkitInfo({ - EnableTerminationProtection: true, + await bootstrapper.bootstrapEnvironment(env, sdk, { + terminationProtection: false, + parameters: { + cloudFormationExecutionPolicies: ['arn:policy'], + }, + }); + + expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({ + stack: expect.objectContaining({ + terminationProtection: false, + }), + })); }); + }); - await bootstrapper.bootstrapEnvironment(env, sdk, { - terminationProtection: false, - parameters: { - cloudFormationExecutionPolicies: ['arn:policy'], - }, + describe('KMS key', () => { + test.each([ + // Default case + [undefined, 'AWS_MANAGED_KEY'], + // Create a new key + [true, ''], + // Don't create a new key + [false, 'AWS_MANAGED_KEY'], + ])('(new stack) createCustomerMasterKey=%p => parameter becomes %p ', async (createCustomerMasterKey, paramKeyId) => { + // GIVEN: no existing stack + + // WHEN + await bootstrapper.bootstrapEnvironment(env, sdk, { + parameters: { + createCustomerMasterKey, + cloudFormationExecutionPolicies: ['arn:booh'], + }, + }); + + // THEN + expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({ + parameters: expect.objectContaining({ + FileAssetsBucketKmsKeyId: paramKeyId, + }), + })); }); - expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({ - stack: expect.objectContaining({ - terminationProtection: false, - }), - })); - }); - - afterEach(() => { - mockDeployStack.mockClear(); + test.each([ + // Old bootstrap stack being upgraded to new one + [undefined, undefined, 'AWS_MANAGED_KEY'], + // There is a value, user doesn't request a change + ['arn:aws:key', undefined, undefined], + // Switch off existing key + ['arn:aws:key', false, 'AWS_MANAGED_KEY'], + // Switch on existing key + ['AWS_MANAGED_KEY', true, ''], + ])('(upgrading) current param %p, createCustomerMasterKey=%p => parameter becomes %p ', async (currentKeyId, createCustomerMasterKey, paramKeyId) => { + // GIVEN + mockTheToolkitInfo = mockToolkitInfo({ + Parameters: currentKeyId ? [{ ParameterKey: 'FileAssetsBucketKmsKeyId', ParameterValue: currentKeyId }] : undefined, + }); + + // WHEN + await bootstrapper.bootstrapEnvironment(env, sdk, { + parameters: { + createCustomerMasterKey, + cloudFormationExecutionPolicies: ['arn:booh'], + }, + }); + + // THEN + expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({ + parameters: expect.objectContaining({ + FileAssetsBucketKmsKeyId: paramKeyId, + }), + })); + }); }); }); \ No newline at end of file diff --git a/packages/aws-cdk/test/api/cloud-assembly.test.ts b/packages/aws-cdk/test/api/cloud-assembly.test.ts index c0bd1528da8ef..3e192e3514c23 100644 --- a/packages/aws-cdk/test/api/cloud-assembly.test.ts +++ b/packages/aws-cdk/test/api/cloud-assembly.test.ts @@ -82,5 +82,5 @@ async function testCloudAssembly({ env }: { env?: string, versionReporting?: boo }], }); - return await cloudExec.synthesize(); + return cloudExec.synthesize(); } diff --git a/packages/aws-cdk/test/api/sdk-provider.test.ts b/packages/aws-cdk/test/api/sdk-provider.test.ts index 518cc80660654..70319a113f829 100644 --- a/packages/aws-cdk/test/api/sdk-provider.test.ts +++ b/packages/aws-cdk/test/api/sdk-provider.test.ts @@ -1,3 +1,4 @@ +import * as os from 'os'; import * as cxapi from '@aws-cdk/cx-api'; import * as AWS from 'aws-sdk'; import * as SDKMock from 'aws-sdk-mock'; @@ -152,6 +153,22 @@ describe('with default config files', () => { expect(sdkConfig(sdk).region).toEqual('eu-bla-5'); }); + test('passing profile does not use EnvironmentCredentials', async () => { + // GIVEN + const provider = await SdkProvider.withAwsCliCompatibleDefaults({ ...defaultCredOptions, profile: 'foo' }); + + const environmentCredentialsPrototype = (new AWS.EnvironmentCredentials('AWS')).constructor.prototype; + + await withMocked(environmentCredentialsPrototype, 'refresh', async (refresh) => { + refresh.mockImplementation((callback: (err?: Error) => void) => callback(new Error('This function should not have been called'))); + + // WHEN + await provider.defaultAccount(); + + expect(refresh).not.toHaveBeenCalled(); + }); + }); + test('mixed profile credentials', async () => { // WHEN const provider = await SdkProvider.withAwsCliCompatibleDefaults({ ...defaultCredOptions, profile: 'foo' }); @@ -255,6 +272,44 @@ describe('with default config files', () => { await expect(sdk.s3().listBuckets().promise()).rejects.toThrow('did you bootstrap'); await expect(sdk.s3().listBuckets().promise()).rejects.toThrow('Nope!'); }); + + test('assuming a role sanitizes the username into the session name', async () => { + // GIVEN + SDKMock.restore(); + + await withMocked(os, 'userInfo', async (userInfo) => { + userInfo.mockReturnValue({ username: 'skål', uid: 1, gid: 1, homedir: '/here', shell: '/bin/sh' }); + + await withMocked((new AWS.STS()).constructor.prototype, 'assumeRole', async (assumeRole) => { + let assumeRoleRequest; + + assumeRole.mockImplementation(function ( + this: any, + request: AWS.STS.Types.AssumeRoleRequest, + cb?: (err: Error | null, x: AWS.STS.Types.AssumeRoleResponse) => void) { + + // Part of the request is stored on "this" + assumeRoleRequest = { ...this.config.params, ...request }; + + const response = { + Credentials: { AccessKeyId: `${uid}aid`, Expiration: new Date(), SecretAccessKey: 's', SessionToken: '' }, + }; + if (cb) { cb(null, response); } + return { promise: () => Promise.resolve(response) }; + }); + + // WHEN + const provider = new SdkProvider(new AWS.CredentialProviderChain([() => new AWS.Credentials({ accessKeyId: 'a', secretAccessKey: 's' })]), 'eu-somewhere'); + const sdk = await provider.withAssumedRole('bla.role.arn', undefined, undefined); + + await sdk.currentCredentials(); + + expect(assumeRoleRequest).toEqual(expect.objectContaining({ + RoleSessionName: 'aws-cdk-sk@l', + })); + }); + }); + }); }); describe('Plugins', () => { @@ -309,9 +364,6 @@ test('can assume role without a [default] profile', async () => { const provider = await SdkProvider.withAwsCliCompatibleDefaults({ ...defaultCredOptions, profile: 'assumable', - httpOptions: { - proxyAddress: 'http://DOESNTMATTER/', - }, }); const account = await provider.defaultAccount(); @@ -326,8 +378,7 @@ test('can assume role with ecs credentials', async () => { // GIVEN bockfs({ - '/home/me/.bxt/credentials': dedent(` - `), + '/home/me/.bxt/credentials': '', '/home/me/.bxt/config': dedent(` [profile ecs] role_arn=arn:aws:iam::12356789012:role/Assumable @@ -343,9 +394,6 @@ test('can assume role with ecs credentials', async () => { const provider = await SdkProvider.withAwsCliCompatibleDefaults({ ...defaultCredOptions, profile: 'ecs', - httpOptions: { - proxyAddress: 'http://DOESNTMATTER/', - }, }); await provider.defaultAccount(); @@ -364,8 +412,7 @@ test('can assume role with ec2 credentials', async () => { // GIVEN bockfs({ - '/home/me/.bxt/credentials': dedent(` - `), + '/home/me/.bxt/credentials': '', '/home/me/.bxt/config': dedent(` [profile ecs] role_arn=arn:aws:iam::12356789012:role/Assumable @@ -381,9 +428,6 @@ test('can assume role with ec2 credentials', async () => { const provider = await SdkProvider.withAwsCliCompatibleDefaults({ ...defaultCredOptions, profile: 'ecs', - httpOptions: { - proxyAddress: 'http://DOESNTMATTER/', - }, }); await provider.defaultAccount(); @@ -402,8 +446,7 @@ test('can assume role with env credentials', async () => { // GIVEN bockfs({ - '/home/me/.bxt/credentials': dedent(` - `), + '/home/me/.bxt/credentials': '', '/home/me/.bxt/config': dedent(` [profile ecs] role_arn=arn:aws:iam::12356789012:role/Assumable @@ -419,9 +462,6 @@ test('can assume role with env credentials', async () => { const provider = await SdkProvider.withAwsCliCompatibleDefaults({ ...defaultCredOptions, profile: 'ecs', - httpOptions: { - proxyAddress: 'http://DOESNTMATTER/', - }, }); await provider.defaultAccount(); @@ -437,6 +477,7 @@ test('can assume role with env credentials', async () => { test('assume fails with unsupported credential_source', async () => { // GIVEN bockfs({ + '/home/me/.bxt/credentials': '', '/home/me/.bxt/config': dedent(` [profile assumable] role_arn=arn:aws:iam::12356789012:role/Assumable @@ -463,9 +504,6 @@ test('assume fails with unsupported credential_source', async () => { const provider = await SdkProvider.withAwsCliCompatibleDefaults({ ...defaultCredOptions, profile: 'assumable', - httpOptions: { - proxyAddress: 'http://DOESNTMATTER/', - }, }); const account = await provider.defaultAccount(); diff --git a/packages/aws-cdk/test/context.test.ts b/packages/aws-cdk/test/context.test.ts index 373c42090daec..04a5626c2d4b7 100644 --- a/packages/aws-cdk/test/context.test.ts +++ b/packages/aws-cdk/test/context.test.ts @@ -100,7 +100,7 @@ test('surive no context in old file', async () => { test('command line context is merged with stored context', async () => { // GIVEN await fs.writeJSON('cdk.context.json', { boo: 'far' }); - const config = await new Configuration({ context: ['foo=bar'] } as any).load(); + const config = await new Configuration({ context: ['foo=bar'], _: ['command'] } as any).load(); // WHEN expect(config.context.all).toEqual({ foo: 'bar', boo: 'far' }); diff --git a/packages/aws-cdk/test/integ/cli-regression-patches/v1.63.0/NOTES.md b/packages/aws-cdk/test/integ/cli-regression-patches/v1.63.0/NOTES.md new file mode 100644 index 0000000000000..1a2609d91103e --- /dev/null +++ b/packages/aws-cdk/test/integ/cli-regression-patches/v1.63.0/NOTES.md @@ -0,0 +1 @@ +We made --cloudformation-execution-policies required, old tests don't pass it yet \ No newline at end of file diff --git a/packages/aws-cdk/test/integ/cli-regression-patches/v1.63.0/skip-tests.txt b/packages/aws-cdk/test/integ/cli-regression-patches/v1.63.0/skip-tests.txt new file mode 100644 index 0000000000000..ee9ae218013ad --- /dev/null +++ b/packages/aws-cdk/test/integ/cli-regression-patches/v1.63.0/skip-tests.txt @@ -0,0 +1,7 @@ +# We made --cloudformation-execution-policies required, old tests don't pass it yet + +upgrade legacy bootstrap stack to new bootstrap stack while in use +deploy new style synthesis to new style bootstrap +deploy new style synthesis to new style bootstrap (with docker image) +switch on termination protection, switch is left alone on re-bootstrap +add tags, left alone on re-bootstrap diff --git a/packages/aws-cdk/test/integ/cli/aws-helpers.ts b/packages/aws-cdk/test/integ/cli/aws-helpers.ts index a8058ba6595ef..7c6435fdfba91 100644 --- a/packages/aws-cdk/test/integ/cli/aws-helpers.ts +++ b/packages/aws-cdk/test/integ/cli/aws-helpers.ts @@ -121,7 +121,7 @@ async function awsCall< const cfn = new ctor(config); const response = cfn[call](request); try { - return await response.promise(); + return response.promise(); } catch (e) { const newErr = new Error(`${call}(${JSON.stringify(request)}): ${e.message}`); (newErr as any).code = e.code; diff --git a/packages/aws-cdk/test/integ/cli/bootstrapping.integtest.ts b/packages/aws-cdk/test/integ/cli/bootstrapping.integtest.ts index bb2d65211c037..1feb254316af0 100644 --- a/packages/aws-cdk/test/integ/cli/bootstrapping.integtest.ts +++ b/packages/aws-cdk/test/integ/cli/bootstrapping.integtest.ts @@ -196,7 +196,10 @@ integTest('switch on termination protection, switch is left alone on re-bootstra await fixture.cdk(['bootstrap', '-v', '--toolkit-stack-name', bootstrapStackName, '--termination-protection', 'true', - '--qualifier', fixture.qualifier], { modEnv: { CDK_NEW_BOOTSTRAP: '1' } }); + '--qualifier', fixture.qualifier, + '--cloudformation-execution-policies', 'arn:aws:iam::aws:policy/AdministratorAccess'], { + modEnv: { CDK_NEW_BOOTSTRAP: '1' }, + }); await fixture.cdk(['bootstrap', '-v', '--toolkit-stack-name', bootstrapStackName, '--force'], { modEnv: { CDK_NEW_BOOTSTRAP: '1' } }); const response = await fixture.aws.cloudFormation('describeStacks', { StackName: bootstrapStackName }); @@ -208,7 +211,10 @@ integTest('add tags, left alone on re-bootstrap', withDefaultFixture(async (fixt await fixture.cdk(['bootstrap', '-v', '--toolkit-stack-name', bootstrapStackName, '--tags', 'Foo=Bar', - '--qualifier', fixture.qualifier], { modEnv: { CDK_NEW_BOOTSTRAP: '1' } }); + '--qualifier', fixture.qualifier, + '--cloudformation-execution-policies', 'arn:aws:iam::aws:policy/AdministratorAccess'], { + modEnv: { CDK_NEW_BOOTSTRAP: '1' }, + }); await fixture.cdk(['bootstrap', '-v', '--toolkit-stack-name', bootstrapStackName, '--force'], { modEnv: { CDK_NEW_BOOTSTRAP: '1' } }); const response = await fixture.aws.cloudFormation('describeStacks', { StackName: bootstrapStackName }); diff --git a/packages/aws-cdk/test/integ/cli/cdk-helpers.ts b/packages/aws-cdk/test/integ/cli/cdk-helpers.ts index 8604135d895ef..66c6799164fd8 100644 --- a/packages/aws-cdk/test/integ/cli/cdk-helpers.ts +++ b/packages/aws-cdk/test/integ/cli/cdk-helpers.ts @@ -150,7 +150,7 @@ export class TestFixture { } public async shell(command: string[], options: Omit = {}): Promise { - return await shell(command, { + return shell(command, { output: this.output, cwd: this.integTestDir, ...options, @@ -178,7 +178,7 @@ export class TestFixture { } public async cdk(args: string[], options: CdkCliOptions = {}) { - return await this.shell(['cdk', ...args], { + return this.shell(['cdk', ...args], { ...options, modEnv: { AWS_REGION: this.aws.region, diff --git a/packages/aws-cdk/test/settings.test.ts b/packages/aws-cdk/test/settings.test.ts index 28d07d686dcc8..b3bc9dded811c 100644 --- a/packages/aws-cdk/test/settings.test.ts +++ b/packages/aws-cdk/test/settings.test.ts @@ -1,4 +1,4 @@ -import { Context, Settings } from '../lib/settings'; +import { Command, Context, Settings } from '../lib/settings'; test('can delete values from Context object', () => { // GIVEN @@ -62,8 +62,8 @@ test('can clear all values in all objects', () => { test('can parse string context from command line arguments', () => { // GIVEN - const settings1 = Settings.fromCommandLineArguments({ context: ['foo=bar'] }); - const settings2 = Settings.fromCommandLineArguments({ context: ['foo='] }); + const settings1 = Settings.fromCommandLineArguments({ context: ['foo=bar'], _: [Command.DEPLOY] }); + const settings2 = Settings.fromCommandLineArguments({ context: ['foo='], _: [Command.DEPLOY] }); // THEN expect(settings1.get(['context']).foo).toEqual( 'bar'); @@ -72,10 +72,42 @@ test('can parse string context from command line arguments', () => { test('can parse string context from command line arguments with equals sign in value', () => { // GIVEN - const settings1 = Settings.fromCommandLineArguments({ context: ['foo==bar='] }); - const settings2 = Settings.fromCommandLineArguments({ context: ['foo=bar='] }); + const settings1 = Settings.fromCommandLineArguments({ context: ['foo==bar='], _: [Command.DEPLOY] }); + const settings2 = Settings.fromCommandLineArguments({ context: ['foo=bar='], _: [Command.DEPLOY] }); // THEN expect(settings1.get(['context']).foo).toEqual( '=bar='); expect(settings2.get(['context']).foo).toEqual( 'bar='); }); + +test('bundling stacks defaults to an empty list', () => { + // GIVEN + const settings = Settings.fromCommandLineArguments({ + _: [Command.LIST], + }); + + // THEN + expect(settings.get(['bundlingStacks'])).toEqual([]); +}); + +test('bundling stacks defaults to * for deploy', () => { + // GIVEN + const settings = Settings.fromCommandLineArguments({ + _: [Command.DEPLOY], + }); + + // THEN + expect(settings.get(['bundlingStacks'])).toEqual(['*']); +}); + +test('bundling stacks with deploy exclusively', () => { + // GIVEN + const settings = Settings.fromCommandLineArguments({ + _: [Command.DEPLOY], + exclusively: true, + STACKS: ['cool-stack'], + }); + + // THEN + expect(settings.get(['bundlingStacks'])).toEqual(['cool-stack']); +}); diff --git a/packages/aws-cdk/test/util.ts b/packages/aws-cdk/test/util.ts index f21c0bb2dd78e..17f8860b01df7 100644 --- a/packages/aws-cdk/test/util.ts +++ b/packages/aws-cdk/test/util.ts @@ -166,20 +166,18 @@ export function withMocked(obj: A, key: const mockFn = jest.fn(); (obj as any)[key] = mockFn; - let ret; + let asyncFinally: boolean = false; try { - ret = block(mockFn as any); - } catch (e) { - obj[key] = original; - throw e; - } + const ret = block(mockFn as any); + if (!isPromise(ret)) { return ret; } - if (!isPromise(ret)) { - obj[key] = original; - return ret; + asyncFinally = true; + return ret.finally(() => { obj[key] = original; }) as any; + } finally { + if (!asyncFinally) { + obj[key] = original; + } } - - return ret.finally(() => { obj[key] = original; }) as any; } function isPromise(object: any): object is Promise { diff --git a/packages/aws-cdk/test/util/cloudformation.test.ts b/packages/aws-cdk/test/util/cloudformation.test.ts index ac27720d7747b..ca7b2afc570ca 100644 --- a/packages/aws-cdk/test/util/cloudformation.test.ts +++ b/packages/aws-cdk/test/util/cloudformation.test.ts @@ -86,6 +86,18 @@ test('if a parameter is retrieved from SSM, the parameters always count as chang expect(params.diff({ Foo: '/Some/Key' }, { Foo: '/Some/Key' }).changed).toEqual(true); }); +test('empty string is a valid update value', () => { + const params = TemplateParameters.fromTemplate({ + Parameters: { + Foo: { Type: 'String', Default: 'Foo' }, + }, + }); + + expect(params.diff({ Foo: '' }, { Foo: 'ThisIsOld' }).apiParameters).toEqual([ + { ParameterKey: 'Foo', ParameterValue: '' }, + ]); +}); + test('unknown parameter in overrides, pass it anyway', () => { // Not sure if we really want this. It seems like it would be nice // to not pass parameters that aren't expected, given that CFN will diff --git a/packages/aws-cdk/test/yaml.test.ts b/packages/aws-cdk/test/yaml.test.ts index aabcd090fbfea..e953e70758e63 100644 --- a/packages/aws-cdk/test/yaml.test.ts +++ b/packages/aws-cdk/test/yaml.test.ts @@ -1,4 +1,4 @@ -import { fromYAML, toYAML } from '../lib/serialize'; +import { deserializeStructure, toYAML } from '../lib/serialize'; // Preferred quote of the YAML library const q = '"'; @@ -62,7 +62,7 @@ test('validate emission of very long lines', () => { const output = toYAML(template); - const parsed = fromYAML(output); + const parsed = deserializeStructure(output); expect(template).toEqual(parsed); }); diff --git a/packages/awslint/package.json b/packages/awslint/package.json index 0492e36546ea5..10371217cdce3 100644 --- a/packages/awslint/package.json +++ b/packages/awslint/package.json @@ -16,12 +16,12 @@ "awslint": "bin/awslint" }, "dependencies": { - "@jsii/spec": "^1.11.0", + "@jsii/spec": "^1.12.0", "camelcase": "^6.0.0", "colors": "^1.4.0", "fs-extra": "^9.0.1", - "jsii-reflect": "^1.11.0", - "yargs": "^15.4.1" + "jsii-reflect": "^1.12.0", + "yargs": "^16.0.3" }, "devDependencies": { "@types/fs-extra": "^8.1.1", diff --git a/packages/cdk-assets/bin/publish.ts b/packages/cdk-assets/bin/publish.ts index 12a0e318d0f78..20b7a609bfdd0 100644 --- a/packages/cdk-assets/bin/publish.ts +++ b/packages/cdk-assets/bin/publish.ts @@ -140,7 +140,7 @@ class DefaultAwsClient implements IAws { params: { RoleArn: roleArn, ExternalId: externalId, - RoleSessionName: `cdk-assets-${os.userInfo().username}`, + RoleSessionName: `cdk-assets-${safeUsername()}`, }, stsConfig: { region, @@ -149,3 +149,12 @@ class DefaultAwsClient implements IAws { }); } } + +/** + * Return the username with characters invalid for a RoleSessionName removed + * + * @see https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html#API_AssumeRole_RequestParameters + */ +function safeUsername() { + return os.userInfo().username.replace(/[^\w+=,.@-]/g, '@'); +} \ No newline at end of file diff --git a/packages/cdk-assets/package.json b/packages/cdk-assets/package.json index 7bf00e59950e6..cde9251f3232d 100644 --- a/packages/cdk-assets/package.json +++ b/packages/cdk-assets/package.json @@ -32,13 +32,13 @@ "devDependencies": { "@types/archiver": "^3.1.0", "@types/glob": "^7.1.3", - "@types/jest": "^26.0.10", + "@types/jest": "^26.0.14", "@types/jszip": "^3.4.1", "@types/mock-fs": "^4.10.0", - "@types/node": "^10.17.28", + "@types/node": "^10.17.35", "@types/yargs": "^15.0.5", "cdk-build-tools": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "jszip": "^3.5.0", "mock-fs": "^4.13.0", "pkglint": "0.0.0" @@ -46,10 +46,10 @@ "dependencies": { "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "archiver": "^4.0.2", + "archiver": "^5.0.2", "aws-sdk": "^2.739.0", "glob": "^7.1.6", - "yargs": "^15.4.1" + "yargs": "^16.0.3" }, "repository": { "url": "https://github.com/aws/aws-cdk.git", diff --git a/packages/cdk-dasm/package.json b/packages/cdk-dasm/package.json index f7a9dd91443e2..0a27c4a75f87e 100644 --- a/packages/cdk-dasm/package.json +++ b/packages/cdk-dasm/package.json @@ -26,13 +26,13 @@ }, "license": "Apache-2.0", "dependencies": { - "codemaker": "^1.11.0", + "codemaker": "^1.12.0", "yaml": "1.10.0" }, "devDependencies": { - "@types/jest": "^26.0.10", + "@types/jest": "^26.0.14", "@types/yaml": "1.9.7", - "jest": "^25.5.4" + "jest": "^26.4.2" }, "keywords": [ "aws", diff --git a/packages/decdk/package.json b/packages/decdk/package.json index d6ec79db6d37d..e6497ee5372e6 100644 --- a/packages/decdk/package.json +++ b/packages/decdk/package.json @@ -28,7 +28,6 @@ "license": "Apache-2.0", "dependencies": { "@aws-cdk/alexa-ask": "0.0.0", - "@aws-cdk/pipelines": "0.0.0", "@aws-cdk/app-delivery": "0.0.0", "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-accessanalyzer": "0.0.0", @@ -39,6 +38,7 @@ "@aws-cdk/aws-apigatewayv2": "0.0.0", "@aws-cdk/aws-appconfig": "0.0.0", "@aws-cdk/aws-applicationautoscaling": "0.0.0", + "@aws-cdk/aws-applicationinsights": "0.0.0", "@aws-cdk/aws-appmesh": "0.0.0", "@aws-cdk/aws-appstream": "0.0.0", "@aws-cdk/aws-appsync": "0.0.0", @@ -65,6 +65,7 @@ "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-codedeploy": "0.0.0", "@aws-cdk/aws-codeguruprofiler": "0.0.0", + "@aws-cdk/aws-codegurureviewer": "0.0.0", "@aws-cdk/aws-codepipeline": "0.0.0", "@aws-cdk/aws-codepipeline-actions": "0.0.0", "@aws-cdk/aws-codestar": "0.0.0", @@ -114,6 +115,7 @@ "@aws-cdk/aws-iotanalytics": "0.0.0", "@aws-cdk/aws-iotevents": "0.0.0", "@aws-cdk/aws-iotthingsgraph": "0.0.0", + "@aws-cdk/aws-kendra": "0.0.0", "@aws-cdk/aws-kinesis": "0.0.0", "@aws-cdk/aws-kinesisanalytics": "0.0.0", "@aws-cdk/aws-kinesisfirehose": "0.0.0", @@ -165,6 +167,7 @@ "@aws-cdk/aws-sns-subscriptions": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", + "@aws-cdk/aws-sso": "0.0.0", "@aws-cdk/aws-stepfunctions": "0.0.0", "@aws-cdk/aws-stepfunctions-tasks": "0.0.0", "@aws-cdk/aws-synthetics": "0.0.0", @@ -178,21 +181,23 @@ "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", "@aws-cdk/cx-api": "0.0.0", + "@aws-cdk/pipelines": "0.0.0", "@aws-cdk/region-info": "0.0.0", + "@aws-cdk/yaml-cfn": "0.0.0", "constructs": "^3.0.4", "fs-extra": "^9.0.1", - "jsii-reflect": "^1.11.0", + "jsii-reflect": "^1.12.0", "jsonschema": "^1.2.6", - "yaml": "1.9.2", - "yargs": "^15.4.1" + "yaml": "1.10.0", + "yargs": "^16.0.3" }, "devDependencies": { "@types/fs-extra": "^8.1.1", - "@types/jest": "^26.0.10", + "@types/jest": "^26.0.14", "@types/yaml": "1.9.7", "@types/yargs": "^15.0.5", - "jest": "^25.5.4", - "jsii": "^1.11.0" + "jest": "^26.4.2", + "jsii": "^1.12.0" }, "keywords": [ "aws", diff --git a/packages/monocdk-experiment/package.json b/packages/monocdk-experiment/package.json index cad3ccd08550c..601234c3ae67f 100644 --- a/packages/monocdk-experiment/package.json +++ b/packages/monocdk-experiment/package.json @@ -90,13 +90,12 @@ "dependencies": { "case": "1.6.3", "fs-extra": "^9.0.1", - "jsonschema": "^1.2.5", + "jsonschema": "^1.2.6", "minimatch": "^3.0.4", - "semver": "^7.2.2", + "semver": "^7.3.2", "yaml": "1.10.0" }, "devDependencies": { - "constructs": "^3.0.4", "@aws-cdk/alexa-ask": "0.0.0", "@aws-cdk/app-delivery": "0.0.0", "@aws-cdk/assets": "0.0.0", @@ -108,6 +107,7 @@ "@aws-cdk/aws-apigatewayv2": "0.0.0", "@aws-cdk/aws-appconfig": "0.0.0", "@aws-cdk/aws-applicationautoscaling": "0.0.0", + "@aws-cdk/aws-applicationinsights": "0.0.0", "@aws-cdk/aws-appmesh": "0.0.0", "@aws-cdk/aws-appstream": "0.0.0", "@aws-cdk/aws-appsync": "0.0.0", @@ -134,6 +134,7 @@ "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-codedeploy": "0.0.0", "@aws-cdk/aws-codeguruprofiler": "0.0.0", + "@aws-cdk/aws-codegurureviewer": "0.0.0", "@aws-cdk/aws-codepipeline": "0.0.0", "@aws-cdk/aws-codepipeline-actions": "0.0.0", "@aws-cdk/aws-codestar": "0.0.0", @@ -186,6 +187,7 @@ "@aws-cdk/aws-kinesis": "0.0.0", "@aws-cdk/aws-kinesisanalytics": "0.0.0", "@aws-cdk/aws-kinesisfirehose": "0.0.0", + "@aws-cdk/aws-kendra": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-lakeformation": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", @@ -234,6 +236,7 @@ "@aws-cdk/aws-sns-subscriptions": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", + "@aws-cdk/aws-sso": "0.0.0", "@aws-cdk/aws-stepfunctions": "0.0.0", "@aws-cdk/aws-stepfunctions-tasks": "0.0.0", "@aws-cdk/aws-synthetics": "0.0.0", @@ -249,12 +252,14 @@ "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/pipelines": "0.0.0", "@aws-cdk/region-info": "0.0.0", + "@aws-cdk/yaml-cfn": "0.0.0", "@types/fs-extra": "^8.1.1", - "@types/node": "^10.17.28", + "@types/node": "^10.17.35", "cdk-build-tools": "0.0.0", + "constructs": "^3.0.4", "fs-extra": "^9.0.1", "pkglint": "0.0.0", - "ts-node": "^8.10.2", + "ts-node": "^9.0.0", "typescript": "~3.8.3", "ubergen": "0.0.0" }, diff --git a/tools/cdk-build-tools/config/eslintrc.js b/tools/cdk-build-tools/config/eslintrc.js index d5b55ed2764ef..4b6c03c16f815 100644 --- a/tools/cdk-build-tools/config/eslintrc.js +++ b/tools/cdk-build-tools/config/eslintrc.js @@ -55,6 +55,7 @@ module.exports = { 'keyword-spacing': ['error'], // require a space before & after keywords 'brace-style': ['error', '1tbs', { allowSingleLine: true }], // enforce one true brace style 'space-before-blocks': 'error', // require space before blocks + 'curly': ['error', 'multi-line', 'consistent'], // require curly braces for multiline control statements // Require all imported dependencies are actually declared in package.json 'import/no-extraneous-dependencies': [ @@ -85,7 +86,8 @@ module.exports = { 'no-duplicate-imports': ['error'], // Cannot shadow names - 'no-shadow': ['error'], + 'no-shadow': ['off'], + '@typescript-eslint/no-shadow': ['error'], // Required spacing in property declarations (copied from TSLint, defaults are good) 'key-spacing': ['error'], @@ -112,6 +114,11 @@ module.exports = { // One of the easiest mistakes to make '@typescript-eslint/no-floating-promises': ['error'], + // Make sure that inside try/catch blocks, promises are 'return await'ed + // (must disable the base rule as it can report incorrect errors) + 'no-return-await': 'off', + '@typescript-eslint/return-await': 'error', + // Don't leave log statements littering the premises! 'no-console': ['error'], diff --git a/tools/cdk-build-tools/package.json b/tools/cdk-build-tools/package.json index 2fd2a8a008691..6e6698cdebe34 100644 --- a/tools/cdk-build-tools/package.json +++ b/tools/cdk-build-tools/package.json @@ -34,28 +34,28 @@ "license": "Apache-2.0", "devDependencies": { "@types/fs-extra": "^8.1.1", - "@types/jest": "^26.0.10", + "@types/jest": "^26.0.14", "@types/yargs": "^15.0.5", "pkglint": "0.0.0" }, "dependencies": { - "@typescript-eslint/eslint-plugin": "^3.10.1", - "@typescript-eslint/parser": "^3.10.1", + "@typescript-eslint/eslint-plugin": "^4.1.1", + "@typescript-eslint/parser": "^4.1.1", "awslint": "0.0.0", "colors": "^1.4.0", - "eslint": "^6.8.0", + "eslint": "^7.9.0", "eslint-import-resolver-node": "^0.3.4", - "eslint-import-resolver-typescript": "^2.2.1", + "eslint-import-resolver-typescript": "^2.3.0", "eslint-plugin-import": "^2.22.0", "fs-extra": "^9.0.1", - "jest": "^25.5.4", - "jsii": "^1.11.0", - "jsii-pacmak": "^1.11.0", + "jest": "^26.4.2", + "jsii": "^1.12.0", + "jsii-pacmak": "^1.12.0", "nodeunit": "^0.11.3", "nyc": "^15.1.0", - "ts-jest": "^26.2.0", + "ts-jest": "^26.3.0", "typescript": "~3.9.7", - "yargs": "^15.4.1", + "yargs": "^16.0.3", "yarn-cling": "0.0.0" }, "keywords": [ diff --git a/tools/cdk-integ-tools/package.json b/tools/cdk-integ-tools/package.json index 458400f409403..87a859aa4514f 100644 --- a/tools/cdk-integ-tools/package.json +++ b/tools/cdk-integ-tools/package.json @@ -40,7 +40,7 @@ "@aws-cdk/assert": "0.0.0", "aws-cdk": "0.0.0", "fs-extra": "^9.0.1", - "yargs": "^15.4.1" + "yargs": "^16.0.3" }, "keywords": [ "aws", diff --git a/tools/cfn2ts/bin/cfn2ts.ts b/tools/cfn2ts/bin/cfn2ts.ts index dd3daf6aee6f6..1a4628c45cc17 100755 --- a/tools/cfn2ts/bin/cfn2ts.ts +++ b/tools/cfn2ts/bin/cfn2ts.ts @@ -50,5 +50,5 @@ async function tryReadPackageJson() { return undefined; } - return await fs.readJSON('./package.json'); + return fs.readJSON('./package.json'); } \ No newline at end of file diff --git a/tools/cfn2ts/lib/augmentation-generator.ts b/tools/cfn2ts/lib/augmentation-generator.ts index f23462b02b188..847c7f15c4187 100644 --- a/tools/cfn2ts/lib/augmentation-generator.ts +++ b/tools/cfn2ts/lib/augmentation-generator.ts @@ -39,7 +39,7 @@ export class AugmentationGenerator { */ public async save(dir: string): Promise { this.code.closeFile(this.outputFile); - return await this.code.save(dir); + return this.code.save(dir); } private emitMetricAugmentations(resourceTypeName: string, metrics: schema.ResourceMetricAugmentations, options?: schema.AugmentationOptions): void { diff --git a/tools/cfn2ts/lib/codegen.ts b/tools/cfn2ts/lib/codegen.ts index 8b45227b1c49a..d208976668925 100644 --- a/tools/cfn2ts/lib/codegen.ts +++ b/tools/cfn2ts/lib/codegen.ts @@ -80,7 +80,7 @@ export default class CodeGenerator { */ public async save(dir: string): Promise { this.code.closeFile(this.outputFile); - return await this.code.save(dir); + return this.code.save(dir); } /** @@ -478,6 +478,9 @@ export default class CodeGenerator { visitMap(itemType: genspec.CodeName) { return `${CORE}.hashMapper(${this.visitAtom(itemType)})`; }, + visitMapOfLists(itemType: genspec.CodeName) { + return `${CORE}.hashMapper(${CORE}.listMapper(${this.visitAtom(itemType)}))`; + }, visitUnionMap(itemTypes: genspec.CodeName[]) { const validators = itemTypes.map(type => genspec.validatorName(type).fqn); const mappers = itemTypes.map(type => this.visitAtom(type)); @@ -566,6 +569,11 @@ export default class CodeGenerator { return `${CFN_PARSE}.FromCloudFormation.getMap(${this.visitAtom(itemType)})`; } + public visitMapOfLists(itemType: genspec.CodeName): string { + return `${CFN_PARSE}.FromCloudFormation.getMap(` + + `${CFN_PARSE}.FromCloudFormation.getArray(${this.visitAtom(itemType)}))`; + } + public visitAtomUnion(types: genspec.CodeName[]): string { const validatorNames = types.map(type => genspec.validatorName(type).fqn).join(', '); const mappers = types.map(type => this.visitAtom(type)).join(', '); @@ -694,6 +702,9 @@ export default class CodeGenerator { visitMap(itemType: genspec.CodeName) { return `${CORE}.hashValidator(${this.visitAtom(itemType)})`; }, + visitMapOfLists(itemType: genspec.CodeName) { + return `${CORE}.hashValidator(${CORE}.listValidator(${this.visitAtom(itemType)}))`; + }, visitUnionMap(itemTypes: genspec.CodeName[]) { return `${CORE}.hashValidator(${CORE}.unionValidator(${itemTypes.map(type => this.visitAtom(type)).join(', ')}))`; }, @@ -945,4 +956,4 @@ interface EmitPropertyProps { propName: string; spec: schema.Property; additionalDocs: string; -} \ No newline at end of file +} diff --git a/tools/cfn2ts/lib/genspec.ts b/tools/cfn2ts/lib/genspec.ts index 80f28b1bb8ce8..f0fa9ff5f2780 100644 --- a/tools/cfn2ts/lib/genspec.ts +++ b/tools/cfn2ts/lib/genspec.ts @@ -43,7 +43,7 @@ export class CodeName { return new CodeName('', '', primitiveName); } - /* eslint-disable no-shadow */ + /* eslint-disable @typescript-eslint/no-shadow */ constructor( readonly packageName: string, readonly namespace: string, @@ -51,7 +51,7 @@ export class CodeName { readonly specName?: SpecName, readonly methodName?: string) { } - /* eslint-enable no-shadow */ + /* eslint-enable @typescript-eslint/no-shadow */ /** * Alias for className @@ -262,6 +262,10 @@ export function isPrimitive(type: CodeName): boolean { } function specTypeToCodeType(resourceContext: CodeName, type: string): CodeName { + if (type.endsWith('[]')) { + const itemType = specTypeToCodeType(resourceContext, type.substr(0, type.length - 2)); + return CodeName.forPrimitive(`${itemType.className}[]`); + } if (schema.isPrimitiveType(type)) { return specPrimitiveToCodePrimitive(type); } else if (type === 'Tag') { @@ -313,6 +317,11 @@ export interface PropertyVisitor { */ visitUnionMap(itemTypes: CodeName[]): T; + /** + * Map of lists + */ + visitMapOfLists(itemType: CodeName): T; + /** * Union of list type and atom type */ @@ -337,6 +346,12 @@ export function typeDispatch(resourceContext: CodeName, spec: schema.Property if (schema.isCollectionProperty(spec)) { // List or map, of either atoms or unions if (schema.isMapProperty(spec)) { + if (schema.isMapOfListsOfPrimitivesProperty(spec)) { + // remove the '[]' from the type + const baseType = itemTypes[0].className; + const itemType = CodeName.forPrimitive(baseType.substr(0, baseType.length - 2)); + return visitor.visitMapOfLists(itemType); + } if (itemTypes.length > 1) { return visitor.visitUnionMap(itemTypes); } else { diff --git a/tools/cfn2ts/lib/spec-utils.ts b/tools/cfn2ts/lib/spec-utils.ts index 45310f3cffa0f..13254a084e753 100644 --- a/tools/cfn2ts/lib/spec-utils.ts +++ b/tools/cfn2ts/lib/spec-utils.ts @@ -78,7 +78,7 @@ export function itemTypeNames(spec: schema.CollectionProperty): string[] { } function complexItemTypeNames(spec: schema.CollectionProperty): string[] { - if (schema.isComplexListProperty(spec) || schema.isComplexMapProperty(spec)) { + if (schema.isComplexListProperty(spec) || schema.isMapOfStructsProperty(spec)) { return [spec.ItemType]; } else if (schema.isUnionProperty(spec)) { return spec.ItemTypes || []; @@ -87,7 +87,9 @@ function complexItemTypeNames(spec: schema.CollectionProperty): string[] { } function primitiveItemTypeNames(spec: schema.CollectionProperty): string[] { - if (schema.isPrimitiveListProperty(spec) || schema.isPrimitiveMapProperty(spec)) { + if (schema.isMapOfListsOfPrimitivesProperty(spec)) { + return [`${spec.PrimitiveItemItemType}[]`]; // <--- read in specTypeToCodeType() + } else if (schema.isPrimitiveListProperty(spec) || schema.isPrimitiveMapProperty(spec)) { return [spec.PrimitiveItemType]; } else if (schema.isUnionProperty(spec)) { return spec.PrimitiveItemTypes || []; diff --git a/tools/cfn2ts/package.json b/tools/cfn2ts/package.json index cc3b1bce4d67d..28216a04628c9 100644 --- a/tools/cfn2ts/package.json +++ b/tools/cfn2ts/package.json @@ -30,17 +30,17 @@ "license": "Apache-2.0", "dependencies": { "@aws-cdk/cfnspec": "0.0.0", - "codemaker": "^1.11.0", + "codemaker": "^1.12.0", "fast-json-patch": "^3.0.0-1", "fs-extra": "^9.0.1", - "yargs": "^15.4.1" + "yargs": "^16.0.3" }, "devDependencies": { "@types/fs-extra": "^8.1.1", - "@types/jest": "^26.0.10", + "@types/jest": "^26.0.14", "@types/yargs": "^15.0.5", "cdk-build-tools": "0.0.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "pkglint": "0.0.0" }, "keywords": [ diff --git a/tools/nodeunit-shim/package.json b/tools/nodeunit-shim/package.json index d68627131d295..ebec2519fd49a 100644 --- a/tools/nodeunit-shim/package.json +++ b/tools/nodeunit-shim/package.json @@ -12,12 +12,12 @@ "build+test": "npm run build && npm test" }, "devDependencies": { - "@types/jest": "^26.0.10", - "@types/node": "^10.17.28", + "@types/jest": "^26.0.14", + "@types/node": "^10.17.35", "typescript": "~3.9.7" }, "dependencies": { - "jest": "^25.5.4" + "jest": "^26.4.2" }, "keywords": [], "author": "", diff --git a/tools/pkglint/bin/pkglint.ts b/tools/pkglint/bin/pkglint.ts index 7306697d45ebc..625c8ab00223f 100644 --- a/tools/pkglint/bin/pkglint.ts +++ b/tools/pkglint/bin/pkglint.ts @@ -3,7 +3,7 @@ import * as path from 'path'; import * as yargs from 'yargs'; import { findPackageJsons, ValidationRule } from '../lib'; -/* eslint-disable no-shadow */ +/* eslint-disable @typescript-eslint/no-shadow */ const argv = yargs .usage('$0 [directory]') .option('fix', { type: 'boolean', alias: 'f', desc: 'Fix package.json in addition to reporting mistakes' }) diff --git a/tools/pkglint/lib/rules.ts b/tools/pkglint/lib/rules.ts index 709ed2953dd71..ca50e7c03a8de 100644 --- a/tools/pkglint/lib/rules.ts +++ b/tools/pkglint/lib/rules.ts @@ -862,6 +862,7 @@ export class MustDependonCdkByPointVersions extends ValidationRule { '@aws-cdk/cx-api', '@aws-cdk/cloud-assembly-schema', '@aws-cdk/region-info', + '@aws-cdk/yaml-cfn', ]; for (const [depName, depVersion] of Object.entries(pkg.dependencies)) { diff --git a/tools/pkglint/package.json b/tools/pkglint/package.json index 63614b840f4d9..7581aa694dc49 100644 --- a/tools/pkglint/package.json +++ b/tools/pkglint/package.json @@ -36,9 +36,9 @@ "license": "Apache-2.0", "devDependencies": { "@types/fs-extra": "^8.1.1", - "@types/semver": "^7.3.3", + "@types/semver": "^7.3.4", "@types/yargs": "^15.0.5", - "jest": "^25.5.4", + "jest": "^26.4.2", "typescript": "~3.9.7" }, "dependencies": { @@ -46,7 +46,7 @@ "colors": "^1.4.0", "fs-extra": "^9.0.1", "glob": "^7.1.6", - "semver": "^7.2.2", - "yargs": "^15.4.1" + "semver": "^7.3.2", + "yargs": "^16.0.3" } } diff --git a/tools/pkgtools/bin/find-jsii-packages.ts b/tools/pkgtools/bin/find-jsii-packages.ts index c240e59fec10f..8fc175e9883f0 100644 --- a/tools/pkgtools/bin/find-jsii-packages.ts +++ b/tools/pkgtools/bin/find-jsii-packages.ts @@ -5,7 +5,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as yargs from 'yargs'; -/* eslint-disable no-shadow */ +/* eslint-disable @typescript-eslint/no-shadow */ const argv = yargs .usage('$0') .option('verbose', { alias: 'v', type: 'boolean', desc: 'Turn on verbose logging' }) diff --git a/tools/pkgtools/package.json b/tools/pkgtools/package.json index dd54d679ee5c7..87bd33b472368 100644 --- a/tools/pkgtools/package.json +++ b/tools/pkgtools/package.json @@ -36,7 +36,7 @@ }, "dependencies": { "fs-extra": "^9.0.1", - "yargs": "^15.4.1" + "yargs": "^16.0.3" }, "keywords": [ "aws", diff --git a/tools/prlint/package.json b/tools/prlint/package.json index 0467d3d8bd049..22a7fd221163d 100644 --- a/tools/prlint/package.json +++ b/tools/prlint/package.json @@ -9,17 +9,13 @@ "name": "Amazon Web Services", "url": "https://aws.amazon.com" }, - "scripts": { - "build": "echo success" - }, "license": "Apache-2.0", "dependencies": { - "github-api": "^3.3.0", - "make-runnable": "^1.3.6" + "github-api": "^3.3.0" }, "scripts": { "build": "echo success", "test": "echo sucees", "build+test": "npm run build test && npm run test" } -} \ No newline at end of file +} diff --git a/tools/ubergen/bin/ubergen.ts b/tools/ubergen/bin/ubergen.ts index 7f654bdafb97d..2500c05377c27 100644 --- a/tools/ubergen/bin/ubergen.ts +++ b/tools/ubergen/bin/ubergen.ts @@ -289,13 +289,13 @@ async function copyOrTransformFiles(from: string, to: string, libraries: readonl return copyOrTransformFiles(source, destination, libraries); } if (name.endsWith('.ts')) { - return await fs.writeFile( + return fs.writeFile( destination, await rewriteImports(source, to, libraries), { encoding: 'utf8' }, ); } else { - return await fs.copyFile(source, destination); + return fs.copyFile(source, destination); } }); diff --git a/tools/yarn-cling/package.json b/tools/yarn-cling/package.json index 6452a5acf74d9..4a5e222dc7e28 100644 --- a/tools/yarn-cling/package.json +++ b/tools/yarn-cling/package.json @@ -38,10 +38,10 @@ ] }, "devDependencies": { - "@types/jest": "^26.0.10", - "@types/node": "^10.17.28", + "@types/jest": "^26.0.14", + "@types/node": "^10.17.35", "@types/yarnpkg__lockfile": "^1.1.3", - "jest": "^25.5.4", + "jest": "^26.4.2", "pkglint": "0.0.0", "typescript": "~3.9.7" }, diff --git a/yarn.lock b/yarn.lock index f41f34bc39dfc..074fb6bae06ee 100644 --- a/yarn.lock +++ b/yarn.lock @@ -920,7 +920,7 @@ "@babel/plugin-transform-react-jsx-source" "^7.10.4" "@babel/plugin-transform-react-pure-annotations" "^7.10.4" -"@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.8.4": version "7.11.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw== @@ -973,6 +973,22 @@ exec-sh "^0.3.2" minimist "^1.2.0" +"@eslint/eslintrc@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.1.3.tgz#7d1a2b2358552cc04834c0979bd4275362e37085" + integrity sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA== + dependencies: + ajv "^6.12.4" + debug "^4.1.1" + espree "^7.3.0" + globals "^12.1.0" + ignore "^4.0.6" + import-fresh "^3.2.1" + js-yaml "^3.13.1" + lodash "^4.17.19" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" + "@evocateur/libnpmaccess@^3.1.2": version "3.1.2" resolved "https://registry.yarnpkg.com/@evocateur/libnpmaccess/-/libnpmaccess-3.1.2.tgz#ecf7f6ce6b004e9f942b098d92200be4a4b1c845" @@ -1068,17 +1084,6 @@ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== -"@jest/console@^25.5.0": - version "25.5.0" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-25.5.0.tgz#770800799d510f37329c508a9edd0b7b447d9abb" - integrity sha512-T48kZa6MK1Y6k4b89sexwmSF4YLeZS/Udqg3Jj3jG/cHH+N/sLFCEoXEDMOKugJQ9FxPN1osxIknvKkxt6MKyw== - dependencies: - "@jest/types" "^25.5.0" - chalk "^3.0.0" - jest-message-util "^25.5.0" - jest-util "^25.5.0" - slash "^3.0.0" - "@jest/console@^26.3.0": version "26.3.0" resolved "https://registry.yarnpkg.com/@jest/console/-/console-26.3.0.tgz#ed04063efb280c88ba87388b6f16427c0a85c856" @@ -1091,40 +1096,6 @@ jest-util "^26.3.0" slash "^3.0.0" -"@jest/core@^25.5.4": - version "25.5.4" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-25.5.4.tgz#3ef7412f7339210f003cdf36646bbca786efe7b4" - integrity sha512-3uSo7laYxF00Dg/DMgbn4xMJKmDdWvZnf89n8Xj/5/AeQ2dOQmn6b6Hkj/MleyzZWXpwv+WSdYWl4cLsy2JsoA== - dependencies: - "@jest/console" "^25.5.0" - "@jest/reporters" "^25.5.1" - "@jest/test-result" "^25.5.0" - "@jest/transform" "^25.5.1" - "@jest/types" "^25.5.0" - ansi-escapes "^4.2.1" - chalk "^3.0.0" - exit "^0.1.2" - graceful-fs "^4.2.4" - jest-changed-files "^25.5.0" - jest-config "^25.5.4" - jest-haste-map "^25.5.1" - jest-message-util "^25.5.0" - jest-regex-util "^25.2.6" - jest-resolve "^25.5.1" - jest-resolve-dependencies "^25.5.4" - jest-runner "^25.5.4" - jest-runtime "^25.5.4" - jest-snapshot "^25.5.1" - jest-util "^25.5.0" - jest-validate "^25.5.0" - jest-watcher "^25.5.0" - micromatch "^4.0.2" - p-each-series "^2.1.0" - realpath-native "^2.0.0" - rimraf "^3.0.0" - slash "^3.0.0" - strip-ansi "^6.0.0" - "@jest/core@^26.4.2": version "26.4.2" resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.4.2.tgz#85d0894f31ac29b5bab07aa86806d03dd3d33edc" @@ -1159,15 +1130,6 @@ slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/environment@^25.5.0": - version "25.5.0" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-25.5.0.tgz#aa33b0c21a716c65686638e7ef816c0e3a0c7b37" - integrity sha512-U2VXPEqL07E/V7pSZMSQCvV5Ea4lqOlT+0ZFijl/i316cRMHvZ4qC+jBdryd+lmRetjQo0YIQr6cVPNxxK87mA== - dependencies: - "@jest/fake-timers" "^25.5.0" - "@jest/types" "^25.5.0" - jest-mock "^25.5.0" - "@jest/environment@^26.3.0": version "26.3.0" resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-26.3.0.tgz#e6953ab711ae3e44754a025f838bde1a7fd236a0" @@ -1178,17 +1140,6 @@ "@types/node" "*" jest-mock "^26.3.0" -"@jest/fake-timers@^25.5.0": - version "25.5.0" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-25.5.0.tgz#46352e00533c024c90c2bc2ad9f2959f7f114185" - integrity sha512-9y2+uGnESw/oyOI3eww9yaxdZyHq7XvprfP/eeoCsjqKYts2yRlsHS/SgjPDV8FyMfn2nbMy8YzUk6nyvdLOpQ== - dependencies: - "@jest/types" "^25.5.0" - jest-message-util "^25.5.0" - jest-mock "^25.5.0" - jest-util "^25.5.0" - lolex "^5.0.0" - "@jest/fake-timers@^26.3.0": version "26.3.0" resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-26.3.0.tgz#f515d4667a6770f60ae06ae050f4e001126c666a" @@ -1201,15 +1152,6 @@ jest-mock "^26.3.0" jest-util "^26.3.0" -"@jest/globals@^25.5.2": - version "25.5.2" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-25.5.2.tgz#5e45e9de8d228716af3257eeb3991cc2e162ca88" - integrity sha512-AgAS/Ny7Q2RCIj5kZ+0MuKM1wbF0WMLxbCVl/GOMoCNbODRdJ541IxJ98xnZdVSZXivKpJlNPIWa3QmY0l4CXA== - dependencies: - "@jest/environment" "^25.5.0" - "@jest/types" "^25.5.0" - expect "^25.5.0" - "@jest/globals@^26.4.2": version "26.4.2" resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.4.2.tgz#73c2a862ac691d998889a241beb3dc9cada40d4a" @@ -1219,38 +1161,6 @@ "@jest/types" "^26.3.0" expect "^26.4.2" -"@jest/reporters@^25.5.1": - version "25.5.1" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-25.5.1.tgz#cb686bcc680f664c2dbaf7ed873e93aa6811538b" - integrity sha512-3jbd8pPDTuhYJ7vqiHXbSwTJQNavczPs+f1kRprRDxETeE3u6srJ+f0NPuwvOmk+lmunZzPkYWIFZDLHQPkviw== - dependencies: - "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^25.5.0" - "@jest/test-result" "^25.5.0" - "@jest/transform" "^25.5.1" - "@jest/types" "^25.5.0" - chalk "^3.0.0" - collect-v8-coverage "^1.0.0" - exit "^0.1.2" - glob "^7.1.2" - graceful-fs "^4.2.4" - istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^4.0.0" - istanbul-lib-report "^3.0.0" - istanbul-lib-source-maps "^4.0.0" - istanbul-reports "^3.0.2" - jest-haste-map "^25.5.1" - jest-resolve "^25.5.1" - jest-util "^25.5.0" - jest-worker "^25.5.0" - slash "^3.0.0" - source-map "^0.6.0" - string-length "^3.1.0" - terminal-link "^2.0.0" - v8-to-istanbul "^4.1.3" - optionalDependencies: - node-notifier "^6.0.0" - "@jest/reporters@^26.4.1": version "26.4.1" resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.4.1.tgz#3b4d6faf28650f3965f8b97bc3d114077fb71795" @@ -1283,15 +1193,6 @@ optionalDependencies: node-notifier "^8.0.0" -"@jest/source-map@^25.5.0": - version "25.5.0" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-25.5.0.tgz#df5c20d6050aa292c2c6d3f0d2c7606af315bd1b" - integrity sha512-eIGx0xN12yVpMcPaVpjXPnn3N30QGJCJQSkEDUt9x1fI1Gdvb07Ml6K5iN2hG7NmMP6FDmtPEssE3z6doOYUwQ== - dependencies: - callsites "^3.0.0" - graceful-fs "^4.2.4" - source-map "^0.6.0" - "@jest/source-map@^26.3.0": version "26.3.0" resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-26.3.0.tgz#0e646e519883c14c551f7b5ae4ff5f1bfe4fc3d9" @@ -1301,16 +1202,6 @@ graceful-fs "^4.2.4" source-map "^0.6.0" -"@jest/test-result@^25.5.0": - version "25.5.0" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-25.5.0.tgz#139a043230cdeffe9ba2d8341b27f2efc77ce87c" - integrity sha512-oV+hPJgXN7IQf/fHWkcS99y0smKLU2czLBJ9WA0jHITLst58HpQMtzSYxzaBvYc6U5U6jfoMthqsUlUlbRXs0A== - dependencies: - "@jest/console" "^25.5.0" - "@jest/types" "^25.5.0" - "@types/istanbul-lib-coverage" "^2.0.0" - collect-v8-coverage "^1.0.0" - "@jest/test-result@^26.3.0": version "26.3.0" resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-26.3.0.tgz#46cde01fa10c0aaeb7431bf71e4a20d885bc7fdb" @@ -1321,17 +1212,6 @@ "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^25.5.4": - version "25.5.4" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-25.5.4.tgz#9b4e685b36954c38d0f052e596d28161bdc8b737" - integrity sha512-pTJGEkSeg1EkCO2YWq6hbFvKNXk8ejqlxiOg1jBNLnWrgXOkdY6UmqZpwGFXNnRt9B8nO1uWMzLLZ4eCmhkPNA== - dependencies: - "@jest/test-result" "^25.5.0" - graceful-fs "^4.2.4" - jest-haste-map "^25.5.1" - jest-runner "^25.5.4" - jest-runtime "^25.5.4" - "@jest/test-sequencer@^26.4.2": version "26.4.2" resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-26.4.2.tgz#58a3760a61eec758a2ce6080201424580d97cbba" @@ -1343,28 +1223,6 @@ jest-runner "^26.4.2" jest-runtime "^26.4.2" -"@jest/transform@^25.5.1": - version "25.5.1" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-25.5.1.tgz#0469ddc17699dd2bf985db55fa0fb9309f5c2db3" - integrity sha512-Y8CEoVwXb4QwA6Y/9uDkn0Xfz0finGkieuV0xkdF9UtZGJeLukD5nLkaVrVsODB1ojRWlaoD0AJZpVHCSnJEvg== - dependencies: - "@babel/core" "^7.1.0" - "@jest/types" "^25.5.0" - babel-plugin-istanbul "^6.0.0" - chalk "^3.0.0" - convert-source-map "^1.4.0" - fast-json-stable-stringify "^2.0.0" - graceful-fs "^4.2.4" - jest-haste-map "^25.5.1" - jest-regex-util "^25.2.6" - jest-util "^25.5.0" - micromatch "^4.0.2" - pirates "^4.0.1" - realpath-native "^2.0.0" - slash "^3.0.0" - source-map "^0.6.1" - write-file-atomic "^3.0.0" - "@jest/transform@^26.3.0": version "26.3.0" resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-26.3.0.tgz#c393e0e01459da8a8bfc6d2a7c2ece1a13e8ba55" @@ -1407,10 +1265,10 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" -"@jsii/spec@^1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@jsii/spec/-/spec-1.11.0.tgz#ab3c33cc06b935d438dca69571f54d9977eee871" - integrity sha512-rRPbq3QGJ0OldafFPfU0vUyjubCe2Scm0xpWEt7EzmY2d8eauCEO9xBJwHSFdnkUFvMFZEgYjF2F856DepAl2Q== +"@jsii/spec@^1.12.0": + version "1.12.0" + resolved "https://registry.yarnpkg.com/@jsii/spec/-/spec-1.12.0.tgz#4b13acc5fe591a4c70137f38275ac3d8a977a958" + integrity sha512-xqiROAZjOLNhvGzVCdyNu1sJ4CLU+jxcQcRvXz3qkQobHeHRk4MMiqRVOk6LWaBNVtDjil4HlP1sRm5j/ZqYeQ== dependencies: jsonschema "^1.2.6" @@ -3035,10 +2893,10 @@ dependencies: "@types/glob" "*" -"@types/aws-lambda@^8.10.61": - version "8.10.61" - resolved "https://registry.yarnpkg.com/@types/aws-lambda/-/aws-lambda-8.10.61.tgz#7471e08843dbdcf09b2494ac5b34c4d1a391e6d0" - integrity sha512-+FeZ/52VG4rBSJ0cRE/aB6hMKQzjIgpiSQrGq0eR8ZrXWee7Z2zoGeJzTHVcOeZNawLb+5zvwZNIRGC7X+kQ7Q== +"@types/aws-lambda@^8.10.62": + version "8.10.62" + resolved "https://registry.yarnpkg.com/@types/aws-lambda/-/aws-lambda-8.10.62.tgz#857de3f73ab503136f2eefe965b1b67e5f397b62" + integrity sha512-43XhJY5jvyH03U0cRsSqeHWhvmGZNoLzTPSAZ3JAqgG9p20uw+Sx9Auk5OAefJajd9ZcfjDJ/9lJ2BiBxfKJRw== "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7": version "7.1.9" @@ -3078,11 +2936,6 @@ resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== -"@types/eslint-visitor-keys@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" - integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== - "@types/fs-extra@^8.1.1": version "8.1.1" resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-8.1.1.tgz#1e49f22d09aa46e19b51c0b013cb63d0d923a068" @@ -3132,7 +2985,7 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@26.x", "@types/jest@^26.0.10": +"@types/jest@26.x": version "26.0.10" resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.10.tgz#8faf7e9756c033c39014ae76a7329efea00ea607" integrity sha512-i2m0oyh8w/Lum7wWK/YOZJakYF8Mx08UaKA1CtbmFeDquVhAEdA7znacsVSf2hJ1OQ/OfVMGN90pw/AtzF8s/Q== @@ -3140,11 +2993,24 @@ jest-diff "^25.2.1" pretty-format "^25.2.1" +"@types/jest@^26.0.14": + version "26.0.14" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.14.tgz#078695f8f65cb55c5a98450d65083b2b73e5a3f3" + integrity sha512-Hz5q8Vu0D288x3iWXePSn53W7hAjP0H7EQ6QvDO9c7t46mR0lNOLlfuwQ+JkVxuhygHzlzPX+0jKdA3ZgSh+Vg== + dependencies: + jest-diff "^25.2.1" + pretty-format "^25.2.1" + "@types/json-schema@^7.0.3": version "7.0.5" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.5.tgz#dcce4430e64b443ba8945f0290fb564ad5bac6dd" integrity sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ== +"@types/json-schema@^7.0.5": + version "7.0.6" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0" + integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw== + "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" @@ -3157,10 +3023,10 @@ dependencies: jszip "*" -"@types/lodash@^4.14.160": - version "4.14.160" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.160.tgz#2f1bba6500bc3cb9a732c6d66a083378fb0b0b29" - integrity sha512-aP03BShJoO+WVndoVj/WNcB/YBPt+CIU1mvaao2GRAHy2yg4pT/XS4XnVHEQBjPJGycWf/9seKEO9vopTJGkvA== +"@types/lodash@^4.14.161": + version "4.14.161" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.161.tgz#a21ca0777dabc6e4f44f3d07f37b765f54188b18" + integrity sha512-EP6O3Jkr7bXvZZSZYlsgt5DIjiGr0dXP1/jVEwVLTFgg0d+3lWVQkRavYVQszV7dYUwvg0B8R0MBDpcmXg7XIA== "@types/md5@^2.2.0": version "2.2.0" @@ -3196,10 +3062,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.6.0.tgz#7d4411bf5157339337d7cff864d9ff45f177b499" integrity sha512-mikldZQitV94akrc4sCcSjtJfsTKt4p+e/s0AGscVA6XArQ9kFclP+ZiYUMnq987rc6QlYxXv/EivqlfSLxpKA== -"@types/node@^10.17.28": - version "10.17.28" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.28.tgz#0e36d718a29355ee51cec83b42d921299200f6d9" - integrity sha512-dzjES1Egb4c1a89C7lKwQh8pwjYmlOAG9dW1pBgxEk57tMrLnssOfEthz8kdkNaBd7lIqQx7APm5+mZ619IiCQ== +"@types/node@^10.17.35": + version "10.17.35" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.35.tgz#58058f29b870e6ae57b20e4f6e928f02b7129f56" + integrity sha512-gXx7jAWpMddu0f7a+L+txMplp3FnHl53OhQIF9puXKq3hDGY/GjH+MF04oWnV/adPSCrbtHumDCFwzq2VhltWA== "@types/nodeunit@^0.0.31": version "0.0.31" @@ -3216,11 +3082,6 @@ resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== -"@types/prettier@^1.19.0": - version "1.19.1" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-1.19.1.tgz#33509849f8e679e4add158959fdb086440e9553f" - integrity sha512-5qOlnZscTn4xxM5MeGXAMOsIOIKIbh9e85zJWfBRVPlRMEVawzoPhINYbRGkBZCI8LxvBe7tJCdWiarA99OZfQ== - "@types/prettier@^2.0.0": version "2.0.2" resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.0.2.tgz#5bb52ee68d0f8efa9cc0099920e56be6cc4e37f3" @@ -3243,10 +3104,10 @@ resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24" integrity sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug== -"@types/semver@^7.3.3": - version "7.3.3" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.3.tgz#3ad6ed949e7487e7bda6f886b4a2434a2c3d7b1a" - integrity sha512-jQxClWFzv9IXdLdhSaTf16XI3NYe6zrEbckSpb5xhKfPbWgIyAY0AFyWWWfaiDcBuj3UHmMkCIwSRqpKMTZL2Q== +"@types/semver@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.4.tgz#43d7168fec6fa0988bb1a513a697b29296721afb" + integrity sha512-+nVsLKlcUCeMzD2ufHEYuJ9a2ovstb6Dp52A5VsoKxDXgvE051XgHI/33I1EymwkRGQkwnA0LkhnUzituGs4EQ== "@types/sinon@^9.0.5": version "9.0.5" @@ -3272,10 +3133,10 @@ dependencies: string-width "*" -"@types/table@^4.0.7": - version "4.0.7" - resolved "https://registry.yarnpkg.com/@types/table/-/table-4.0.7.tgz#c21100d37d4924abbbde85414170260d4d7b0316" - integrity sha512-HKtXvBxU8U8evZCSlUi9HbfT/SFW7nSGCoiBEheB06jAhXeW6JbGh8biEAqIFG5rZo9f8xeJVdIn455sddmIcw== +"@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/uuid@^8.3.0": version "8.3.0" @@ -3287,10 +3148,12 @@ resolved "https://registry.yarnpkg.com/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz#18b97a972f94f60a679fd5c796d96421b9abb9fd" integrity sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g== -"@types/yaml@1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@types/yaml/-/yaml-1.2.0.tgz#4ed577fc4ebbd6b829b28734e56d10c9e6984e09" - integrity sha512-GW8b9qM+ebgW3/zjzPm0I1NxMvLaz/YKT9Ph6tTb+Fkeyzd9yLTvQ6ciQ2MorTRmb/qXmfjMerRpG4LviixaqQ== +"@types/yaml@1.9.6": + version "1.9.6" + resolved "https://registry.yarnpkg.com/@types/yaml/-/yaml-1.9.6.tgz#9e30a14aecbba978ad7156d03201ecd97478a712" + integrity sha512-VKOCuDN57wngmyQnRqcn4vuGWCXViISHv+UCCjrKcf1yt4zyfMmOGlZDI2ucTHK72V8ki+sd7h21OZL6O5S52A== + dependencies: + yaml "*" "@types/yaml@1.9.7", "@types/yaml@^1.9.7": version "1.9.7" @@ -3316,65 +3179,75 @@ resolved "https://registry.yarnpkg.com/@types/yarnpkg__lockfile/-/yarnpkg__lockfile-1.1.3.tgz#38fb31d82ed07dea87df6bd565721d11979fd761" integrity sha512-mhdQq10tYpiNncMkg1vovCud5jQm+rWeRVz6fxjCJlY6uhDlAn9GnMSmBa2DQwqPf/jS5YR0K/xChDEh1jdOQg== -"@typescript-eslint/eslint-plugin@^3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.10.1.tgz#7e061338a1383f59edc204c605899f93dc2e2c8f" - integrity sha512-PQg0emRtzZFWq6PxBcdxRH3QIQiyFO3WCVpRL3fgj5oQS3CDs3AeAKfv4DxNhzn8ITdNJGJ4D3Qw8eAJf3lXeQ== +"@typescript-eslint/eslint-plugin@^4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.1.1.tgz#78d5b18e259b13c2f4ec41dd9105af269a161a75" + integrity sha512-Hoxyt99EA9LMmqo/5PuWWPeWeB3mKyvibfJ1Hy5SfiUpjE8Nqp+5QNd9fOkzL66+fqvIWSIE+Ett16LGMzCGnQ== dependencies: - "@typescript-eslint/experimental-utils" "3.10.1" + "@typescript-eslint/experimental-utils" "4.1.1" + "@typescript-eslint/scope-manager" "4.1.1" debug "^4.1.1" functional-red-black-tree "^1.0.1" regexpp "^3.0.0" semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/experimental-utils@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-3.10.1.tgz#e179ffc81a80ebcae2ea04e0332f8b251345a686" - integrity sha512-DewqIgscDzmAfd5nOGe4zm6Bl7PKtMG2Ad0KG8CUZAHlXfAKTF9Ol5PXhiMh39yRL2ChRH1cuuUGOcVyyrhQIw== +"@typescript-eslint/experimental-utils@4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.1.1.tgz#52ff4e37c93113eb96385a4e6d075abece1ea72d" + integrity sha512-jzYsNciHoa4Z3c1URtmeT/bamYm8Dwfw6vuN3WHIE/BXb1iC4KveAnXDErTAZtPVxTYBaYn3n2gbt6F6D2rm1A== dependencies: "@types/json-schema" "^7.0.3" - "@typescript-eslint/types" "3.10.1" - "@typescript-eslint/typescript-estree" "3.10.1" + "@typescript-eslint/scope-manager" "4.1.1" + "@typescript-eslint/types" "4.1.1" + "@typescript-eslint/typescript-estree" "4.1.1" eslint-scope "^5.0.0" eslint-utils "^2.0.0" -"@typescript-eslint/parser@^3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-3.10.1.tgz#1883858e83e8b442627e1ac6f408925211155467" - integrity sha512-Ug1RcWcrJP02hmtaXVS3axPPTTPnZjupqhgj+NnZ6BCkwSImWk/283347+x9wN+lqOdK9Eo3vsyiyDHgsmiEJw== +"@typescript-eslint/parser@^4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.1.1.tgz#324b4b35e314075adbc92bd8330cf3ef0c88cf3e" + integrity sha512-NLIhmicpKGfJbdXyQBz9j48PA6hq6e+SDOoXy7Ak6bq1ebGqbgG+fR1UIDAuay6OjQdot69c/URu2uLlsP8GQQ== dependencies: - "@types/eslint-visitor-keys" "^1.0.0" - "@typescript-eslint/experimental-utils" "3.10.1" - "@typescript-eslint/types" "3.10.1" - "@typescript-eslint/typescript-estree" "3.10.1" - eslint-visitor-keys "^1.1.0" + "@typescript-eslint/scope-manager" "4.1.1" + "@typescript-eslint/types" "4.1.1" + "@typescript-eslint/typescript-estree" "4.1.1" + debug "^4.1.1" -"@typescript-eslint/types@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-3.10.1.tgz#1d7463fa7c32d8a23ab508a803ca2fe26e758727" - integrity sha512-+3+FCUJIahE9q0lDi1WleYzjCwJs5hIsbugIgnbB+dSCYUxl8L6PwmsyOPFZde2hc1DlTo/xnkOgiTLSyAbHiQ== +"@typescript-eslint/scope-manager@4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.1.1.tgz#bdb8526e82435f32b4ccd9dd4cec01af97b48850" + integrity sha512-0W8TTobCvIIQ2FsrYTffyZGAAFUyIbEHq5EYJb1m7Rpd005jrnOvKOo8ywCLhs/Bm17C+KsrUboBvBAARQVvyA== + dependencies: + "@typescript-eslint/types" "4.1.1" + "@typescript-eslint/visitor-keys" "4.1.1" -"@typescript-eslint/typescript-estree@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-3.10.1.tgz#fd0061cc38add4fad45136d654408569f365b853" - integrity sha512-QbcXOuq6WYvnB3XPsZpIwztBoquEYLXh2MtwVU+kO8jgYCiv4G5xrSP/1wg4tkvrEE+esZVquIPX/dxPlePk1w== +"@typescript-eslint/types@4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.1.1.tgz#57500c4a86b28cb47094c1a62f1177ea279a09cb" + integrity sha512-zrBiqOKYerMTllKcn+BP+i1b7LW/EbMMYytroXMxUTvFPn1smkCu0D7lSAx29fTUO4jnwV0ljSvYQtn2vNrNxA== + +"@typescript-eslint/typescript-estree@4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.1.1.tgz#2015a84d71303ecdb6f46efd807ac19a51aab490" + integrity sha512-2AUg5v0liVBsqbGxBphbJ0QbGqSRVaF5qPoTPWcxop+66vMdU1h4CCvHxTC47+Qb+Pr4l2RhXDd41JNpwcQEKw== dependencies: - "@typescript-eslint/types" "3.10.1" - "@typescript-eslint/visitor-keys" "3.10.1" + "@typescript-eslint/types" "4.1.1" + "@typescript-eslint/visitor-keys" "4.1.1" debug "^4.1.1" - glob "^7.1.6" + globby "^11.0.1" is-glob "^4.0.1" lodash "^4.17.15" semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/visitor-keys@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-3.10.1.tgz#cd4274773e3eb63b2e870ac602274487ecd1e931" - integrity sha512-9JgC82AaQeglebjZMgYR5wgmfUdUc+EitGUUMW8u2nDckaeimzW+VsoLV6FoimPv2id3VQzfjwBxEMVz08ameQ== +"@typescript-eslint/visitor-keys@4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.1.1.tgz#bb05664bf4bea28dc120d1da94f3027d42ab0f6f" + integrity sha512-/EOOXbA2ferGLG6RmCHEQ0lTTLkOlXYDgblCmQk3tIU7mTPLm4gKhFMeeUSe+bcchTUsKeCk8xcpbop5Zr/8Rw== dependencies: - eslint-visitor-keys "^1.1.0" + "@typescript-eslint/types" "4.1.1" + eslint-visitor-keys "^2.0.0" "@yarnpkg/lockfile@^1.1.0": version "1.1.0" @@ -3413,7 +3286,7 @@ abortcontroller-polyfill@^1.1.9: resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.5.0.tgz#2c562f530869abbcf88d949a2b60d1d402e87a7c" integrity sha512-O6Xk757Jb4o0LMzMOMdWvxpHWrQzruYBaUruFaIOfAQRnWFxfdXYobw12jrVHGtoXk6WiiyYzc0QWN9aL62HQA== -acorn-globals@^4.3.0, acorn-globals@^4.3.2: +acorn-globals@^4.3.0: version "4.3.4" resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7" integrity sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A== @@ -3449,7 +3322,7 @@ acorn@^6.0.1, acorn@^6.0.4: resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== -acorn@^7.1.0, acorn@^7.1.1: +acorn@^7.1.1, acorn@^7.4.0: version "7.4.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.0.tgz#e1ad486e6c54501634c6c397c5c121daa383607c" integrity sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w== @@ -3498,6 +3371,16 @@ ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^6.12.4: + version "6.12.5" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.5.tgz#19b0e8bae8f476e5ba666300387775fb1a00a4da" + integrity sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + alphanum-sort@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" @@ -3586,6 +3469,11 @@ anymatch@^3.0.3: normalize-path "^3.0.0" picomatch "^2.0.4" +app-root-path@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.2.1.tgz#d0df4a682ee408273583d43f6f79e9892624bc9a" + integrity sha512-91IFKeKk7FjfmezPKkwtaRvSpnUc4gDwPAjA1YZ9Gn0q0PPeW+vbeUsZuyDwjI7+QTHhcLen2v25fi/AmhvbJA== + append-transform@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-1.0.0.tgz#046a52ae582a228bd72f58acfbe2967c678759ab" @@ -3626,18 +3514,18 @@ archiver-utils@^2.1.0: normalize-path "^3.0.0" readable-stream "^2.0.0" -archiver@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/archiver/-/archiver-4.0.2.tgz#43c72865eadb4ddaaa2fb74852527b6a450d927c" - integrity sha512-B9IZjlGwaxF33UN4oPbfBkyA4V1SxNLeIhR1qY8sRXSsbdUkEHrrOvwlYFPx+8uQeCe9M+FG6KgO+imDmQ79CQ== +archiver@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/archiver/-/archiver-5.0.2.tgz#b2c435823499b1f46eb07aa18e7bcb332f6ca3fc" + integrity sha512-Tq3yV/T4wxBsD2Wign8W9VQKhaUxzzRmjEiSoOK0SLqPgDP/N1TKdYyBeIEu56T4I9iO4fKTTR0mN9NWkBA0sg== dependencies: archiver-utils "^2.1.0" async "^3.2.0" buffer-crc32 "^0.2.1" - glob "^7.1.6" readable-stream "^3.6.0" - tar-stream "^2.1.2" - zip-stream "^3.0.1" + readdir-glob "^1.0.0" + tar-stream "^2.1.4" + zip-stream "^4.0.0" archy@^1.0.0: version "1.0.0" @@ -3720,6 +3608,11 @@ array-union@^1.0.2: dependencies: array-uniq "^1.0.1" +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + array-uniq@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" @@ -3848,6 +3741,21 @@ aws-sdk-mock@^5.1.0: sinon "^9.0.1" traverse "^0.6.6" +aws-sdk@^2.596.0: + version "2.754.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.754.0.tgz#8a224d24d8597b084d01a76e2496533c73a45630" + integrity sha512-87WVpDOY9LlJtbN6/RszHrr8NxN/M/Qb5luNX3IayUUt+emkBrl6ZKPrG+N1s+WXEyLxkNE4fxiBkiS/5/TiEg== + dependencies: + buffer "4.9.2" + events "1.1.1" + ieee754 "1.1.13" + jmespath "0.15.0" + querystring "0.2.0" + sax "1.2.1" + url "0.10.3" + uuid "3.3.2" + xml2js "0.4.19" + aws-sdk@^2.637.0, aws-sdk@^2.739.0: version "2.739.0" resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.739.0.tgz#10b0b29be18c3f0f85ca145cbed8b10793ddc7a7" @@ -3880,20 +3788,6 @@ axios@^0.19.0: dependencies: follow-redirects "1.5.10" -babel-jest@^25.5.1: - version "25.5.1" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-25.5.1.tgz#bc2e6101f849d6f6aec09720ffc7bc5332e62853" - integrity sha512-9dA9+GmMjIzgPnYtkhBg73gOo/RHqPmLruP3BaGL4KEX3Dwz6pI8auSN8G8+iuEG90+GSswyKvslN+JYSaacaQ== - dependencies: - "@jest/transform" "^25.5.1" - "@jest/types" "^25.5.0" - "@types/babel__core" "^7.1.7" - babel-plugin-istanbul "^6.0.0" - babel-preset-jest "^25.5.0" - chalk "^3.0.0" - graceful-fs "^4.2.4" - slash "^3.0.0" - babel-jest@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.3.0.tgz#10d0ca4b529ca3e7d1417855ef7d7bd6fc0c3463" @@ -3926,15 +3820,6 @@ babel-plugin-istanbul@^6.0.0: istanbul-lib-instrument "^4.0.0" test-exclude "^6.0.0" -babel-plugin-jest-hoist@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-25.5.0.tgz#129c80ba5c7fc75baf3a45b93e2e372d57ca2677" - integrity sha512-u+/W+WAjMlvoocYGTwthAiQSxDcJAyHpQ6oWlHdFZaaN+Rlk8Q7iiwDPg2lN/FyJtAYnKjFxbn7xus4HCFkg5g== - dependencies: - "@babel/template" "^7.3.3" - "@babel/types" "^7.3.3" - "@types/babel__traverse" "^7.0.6" - babel-plugin-jest-hoist@^26.2.0: version "26.2.0" resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.2.0.tgz#bdd0011df0d3d513e5e95f76bd53b51147aca2dd" @@ -3945,7 +3830,7 @@ babel-plugin-jest-hoist@^26.2.0: "@types/babel__core" "^7.0.0" "@types/babel__traverse" "^7.0.6" -babel-preset-current-node-syntax@^0.1.2, babel-preset-current-node-syntax@^0.1.3: +babel-preset-current-node-syntax@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.3.tgz#b4b547acddbf963cba555ba9f9cbbb70bfd044da" integrity sha512-uyexu1sVwcdFnyq9o8UQYsXwXflIh8LvrF5+cKrYam93ned1CStffB3+BEcsxGSgagoA3GEyjDqO4a/58hyPYQ== @@ -3962,14 +3847,6 @@ babel-preset-current-node-syntax@^0.1.2, babel-preset-current-node-syntax@^0.1.3 "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" "@babel/plugin-syntax-optional-chaining" "^7.8.3" -babel-preset-jest@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-25.5.0.tgz#c1d7f191829487a907764c65307faa0e66590b49" - integrity sha512-8ZczygctQkBU+63DtSOKGh7tFL0CeCuz+1ieud9lJ1WPQ9O6A1a/r+LGn6Y705PA6whHQ3T1XuB/PmpfNYf8Fw== - dependencies: - babel-plugin-jest-hoist "^25.5.0" - babel-preset-current-node-syntax "^0.1.2" - babel-preset-jest@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-26.3.0.tgz#ed6344506225c065fd8a0b53e191986f74890776" @@ -4018,7 +3895,7 @@ bind-obj-methods@^2.0.0: resolved "https://registry.yarnpkg.com/bind-obj-methods/-/bind-obj-methods-2.0.0.tgz#0178140dbe7b7bb67dc74892ace59bc0247f06f0" integrity sha512-3/qRXczDi2Cdbz6jE+W3IflJOutRVica8frpBn14de1mBOkzDo+6tY33kNhvkw54Kn3PzRRD2VnGbGPcTAk4sw== -bl@^4.0.1: +bl@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/bl/-/bl-4.0.3.tgz#12d6287adc29080e22a705e5764b2a9522cdc489" integrity sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg== @@ -4027,7 +3904,7 @@ bl@^4.0.1: inherits "^2.0.4" readable-stream "^3.4.0" -bluebird@^3.5.0, bluebird@^3.5.1, bluebird@^3.5.3, bluebird@^3.5.5: +bluebird@^3.5.1, bluebird@^3.5.3, bluebird@^3.5.5: version "3.7.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== @@ -4088,13 +3965,6 @@ 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== -browser-resolve@^1.11.3: - version "1.11.3" - resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6" - integrity sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ== - dependencies: - resolve "1.1.7" - browserify-aes@^1.0.0, browserify-aes@^1.0.4: version "1.2.0" resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" @@ -4358,11 +4228,6 @@ camelcase@^2.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= -camelcase@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" - integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo= - camelcase@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" @@ -4550,20 +4415,6 @@ cli-width@^2.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== -cli-width@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" - integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== - -cliui@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" - integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0= - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - wrap-ansi "^2.0.0" - cliui@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" @@ -4582,6 +4433,15 @@ cliui@^6.0.0: strip-ansi "^6.0.0" wrap-ansi "^6.2.0" +cliui@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.1.tgz#a4cb67aad45cd83d8d05128fc9f4d8fbb887e6b3" + integrity sha512-rcvHOWyGyid6I1WjT/3NatKj2kDt9OdSHSXpyLXaMWFbKpGACNW8pRhhdPUq9MWUOdwn8Rz9AVETjF4105rZZQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + clone-deep@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" @@ -4620,10 +4480,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.11.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/codemaker/-/codemaker-1.11.0.tgz#4b63b5a04e1566b58fdd80583c383c061f2a8ce1" - integrity sha512-cBTHf17J9ukOqwmPFfU7VTqBsl/WLIHh2LQk4mTA8GQgeBSD9E5u52nqHCB3Ca5PY8vBol5ifgtuukJkHqlgqQ== +codemaker@^1.12.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/codemaker/-/codemaker-1.12.0.tgz#4a6a5ec7b6c25a218790060fe547eda96af0e1a0" + integrity sha512-QTToXDgTjeFWptxh1cI2FtHPYbKQ4EJ5tIJjriSUYx90arqpp1huykYfyxIqvSwGBRXPhkZxolwf/WEiGTiqLA== dependencies: camelcase "^6.0.0" decamelize "^4.0.0" @@ -4760,15 +4620,15 @@ component-emitter@^1.2.1: resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== -compress-commons@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-3.0.0.tgz#833944d84596e537224dd91cf92f5246823d4f1d" - integrity sha512-FyDqr8TKX5/X0qo+aVfaZ+PVmNJHJeckFBlq8jZGSJOgnynhfifoyl24qaqdUdDIBe0EVTHByN6NAkqYvE/2Xg== +compress-commons@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-4.0.1.tgz#c5fa908a791a0c71329fba211d73cd2a32005ea8" + integrity sha512-xZm9o6iikekkI0GnXCmAl3LQGZj5TBDj0zLowsqi7tJtEa3FMGSEcHcqrSJIrOAk1UG/NBbDn/F1q+MG/p/EsA== dependencies: buffer-crc32 "^0.2.13" - crc32-stream "^3.0.1" + crc32-stream "^4.0.0" normalize-path "^3.0.0" - readable-stream "^2.3.7" + readable-stream "^3.6.0" concat-map@0.0.1: version "0.0.1" @@ -5133,10 +4993,10 @@ cp-file@^6.2.0: pify "^4.0.1" safe-buffer "^5.0.1" -crc32-stream@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-3.0.1.tgz#cae6eeed003b0e44d739d279de5ae63b171b4e85" - integrity sha512-mctvpXlbzsvK+6z8kJwSJ5crm7yBwrQMTybJzMw1O4lLGJqjlDCXY2Zw7KheiA6XBEcBmfLx1D88mjRGVJtY9w== +crc32-stream@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-4.0.0.tgz#05b7ca047d831e98c215538666f372b756d91893" + integrity sha512-tyMw2IeUX6t9jhgXI6um0eKfWq4EIDpfv5m7GX4Jzp7eVelQ360xd8EPXJhp2mHwLQIkqlnMLjzqSZI3a+0wRw== dependencies: crc "^3.4.4" readable-stream "^3.4.0" @@ -5187,7 +5047,7 @@ cross-spawn@^4: lru-cache "^4.0.1" which "^1.2.9" -cross-spawn@^6.0.0, cross-spawn@^6.0.4, cross-spawn@^6.0.5: +cross-spawn@^6.0.0, cross-spawn@^6.0.4: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== @@ -5198,7 +5058,7 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.4, cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^7.0.0: +cross-spawn@^7.0.0, cross-spawn@^7.0.2: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -5383,7 +5243,7 @@ cssom@0.3.x, cssom@^0.3.4, cssom@~0.3.6: resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== -cssom@^0.4.1, cssom@^0.4.4: +cssom@^0.4.4: version "0.4.4" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== @@ -5395,7 +5255,7 @@ cssstyle@^1.1.1: dependencies: cssom "0.3.x" -cssstyle@^2.0.0, cssstyle@^2.2.0: +cssstyle@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== @@ -5507,7 +5367,7 @@ decamelize-keys@^1.0.0, decamelize-keys@^1.1.0: decamelize "^1.1.0" map-obj "^1.0.0" -decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0: +decamelize@^1.1.0, decamelize@^1.1.2, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= @@ -5552,7 +5412,7 @@ deep-equal@^2.0.3: which-collection "^1.0.1" which-typed-array "^1.1.2" -deep-is@~0.1.3: +deep-is@^0.1.3, deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= @@ -5720,6 +5580,13 @@ dir-glob@^2.2.2: dependencies: path-type "^3.0.0" +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + doctrine@1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" @@ -5811,11 +5678,21 @@ dotenv-expand@^5.1.0: resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== +dotenv-json@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dotenv-json/-/dotenv-json-1.0.0.tgz#fc7f672aafea04bed33818733b9f94662332815c" + integrity sha512-jAssr+6r4nKhKRudQ0HOzMskOFFi9+ubXWwmrSGJFgTvpjyPXCXsCsYbjif6mXp7uxA7xY3/LGaiTQukZzSbOQ== + dotenv@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-7.0.0.tgz#a2be3cd52736673206e8a85fb5210eea29628e7c" integrity sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g== +dotenv@^8.0.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" + integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== + dotgitignore@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/dotgitignore/-/dotgitignore-2.1.0.tgz#a4b15a4e4ef3cf383598aaf1dfa4a04bcc089b7b" @@ -5925,7 +5802,7 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" -enquirer@^2.3.6: +enquirer@^2.3.5, enquirer@^2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== @@ -6073,7 +5950,7 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -escodegen@1.x.x, escodegen@^1.11.0, escodegen@^1.11.1, escodegen@^1.14.1: +escodegen@1.x.x, escodegen@^1.11.0, escodegen@^1.14.1: version "1.14.3" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== @@ -6085,6 +5962,11 @@ escodegen@1.x.x, escodegen@^1.11.0, escodegen@^1.11.1, escodegen@^1.14.1: optionalDependencies: source-map "~0.6.1" +eslint-config-standard@^14.1.1: + version "14.1.1" + resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-14.1.1.tgz#830a8e44e7aef7de67464979ad06b406026c56ea" + integrity sha512-Z9B+VR+JIXRxz21udPTL9HpFMyoMUEeX1G251EQ6e05WD9aPVtVBn09XUmZ259wCMlCDmYDSZG62Hhm+ZTJcUg== + eslint-import-resolver-node@^0.3.3, eslint-import-resolver-node@^0.3.4: version "0.3.4" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717" @@ -6093,10 +5975,10 @@ eslint-import-resolver-node@^0.3.3, eslint-import-resolver-node@^0.3.4: debug "^2.6.9" resolve "^1.13.1" -eslint-import-resolver-typescript@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.2.1.tgz#4b9bdfb51af7e14947ebc40ffdd6c32d5924b905" - integrity sha512-wxlVdwuWY6R5+CoesIy6n8EZX4k9lEeZGWTVBoX9g//8Xma8JMtL/p3AGnG43rRyXmIrX+/0IN8lpOPzrw1fSw== +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== dependencies: debug "^4.1.1" glob "^7.1.6" @@ -6112,6 +5994,14 @@ eslint-module-utils@^2.6.0: debug "^2.6.9" pkg-dir "^2.0.0" +eslint-plugin-es@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz#75a7cdfdccddc0589934aeeb384175f221c57893" + integrity sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ== + dependencies: + eslint-utils "^2.0.0" + regexpp "^3.0.0" + eslint-plugin-import@^2.22.0: version "2.22.0" resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.22.0.tgz#92f7736fe1fde3e2de77623c838dd992ff5ffb7e" @@ -6131,6 +6021,28 @@ eslint-plugin-import@^2.22.0: resolve "^1.17.0" tsconfig-paths "^3.9.0" +eslint-plugin-node@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz#c95544416ee4ada26740a30474eefc5402dc671d" + integrity sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g== + dependencies: + eslint-plugin-es "^3.0.0" + eslint-utils "^2.0.0" + ignore "^5.1.1" + minimatch "^3.0.4" + resolve "^1.10.1" + semver "^6.1.0" + +eslint-plugin-promise@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz#845fd8b2260ad8f82564c1222fce44ad71d9418a" + integrity sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw== + +eslint-plugin-standard@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-4.0.1.tgz#ff0519f7ffaff114f76d1bd7c3996eef0f6e20b4" + integrity sha512-v/KBnfyaOMPmZc/dmc6ozOdWqekGp7bBGq4jLAecEfPGmfKiWS4sA8sC0LqiV9w5qmXAtXVn4M3p1jSyhY85SQ== + eslint-scope@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.0.tgz#d0f971dfe59c69e0cada684b23d49dbf82600ce5" @@ -6139,41 +6051,49 @@ eslint-scope@^5.0.0: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-utils@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" - integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== +eslint-scope@^5.1.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== dependencies: - eslint-visitor-keys "^1.1.0" + esrecurse "^4.3.0" + estraverse "^4.1.1" -eslint-utils@^2.0.0: +eslint-utils@^2.0.0, eslint-utils@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== dependencies: eslint-visitor-keys "^1.1.0" -eslint-visitor-keys@^1.1.0: +eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== -eslint@^6.8.0: - version "6.8.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb" - integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig== +eslint-visitor-keys@^2.0.0: + version "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.9.0: + version "7.9.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.9.0.tgz#522aeccc5c3a19017cf0cb46ebfd660a79acf337" + integrity sha512-V6QyhX21+uXp4T+3nrNfI3hQNBDa/P8ga7LoQOenwrlEFXrEnUEE+ok1dMtaS3b6rmLXhT1TkTIsG75HMLbknA== dependencies: "@babel/code-frame" "^7.0.0" + "@eslint/eslintrc" "^0.1.3" ajv "^6.10.0" - chalk "^2.1.0" - cross-spawn "^6.0.5" + chalk "^4.0.0" + cross-spawn "^7.0.2" debug "^4.0.1" doctrine "^3.0.0" - eslint-scope "^5.0.0" - eslint-utils "^1.4.3" - eslint-visitor-keys "^1.1.0" - espree "^6.1.2" - esquery "^1.0.1" + enquirer "^2.3.5" + eslint-scope "^5.1.0" + eslint-utils "^2.1.0" + eslint-visitor-keys "^1.3.0" + espree "^7.3.0" + esquery "^1.2.0" esutils "^2.0.2" file-entry-cache "^5.0.1" functional-red-black-tree "^1.0.1" @@ -6182,21 +6102,19 @@ eslint@^6.8.0: ignore "^4.0.6" import-fresh "^3.0.0" imurmurhash "^0.1.4" - inquirer "^7.0.0" is-glob "^4.0.0" js-yaml "^3.13.1" json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.14" + levn "^0.4.1" + lodash "^4.17.19" minimatch "^3.0.4" - mkdirp "^0.5.1" natural-compare "^1.4.0" - optionator "^0.8.3" + optionator "^0.9.1" progress "^2.0.0" - regexpp "^2.0.1" - semver "^6.1.2" - strip-ansi "^5.2.0" - strip-json-comments "^3.0.1" + regexpp "^3.1.0" + semver "^7.2.1" + strip-ansi "^6.0.0" + strip-json-comments "^3.1.0" table "^5.2.3" text-table "^0.2.0" v8-compile-cache "^2.0.3" @@ -6206,14 +6124,14 @@ esm@^3.2.5: resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10" integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA== -espree@^6.1.2: - version "6.2.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" - integrity sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw== +espree@^7.3.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.0.tgz#dc30437cf67947cf576121ebd780f15eeac72348" + integrity sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw== dependencies: - acorn "^7.1.1" + acorn "^7.4.0" acorn-jsx "^5.2.0" - eslint-visitor-keys "^1.1.0" + eslint-visitor-keys "^1.3.0" esprima@3.x.x: version "3.1.3" @@ -6225,7 +6143,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.0.1: +esquery@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57" integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ== @@ -6239,12 +6157,19 @@ esrecurse@^4.1.0: dependencies: estraverse "^4.1.0" +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== -estraverse@^5.1.0: +estraverse@^5.1.0, estraverse@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== @@ -6305,22 +6230,6 @@ execa@^1.0.0: signal-exit "^3.0.0" strip-eof "^1.0.0" -execa@^3.2.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-3.4.0.tgz#c08ed4550ef65d858fac269ffc8572446f37eb89" - integrity sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g== - dependencies: - cross-spawn "^7.0.0" - get-stream "^5.0.0" - human-signals "^1.1.1" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.0" - onetime "^5.1.0" - p-finally "^2.0.0" - signal-exit "^3.0.2" - strip-final-newline "^2.0.0" - execa@^4.0.0, execa@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/execa/-/execa-4.0.3.tgz#0a34dabbad6d66100bd6f2c576c8669403f317f2" @@ -6354,18 +6263,6 @@ expand-brackets@^2.1.4: snapdragon "^0.8.1" to-regex "^3.0.1" -expect@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-25.5.0.tgz#f07f848712a2813bb59167da3fb828ca21f58bba" - integrity sha512-w7KAXo0+6qqZZhovCaBVPSIqQp7/UTcx4M9uKt2m6pd2VB1voyC8JizLRqeEqud3AAVP02g+hbErDu5gu64tlA== - dependencies: - "@jest/types" "^25.5.0" - ansi-styles "^4.0.0" - jest-get-type "^25.2.6" - jest-matcher-utils "^25.5.0" - jest-message-util "^25.5.0" - jest-regex-util "^25.2.6" - expect@^26.4.2: version "26.4.2" resolved "https://registry.yarnpkg.com/expect/-/expect-26.4.2.tgz#36db120928a5a2d7d9736643032de32f24e1b2a1" @@ -6431,13 +6328,12 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= -fast-check@^1.26.0: - version "1.26.0" - resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-1.26.0.tgz#3a85998a9c30ed7f58976276e06046645e0de18a" - integrity sha512-B1AjSfe0bmi6FdFIzmrrGSjrsF6e2MCmZiM6zJaRbBMP+gIvdNakle5FIMKi0xbS9KlN9BZho1R7oB/qoNIQuA== +fast-check@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-2.3.0.tgz#5292727f5971f44155c07a0e7c3930174c625eda" + integrity sha512-VnU5lzab1vlXj3tUVe4bqWabZhUNyE/DJ+iilpQWW1GLnrp7OZBHccCz7NzZaNv7cEdrp4YgXoguKQjSVREXng== dependencies: - pure-rand "^2.0.0" - tslib "^2.0.0" + pure-rand "^3.0.0" fast-deep-equal@^2.0.1: version "2.0.1" @@ -6472,6 +6368,18 @@ fast-glob@^2.2.6: merge2 "^1.2.3" micromatch "^3.1.10" +fast-glob@^3.1.1: + version "3.2.4" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.4.tgz#d20aefbf99579383e7f3cc66529158c9b98554d3" + integrity sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.0" + merge2 "^1.3.0" + micromatch "^4.0.2" + picomatch "^2.2.1" + fast-json-patch@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/fast-json-patch/-/fast-json-patch-2.2.1.tgz#18150d36c9ab65c7209e7d4eb113f4f8eaabe6d9" @@ -6489,7 +6397,7 @@ fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== -fast-levenshtein@~2.0.6: +fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= @@ -6532,7 +6440,7 @@ figures@^2.0.0: dependencies: escape-string-regexp "^1.0.5" -figures@^3.0.0, figures@^3.1.0, figures@^3.2.0: +figures@^3.1.0, figures@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== @@ -6851,12 +6759,7 @@ gensync@^1.0.0-beta.1: resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== -get-caller-file@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" - integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== - -get-caller-file@^2.0.1: +get-caller-file@^2.0.1, get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== @@ -7017,7 +6920,7 @@ glob-to-regexp@^0.3.0: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= -glob@^7.0.0, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@~7.1.4: +glob@^7.0.0, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@~7.1.6: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== @@ -7041,6 +6944,18 @@ globals@^12.1.0: dependencies: type-fest "^0.8.1" +globby@^11.0.1: + version "11.0.1" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.1.tgz#9a2bf107a068f3ffeabc49ad702c79ede8cfd357" + integrity sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + globby@^9.2.0: version "9.2.0" resolved "https://registry.yarnpkg.com/globby/-/globby-9.2.0.tgz#fd029a706c703d29bdd170f4b6db3a3f7a7cb63d" @@ -7422,6 +7337,11 @@ ignore@^4.0.3, ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== +ignore@^5.1.1, ignore@^5.1.4: + version "5.1.8" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" + integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== + immediate@~3.0.5: version "3.0.6" resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" @@ -7542,25 +7462,6 @@ inquirer@^6.2.0: strip-ansi "^5.1.0" through "^2.3.6" -inquirer@^7.0.0: - version "7.3.3" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" - integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== - dependencies: - ansi-escapes "^4.2.1" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-width "^3.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.19" - mute-stream "0.0.8" - run-async "^2.4.0" - rxjs "^6.6.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" - interpret@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" @@ -7573,11 +7474,6 @@ invariant@^2.2.2, invariant@^2.2.4: dependencies: loose-envify "^1.0.0" -invert-kv@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" - integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= - ip-regex@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" @@ -8126,15 +8022,6 @@ istanbul-reports@^3.0.2: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jest-changed-files@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-25.5.0.tgz#141cc23567ceb3f534526f8614ba39421383634c" - integrity sha512-EOw9QEqapsDT7mKF162m8HFzRPbmP8qJQny6ldVOdOVBz3ACgPm/1nAn5fPQ/NDaYhX/AHkrGwwkCncpAVSXcw== - dependencies: - "@jest/types" "^25.5.0" - execa "^3.2.0" - throat "^5.0.0" - jest-changed-files@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.3.0.tgz#68fb2a7eb125f50839dab1f5a17db3607fe195b1" @@ -8144,26 +8031,6 @@ jest-changed-files@^26.3.0: execa "^4.0.0" throat "^5.0.0" -jest-cli@^25.5.4: - version "25.5.4" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-25.5.4.tgz#b9f1a84d1301a92c5c217684cb79840831db9f0d" - integrity sha512-rG8uJkIiOUpnREh1768/N3n27Cm+xPFkSNFO91tgg+8o2rXeVLStz+vkXkGr4UtzH6t1SNbjwoiswd7p4AhHTw== - dependencies: - "@jest/core" "^25.5.4" - "@jest/test-result" "^25.5.0" - "@jest/types" "^25.5.0" - chalk "^3.0.0" - exit "^0.1.2" - graceful-fs "^4.2.4" - import-local "^3.0.2" - is-ci "^2.0.0" - jest-config "^25.5.4" - jest-util "^25.5.0" - jest-validate "^25.5.0" - prompts "^2.0.1" - realpath-native "^2.0.0" - yargs "^15.3.1" - jest-cli@^26.4.2: version "26.4.2" resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.4.2.tgz#24afc6e4dfc25cde4c7ec4226fb7db5f157c21da" @@ -8183,31 +8050,6 @@ jest-cli@^26.4.2: prompts "^2.0.1" yargs "^15.3.1" -jest-config@^25.5.4: - version "25.5.4" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-25.5.4.tgz#38e2057b3f976ef7309b2b2c8dcd2a708a67f02c" - integrity sha512-SZwR91SwcdK6bz7Gco8qL7YY2sx8tFJYzvg216DLihTWf+LKY/DoJXpM9nTzYakSyfblbqeU48p/p7Jzy05Atg== - dependencies: - "@babel/core" "^7.1.0" - "@jest/test-sequencer" "^25.5.4" - "@jest/types" "^25.5.0" - babel-jest "^25.5.1" - chalk "^3.0.0" - deepmerge "^4.2.2" - glob "^7.1.1" - graceful-fs "^4.2.4" - jest-environment-jsdom "^25.5.0" - jest-environment-node "^25.5.0" - jest-get-type "^25.2.6" - jest-jasmine2 "^25.5.4" - jest-regex-util "^25.2.6" - jest-resolve "^25.5.1" - jest-util "^25.5.0" - jest-validate "^25.5.0" - micromatch "^4.0.2" - pretty-format "^25.5.0" - realpath-native "^2.0.0" - jest-config@^26.4.2: version "26.4.2" resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.4.2.tgz#da0cbb7dc2c131ffe831f0f7f2a36256e6086558" @@ -8232,7 +8074,7 @@ jest-config@^26.4.2: micromatch "^4.0.2" pretty-format "^26.4.2" -jest-diff@^25.2.1, jest-diff@^25.5.0: +jest-diff@^25.2.1: version "25.5.0" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-25.5.0.tgz#1dd26ed64f96667c068cef026b677dfa01afcfa9" integrity sha512-z1kygetuPiREYdNIumRpAHY6RXiGmp70YHptjdaxTWGmA085W3iCnXNx0DhflK3vwrKmrRWyY1wUpkPMVxMK7A== @@ -8252,13 +8094,6 @@ jest-diff@^26.4.2: jest-get-type "^26.3.0" pretty-format "^26.4.2" -jest-docblock@^25.3.0: - version "25.3.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-25.3.0.tgz#8b777a27e3477cd77a168c05290c471a575623ef" - integrity sha512-aktF0kCar8+zxRHxQZwxMy70stc9R1mOmrLsT5VO3pIT0uzGRSDAXxSlz4NqQWpuLjPpuMhPRl7H+5FRsvIQAg== - dependencies: - detect-newline "^3.0.0" - jest-docblock@^26.0.0: version "26.0.0" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5" @@ -8266,17 +8101,6 @@ jest-docblock@^26.0.0: dependencies: detect-newline "^3.0.0" -jest-each@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-25.5.0.tgz#0c3c2797e8225cb7bec7e4d249dcd96b934be516" - integrity sha512-QBogUxna3D8vtiItvn54xXde7+vuzqRrEeaw8r1s+1TG9eZLVJE5ZkKoSUlqFwRjnlaA4hyKGiu9OlkFIuKnjA== - dependencies: - "@jest/types" "^25.5.0" - chalk "^3.0.0" - jest-get-type "^25.2.6" - jest-util "^25.5.0" - pretty-format "^25.5.0" - jest-each@^26.4.2: version "26.4.2" resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-26.4.2.tgz#bb14f7f4304f2bb2e2b81f783f989449b8b6ffae" @@ -8288,18 +8112,6 @@ jest-each@^26.4.2: jest-util "^26.3.0" pretty-format "^26.4.2" -jest-environment-jsdom@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-25.5.0.tgz#dcbe4da2ea997707997040ecf6e2560aec4e9834" - integrity sha512-7Jr02ydaq4jaWMZLY+Skn8wL5nVIYpWvmeatOHL3tOcV3Zw8sjnPpx+ZdeBfc457p8jCR9J6YCc+Lga0oIy62A== - dependencies: - "@jest/environment" "^25.5.0" - "@jest/fake-timers" "^25.5.0" - "@jest/types" "^25.5.0" - jest-mock "^25.5.0" - jest-util "^25.5.0" - jsdom "^15.2.1" - jest-environment-jsdom@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-26.3.0.tgz#3b749ba0f3a78e92ba2c9ce519e16e5dd515220c" @@ -8313,18 +8125,6 @@ jest-environment-jsdom@^26.3.0: jest-util "^26.3.0" jsdom "^16.2.2" -jest-environment-node@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-25.5.0.tgz#0f55270d94804902988e64adca37c6ce0f7d07a1" - integrity sha512-iuxK6rQR2En9EID+2k+IBs5fCFd919gVVK5BeND82fYeLWPqvRcFNPKu9+gxTwfB5XwBGBvZ0HFQa+cHtIoslA== - dependencies: - "@jest/environment" "^25.5.0" - "@jest/fake-timers" "^25.5.0" - "@jest/types" "^25.5.0" - jest-mock "^25.5.0" - jest-util "^25.5.0" - semver "^6.3.0" - jest-environment-node@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-26.3.0.tgz#56c6cfb506d1597f94ee8d717072bda7228df849" @@ -8347,26 +8147,6 @@ jest-get-type@^26.3.0: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== -jest-haste-map@^25.5.1: - version "25.5.1" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-25.5.1.tgz#1df10f716c1d94e60a1ebf7798c9fb3da2620943" - integrity sha512-dddgh9UZjV7SCDQUrQ+5t9yy8iEgKc1AKqZR9YDww8xsVOtzPQSMVLDChc21+g29oTRexb9/B0bIlZL+sWmvAQ== - dependencies: - "@jest/types" "^25.5.0" - "@types/graceful-fs" "^4.1.2" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.4" - jest-serializer "^25.5.0" - jest-util "^25.5.0" - jest-worker "^25.5.0" - micromatch "^4.0.2" - sane "^4.0.3" - walker "^1.0.7" - which "^2.0.2" - optionalDependencies: - fsevents "^2.1.2" - jest-haste-map@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.3.0.tgz#c51a3b40100d53ab777bfdad382d2e7a00e5c726" @@ -8388,29 +8168,6 @@ jest-haste-map@^26.3.0: optionalDependencies: fsevents "^2.1.2" -jest-jasmine2@^25.5.4: - version "25.5.4" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-25.5.4.tgz#66ca8b328fb1a3c5364816f8958f6970a8526968" - integrity sha512-9acbWEfbmS8UpdcfqnDO+uBUgKa/9hcRh983IHdM+pKmJPL77G0sWAAK0V0kr5LK3a8cSBfkFSoncXwQlRZfkQ== - dependencies: - "@babel/traverse" "^7.1.0" - "@jest/environment" "^25.5.0" - "@jest/source-map" "^25.5.0" - "@jest/test-result" "^25.5.0" - "@jest/types" "^25.5.0" - chalk "^3.0.0" - co "^4.6.0" - expect "^25.5.0" - is-generator-fn "^2.0.0" - jest-each "^25.5.0" - jest-matcher-utils "^25.5.0" - jest-message-util "^25.5.0" - jest-runtime "^25.5.4" - jest-snapshot "^25.5.1" - jest-util "^25.5.0" - pretty-format "^25.5.0" - throat "^5.0.0" - jest-jasmine2@^26.4.2: version "26.4.2" resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.4.2.tgz#18a9d5bec30904267ac5e9797570932aec1e2257" @@ -8445,14 +8202,6 @@ jest-junit@^11.1.0: uuid "^3.3.3" xml "^1.0.1" -jest-leak-detector@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-25.5.0.tgz#2291c6294b0ce404241bb56fe60e2d0c3e34f0bb" - integrity sha512-rV7JdLsanS8OkdDpZtgBf61L5xZ4NnYLBq72r6ldxahJWWczZjXawRsoHyXzibM5ed7C2QRjpp6ypgwGdKyoVA== - dependencies: - jest-get-type "^25.2.6" - pretty-format "^25.5.0" - jest-leak-detector@^26.4.2: version "26.4.2" resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-26.4.2.tgz#c73e2fa8757bf905f6f66fb9e0070b70fa0f573f" @@ -8461,16 +8210,6 @@ jest-leak-detector@^26.4.2: jest-get-type "^26.3.0" pretty-format "^26.4.2" -jest-matcher-utils@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-25.5.0.tgz#fbc98a12d730e5d2453d7f1ed4a4d948e34b7867" - integrity sha512-VWI269+9JS5cpndnpCwm7dy7JtGQT30UHfrnM3mXl22gHGt/b7NkjBqXfbhZ8V4B7ANUsjK18PlSBmG0YH7gjw== - dependencies: - chalk "^3.0.0" - jest-diff "^25.5.0" - jest-get-type "^25.2.6" - pretty-format "^25.5.0" - jest-matcher-utils@^26.4.2: version "26.4.2" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.4.2.tgz#fa81f3693f7cb67e5fc1537317525ef3b85f4b06" @@ -8481,20 +8220,6 @@ jest-matcher-utils@^26.4.2: jest-get-type "^26.3.0" pretty-format "^26.4.2" -jest-message-util@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-25.5.0.tgz#ea11d93204cc7ae97456e1d8716251185b8880ea" - integrity sha512-ezddz3YCT/LT0SKAmylVyWWIGYoKHOFOFXx3/nA4m794lfVUskMcwhip6vTgdVrOtYdjeQeis2ypzes9mZb4EA== - dependencies: - "@babel/code-frame" "^7.0.0" - "@jest/types" "^25.5.0" - "@types/stack-utils" "^1.0.1" - chalk "^3.0.0" - graceful-fs "^4.2.4" - micromatch "^4.0.2" - slash "^3.0.0" - stack-utils "^1.0.1" - jest-message-util@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.3.0.tgz#3bdb538af27bb417f2d4d16557606fd082d5841a" @@ -8509,13 +8234,6 @@ jest-message-util@^26.3.0: slash "^3.0.0" stack-utils "^2.0.2" -jest-mock@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-25.5.0.tgz#a91a54dabd14e37ecd61665d6b6e06360a55387a" - integrity sha512-eXWuTV8mKzp/ovHc5+3USJMYsTBhyQ+5A1Mak35dey/RG8GlM4YWVylZuGgVXinaW6tpvk/RSecmF37FKUlpXA== - dependencies: - "@jest/types" "^25.5.0" - jest-mock@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.3.0.tgz#ee62207c3c5ebe5f35b760e1267fee19a1cfdeba" @@ -8524,30 +8242,16 @@ jest-mock@^26.3.0: "@jest/types" "^26.3.0" "@types/node" "*" -jest-pnp-resolver@^1.2.1, jest-pnp-resolver@^1.2.2: +jest-pnp-resolver@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== -jest-regex-util@^25.2.6: - version "25.2.6" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-25.2.6.tgz#d847d38ba15d2118d3b06390056028d0f2fd3964" - integrity sha512-KQqf7a0NrtCkYmZZzodPftn7fL1cq3GQAFVMn5Hg8uKx/fIenLEobNanUxb7abQ1sjADHBseG/2FGpsv/wr+Qw== - jest-regex-util@^26.0.0: version "26.0.0" resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== -jest-resolve-dependencies@^25.5.4: - version "25.5.4" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-25.5.4.tgz#85501f53957c8e3be446e863a74777b5a17397a7" - integrity sha512-yFmbPd+DAQjJQg88HveObcGBA32nqNZ02fjYmtL16t1xw9bAttSn5UGRRhzMHIQbsep7znWvAvnD4kDqOFM0Uw== - dependencies: - "@jest/types" "^25.5.0" - jest-regex-util "^25.2.6" - jest-snapshot "^25.5.1" - jest-resolve-dependencies@^26.4.2: version "26.4.2" resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-26.4.2.tgz#739bdb027c14befb2fe5aabbd03f7bab355f1dc5" @@ -8557,21 +8261,6 @@ jest-resolve-dependencies@^26.4.2: jest-regex-util "^26.0.0" jest-snapshot "^26.4.2" -jest-resolve@^25.5.1: - version "25.5.1" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-25.5.1.tgz#0e6fbcfa7c26d2a5fe8f456088dc332a79266829" - integrity sha512-Hc09hYch5aWdtejsUZhA+vSzcotf7fajSlPA6EZPE1RmPBAD39XtJhvHWFStid58iit4IPDLI/Da4cwdDmAHiQ== - dependencies: - "@jest/types" "^25.5.0" - browser-resolve "^1.11.3" - chalk "^3.0.0" - graceful-fs "^4.2.4" - jest-pnp-resolver "^1.2.1" - read-pkg-up "^7.0.1" - realpath-native "^2.0.0" - resolve "^1.17.0" - slash "^3.0.0" - jest-resolve@^26.4.0: version "26.4.0" resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.4.0.tgz#6dc0af7fb93e65b73fec0368ca2b76f3eb59a6d7" @@ -8586,31 +8275,6 @@ jest-resolve@^26.4.0: resolve "^1.17.0" slash "^3.0.0" -jest-runner@^25.5.4: - version "25.5.4" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-25.5.4.tgz#ffec5df3875da5f5c878ae6d0a17b8e4ecd7c71d" - integrity sha512-V/2R7fKZo6blP8E9BL9vJ8aTU4TH2beuqGNxHbxi6t14XzTb+x90B3FRgdvuHm41GY8ch4xxvf0ATH4hdpjTqg== - dependencies: - "@jest/console" "^25.5.0" - "@jest/environment" "^25.5.0" - "@jest/test-result" "^25.5.0" - "@jest/types" "^25.5.0" - chalk "^3.0.0" - exit "^0.1.2" - graceful-fs "^4.2.4" - jest-config "^25.5.4" - jest-docblock "^25.3.0" - jest-haste-map "^25.5.1" - jest-jasmine2 "^25.5.4" - jest-leak-detector "^25.5.0" - jest-message-util "^25.5.0" - jest-resolve "^25.5.1" - jest-runtime "^25.5.4" - jest-util "^25.5.0" - jest-worker "^25.5.0" - source-map-support "^0.5.6" - throat "^5.0.0" - jest-runner@^26.4.2: version "26.4.2" resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-26.4.2.tgz#c3ec5482c8edd31973bd3935df5a449a45b5b853" @@ -8637,38 +8301,6 @@ jest-runner@^26.4.2: source-map-support "^0.5.6" throat "^5.0.0" -jest-runtime@^25.5.4: - version "25.5.4" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-25.5.4.tgz#dc981fe2cb2137abcd319e74ccae7f7eeffbfaab" - integrity sha512-RWTt8LeWh3GvjYtASH2eezkc8AehVoWKK20udV6n3/gC87wlTbE1kIA+opCvNWyyPeBs6ptYsc6nyHUb1GlUVQ== - dependencies: - "@jest/console" "^25.5.0" - "@jest/environment" "^25.5.0" - "@jest/globals" "^25.5.2" - "@jest/source-map" "^25.5.0" - "@jest/test-result" "^25.5.0" - "@jest/transform" "^25.5.1" - "@jest/types" "^25.5.0" - "@types/yargs" "^15.0.0" - chalk "^3.0.0" - collect-v8-coverage "^1.0.0" - exit "^0.1.2" - glob "^7.1.3" - graceful-fs "^4.2.4" - jest-config "^25.5.4" - jest-haste-map "^25.5.1" - jest-message-util "^25.5.0" - jest-mock "^25.5.0" - jest-regex-util "^25.2.6" - jest-resolve "^25.5.1" - jest-snapshot "^25.5.1" - jest-util "^25.5.0" - jest-validate "^25.5.0" - realpath-native "^2.0.0" - slash "^3.0.0" - strip-bom "^4.0.0" - yargs "^15.3.1" - jest-runtime@^26.4.2: version "26.4.2" resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.4.2.tgz#94ce17890353c92e4206580c73a8f0c024c33c42" @@ -8701,13 +8333,6 @@ jest-runtime@^26.4.2: strip-bom "^4.0.0" yargs "^15.3.1" -jest-serializer@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-25.5.0.tgz#a993f484e769b4ed54e70e0efdb74007f503072b" - integrity sha512-LxD8fY1lByomEPflwur9o4e2a5twSQ7TaVNLlFUuToIdoJuBt8tzHfCsZ42Ok6LkKXWzFWf3AGmheuLAA7LcCA== - dependencies: - graceful-fs "^4.2.4" - jest-serializer@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.3.0.tgz#1c9d5e1b74d6e5f7e7f9627080fa205d976c33ef" @@ -8716,27 +8341,6 @@ jest-serializer@^26.3.0: "@types/node" "*" graceful-fs "^4.2.4" -jest-snapshot@^25.5.1: - version "25.5.1" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-25.5.1.tgz#1a2a576491f9961eb8d00c2e5fd479bc28e5ff7f" - integrity sha512-C02JE1TUe64p2v1auUJ2ze5vcuv32tkv9PyhEb318e8XOKF7MOyXdJ7kdjbvrp3ChPLU2usI7Rjxs97Dj5P0uQ== - dependencies: - "@babel/types" "^7.0.0" - "@jest/types" "^25.5.0" - "@types/prettier" "^1.19.0" - chalk "^3.0.0" - expect "^25.5.0" - graceful-fs "^4.2.4" - jest-diff "^25.5.0" - jest-get-type "^25.2.6" - jest-matcher-utils "^25.5.0" - jest-message-util "^25.5.0" - jest-resolve "^25.5.1" - make-dir "^3.0.0" - natural-compare "^1.4.0" - pretty-format "^25.5.0" - semver "^6.3.0" - jest-snapshot@^26.4.2: version "26.4.2" resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.4.2.tgz#87d3ac2f2bd87ea8003602fbebd8fcb9e94104f6" @@ -8770,29 +8374,6 @@ jest-util@26.x, jest-util@^26.3.0: is-ci "^2.0.0" micromatch "^4.0.2" -jest-util@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-25.5.0.tgz#31c63b5d6e901274d264a4fec849230aa3fa35b0" - integrity sha512-KVlX+WWg1zUTB9ktvhsg2PXZVdkI1NBevOJSkTKYAyXyH4QSvh+Lay/e/v+bmaFfrkfx43xD8QTfgobzlEXdIA== - dependencies: - "@jest/types" "^25.5.0" - chalk "^3.0.0" - graceful-fs "^4.2.4" - is-ci "^2.0.0" - make-dir "^3.0.0" - -jest-validate@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-25.5.0.tgz#fb4c93f332c2e4cf70151a628e58a35e459a413a" - integrity sha512-okUFKqhZIpo3jDdtUXUZ2LxGUZJIlfdYBvZb1aczzxrlyMlqdnnws9MOxezoLGhSaFc2XYaHNReNQfj5zPIWyQ== - dependencies: - "@jest/types" "^25.5.0" - camelcase "^5.3.1" - chalk "^3.0.0" - jest-get-type "^25.2.6" - leven "^3.1.0" - pretty-format "^25.5.0" - jest-validate@^26.4.2: version "26.4.2" resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.4.2.tgz#e871b0dfe97747133014dcf6445ee8018398f39c" @@ -8805,18 +8386,6 @@ jest-validate@^26.4.2: leven "^3.1.0" pretty-format "^26.4.2" -jest-watcher@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-25.5.0.tgz#d6110d101df98badebe435003956fd4a465e8456" - integrity sha512-XrSfJnVASEl+5+bb51V0Q7WQx65dTSk7NL4yDdVjPnRNpM0hG+ncFmDYJo9O8jaSRcAitVbuVawyXCRoxGrT5Q== - dependencies: - "@jest/test-result" "^25.5.0" - "@jest/types" "^25.5.0" - ansi-escapes "^4.2.1" - chalk "^3.0.0" - jest-util "^25.5.0" - string-length "^3.1.0" - jest-watcher@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-26.3.0.tgz#f8ef3068ddb8af160ef868400318dc4a898eed08" @@ -8830,14 +8399,6 @@ jest-watcher@^26.3.0: jest-util "^26.3.0" string-length "^4.0.1" -jest-worker@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-25.5.0.tgz#2611d071b79cea0f43ee57a3d118593ac1547db1" - integrity sha512-/dsSmUkIy5EBGfv/IjjqmFxrNAUpBERfGs1oHROyD7yxjG/w+t0GOJDX8O1k32ySmd7+a5IhnJU2qQFcJ4n1vw== - dependencies: - merge-stream "^2.0.0" - supports-color "^7.0.0" - jest-worker@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.3.0.tgz#7c8a97e4f4364b4f05ed8bca8ca0c24de091871f" @@ -8847,15 +8408,6 @@ jest-worker@^26.3.0: merge-stream "^2.0.0" supports-color "^7.0.0" -jest@^25.4.0, jest@^25.5.2, jest@^25.5.3, jest@^25.5.4: - version "25.5.4" - resolved "https://registry.yarnpkg.com/jest/-/jest-25.5.4.tgz#f21107b6489cfe32b076ce2adcadee3587acb9db" - integrity sha512-hHFJROBTqZahnO+X+PMtT6G2/ztqAZJveGqz//FnWWHurizkD05PQGzRZOhF3XP6z7SJmL+5tCfW8qV06JypwQ== - dependencies: - "@jest/core" "^25.5.4" - import-local "^3.0.2" - jest-cli "^25.5.4" - jest@^26.4.2: version "26.4.2" resolved "https://registry.yarnpkg.com/jest/-/jest-26.4.2.tgz#7e8bfb348ec33f5459adeaffc1a25d5752d9d312" @@ -8930,38 +8482,6 @@ jsdom@^14.1.0: ws "^6.1.2" xml-name-validator "^3.0.0" -jsdom@^15.2.1: - version "15.2.1" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-15.2.1.tgz#d2feb1aef7183f86be521b8c6833ff5296d07ec5" - integrity sha512-fAl1W0/7T2G5vURSyxBzrJ1LSdQn6Tr5UX/xD4PXDx/PDgwygedfW6El/KIj3xJ7FU61TTYnc/l/B7P49Eqt6g== - dependencies: - abab "^2.0.0" - acorn "^7.1.0" - acorn-globals "^4.3.2" - array-equal "^1.0.0" - cssom "^0.4.1" - cssstyle "^2.0.0" - data-urls "^1.1.0" - domexception "^1.0.1" - escodegen "^1.11.1" - html-encoding-sniffer "^1.0.2" - nwsapi "^2.2.0" - parse5 "5.1.0" - pn "^1.1.0" - request "^2.88.0" - request-promise-native "^1.0.7" - saxes "^3.1.9" - symbol-tree "^3.2.2" - tough-cookie "^3.0.1" - w3c-hr-time "^1.0.1" - w3c-xmlserializer "^1.1.2" - webidl-conversions "^4.0.2" - whatwg-encoding "^1.0.5" - whatwg-mimetype "^2.3.0" - whatwg-url "^7.0.0" - ws "^7.0.0" - xml-name-validator "^3.0.0" - jsdom@^16.2.2: version "16.4.0" resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.4.0.tgz#36005bde2d136f73eee1a830c6d45e55408edddb" @@ -9004,65 +8524,65 @@ jsesc@~0.5.0: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= -jsii-diff@^1.11.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/jsii-diff/-/jsii-diff-1.11.0.tgz#b595cdee5289d359c61b3a1e75dd2e70942ab020" - integrity sha512-FQTPmSOV7Iok8gmq31dGSW6KclJ2YTi2TNHeuXTwESooZ9NO1XzpuGz0GvNX469ADBuVb4XrWNmJbd+lctdkdg== +jsii-diff@^1.12.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/jsii-diff/-/jsii-diff-1.12.0.tgz#033f09d241c20a3e503815ce610eaab4d2f26084" + integrity sha512-0ny2T36hWzf3aVZqWCBy1pnIs69gpiO24EneEAPs20xLzmyU+MoHJlyM/4E2nsjGVn9+iXks4YmR5gx+Q2CeRg== dependencies: - "@jsii/spec" "^1.11.0" + "@jsii/spec" "^1.12.0" fs-extra "^9.0.1" - jsii-reflect "^1.11.0" + jsii-reflect "^1.12.0" log4js "^6.3.0" typescript "~3.9.7" yargs "^15.4.1" -jsii-pacmak@^1.11.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/jsii-pacmak/-/jsii-pacmak-1.11.0.tgz#2110764ed4f37192ba6fc3b3911b2869b59038fd" - integrity sha512-rfu13yMmL/KUv3MSaPyhOUvQ5RlOb8NJV/eM6wldJprySDef0sDYHoQJJPfhFtlwuAFmBPxefiXd0+FldLk7AQ== +jsii-pacmak@^1.12.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/jsii-pacmak/-/jsii-pacmak-1.12.0.tgz#a3d7e1c0d649d53066a91044b319a1517e8c5481" + integrity sha512-kSi447LpGZtEBqje13/vO7Kp6rnPGwWhYA/hK9gcS4L6+2DAktfQdiVd9Ff5c0iAzNqaHs3ouDcf0aitSK6GBg== dependencies: - "@jsii/spec" "^1.11.0" + "@jsii/spec" "^1.12.0" clone "^2.1.2" - codemaker "^1.11.0" + codemaker "^1.12.0" commonmark "^0.29.1" escape-string-regexp "^4.0.0" fs-extra "^9.0.1" - jsii-reflect "^1.11.0" - jsii-rosetta "^1.11.0" + jsii-reflect "^1.12.0" + jsii-rosetta "^1.12.0" semver "^7.3.2" spdx-license-list "^6.2.0" xmlbuilder "^15.1.1" yargs "^15.4.1" -jsii-reflect@^1.11.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/jsii-reflect/-/jsii-reflect-1.11.0.tgz#45739fcff6b6ff0a8675893c3285489b555d9d42" - integrity sha512-XZTC5A66lT2rjAc3mKXzN6VnHA6JDOOespmhAlYxVg9Mo7u5lEl5nupoS7wBUvXHfINX8h+0XkmdCvZbMuKlQQ== +jsii-reflect@^1.12.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/jsii-reflect/-/jsii-reflect-1.12.0.tgz#e894a823e1abc7d4e0c61e7a8f8ff45f6757566a" + integrity sha512-wADLvHWARzV4tSYFwqO3FpUuYmhcwnJENppJ5UY9ONt1E/r5CtxBCxHChnEeMWywyAy+rhl3CXVyCfV0IoPj3g== dependencies: - "@jsii/spec" "^1.11.0" + "@jsii/spec" "^1.12.0" colors "^1.4.0" fs-extra "^9.0.1" - oo-ascii-tree "^1.11.0" + oo-ascii-tree "^1.12.0" yargs "^15.4.1" -jsii-rosetta@^1.11.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/jsii-rosetta/-/jsii-rosetta-1.11.0.tgz#73688c1106e811bdb30922439ee80e482ad2cfc9" - integrity sha512-TvWOu+GM5pumNb5U+oDtIBXwVEFfo1HrGCdvb5Y6ysakLtHN521m39/tt1JVITi8vz7PlEy5jEPKkHoeR9+lXw== +jsii-rosetta@^1.12.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/jsii-rosetta/-/jsii-rosetta-1.12.0.tgz#75b4109fbc3aa6be52960f33c9e43dd943589ce3" + integrity sha512-vdir+2Btee/INqxEA+UtX6MfibHXsu/NBIRKXLmchCwinvfKVz0K3mDhgE1YLBkxEb2R2iU5HEnXOdW1cUhOAA== dependencies: - "@jsii/spec" "^1.11.0" + "@jsii/spec" "^1.12.0" commonmark "^0.29.1" fs-extra "^9.0.1" typescript "~3.9.7" xmldom "^0.3.0" yargs "^15.4.1" -jsii@^1.11.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/jsii/-/jsii-1.11.0.tgz#104454263fa7a57a73977e27de06b0416c894b1f" - integrity sha512-5/YZPqpSoXSi6h1JLMv8fa4iIyGfL14Va5p1J2NXkB7cQj5gPbl8gvi0KJiqmQXyF7urczGJB8vzuU15FyCalg== +jsii@^1.12.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/jsii/-/jsii-1.12.0.tgz#bb0558cbaa298e4a0cf82846dace2b4db67259b9" + integrity sha512-IRTjtmNdsUVpb1uB6wP1GMtOYBhOouXfPLquurU+JvSauLFaTPX2piO4yV8xGKnoZwRwCK+QRKB/DPUkYlDQ9w== dependencies: - "@jsii/spec" "^1.11.0" + "@jsii/spec" "^1.12.0" case "^1.6.3" colors "^1.4.0" deep-equal "^2.0.3" @@ -9166,7 +8686,7 @@ jsonparse@^1.2.0: resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= -jsonschema@^1.2.5, jsonschema@^1.2.6: +jsonschema@^1.2.6: version "1.2.6" resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.2.6.tgz#52b0a8e9dc06bbae7295249d03e4b9faee8a0c0b" integrity sha512-SqhURKZG07JyKKeo/ir24QnS4/BV7a6gQy93bUSe4lUdNp0QNpIz2c9elWJQ9dpc5cQYY6cvCzgRwy0MQCLyqA== @@ -9225,6 +8745,24 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== +lambda-leak@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lambda-leak/-/lambda-leak-2.0.0.tgz#771985d3628487f6e885afae2b54510dcfb2cd7e" + integrity sha1-dxmF02KEh/boha+uK1RRDc+yzX4= + +lambda-tester@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/lambda-tester/-/lambda-tester-3.6.0.tgz#ceb7d4f4f0da768487a05cff37dcd088508b5247" + integrity sha512-F2ZTGWCLyIR95o/jWK46V/WnOCFAEUG/m/V7/CLhPJ7PCM+pror1rZ6ujP3TkItSGxUfpJi0kqwidw+M/nEqWw== + dependencies: + app-root-path "^2.2.1" + dotenv "^8.0.0" + dotenv-json "^1.0.0" + lambda-leak "^2.0.0" + semver "^6.1.1" + uuid "^3.3.2" + vandium-utils "^1.1.1" + lazystream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4" @@ -9232,13 +8770,6 @@ lazystream@^1.0.0: dependencies: readable-stream "^2.0.5" -lcid@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" - integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= - dependencies: - invert-kv "^1.0.0" - lcov-parse@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-1.0.0.tgz#eb0d46b54111ebc561acb4c408ef9363bdc8f7e0" @@ -9280,7 +8811,15 @@ levenary@^1.1.1: dependencies: leven "^3.1.0" -levn@^0.3.0, levn@~0.3.0: +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= @@ -9405,11 +8944,6 @@ lodash._reinterpolate@^3.0.0: resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= -lodash.assign@^4.0.3, lodash.assign@^4.0.6: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" - integrity sha1-DZnzzNem0mHRm9rrkkUAXShYCOc= - lodash.clone@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clone/-/lodash.clone-4.5.0.tgz#195870450f5a13192478df4bc3d23d2dea1907b6" @@ -9540,13 +9074,6 @@ log4js@^6.3.0: rfdc "^1.1.4" streamroller "^2.2.4" -lolex@^5.0.0: - version "5.1.2" - resolved "https://registry.yarnpkg.com/lolex/-/lolex-5.1.2.tgz#953694d098ce7c07bc5ed6d0e42bc6c0c6d5a367" - integrity sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A== - dependencies: - "@sinonjs/commons" "^1.7.0" - loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -9634,14 +9161,6 @@ make-fetch-happen@^5.0.0: socks-proxy-agent "^4.0.0" ssri "^6.0.0" -make-runnable@^1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-runnable/-/make-runnable-1.3.6.tgz#ca9b1d31b06f051e37570fb7ad98bc5369f982be" - integrity sha1-ypsdMbBvBR43Vw+3rZi8U2n5gr4= - dependencies: - bluebird "^3.5.0" - yargs "^4.7.1" - makeerror@1.0.x: version "1.0.11" resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" @@ -10079,7 +9598,7 @@ nise@^4.0.4: just-extend "^4.0.2" path-to-regexp "^1.7.0" -nock@^13.0.2, nock@^13.0.4: +nock@^13.0.4: version "13.0.4" resolved "https://registry.yarnpkg.com/nock/-/nock-13.0.4.tgz#9fb74db35d0aa056322e3c45be14b99105cd7510" integrity sha512-alqTV8Qt7TUbc74x1pKRLSENzfjp4nywovcJgi/1aXDiUxXdt7TkruSTF5MDWPP7UoPVgea4F9ghVdmX0xxnSA== @@ -10150,17 +9669,6 @@ node-modules-regexp@^1.0.0: resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= -node-notifier@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-6.0.0.tgz#cea319e06baa16deec8ce5cd7f133c4a46b68e12" - integrity sha512-SVfQ/wMw+DesunOm5cKqr6yDcvUTDl/yc97ybGHMrteNEY6oekXpNpS3lZwgLlwz0FLgHoiW28ZpmBHUDg37cw== - dependencies: - growly "^1.3.0" - is-wsl "^2.1.1" - semver "^6.3.0" - shellwords "^0.1.1" - which "^1.3.1" - node-notifier@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.0.tgz#a7eee2d51da6d0f7ff5094bc7108c911240c1620" @@ -10514,10 +10022,10 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" -oo-ascii-tree@^1.11.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/oo-ascii-tree/-/oo-ascii-tree-1.11.0.tgz#f05084deb08e41b4d14b62bf9613821616654e66" - integrity sha512-I5EDW45Ou4ZgNFWEnPySPdLXqR6V18spR1QKxuiKsQ2/4TjRshfWkdUdWDo05iZjGvPdOXEjCEoSZwfiO1ClFg== +oo-ascii-tree@^1.12.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/oo-ascii-tree/-/oo-ascii-tree-1.12.0.tgz#896859cf96c3a6656deb399cf3f413bbfd409fbf" + integrity sha512-nidKriODh94KACsubEzkjbV25wd+HUQAjr9yGi6J8l4BfNaYT1AxRDSXQKfiNgrBh/11FqzpPUC7iiWEcbk4qg== open@^7.0.3: version "7.2.0" @@ -10532,7 +10040,7 @@ opener@^1.5.1: resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.1.tgz#6d2f0e77f1a0af0032aca716c2c1fbb8e7e8abed" integrity sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA== -optionator@^0.8.1, optionator@^0.8.3: +optionator@^0.8.1: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== @@ -10544,6 +10052,18 @@ optionator@^0.8.1, optionator@^0.8.3: type-check "~0.3.2" word-wrap "~1.2.3" +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + ora@^4.0.3: version "4.1.1" resolved "https://registry.yarnpkg.com/ora/-/ora-4.1.1.tgz#566cc0348a15c36f5f0e979612842e02ba9dddbc" @@ -10568,13 +10088,6 @@ os-homedir@^1.0.0, os-homedir@^1.0.1, os-homedir@^1.0.2: resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= -os-locale@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" - integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk= - dependencies: - lcid "^1.0.0" - os-name@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/os-name/-/os-name-3.1.0.tgz#dec19d966296e1cd62d701a5a66ee1ddeae70801" @@ -10618,11 +10131,6 @@ p-finally@^1.0.0: resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= -p-finally@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561" - integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw== - p-limit@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" @@ -10979,7 +10487,7 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= -picomatch@^2.0.4, picomatch@^2.0.5: +picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1: version "2.2.2" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== @@ -11424,6 +10932,11 @@ posthtml@^0.13.1: posthtml-parser "^0.5.0" posthtml-render "^1.2.3" +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" @@ -11628,10 +11141,10 @@ punycode@^2.0.0, punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -pure-rand@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-2.0.0.tgz#3324633545207907fe964c2f0ebf05d8e9a7f129" - integrity sha512-mk98aayyd00xbfHgE3uEmAUGzz3jCdm8Mkf5DUXUhc7egmOaGG2D7qhVlynGenNe9VaNJZvzO9hkc8myuTkDgw== +pure-rand@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-3.1.0.tgz#646b812635cbac86105c46b0b03aa5dac1c759b3" + integrity sha512-xkCSMNjEnLG/A8iTH9M5ayXN4SCWRP+ih3rxi09Q7Fu0b9jAP6V9H59pOtcB37IsVt3eHxf1FMy9n7YrqdDdSA== purgecss@^2.3.0: version "2.3.0" @@ -11828,7 +11341,7 @@ read@1, read@^1.0.4, read@~1.0.1: dependencies: mute-stream "~0.0.4" -"readable-stream@1 || 2", readable-stream@2, readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.6, readable-stream@^2.3.7, readable-stream@~2.3.6: +"readable-stream@1 || 2", readable-stream@2, readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.6, readable-stream@~2.3.6: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -11860,6 +11373,13 @@ readable-stream@1.1.x: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readdir-glob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.0.0.tgz#a495436934bbe57be6a68039d16e8946621eb8c5" + integrity sha512-km0DIcwQVZ1ZUhXhMWpF74/Wm5aFEd5/jDiVWF1Hkw2myPQovG8vCQ8+FQO2KXE9npQQvCnAMZhhWuUee4WcCQ== + dependencies: + minimatch "^3.0.4" + readdir-scoped-modules@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz#8d45407b4f870a0dcaebc0e28670d18e74514309" @@ -11870,11 +11390,6 @@ readdir-scoped-modules@^1.0.0: graceful-fs "^4.1.2" once "^1.3.0" -realpath-native@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-2.0.0.tgz#7377ac429b6e1fd599dc38d08ed942d0d7beb866" - integrity sha512-v1SEYUOXXdbBZK8ZuNgO4TBjamPsiSgcFr0aP+tEKpQZK8vooEUqV6nm6Cv502mX4NF2EfsnVqtNAHG+/6Ur1Q== - rechoir@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" @@ -11946,12 +11461,7 @@ regexp.prototype.flags@^1.3.0: define-properties "^1.1.3" es-abstract "^1.17.0-next.1" -regexpp@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" - integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== - -regexpp@^3.0.0: +regexpp@^3.0.0, regexpp@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== @@ -12016,7 +11526,7 @@ request-promise-core@1.1.4: dependencies: lodash "^4.17.19" -request-promise-native@^1.0.5, request-promise-native@^1.0.7, request-promise-native@^1.0.8: +request-promise-native@^1.0.5, request-promise-native@^1.0.8: version "1.0.9" resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.9.tgz#e407120526a5efdc9a39b28a5679bf47b9d9dc28" integrity sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g== @@ -12056,11 +11566,6 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= -require-main-filename@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" - integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= - require-main-filename@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" @@ -12105,12 +11610,7 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" - integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= - -resolve@^1.1.6, resolve@^1.10.0, resolve@^1.11.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.3.2: +resolve@^1.1.6, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.11.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.3.2: version "1.17.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== @@ -12197,7 +11697,7 @@ rsvp@^4.8.4: resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== -run-async@^2.2.0, run-async@^2.4.0: +run-async@^2.2.0: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== @@ -12214,7 +11714,7 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" -rxjs@^6.4.0, rxjs@^6.6.0, rxjs@^6.6.2: +rxjs@^6.4.0, rxjs@^6.6.2: version "6.6.2" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.2.tgz#8096a7ac03f2cc4fe5860ef6e572810d9e01c0d2" integrity sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg== @@ -12304,12 +11804,12 @@ semver@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.2, semver@^7.3.2: +semver@7.x, semver@^7.1.1, semver@^7.2.1, semver@^7.3.2: version "7.3.2" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== -semver@^6.0.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: +semver@^6.0.0, semver@^6.1.0, semver@^6.1.1, semver@^6.2.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== @@ -12422,7 +11922,7 @@ simple-swizzle@^0.2.2: dependencies: is-arrayish "^0.3.1" -sinon@^9.0.1, sinon@^9.0.2, sinon@^9.0.3: +sinon@^9.0.1, sinon@^9.0.3: version "9.0.3" resolved "https://registry.yarnpkg.com/sinon/-/sinon-9.0.3.tgz#bffc3ec28c936332cd2a41833547b9eed201ecff" integrity sha512-IKo9MIM111+smz9JGwLmw5U1075n1YXeAq8YeSFlndCLhAL5KGn6bLgu7b/4AYHTV/LcEMcRm2wU2YiL55/6Pg== @@ -12703,7 +12203,7 @@ stable@^0.1.8: resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== -stack-utils@^1.0.1, stack-utils@^1.0.2: +stack-utils@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.2.tgz#33eba3897788558bebfc2db059dc158ec36cebb8" integrity sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA== @@ -12791,14 +12291,6 @@ string-argv@0.3.1: resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== -string-length@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-3.1.0.tgz#107ef8c23456e187a8abd4a61162ff4ac6e25837" - integrity sha512-Ttp5YvkGm5v9Ijagtaz1BnN+k9ObpvS0eIBblPMp2YWL8FBmi9qblQ9fexc2k/CXFgrTIteU3jAw3payCnwSTA== - dependencies: - astral-regex "^1.0.0" - strip-ansi "^5.2.0" - string-length@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.1.tgz#4a973bf31ef77c4edbceadd6af2611996985f8a1" @@ -12970,7 +12462,7 @@ strip-indent@^3.0.0: dependencies: min-indent "^1.0.0" -strip-json-comments@^3.0.1: +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -13058,7 +12550,7 @@ symbol-tree@^3.2.2, symbol-tree@^3.2.4: resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== -table@^5.2.3, table@^5.4.6: +table@^5.2.3: version "5.4.6" resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== @@ -13068,6 +12560,16 @@ table@^5.2.3, table@^5.4.6: slice-ansi "^2.1.0" string-width "^3.0.0" +table@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/table/-/table-6.0.3.tgz#e5b8a834e37e27ad06de2e0fda42b55cfd8a0123" + integrity sha512-8321ZMcf1B9HvVX/btKv8mMZahCjn2aYrDlpqHaBFCfnox64edeH9kEid0vTLTRR8gWR2A20aDgeuTTea4sVtw== + dependencies: + ajv "^6.12.4" + lodash "^4.17.20" + slice-ansi "^4.0.0" + string-width "^4.2.0" + tap-mocha-reporter@^3.0.9, tap-mocha-reporter@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/tap-mocha-reporter/-/tap-mocha-reporter-5.0.1.tgz#74f00be2ddd2a380adad45e085795137bc39497a" @@ -13147,12 +12649,12 @@ tap@^12.0.1: write-file-atomic "^2.4.2" yapool "^1.0.0" -tar-stream@^2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.3.tgz#1e2022559221b7866161660f118255e20fa79e41" - integrity sha512-Z9yri56Dih8IaK8gncVPx4Wqt86NDmQTSh49XLZgjWpGZL9GK9HKParS2scqHCC4w6X9Gh2jwaU45V47XTKwVA== +tar-stream@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.4.tgz#c4fb1a11eb0da29b893a5b25476397ba2d053bfa" + integrity sha512-o3pS2zlG4gxr67GmFYBLlq+dM8gyRGUOvsrHclSkvtVtQbjV0s/+ZE8OpICbaj8clrX3tjeHngYGP7rweaBnuw== dependencies: - bl "^4.0.1" + bl "^4.0.3" end-of-stream "^1.4.1" fs-constants "^1.0.0" inherits "^2.0.3" @@ -13438,10 +12940,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.2.0: - version "26.2.0" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.2.0.tgz#7ec22faceb05ee1467fdb5265d1b33c27441f163" - integrity sha512-9+y2qwzXdAImgLSYLXAb/Rhq9+K4rbt0417b8ai987V60g2uoNWBBmMkYgutI7D8Zhu+IbCSHbBtrHxB9d7xyA== +ts-jest@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.3.0.tgz#6b2845045347dce394f069bb59358253bc1338a9" + integrity sha512-Jq2uKfx6bPd9+JDpZNMBJMdMQUC3sJ08acISj8NXlVgR2d5OqslEHOR2KHMgwymu8h50+lKIm0m0xj/ioYdW2Q== dependencies: "@types/jest" "26.x" bs-logger "0.x" @@ -13455,12 +12957,12 @@ ts-jest@^26.2.0: semver "7.x" yargs-parser "18.x" -ts-mock-imports@^1.2.6, ts-mock-imports@^1.3.0: +ts-mock-imports@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/ts-mock-imports/-/ts-mock-imports-1.3.0.tgz#ed9b743349f3c27346afe5b7454ffd2bcaa2302d" integrity sha512-cCrVcRYsp84eDvPict0ZZD/D7ppQ0/JSx4ve6aEU8DjlsaWRJWV6ADMovp2sCuh6pZcduLFoIYhKTDU2LARo7Q== -ts-node@^8.0.2, ts-node@^8.10.2: +ts-node@^8.0.2: version "8.10.2" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.10.2.tgz#eee03764633b1234ddd37f8db9ec10b75ec7fb8d" integrity sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA== @@ -13471,6 +12973,17 @@ ts-node@^8.0.2, ts-node@^8.10.2: source-map-support "^0.5.17" yn "3.1.1" +ts-node@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.0.0.tgz#e7699d2a110cc8c0d3b831715e417688683460b3" + integrity sha512-/TqB4SnererCDR/vb4S/QvSZvzQMJN8daAslg7MeaiHvD8rDZsSfXmNeNumyZZzMned72Xoq/isQljYSt8Ynfg== + dependencies: + arg "^4.1.0" + diff "^4.0.1" + make-error "^1.1.1" + source-map-support "^0.5.17" + yn "3.1.1" + tsame@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/tsame/-/tsame-2.0.1.tgz#70410ddbefcd29c61e2d68549b3347b0444d613f" @@ -13491,7 +13004,7 @@ tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q== -tslib@^2.0.0, tslib@^2.0.1: +tslib@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.1.tgz#410eb0d113e5b6356490eec749603725b021b43e" integrity sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ== @@ -13520,6 +13033,13 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" @@ -13569,18 +13089,18 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript-json-schema@^0.42.0: - version "0.42.0" - resolved "https://registry.yarnpkg.com/typescript-json-schema/-/typescript-json-schema-0.42.0.tgz#695f212a72d91d47c0605371dc697597b7817c1b" - integrity sha512-9WO+lVmlph7Ecb7lPd9tU84XFUQh44kpAf3cWe/Ym4G5EKw/SS6XGpi1DZDthvxqkIdNSDlWi7FhKfxuIV/3yw== +typescript-json-schema@^0.43.0: + version "0.43.0" + resolved "https://registry.yarnpkg.com/typescript-json-schema/-/typescript-json-schema-0.43.0.tgz#8bd9c832f1f15f006ff933907ce192222fdfd92f" + integrity sha512-4c9IMlIlHYJiQtzL1gh2nIPJEjBgJjDUs50gsnnc+GFyDSK1oFM3uQIBSVosiuA/4t6LSAXDS9vTdqbQC6EcgA== dependencies: - "@types/json-schema" "^7.0.3" - glob "~7.1.4" + "@types/json-schema" "^7.0.5" + glob "~7.1.6" json-stable-stringify "^1.0.1" - typescript "^3.5.3" - yargs "^14.0.0" + typescript "~4.0.2" + yargs "^15.4.1" -typescript@^3.3.3, typescript@^3.5.3, typescript@~3.9.7: +typescript@^3.3.3, typescript@~3.9.7: version "3.9.7" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw== @@ -13590,6 +13110,11 @@ typescript@~3.8.3: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== +typescript@~4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.2.tgz#7ea7c88777c723c681e33bf7988be5d008d05ac2" + integrity sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ== + uglify-js@^3.1.4: version "3.10.2" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.10.2.tgz#8cfa1209fd04199cc8a7f9930ddedb30b0f1912d" @@ -13827,15 +13352,6 @@ v8-compile-cache@^2.0.0, v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745" integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ== -v8-to-istanbul@^4.1.3: - version "4.1.4" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-4.1.4.tgz#b97936f21c0e2d9996d4985e5c5156e9d4e49cd6" - integrity sha512-Rw6vJHj1mbdK8edjR7+zuJrpDtKIgNdAvTSAcpYfgMIw+u2dPDntD3dgN4XQFLU2/fvFQdzj+EeSGfd/jnY5fQ== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^1.6.0" - source-map "^0.7.3" - v8-to-istanbul@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-5.0.1.tgz#0608f5b49a481458625edb058488607f25498ba5" @@ -13860,6 +13376,11 @@ validate-npm-package-name@^3.0.0: dependencies: builtins "^1.0.3" +vandium-utils@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/vandium-utils/-/vandium-utils-1.2.0.tgz#44735de4b7641a05de59ebe945f174e582db4f59" + integrity sha1-RHNd5LdkGgXeWevpRfF05YLbT1k= + vendors@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e" @@ -13982,11 +13503,6 @@ which-collection@^1.0.1: is-weakmap "^2.0.1" is-weakset "^2.0.1" -which-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" - integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8= - which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" @@ -14025,11 +13541,6 @@ wide-align@^1.1.0: dependencies: string-width "^1.0.2 || 2" -window-size@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" - integrity sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU= - windows-release@^3.1.0: version "3.3.3" resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.3.3.tgz#1c10027c7225743eec6b89df160d64c2e0293999" @@ -14037,7 +13548,7 @@ windows-release@^3.1.0: dependencies: execa "^1.0.0" -word-wrap@~1.2.3: +word-wrap@^1.2.3, word-wrap@~1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== @@ -14047,14 +13558,6 @@ wordwrap@>=0.0.2, wordwrap@^1.0.0: resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= -wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - wrap-ansi@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" @@ -14152,7 +13655,7 @@ ws@^6.1.2, ws@^6.2.0: dependencies: async-limiter "~1.0.0" -ws@^7.0.0, ws@^7.2.3: +ws@^7.2.3: version "7.3.1" resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.1.tgz#d0547bf67f7ce4f12a72dfe31262c68d7dc551c8" integrity sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA== @@ -14205,16 +13708,16 @@ xtend@^4.0.2, xtend@~4.0.1: resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== -y18n@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" - integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= - y18n@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== +y18n@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.1.tgz#1ad2a7eddfa8bce7caa2e1f6b5da96c39d99d571" + integrity sha512-/jJ831jEs4vGDbYPQp4yGKDYPSCCEQ45uZWJHE1AoYBzqdZi8+LDWas0z4HrmJXmKdpFsTiowSHXdxyFhpmdMg== + yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" @@ -14235,13 +13738,6 @@ yaml@*, yaml@1.10.0, yaml@^1.10.0, yaml@^1.5.0: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.0.tgz#3b593add944876077d4d683fee01081bd9fff31e" integrity sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg== -yaml@1.9.2: - version "1.9.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.9.2.tgz#f0cfa865f003ab707663e4f04b3956957ea564ed" - integrity sha512-HPT7cGGI0DuRcsO51qC1j9O16Dh1mZ2bnXwsi0jrSpsLz0WxOLSLXfkABVl6bZO629py3CU+OMJtpNHDLB97kg== - dependencies: - "@babel/runtime" "^7.9.2" - yapool@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/yapool/-/yapool-1.0.0.tgz#f693f29a315b50d9a9da2646a7a6645c96985b6a" @@ -14271,13 +13767,10 @@ yargs-parser@^15.0.1: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-2.4.1.tgz#85568de3cf150ff49fa51825f03a8c880ddcc5c4" - integrity sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ= - dependencies: - camelcase "^3.0.0" - lodash.assign "^4.0.6" +yargs-parser@^20.0.0: + version "20.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.0.0.tgz#c65a1daaa977ad63cebdd52159147b789a4e19a9" + integrity sha512-8eblPHTL7ZWRkyjIZJjnGf+TijiKJSwA24svzLRVvtgoi/RZiKa9fFQTrlx0OKLnyHSdt/enrdadji6WFfESVA== yargs@^13.2.2: version "13.3.2" @@ -14295,7 +13788,7 @@ yargs@^13.2.2: y18n "^4.0.0" yargs-parser "^13.1.2" -yargs@^14.0.0, yargs@^14.2.2: +yargs@^14.2.2: version "14.2.3" resolved "https://registry.yarnpkg.com/yargs/-/yargs-14.2.3.tgz#1a1c3edced1afb2a2fea33604bc6d1d8d688a414" integrity sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg== @@ -14329,36 +13822,29 @@ yargs@^15.0.2, yargs@^15.3.1, yargs@^15.4.1: y18n "^4.0.0" yargs-parser "^18.1.2" -yargs@^4.7.1: - version "4.8.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-4.8.1.tgz#c0c42924ca4aaa6b0e6da1739dfb216439f9ddc0" - integrity sha1-wMQpJMpKqmsObaFznfshZDn53cA= +yargs@^16.0.3: + version "16.0.3" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.0.3.tgz#7a919b9e43c90f80d4a142a89795e85399a7e54c" + integrity sha512-6+nLw8xa9uK1BOEOykaiYAJVh6/CjxWXK/q9b5FpRgNslt8s22F2xMBqVIKgCRjNgGvGPBy8Vog7WN7yh4amtA== dependencies: - cliui "^3.2.0" - decamelize "^1.1.1" - get-caller-file "^1.0.1" - lodash.assign "^4.0.3" - os-locale "^1.4.0" - read-pkg-up "^1.0.1" + cliui "^7.0.0" + escalade "^3.0.2" + get-caller-file "^2.0.5" require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^1.0.1" - which-module "^1.0.0" - window-size "^0.2.0" - y18n "^3.2.1" - yargs-parser "^2.4.1" + string-width "^4.2.0" + y18n "^5.0.1" + yargs-parser "^20.0.0" yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== -zip-stream@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-3.0.1.tgz#cb8db9d324a76c09f9b76b31a12a48638b0b9708" - integrity sha512-r+JdDipt93ttDjsOVPU5zaq5bAyY+3H19bDrThkvuVxC0xMQzU1PJcS6D+KrP3u96gH9XLomcHPb+2skoDjulQ== +zip-stream@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-4.0.2.tgz#3a20f1bd7729c2b59fd4efa04df5eb7a5a217d2e" + integrity sha512-TGxB2g+1ur6MHkvM644DuZr8Uzyz0k0OYWtS3YlpfWBEmK4woaC2t3+pozEL3dBfIPmpgmClR5B2QRcMgGt22g== dependencies: archiver-utils "^2.1.0" - compress-commons "^3.0.0" + compress-commons "^4.0.0" readable-stream "^3.6.0"