diff --git a/.github/workflows/auto-approve.yml b/.github/workflows/auto-approve.yml index c289f5381995c..9b185ec0fcd47 100644 --- a/.github/workflows/auto-approve.yml +++ b/.github/workflows/auto-approve.yml @@ -14,6 +14,6 @@ jobs: || github.event.pull_request.user.login == 'dependabot-preview[bot]') runs-on: ubuntu-latest steps: - - uses: hmarr/auto-approve-action@v2.0.0 + - uses: hmarr/auto-approve-action@v2.1.0 with: github-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/issue-label-assign.yml b/.github/workflows/issue-label-assign.yml index 03808c663aab8..237e44deefc36 100644 --- a/.github/workflows/issue-label-assign.yml +++ b/.github/workflows/issue-label-assign.yml @@ -155,7 +155,7 @@ jobs: {"keywords":["(@aws-cdk/aws-sdb)","(aws-sdb)","(sdb)"],"labels":["@aws-cdk/aws-sdb"],"assignees":["njlynch"]}, {"keywords":["(@aws-cdk/aws-secretsmanager)","(aws-secretsmanager)","(secretsmanager)","(secrets manager)","(secrets-manager)"],"labels":["@aws-cdk/aws-secretsmanager"],"assignees":["njlynch"]}, {"keywords":["(@aws-cdk/aws-securityhub)","(aws-securityhub)","(securityhub)","(security hub)","(security-hub)"],"labels":["@aws-cdk/aws-securityhub"],"assignees":["skinny85"]}, - {"keywords":["(@aws-cdk/aws-servicecatalog)","(aws-servicecatalog)","(servicecatalog)","(service catalog)","(service-catalog)"],"labels":["@aws-cdk/aws-servicecatalog"],"assignees":["MrArnoldPalmer"]}, + {"keywords":["(@aws-cdk/aws-servicecatalog)","(aws-servicecatalog)","(servicecatalog)","(service catalog)","(service-catalog)"],"labels":["@aws-cdk/aws-servicecatalog"],"assignees":["skinny85"]}, {"keywords":["(@aws-cdk/aws-servicediscovery)","(aws-servicediscovery)","(servicediscovery)","(service discovery)","(service-discovery)"],"labels":["@aws-cdk/aws-servicediscovery"],"assignees":["MrArnoldPalmer"]}, {"keywords":["(@aws-cdk/aws-ses)","(aws-ses)","(ses)"],"labels":["@aws-cdk/aws-ses"],"assignees":["iliapolo"]}, {"keywords":["(@aws-cdk/aws-ses-actions)","(aws-ses-actions)","(ses-actions)","(ses actions)"],"labels":["@aws-cdk/aws-ses-actions"],"assignees":["iliapolo"]}, diff --git a/.github/workflows/yarn-upgrade.yml b/.github/workflows/yarn-upgrade.yml index b3d8541568a97..13d551cf740cf 100644 --- a/.github/workflows/yarn-upgrade.yml +++ b/.github/workflows/yarn-upgrade.yml @@ -25,7 +25,7 @@ jobs: run: echo "::set-output name=dir::$(yarn cache dir)" - name: Restore Yarn cache - uses: actions/cache@v2.1.4 + uses: actions/cache@v2.1.5 with: path: ${{ steps.yarn-cache.outputs.dir }} key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} @@ -46,11 +46,12 @@ jobs: # 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 # We special-case constructs because we want to stay in control of the minimum compatible version + # We special-case lerna because we have a patch on it that stops applying if Lerna upgrades. Remove this once https://github.com/lerna/lerna/pull/2874 releases. 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,constructs,typescript --target=minor + ncu --upgrade --reject=@types/node,@types/fs-extra,constructs,typescript,lerna --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 diff --git a/.gitignore b/.gitignore index 5f60eac749208..a2281906f6867 100644 --- a/.gitignore +++ b/.gitignore @@ -42,5 +42,6 @@ yarn-error.log # Cloud9 .c9 +.nzm-* /.versionrc.json diff --git a/CHANGELOG.md b/CHANGELOG.md index a9fe72678f70a..8487aaf34742f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,260 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.102.0](https://github.com/aws/aws-cdk/compare/v1.101.0...v1.102.0) (2021-05-04) + + +### Features + +* **cfnspec:** cloudformation spec v35.0.0 ([#14411](https://github.com/aws/aws-cdk/issues/14411)) ([49e49e7](https://github.com/aws/aws-cdk/commit/49e49e7ef50ee008be66b1887e4e15e51a4ae576)) +* **cfnspec:** cloudformation spec v35.1.0 ([#14518](https://github.com/aws/aws-cdk/issues/14518)) ([bcdff3d](https://github.com/aws/aws-cdk/commit/bcdff3dcd4ecc624e8c1121a12e23683804a9aaf)) +* **cli:** directly deploy stacks in nested assemblies ([#14379](https://github.com/aws/aws-cdk/issues/14379)) ([5a6fa7f](https://github.com/aws/aws-cdk/commit/5a6fa7fa17a5dce5e429eed4ebfe2dbbac3d6d07)) +* **elasticsearch:** Support version 7.10 ([#14320](https://github.com/aws/aws-cdk/issues/14320)) ([f3a830c](https://github.com/aws/aws-cdk/commit/f3a830cb0d5b68e8f402791c3aaa5d1bcf2df673)) +* **rds:** allow turning on IAM authentication for Clusters ([#13958](https://github.com/aws/aws-cdk/issues/13958)) ([0e59708](https://github.com/aws/aws-cdk/commit/0e597087bb375a02ac1ce3134d52cf3ee03bb54e)), closes [#13722](https://github.com/aws/aws-cdk/issues/13722) +* **synthetics:** update CloudWatch Synthetics NodeJS runtime ([#14157](https://github.com/aws/aws-cdk/issues/14157)) ([3283225](https://github.com/aws/aws-cdk/commit/3283225811386431da8699c068bc51ce6a729bf1)) + + +### Bug Fixes + +* **aws-cloudwatch:** fix for space in alarm name in alarms for compos… ([#13963](https://github.com/aws/aws-cdk/issues/13963)) ([7cdd541](https://github.com/aws/aws-cdk/commit/7cdd5412e9fed7f9bf877c448196b42725b8edbf)) +* **cli:** 'cdk synth' not able to fail if stacks have errors ([#14475](https://github.com/aws/aws-cdk/issues/14475)) ([963d1c7](https://github.com/aws/aws-cdk/commit/963d1c7755e23ea819481724d7e8c78e31d82294)) +* **CodeBuild:** add resource only once per secret ([#14510](https://github.com/aws/aws-cdk/issues/14510)) ([affaaad](https://github.com/aws/aws-cdk/commit/affaaad4d65e6d4e42a7af465ed990954a0c122a)) +* **neptune:** use correct L1 of DBParameterGroup ([#14447](https://github.com/aws/aws-cdk/issues/14447)) ([057f61f](https://github.com/aws/aws-cdk/commit/057f61fde10d9eaac0701b5ffc44a9c977d923d4)), closes [#14446](https://github.com/aws/aws-cdk/issues/14446) +* **rds:** instance identifiers and endpoints of a Cluster are blank ([#14394](https://github.com/aws/aws-cdk/issues/14394)) ([9597d97](https://github.com/aws/aws-cdk/commit/9597d974bc710afd506606dcc7dd11e32b86cff5)), closes [#14377](https://github.com/aws/aws-cdk/issues/14377) +* **s3:** urlForObject does not consider explicit bucket region ([#14315](https://github.com/aws/aws-cdk/issues/14315)) ([e11d537](https://github.com/aws/aws-cdk/commit/e11d5378c33bea609ed09c998b305fdfd28999a9)) + +## [1.101.0](https://github.com/aws/aws-cdk/compare/v1.100.0...v1.101.0) (2021-04-28) + + +### ⚠ BREAKING CHANGES TO EXPERIMENTAL FEATURES + +* **neptune:** `InstanceType` changed from enum to enum-like static factory. + +### Features + +* **autoscaling:** add getter/setter for instance termination protection ([#14308](https://github.com/aws/aws-cdk/issues/14308)) ([d3bdcfd](https://github.com/aws/aws-cdk/commit/d3bdcfd5af6056932aaa9361392fec628046209e)), closes [#14283](https://github.com/aws/aws-cdk/issues/14283) +* **aws-autoscaling:** add support for NewInstancesProtectedFromScaleIn ([#14283](https://github.com/aws/aws-cdk/issues/14283)) ([da9828b](https://github.com/aws/aws-cdk/commit/da9828b829df248d1c3cf8c6011507561328fd5e)) +* **custom-resources:** AwsSdkCall can assume Role for cross-account custom resources ([#13916](https://github.com/aws/aws-cdk/issues/13916)) ([a0690b9](https://github.com/aws/aws-cdk/commit/a0690b970e5c260b17ccf92df052b6bb1291df99)) +* **ec2:** create NAT Gateways with fixed IPs ([#14250](https://github.com/aws/aws-cdk/issues/14250)) ([24c992a](https://github.com/aws/aws-cdk/commit/24c992ac779fd18829d3597f45dd53141d49594a)), closes [#11884](https://github.com/aws/aws-cdk/issues/11884) [#4067](https://github.com/aws/aws-cdk/issues/4067) +* **events:** API Gateway target ([#13823](https://github.com/aws/aws-cdk/issues/13823)) ([ce789bf](https://github.com/aws/aws-cdk/commit/ce789bf6a451e5f93a846cdcc672c2bba071dd20)), closes [#12708](https://github.com/aws/aws-cdk/issues/12708) +* **iam:** add imported user to a group ([#13698](https://github.com/aws/aws-cdk/issues/13698)) ([bf513bc](https://github.com/aws/aws-cdk/commit/bf513bc55e324d5d0ac23c2ddaa1d570a8d2ea1a)) +* **neptune:** change InstanceType to class that is built from string ([#14273](https://github.com/aws/aws-cdk/issues/14273)) ([fc618f9](https://github.com/aws/aws-cdk/commit/fc618f97128ab1dc25b735bd634c52f2c47ef457)), closes [#13923](https://github.com/aws/aws-cdk/issues/13923) +* **route53:** add support for parentHostedZoneName for CrossAccountZoneDelegationRecord ([#14097](https://github.com/aws/aws-cdk/issues/14097)) ([572ee40](https://github.com/aws/aws-cdk/commit/572ee4083968735b645ceab098059ce82e81b44d)) + + +### Bug Fixes + +* **aws-ecs-patterns, aws-elasticloadbalancingv2:** Pass TargetGroup ProtocolVersion as parameters to higher level constructs ([#14092](https://github.com/aws/aws-cdk/issues/14092)) ([a655819](https://github.com/aws/aws-cdk/commit/a655819128c11309d88d5f5535678e8c02e292a9)), closes [#14091](https://github.com/aws/aws-cdk/issues/14091) +* **codebuild:** Secret env variable from another account fails on Key decryption ([#14226](https://github.com/aws/aws-cdk/issues/14226)) ([8214338](https://github.com/aws/aws-cdk/commit/82143381ef886a3ae39246ba780efca8e24d679d)), closes [#14043](https://github.com/aws/aws-cdk/issues/14043) +* **codepipeline-actions:** CodeCommit source action fails when it's cross-account ([#14260](https://github.com/aws/aws-cdk/issues/14260)) ([1508e60](https://github.com/aws/aws-cdk/commit/1508e6076aa1d2df3129d734a80defd5e11480e3)), closes [#12391](https://github.com/aws/aws-cdk/issues/12391) [#14156](https://github.com/aws/aws-cdk/issues/14156) +* **ec2:** r5ad instance-type has incorrect value ([#14179](https://github.com/aws/aws-cdk/issues/14179)) ([c80e1cf](https://github.com/aws/aws-cdk/commit/c80e1cfc2ae42158bff544ce48394ee1d1ae9a7b)) +* **iam:** unable to configure name of SAML Provider ([#14296](https://github.com/aws/aws-cdk/issues/14296)) ([904202a](https://github.com/aws/aws-cdk/commit/904202a63760afffadc368e73c22bf4ef4021eee)), closes [#14294](https://github.com/aws/aws-cdk/issues/14294) +* **pipelines:** Use LinuxBuildImage.STANDARD_5_0 for Assets and UpdatePipeline stages ([#14338](https://github.com/aws/aws-cdk/issues/14338)) ([f93d940](https://github.com/aws/aws-cdk/commit/f93d9401309cb2af6ea45760c9bc6442fc608def)) + +## [1.100.0](https://github.com/aws/aws-cdk/compare/v1.99.0...v1.100.0) (2021-04-20) + + +### ⚠ BREAKING CHANGES TO EXPERIMENTAL FEATURES + +* **appmesh:** HTTP2 `VirtualNodeListener`s must be now created with `Http2VirtualNodeListenerOptions` +* **appmesh**: HTTP2 `VirtualGatewayListener`s must be now created with `Http2VirtualGatewayListenerOptions` +* **codepipeline-actions:** the Action `ServiceCatalogDeployAction` has been renamed to `ServiceCatalogDeployActionBeta1` +* **codepipeline-actions**: the type `ServiceCatalogDeployActionProps` has been renamed to `ServiceCatalogDeployActionBeta1Props` +* **events-targets:** The `BatchJob` integration now requires the arn and the Resource for the `jobQueue` and the `jobDefinition` +* **lambda-event-sources:** `cluster` was removed from `ManagedKafkaEventSourceProps` and replaced with `clusterArn` +* **route53-targets:** `ApiGatewayv2Domain` was replaced with `ApiGatewayv2DomainProperties` which accepts `regionalDomainName` and `regionalHostedZoneId` +* **stepfunctions-tasks:** `CallApiGatewayHttpApiEndpoint` API now requires the `apiId` and it's containing `Stack` +* **stepfunctions-tasks:** `BatchSubmitJob` now accept `jobDefinitionArn`, `jobQueueArn` and their respective `Resource` +* **stepfunctions-tasks:** `RunBatchJob` now accept `jobDefinitionArn`, `jobQueueArn` and their respective `Resource` + +### Features + +* **apigateway:** integration timeout ([#14154](https://github.com/aws/aws-cdk/issues/14154)) ([d02770e](https://github.com/aws/aws-cdk/commit/d02770ead89d87e55d36490f5d1fa2a4b8a591f2)), closes [#14123](https://github.com/aws/aws-cdk/issues/14123) +* **appmesh:** add Connection Pools for VirtualNode and VirtualGateway ([#13917](https://github.com/aws/aws-cdk/issues/13917)) ([8a949dc](https://github.com/aws/aws-cdk/commit/8a949dc24b13f8b7da17c102501050bac7323bf7)), closes [#11647](https://github.com/aws/aws-cdk/issues/11647) +* **certificatemanager:** allow tagging DnsValidatedCertificate ([#13990](https://github.com/aws/aws-cdk/issues/13990)) ([8360feb](https://github.com/aws/aws-cdk/commit/8360feb58fdc7b1150eca87767e3b71a5e30f50d)), closes [#12382](https://github.com/aws/aws-cdk/issues/12382) [#12382](https://github.com/aws/aws-cdk/issues/12382) +* **codebuild:** allow setting concurrent build limit ([#14185](https://github.com/aws/aws-cdk/issues/14185)) ([3107d03](https://github.com/aws/aws-cdk/commit/3107d03ed2de331ba0eae8ca028aa9a7dbf5a881)) +* **codepipeline:** introduce the Action abstract class ([#14009](https://github.com/aws/aws-cdk/issues/14009)) ([4b6a6cc](https://github.com/aws/aws-cdk/commit/4b6a6cc0e11fd2057b9e23105791098b47c5ca35)) +* **ecs:** add support for elastic inference accelerators in ECS task defintions ([#13950](https://github.com/aws/aws-cdk/issues/13950)) ([23986d7](https://github.com/aws/aws-cdk/commit/23986d70c5cd69ce212b5ffdc1bcf059f438f15b)), closes [#12460](https://github.com/aws/aws-cdk/issues/12460) +* **eks:** Pass bootstrap.sh args to avoid DescribeCluster call and make nodes join the cluster faster ([#12659](https://github.com/aws/aws-cdk/issues/12659)) ([f5616cc](https://github.com/aws/aws-cdk/commit/f5616cc4692975b22db5db4625562dfd0d641045)) +* **secretsmanager:** replicate secrets to multiple regions ([#14266](https://github.com/aws/aws-cdk/issues/14266)) ([b3c288d](https://github.com/aws/aws-cdk/commit/b3c288d7c5781ecb5de90c962a2b68191ed072e1)), closes [#14061](https://github.com/aws/aws-cdk/issues/14061) + + +### Bug Fixes + +* **codepipeline:** incorrect determination of the Action's account when using an imported resource ([#14224](https://github.com/aws/aws-cdk/issues/14224)) ([d88e915](https://github.com/aws/aws-cdk/commit/d88e915c45378cac6a1c7eb31b015391e74f6503)), closes [#14165](https://github.com/aws/aws-cdk/issues/14165) +* **core:** `toJsonString()` does not deal correctly with list tokens ([#14138](https://github.com/aws/aws-cdk/issues/14138)) ([1a6d39f](https://github.com/aws/aws-cdk/commit/1a6d39fc3f22e2fc36949226e8a07f59a92a0bbf)), closes [#14088](https://github.com/aws/aws-cdk/issues/14088) +* **pipelines:** incorrect BuildSpec in synth step if synthesized with `--output` ([#14211](https://github.com/aws/aws-cdk/issues/14211)) ([0f5c74f](https://github.com/aws/aws-cdk/commit/0f5c74f76ad023b163777b8b95f8dbc357994087)), closes [#13303](https://github.com/aws/aws-cdk/issues/13303) +* **rds:** database instances cannot be to be referenced in a different region ([#13865](https://github.com/aws/aws-cdk/issues/13865)) ([74c7fff](https://github.com/aws/aws-cdk/commit/74c7ffffb48fe5578a405b319cc0df973ceb9989)), closes [#13832](https://github.com/aws/aws-cdk/issues/13832) + +## [1.99.0](https://github.com/aws/aws-cdk/compare/v1.98.0...v1.99.0) (2021-04-13) + + +### Features + +* **elasticloadbalancing:** rename 'sslCertificateId' property of LB listener to 'sslCertificateArn'; deprecate sslCertificateId property ([#13766](https://github.com/aws/aws-cdk/issues/13766)) ([1a30272](https://github.com/aws/aws-cdk/commit/1a30272c8bd99a919bde695b5b1b1f5cb458cb64)), closes [#9303](https://github.com/aws/aws-cdk/issues/9303) [#9303](https://github.com/aws/aws-cdk/issues/9303) + + +### Bug Fixes + +* **aws-cloudfront:** distribution comment length not validated ([#14020](https://github.com/aws/aws-cdk/issues/14020)) ([#14094](https://github.com/aws/aws-cdk/issues/14094)) ([54fddc6](https://github.com/aws/aws-cdk/commit/54fddc64c7b541f9192fb904fa9a3b44b8aacf90)) +* **aws-ecs-patterns:** fixes [#11123](https://github.com/aws/aws-cdk/issues/11123) allow for https listeners to use non Route 53 DNS if a certificate is provided ([#14004](https://github.com/aws/aws-cdk/issues/14004)) ([e6c85e4](https://github.com/aws/aws-cdk/commit/e6c85e4167cdb38ed056eda17b869e179a6dd1c5)) +* **cfn-include:** allow deploy-time values in Parameter substitutions in Fn::Sub expressions ([#14068](https://github.com/aws/aws-cdk/issues/14068)) ([111d26a](https://github.com/aws/aws-cdk/commit/111d26a30d220a319bbb7b1b1696aafac865e009)), closes [#14047](https://github.com/aws/aws-cdk/issues/14047) +* **fsx:** Weekday.SUNDAY incorrectly evaluates to 0 (should be 7) ([#14081](https://github.com/aws/aws-cdk/issues/14081)) ([708f23e](https://github.com/aws/aws-cdk/commit/708f23e78fb0eff2aa17593c530500eb0b94067a)), closes [#14080](https://github.com/aws/aws-cdk/issues/14080) + +## [1.98.0](https://github.com/aws/aws-cdk/compare/v1.97.0...v1.98.0) (2021-04-12) + + +### Features + +* **codepipeline-actions:** introduce the CodeStarConnectionsSourceAction ([#13781](https://github.com/aws/aws-cdk/issues/13781)) ([8782e67](https://github.com/aws/aws-cdk/commit/8782e672d6a8f8bbe201f2572c4b0fca7589168d)), closes [#10632](https://github.com/aws/aws-cdk/issues/10632) +* **efs:** graduate to stable 🚀 ([#14033](https://github.com/aws/aws-cdk/issues/14033)) ([3c03d87](https://github.com/aws/aws-cdk/commit/3c03d878dd81454628545b1529691ac083862247)) +* **elasticloadbalancingv2:** add grpc code matcher for alb ([#13948](https://github.com/aws/aws-cdk/issues/13948)) ([a37f178](https://github.com/aws/aws-cdk/commit/a37f178b52a91d43b237013d7cb42c44c1774307)), closes [#13570](https://github.com/aws/aws-cdk/issues/13570) [#13947](https://github.com/aws/aws-cdk/issues/13947) +* **region-info:** graduate to stable 🚀 ([#14013](https://github.com/aws/aws-cdk/issues/14013)) ([0d2755b](https://github.com/aws/aws-cdk/commit/0d2755b97486e4222d1f3b020b8126fefeda20d0)) +* **route-53:** add ability to create NS Records ([#13895](https://github.com/aws/aws-cdk/issues/13895)) ([02c7c1d](https://github.com/aws/aws-cdk/commit/02c7c1d9aab6ed8f806052d3102a037e112b8786)), closes [#13816](https://github.com/aws/aws-cdk/issues/13816) + + +### Bug Fixes + +* **apigateway:** cannot remove first api key from usage plan ([#13817](https://github.com/aws/aws-cdk/issues/13817)) ([036d869](https://github.com/aws/aws-cdk/commit/036d869dc1382d3fb2d8541f5adf534ea3424667)), closes [#11876](https://github.com/aws/aws-cdk/issues/11876) +* **cloudfront:** cannot use same EdgeFunction in multiple stacks ([#13790](https://github.com/aws/aws-cdk/issues/13790)) ([8e2325c](https://github.com/aws/aws-cdk/commit/8e2325cfb7dc5377755b561532b6c81caebc688f)) +* **lambda-nodejs:** esbuild define parameters are incorrectly encoded ([#14065](https://github.com/aws/aws-cdk/issues/14065)) ([5378a77](https://github.com/aws/aws-cdk/commit/5378a7770d5897737ecf4da25d47747c2bbddd94)), closes [#13842](https://github.com/aws/aws-cdk/issues/13842) +* **rds:** deploy fails with "SubnetGroup not found" ([#13986](https://github.com/aws/aws-cdk/issues/13986)) ([ad326da](https://github.com/aws/aws-cdk/commit/ad326da3ae392b78dcfc349f246acdf3a389f283)), closes [#13976](https://github.com/aws/aws-cdk/issues/13976) +* **route53:** cannot set TTL to 0 ([#14060](https://github.com/aws/aws-cdk/issues/14060)) ([ecc9bf3](https://github.com/aws/aws-cdk/commit/ecc9bf386ca088ca82a332c649f13613b9793628)), closes [#14039](https://github.com/aws/aws-cdk/issues/14039) +* **s3:** SSL enforcement doesn't apply on top level bucket requests ([#13961](https://github.com/aws/aws-cdk/issues/13961)) ([d0e831a](https://github.com/aws/aws-cdk/commit/d0e831a2f2b60eae021d10a77d1d636615b0cf04)), closes [#13760](https://github.com/aws/aws-cdk/issues/13760) +* **stepfunctions:** state machine name validation fails when tokens are used. ([#13970](https://github.com/aws/aws-cdk/issues/13970)) ([58de0de](https://github.com/aws/aws-cdk/commit/58de0de5a54b9d8fb4658566e85ef408c8861088)), closes [#13946](https://github.com/aws/aws-cdk/issues/13946) [#13912](https://github.com/aws/aws-cdk/issues/13912) + +## [1.97.0](https://github.com/aws/aws-cdk/compare/v1.96.0...v1.97.0) (2021-04-06) + + +### ⚠ BREAKING CHANGES TO EXPERIMENTAL FEATURES + +* **elasticsearch:** `vpcOptions` was removed. Use `vpc`, `vpcSubnets` and `securityGroups` instead. + +### Features + +* **appmesh:** Implement Outlier Detection for Virtual Nodes ([#13952](https://github.com/aws/aws-cdk/issues/13952)) ([965f130](https://github.com/aws/aws-cdk/commit/965f130dbfc4e1943d384b9fbf5acdf3b547fd57)) +* **cx-api:** graduate to stable 🚀 ([#13859](https://github.com/aws/aws-cdk/issues/13859)) ([d99e13d](https://github.com/aws/aws-cdk/commit/d99e13d523ddacf9e13f6b5169d86d5a20569475)) +* **eks:** Support `secretsEncryptionKey` in FargateCluster ([#13866](https://github.com/aws/aws-cdk/issues/13866)) ([56c6f98](https://github.com/aws/aws-cdk/commit/56c6f98dbcfc98740446f699a8985d7d6b44c503)) +* **eks:** Support bootstrap.sh --dns-cluster-ip arg ([#13890](https://github.com/aws/aws-cdk/issues/13890)) ([56cd863](https://github.com/aws/aws-cdk/commit/56cd8635f77d6a5aefb32c6e1224e1f0a6ca3540)) +* **elasticsearch:** graduate to stable 🚀 ([#13900](https://github.com/aws/aws-cdk/issues/13900)) ([767cd31](https://github.com/aws/aws-cdk/commit/767cd31c2b66b48b3b8fed7cd8d408a6846cf1e1)) +* **s3-deployment:** graduate to stable 🚀 ([#13906](https://github.com/aws/aws-cdk/issues/13906)) ([567d64d](https://github.com/aws/aws-cdk/commit/567d64d70f92adbba9ff9981184d88b46fb95652)) +* **ses:** graduate to stable 🚀 ([#13913](https://github.com/aws/aws-cdk/issues/13913)) ([4f9a715](https://github.com/aws/aws-cdk/commit/4f9a7151b99e8455eeb8b0cd364dfd29624da8c5)) +* **ses-actions:** graduate to stable 🚀 ([#13864](https://github.com/aws/aws-cdk/issues/13864)) ([24f8307](https://github.com/aws/aws-cdk/commit/24f8307b7f9013c5ba909cab8c4a3a3bcdf0041c)) + + +### Bug Fixes + +* **aws-rds:** ServerlessCluster.clusterArn is not correct when clusterIdentifier includes upper cases string. ([#13710](https://github.com/aws/aws-cdk/issues/13710)) ([a8f5b6c](https://github.com/aws/aws-cdk/commit/a8f5b6c54371fe966172a9fb36135bfdc4a01b11)), closes [#12795](https://github.com/aws/aws-cdk/issues/12795) +* **cli:** broken java init template ([#13988](https://github.com/aws/aws-cdk/issues/13988)) ([c6ca2ab](https://github.com/aws/aws-cdk/commit/c6ca2aba915ea4f89e3044b7f388acda231e295d)), closes [#13964](https://github.com/aws/aws-cdk/issues/13964) +* **cloudfront:** Cache Policy headers enforce soft limit of 10 ([#13904](https://github.com/aws/aws-cdk/issues/13904)) ([8a66244](https://github.com/aws/aws-cdk/commit/8a6624477854af17f5ad163fac9be1fd6168cfc4)), closes [#13425](https://github.com/aws/aws-cdk/issues/13425) [#13903](https://github.com/aws/aws-cdk/issues/13903) +* **codepipeline-actions:** EcrSourceAction triggers on a push to every tag ([#13822](https://github.com/aws/aws-cdk/issues/13822)) ([c5a2add](https://github.com/aws/aws-cdk/commit/c5a2addcd87ebb810dcac54c659fa60786f9d345)), closes [#13818](https://github.com/aws/aws-cdk/issues/13818) + +## [1.96.0](https://github.com/aws/aws-cdk/compare/v1.95.2...v1.96.0) (2021-04-01) + + +### ⚠ BREAKING CHANGES TO EXPERIMENTAL FEATURES + +* **globalaccelerator:** automatic naming algorithm has been changed: if you have existing Accelerators you will need to pass an +explicit name to prevent them from being replaced. All endpoints are now added by calling `addEndpoint()` with a +target-specific class that can be found in `@aws-cdk/aws-globalaccelerator-endpoints`. The generated Security Group +is now looked up by calling `endpointGroup.connectionsPeer()`. +* **docdb:** `DatabaseClusterProps.instanceProps` was hoisted and all its properties are now available one level up directly in `DatabaseClusterProps`. +* **docdb**: `DatabaseInstanceProps.instanceClass` renamed to `DatabaseInstanceProps.instanceType`. +* **core:** The type of the `image` property in `BundlingOptions` +is changed from `BundlingDockerImage` to `DockerImage`. +* **core:** The return type of the `DockerImage.fromBuild()` API is +changed from `BundlingDockerImage` to `DockerImage`. + +### Features + +* **autoscaling-common:** graduate to stable 🚀 ([#13862](https://github.com/aws/aws-cdk/issues/13862)) ([2d623d0](https://github.com/aws/aws-cdk/commit/2d623d08d8d5d8c356d871ccd69a8cdac9c4170e)) +* **chatbot:** graduate to stable 🚀 ([#13863](https://github.com/aws/aws-cdk/issues/13863)) ([2384cdd](https://github.com/aws/aws-cdk/commit/2384cdd39bae1639bf3e6bfdeb7a08edc6306cac)) +* **cli:** app init template for golang ([#13840](https://github.com/aws/aws-cdk/issues/13840)) ([41fd42b](https://github.com/aws/aws-cdk/commit/41fd42b89f6f9a95c6e736c17bd404d80c4756a7)), closes [aws/jsii#2678](https://github.com/aws/jsii/issues/2678) +* **cloudformation-diff:** graduate to stable 🚀 ([#13857](https://github.com/aws/aws-cdk/issues/13857)) ([294f546](https://github.com/aws/aws-cdk/commit/294f54692c609eaf20257caba0b53ceb9882ff35)) +* **docdb:** graduate to stable 🚀 ([#13875](https://github.com/aws/aws-cdk/issues/13875)) ([169c2fc](https://github.com/aws/aws-cdk/commit/169c2fc55c3de2426380d0a1151d1d33cbcc2190)) +* **ec2:** allow disabling inline security group rules ([#13613](https://github.com/aws/aws-cdk/issues/13613)) ([793230c](https://github.com/aws/aws-cdk/commit/793230c7a6dcaf93408206e680bd26159ece1b7d)) +* **elasticloadbalancingv2:** graduate to stable 🚀 ([#13861](https://github.com/aws/aws-cdk/issues/13861)) ([08fa5ed](https://github.com/aws/aws-cdk/commit/08fa5ede1721f5165fad5fcf402a83fc2496bc46)) +* **fsx:** graduate to stable 🚀 ([#13860](https://github.com/aws/aws-cdk/issues/13860)) ([b2322aa](https://github.com/aws/aws-cdk/commit/b2322aac00dbbf5b171d5887fef2a3c8f3267c73)) +* **globalaccelerator:** graduate to stable 🚀 ([#13843](https://github.com/aws/aws-cdk/issues/13843)) ([8571008](https://github.com/aws/aws-cdk/commit/8571008884df8e048754fc4e0cfdf06ab20f0149)) +* **lambda:** switch bundling images from DockerHub to ECR public gallery ([#13473](https://github.com/aws/aws-cdk/issues/13473)) ([e2e008b](https://github.com/aws/aws-cdk/commit/e2e008bd19c3ff1b08ccb093dba576551ec73240)), closes [#11296](https://github.com/aws/aws-cdk/issues/11296) +* **lambda-event-sources:** support for batching window to sqs event source ([#13406](https://github.com/aws/aws-cdk/issues/13406)) ([6743e3b](https://github.com/aws/aws-cdk/commit/6743e3bb79a8281a4be5677fff018d702c85038d)), closes [#11722](https://github.com/aws/aws-cdk/issues/11722) [#11724](https://github.com/aws/aws-cdk/issues/11724) [#13770](https://github.com/aws/aws-cdk/issues/13770) +* **lambda-event-sources:** tumbling window ([#13412](https://github.com/aws/aws-cdk/issues/13412)) ([e9f2773](https://github.com/aws/aws-cdk/commit/e9f2773aedeb7f01ebf2a05face719be9bb8b0d7)), closes [#13411](https://github.com/aws/aws-cdk/issues/13411) +* **lambda-nodejs:** graduate to stable 🚀 ([#13844](https://github.com/aws/aws-cdk/issues/13844)) ([37a5502](https://github.com/aws/aws-cdk/commit/37a5502ced1bf1b451ac4bd921752746277461bf)) + + +### Bug Fixes + +* **aws-ecs:** broken splunk-logging `tag`-option in fargate platform version 1.4 ([#13882](https://github.com/aws/aws-cdk/issues/13882)) ([e9d9299](https://github.com/aws/aws-cdk/commit/e9d9299b6bcdab489d94c974074e8c796bce00f3)), closes [#13881](https://github.com/aws/aws-cdk/issues/13881) +* **cloudfront:** auto-generated cache policy name might conflict cross-region ([#13737](https://github.com/aws/aws-cdk/issues/13737)) ([4f067cb](https://github.com/aws/aws-cdk/commit/4f067cb90d43d04659f68dec6b866ba77f10642c)), closes [#13629](https://github.com/aws/aws-cdk/issues/13629) +* **cloudfront:** Origin Request Policy headers enforce soft limit of 10 ([#13907](https://github.com/aws/aws-cdk/issues/13907)) ([9b0a6cf](https://github.com/aws/aws-cdk/commit/9b0a6cf0d349ef3ce1c941b25bbe8e630e09c639)), closes [#13410](https://github.com/aws/aws-cdk/issues/13410) [#13903](https://github.com/aws/aws-cdk/issues/13903) +* **codebuild:** allow passing the ARN of the Secret in environment variables ([#13706](https://github.com/aws/aws-cdk/issues/13706)) ([6f6e079](https://github.com/aws/aws-cdk/commit/6f6e079569fcdb7e0631717fbe269e94f8f7b127)), closes [#12703](https://github.com/aws/aws-cdk/issues/12703) +* **codebuild:** take the account & region of an imported Project from its ARN ([#13708](https://github.com/aws/aws-cdk/issues/13708)) ([fb65123](https://github.com/aws/aws-cdk/commit/fb6512314db1b11fc608cd62753090684ad0d3c4)), closes [#13694](https://github.com/aws/aws-cdk/issues/13694) +* **codedeploy:** script installing CodeDeploy agent fails ([#13758](https://github.com/aws/aws-cdk/issues/13758)) ([25e8d04](https://github.com/aws/aws-cdk/commit/25e8d04d7266a2642f11154750bef49a31b1892e)), closes [#13755](https://github.com/aws/aws-cdk/issues/13755) +* **cognito:** imported userpool not retaining environment from arn ([#13715](https://github.com/aws/aws-cdk/issues/13715)) ([aa9fd9c](https://github.com/aws/aws-cdk/commit/aa9fd9cd9bbaea4149927e08d57d29e547933f49)), closes [#13691](https://github.com/aws/aws-cdk/issues/13691) +* **core:** BundlingDockerImage.fromAsset() does not return a BundlingDockerImage ([#13846](https://github.com/aws/aws-cdk/issues/13846)) ([7176a5d](https://github.com/aws/aws-cdk/commit/7176a5d5208da7d727bbf5112bc12533983380ea)) +* **dynamodb:** table with replicas fails to deploy with "Unresolved resource dependencies" error ([#13889](https://github.com/aws/aws-cdk/issues/13889)) ([5c99d0d](https://github.com/aws/aws-cdk/commit/5c99d0d0e0fde00582e469b667265ebc9f5ef330)) +* **iam:** Role import doesn't fail when forgetting the region in the ARN ([#13821](https://github.com/aws/aws-cdk/issues/13821)) ([560a853](https://github.com/aws/aws-cdk/commit/560a8536ffc31f74fe2366b1365681c1e56e33da)), closes [#13812](https://github.com/aws/aws-cdk/issues/13812) +* **rds:** fail with a descriptive error if Cluster's instance count is a deploy-time value ([#13765](https://github.com/aws/aws-cdk/issues/13765)) ([dd22e8f](https://github.com/aws/aws-cdk/commit/dd22e8fc29f1fc33d391d1bb9ae93963bfd82563)), closes [#13558](https://github.com/aws/aws-cdk/issues/13558) +* **yaml-cfn:** do not deserialize year-month-date as strings ([#13745](https://github.com/aws/aws-cdk/issues/13745)) ([ffea818](https://github.com/aws/aws-cdk/commit/ffea818f26a383e7f314dac3505c46f3b4b4348d)), closes [#13709](https://github.com/aws/aws-cdk/issues/13709) + +## [1.95.2](https://github.com/aws/aws-cdk/compare/v1.95.1...v1.95.2) (2021-04-01) + +* Upgrade a downstream dependency([pac-resolver](https://github.com/TooTallNate/node-pac-resolver)) of the aws-cdk (the CDK CLI), to mitigate [CVE-2021-28918](https://github.com/advisories/GHSA-pch5-whg9-qr2r) ([13914](https://github.com/aws/aws-cdk/pull/13914)) ([794c951](https://github.com/aws/aws-cdk/commit/794c951b5da900fd30827e6f7b0b631bf21df979)) + +## [1.95.1](https://github.com/aws/aws-cdk/compare/v1.95.0...v1.95.1) (2021-03-25) + + +### Bug Fixes + +* **codebuild:** module fails to load with error "Cannot use import statement outside a module" ([b1ffd33](https://github.com/aws/aws-cdk/commit/b1ffd335b6c41a26c1f88db2fc5a739c4c18c7fe)), closes [#13699](https://github.com/aws/aws-cdk/issues/13699) [#13699](https://github.com/aws/aws-cdk/issues/13699) + +## [1.95.0](https://github.com/aws/aws-cdk/compare/v1.94.1...v1.95.0) (2021-03-25) + + +### ⚠ BREAKING CHANGES TO EXPERIMENTAL FEATURES + +* **lambda-nodejs:** The type of `image` property in the +`Bundling` class is changed from `BundlingDockerImage` to +`DockerImage`. +* **lambda-nodejs**: The type of `dockerImage` property in +`BundlingOptions` is changed from `BundlingDockerImage` to +`DockerImage`. +* **apigatewayv2:** The type of `allowMethods` property under `corsPreflight` +section is changed from `HttpMethod` to `CorsHttpMethod`. +* **lambda-nodejs:** the default runtime of a `NodejsFunction` is now Node.js 14.x if the environment from which it is deployed uses Node.js >= 14 and Node.js 12.x otherwise. + +### Features + +* **acmpca:** make the ACM PCA module Generally Available (stable) ([#13778](https://github.com/aws/aws-cdk/issues/13778)) ([7ca79ff](https://github.com/aws/aws-cdk/commit/7ca79ffad7c18692edaa2dd26cd0d4d441ecf468)) +* **apigatewayv2:** http api - default authorizer options ([#13172](https://github.com/aws/aws-cdk/issues/13172)) ([53d9661](https://github.com/aws/aws-cdk/commit/53d96618ac006d7b3f6282c8b5c4ae7aeed2b104)) +* **cfnspec:** cloudformation spec v31.0.0 ([#13633](https://github.com/aws/aws-cdk/issues/13633)) ([9b1c786](https://github.com/aws/aws-cdk/commit/9b1c786846f68fdac94b04b76d546c3d47e2251c)) +* **cfnspec:** cloudformation spec v31.1.0 ([#13763](https://github.com/aws/aws-cdk/issues/13763)) ([41a2b2e](https://github.com/aws/aws-cdk/commit/41a2b2ef39a3d2b46ae6e2c6f3480e786e8022b9)) +* **codepipeline-actions:** Add detectChanges option to BitBucketSourceAction ([#13656](https://github.com/aws/aws-cdk/issues/13656)) ([f2436bf](https://github.com/aws/aws-cdk/commit/f2436bf4ff3ce7665a6cde318ad3fc7716ca941f)) +* **ec2:** client vpn endpoint ([#12234](https://github.com/aws/aws-cdk/issues/12234)) ([4fde59a](https://github.com/aws/aws-cdk/commit/4fde59ac64e8440a05d17a9b5c5622a9dfb43b1f)), closes [#4206](https://github.com/aws/aws-cdk/issues/4206) +* **events:** retry-policy support ([#13660](https://github.com/aws/aws-cdk/issues/13660)) ([7966f8d](https://github.com/aws/aws-cdk/commit/7966f8d48c4bff26beb22856d289f9d0c7e7081d)), closes [#13659](https://github.com/aws/aws-cdk/issues/13659) +* **init-templates:** app template comes with hint comments for 'env' ([#13696](https://github.com/aws/aws-cdk/issues/13696)) ([b940710](https://github.com/aws/aws-cdk/commit/b9407102304f043adcd9a4fc1cde4d23d3da9004)), closes [#12321](https://github.com/aws/aws-cdk/issues/12321) +* **lambda-event-sources:** msk and self-managed kafka event sources ([#12507](https://github.com/aws/aws-cdk/issues/12507)) ([73209e1](https://github.com/aws/aws-cdk/commit/73209e17f314cf61f703d51ef3b9f197d2f1bdc3)), closes [#12099](https://github.com/aws/aws-cdk/issues/12099) +* **rds:** make rds secret name configurable ([#13626](https://github.com/aws/aws-cdk/issues/13626)) ([62a91b7](https://github.com/aws/aws-cdk/commit/62a91b7a30f8b6419a983d7ea7bdb3c39f2fdfd0)), closes [#8984](https://github.com/aws/aws-cdk/issues/8984) +* **sns:** enable passing PolicyDocument to TopicPolicy ([#10559](https://github.com/aws/aws-cdk/issues/10559)) ([0d9c300](https://github.com/aws/aws-cdk/commit/0d9c300f5244d3e5720832343830947f6cc5b352)), closes [#7934](https://github.com/aws/aws-cdk/issues/7934) + + +### Bug Fixes + +* **apigatewayv2:** error while configuring ANY as an allowed method in CORS ([#13313](https://github.com/aws/aws-cdk/issues/13313)) ([34bb338](https://github.com/aws/aws-cdk/commit/34bb338bfc8e2976691a23969baa5fd9d84727e8)), closes [#13280](https://github.com/aws/aws-cdk/issues/13280) [#13643](https://github.com/aws/aws-cdk/issues/13643) +* **aws-ecs:** drain hook lambda allows tasks to stop gracefully ([#13559](https://github.com/aws/aws-cdk/issues/13559)) ([3e1148e](https://github.com/aws/aws-cdk/commit/3e1148e74dce0e15379e2cfa372bd367183f9c6f)), closes [#13506](https://github.com/aws/aws-cdk/issues/13506) +* **codebuild:** Fixed build spec file format to return yaml ([#13445](https://github.com/aws/aws-cdk/issues/13445)) ([fab93c6](https://github.com/aws/aws-cdk/commit/fab93c63ba68c6398499e7df87a56a70d854ab88)) +* **codedeploy:** Use aws-cli instead of awscli for yum ([#13655](https://github.com/aws/aws-cdk/issues/13655)) ([449ce12](https://github.com/aws/aws-cdk/commit/449ce129b860ddc302e1e5270d5819ebe5aa27bf)) +* **codepipeline-actions:** BitBucketAction fails with S3 "Access denied" error ([#13637](https://github.com/aws/aws-cdk/issues/13637)) ([77ce45d](https://github.com/aws/aws-cdk/commit/77ce45d878f2d1cb453e36ae4d83228bee878ef1)), closes [#13557](https://github.com/aws/aws-cdk/issues/13557) +* **core:** `toJsonString()` cannot handle list intrinsics ([#13544](https://github.com/aws/aws-cdk/issues/13544)) ([a5be042](https://github.com/aws/aws-cdk/commit/a5be04270c2a372132964ab13d080a16f1a6f00c)), closes [#13465](https://github.com/aws/aws-cdk/issues/13465) +* **events,applicationautoscaling:** specifying a schedule rate in seconds results in an error ([#13689](https://github.com/aws/aws-cdk/issues/13689)) ([5d62331](https://github.com/aws/aws-cdk/commit/5d6233164611d69ac1bf5c73e1518eb14dbace8d)), closes [#13566](https://github.com/aws/aws-cdk/issues/13566) +* **lambda:** incorrect values for prop UntrustedArtifactOnDeployment ([#13667](https://github.com/aws/aws-cdk/issues/13667)) ([0757686](https://github.com/aws/aws-cdk/commit/0757686790c25ab1cc0f040d9f6039cef6648d44)), closes [#13586](https://github.com/aws/aws-cdk/issues/13586) +* **neptune:** create correct IAM statement in grantConnect() ([#13641](https://github.com/aws/aws-cdk/issues/13641)) ([2e7f046](https://github.com/aws/aws-cdk/commit/2e7f0462fef80714abb923cf0c14ed01d698b4fa)), closes [#13640](https://github.com/aws/aws-cdk/issues/13640) +* **s3:** Notifications fail to deploy due to incompatible node runtime ([#13624](https://github.com/aws/aws-cdk/issues/13624)) ([aa32cf6](https://github.com/aws/aws-cdk/commit/aa32cf64d20e4ba1eb2bc8236daeb05e89e4c12d)) + + +* **lambda-nodejs:** prepare code to reduce merge conflicts when deprecated APIs are stripped ([#13738](https://github.com/aws/aws-cdk/issues/13738)) ([ca391b5](https://github.com/aws/aws-cdk/commit/ca391b596fae1c3130a8811088d32df21a23a434)) +* **lambda-nodejs:** update default runtime ([#13664](https://github.com/aws/aws-cdk/issues/13664)) ([ca42461](https://github.com/aws/aws-cdk/commit/ca42461acd4f42a8bd7c0fb05788c7ea50834de2)) + ## [1.94.1](https://github.com/aws/aws-cdk/compare/v1.94.0...v1.94.1) (2021-03-16) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fab4ce03200c9..0762461d541d5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,8 +2,13 @@ Thanks for your interest in contributing to the AWS CDK! ❤️ -This document describes how to set up a development environment and submit your contributions. Please read it carefully -and let us know if it's not up-to-date (even better, submit a PR with your corrections ;-)). +We highly value contributions, with roughly half of all commits to the CDK +coming from the community. We want to recognize all your hard work +by getting your code merged as quickly as we can, so please read the guidance +here carefully to make sure the review process goes smoothly. + +This document describes how to set up a development environment and submit your changes. Please +let us know if it's not up-to-date (even better, submit a PR with your corrections ;-)). - [Getting Started](#getting-started) - [Pull Requests](#pull-requests) @@ -52,16 +57,16 @@ The following tools need to be installed on your system prior to installing the - [.NET Core SDK 3.1.x](https://www.microsoft.com/net/download) - [Python >= 3.6.5, < 4.0](https://www.python.org/downloads/release/python-365/) -Run the following commands to clone the repository locally. +First fork the repository, and then run the following commands to clone the repository locally. ```console -$ git clone https://github.com/aws/aws-cdk.git +$ git clone https://github.com/{your-account}/aws-cdk.git $ cd aws-cdk $ yarn install ``` We recommend that you use [Visual Studio Code](https://code.visualstudio.com/) to work on the CDK. -We use `eslint` to keep our consistent in terms of style and reducing defects. We recommend installing the +We use `eslint` to keep our code consistent in terms of style and reducing defects. We recommend installing the the [eslint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) as well. ### Repo Layout @@ -185,18 +190,29 @@ contributing your changes. On the other hand, if you are here looking for an issue to work on, explore our [backlog of issues](https://github.com/aws/aws-cdk/issues) and find something that piques your interest. We have labeled all of our -issues for easy filtration. +issues for easy searching. If you are looking for your first contribution, the ['good first issue' label](https://github.com/aws/aws-cdk/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) will be of help. -### Step 2: Design (optional) +It's a good idea to keep the priority of issues in mind when deciding what to +work on. If we have labelled an issue as `P2`, it means it's something we won't +get to soon, and we're waiting on more feedback from the community (in the form +of +1s and comments) to give it a higher priority. A PR for a `P2` issue may +take us some time to review, especially if it involves a complex +implementation. `P1` issues impact a significant number of customers, so we are +much more likely to give a PR for those issues prompt attention. + +### Step 2: Design In some cases, it is useful to seek feedback by iterating on a design document. This is useful when you plan a big change or feature, or you want advice on what would be the best path forward. -In most cases, the GitHub issue is sufficient for such discussions, and can be sufficient to get -clarity on what you plan to do. If the changes are significant or intrusive to the existing CDK experience, -consider writing an RFC in our [RFC repository](https://github.com/aws/aws-cdk-rfcs) before jumping into our code base. +In many cases, the GitHub issue is sufficient for such discussions, and can be +sufficient to get clarity on what you plan to do. If the changes are +significant or intrusive to the existing CDK experience, and especially for a +brand new L2 construct implementation, please write an RFC in our [RFC +repository](https://github.com/aws/aws-cdk-rfcs) before jumping into the code +base. ### Step 3: Work your Magic @@ -307,6 +323,8 @@ BREAKING CHANGE: Description of what broke and how to achieve this behavior now ## Breaking Changes +_NOTE: Breaking changes will not be allowed in the upcoming v2 release. These instructions apply to v1._ + Whenever you are making changes, there is a chance for those changes to be *breaking* existing users of the library. A change is breaking if there are programs that customers could have been writing against the current version diff --git a/DEPRECATED_APIs.md b/DEPRECATED_APIs.md new file mode 100644 index 0000000000000..a08cf9de97f86 --- /dev/null +++ b/DEPRECATED_APIs.md @@ -0,0 +1,865 @@ +# List of deprecated APIs in v1 + +| Module | API Element | Message | +|--------|-------------|---------| +| @aws-cdk/core | AppProps.​runtimeInfo | use `versionReporting` instead | +| @aws-cdk/core | AssetHashType.​BUNDLE | use `OUTPUT` instead | +| @aws-cdk/core | AssetStaging.​sourceHash | see `assetHash`. | +| @aws-cdk/core | AssetStaging.​stagedPath | Use `absoluteStagedPath` instead. | +| @aws-cdk/core | BundlingDockerImage | use DockerImage | +| @aws-cdk/core | BundlingDockerImage.​image | use DockerImage | +| @aws-cdk/core | BundlingDockerImage.​fromAsset() | use DockerImage.fromBuild() | +| @aws-cdk/core | BundlingDockerImage.​fromRegistry() | use DockerImage | +| @aws-cdk/core | BundlingDockerImage.​cp() | use DockerImage | +| @aws-cdk/core | BundlingDockerImage.​run() | use DockerImage | +| @aws-cdk/core | BundlingDockerImage.​toJSON() | use DockerImage | +| @aws-cdk/core | CfnInclude | use the CfnInclude class from the cloudformation-include module instead | +| @aws-cdk/core | CfnInclude.​template | use the CfnInclude class from the cloudformation-include module instead | +| @aws-cdk/core | CfnIncludeProps | use the CfnInclude class from the cloudformation-include module instead | +| @aws-cdk/core | CfnIncludeProps.​template | use the CfnInclude class from the cloudformation-include module instead | +| @aws-cdk/core | ConstructNode.​metadata | use `metadataEntry` | +| @aws-cdk/core | ConstructNode.​uniqueId | use `node.addr` to obtain a consistent 42 character address for this node (see https://github.com/aws/constructs/pull/314) | +| @aws-cdk/core | ConstructNode.​prepare() | Use `app.synth()` instead | +| @aws-cdk/core | ConstructNode.​synth() | Use `app.synth()` or `stage.synth()` instead | +| @aws-cdk/core | ConstructNode.​addError() | use `Annotations.of(construct).addError()` | +| @aws-cdk/core | ConstructNode.​addInfo() | use `Annotations.of(construct).addInfo()` | +| @aws-cdk/core | ConstructNode.​addWarning() | use `Annotations.of(construct).addWarning()` | +| @aws-cdk/core | ConstructNode.​applyAspect() | This API is going to be removed in the next major version of the AWS CDK. Please use `Aspects.of(scope).add()` instead. | +| @aws-cdk/core | CustomResourceProviderRuntime.​NODEJS_​12 | Use {@link NODEJS_12_X} | +| @aws-cdk/core | DefaultStackSynthesizerProps.​fileAssetKeyArnExportName | This property is not used anymore | +| @aws-cdk/core | DockerImageAssetSource.​repositoryName | repository name should be specified at the environment-level and not at the image level | +| @aws-cdk/core | Duration.​toISOString() | Use `toIsoString()` instead. | +| @aws-cdk/core | FileAssetLocation.​kmsKeyArn | Since bootstrap bucket v4, the key policy properly allows use of the key via the bucket and no additional parameters have to be granted anymore. | +| @aws-cdk/core | FileAssetLocation.​s3Url | use `httpUrl` | +| @aws-cdk/core | ITemplateOptions.​transform | use `transforms` instead. | +| @aws-cdk/core | Lazy.​anyValue() | Use `Lazy.any()` or `Lazy.uncachedAny()` instead. | +| @aws-cdk/core | Lazy.​listValue() | Use `Lazy.list()` or `Lazy.uncachedList()` instead. | +| @aws-cdk/core | Lazy.​numberValue() | Use `Lazy.number()` or `Lazy.uncachedNumber()` instead. | +| @aws-cdk/core | Lazy.​stringValue() | Use `Lazy.string()` or `Lazy.uncachedString()` instead. | +| @aws-cdk/core | Size.​pebibyte() | use `pebibytes` instead | +| @aws-cdk/core | Stack.​parentStack | use `nestedStackParent` | +| @aws-cdk/core | Stack.​addDockerImageAsset() | Use `stack.synthesizer.addDockerImageAsset()` if you are calling, and a different `IStackSynthesizer` class if you are implementing. | +| @aws-cdk/core | Stack.​addFileAsset() | Use `stack.synthesizer.addFileAsset()` if you are calling, and a different IStackSynthesizer class if you are implementing. | +| @aws-cdk/core | Stack.​prepareCrossReference() | cross reference handling has been moved to `App.prepare()`. | +| @aws-cdk/core | Stack.​reportMissingContext() | use `reportMissingContextKey()` | +| @aws-cdk/core | SynthesisOptions | use `app.synth()` or `stage.synth()` instead | +| @aws-cdk/core | SynthesisOptions.​outdir | use `app.synth()` or `stage.synth()` instead | +| @aws-cdk/core | SynthesisOptions.​skipValidation | use `app.synth()` or `stage.synth()` instead | +| @aws-cdk/core | Tag.​add() | use `Tags.of(scope).add()` | +| @aws-cdk/core | Tag.​remove() | use `Tags.of(scope).remove()` | +| @aws-cdk/cloud-assembly-schema | ContainerImageAssetMetadataEntry.​imageNameParameter | specify `repositoryName` and `imageTag` instead, and then you know where the image will go. | +| @aws-cdk/cloud-assembly-schema | Manifest.​load() | use `loadAssemblyManifest()` | +| @aws-cdk/cloud-assembly-schema | Manifest.​save() | use `saveAssemblyManifest()` | +| @aws-cdk/cx-api | AssemblyBuildOptions.​runtimeInfo | All template modifications that should result from this should have already been inserted into the template. | +| @aws-cdk/cx-api | CloudAssembly.​getStack() | renamed to `getStackByName` (or `getStackArtifact(id)`) | +| @aws-cdk/cx-api | CloudFormationStackArtifact.​name | renamed to `stackName` | +| @aws-cdk/cx-api | MetadataEntry | moved to package 'cloud-assembly-schema' | +| @aws-cdk/cx-api | MissingContext | moved to package 'cloud-assembly-schema' | +| @aws-cdk/cx-api | MissingContext.​key | moved to package 'cloud-assembly-schema' | +| @aws-cdk/cx-api | MissingContext.​props | moved to package 'cloud-assembly-schema' | +| @aws-cdk/cx-api | MissingContext.​provider | moved to package 'cloud-assembly-schema' | +| @aws-cdk/cx-api | RuntimeInfo | moved to package 'cloud-assembly-schema' | +| constructs | Construct.​onValidate() | use `Node.addValidation()` to subscribe validation functions on this construct instead of overriding this method. | +| constructs | Node.​uniqueId | please avoid using this property and use `uid` instead. This algorithm uses MD5, which is not FIPS-complient and also excludes the identity of the root construct from the calculation. | +| @aws-cdk/assets | CopyOptions | see `core.CopyOptions` | +| @aws-cdk/assets | CopyOptions.​exclude | see `core.CopyOptions` | +| @aws-cdk/assets | CopyOptions.​follow | use `followSymlinks` instead | +| @aws-cdk/assets | CopyOptions.​ignoreMode | see `core.CopyOptions` | +| @aws-cdk/assets | FingerprintOptions | see `core.FingerprintOptions` | +| @aws-cdk/assets | FingerprintOptions.​extraHash | see `core.FingerprintOptions` | +| @aws-cdk/assets | FollowMode | see `core.SymlinkFollowMode` | +| @aws-cdk/assets | FollowMode.​NEVER | see `core.SymlinkFollowMode` | +| @aws-cdk/assets | FollowMode.​ALWAYS | see `core.SymlinkFollowMode` | +| @aws-cdk/assets | FollowMode.​EXTERNAL | see `core.SymlinkFollowMode` | +| @aws-cdk/assets | FollowMode.​BLOCK_​EXTERNAL | see `core.SymlinkFollowMode` | +| @aws-cdk/assets | IAsset | use `core.IAsset` | +| @aws-cdk/assets | IAsset.​sourceHash | use `core.IAsset` | +| @aws-cdk/assets | Staging | use `core.AssetStaging` | +| @aws-cdk/assets | StagingProps | use `core.AssetStagingProps` | +| @aws-cdk/assets | StagingProps.​sourcePath | use `core.AssetStagingProps` | +| @aws-cdk/aws-iam | Anyone | use `AnyPrincipal` | +| @aws-cdk/aws-iam | IPrincipal.​addToPolicy() | Use `addToPrincipalPolicy` instead. | +| @aws-cdk/aws-iam | RoleProps.​externalId | see {@link externalIds} | +| @aws-cdk/aws-kms | KeyProps.​trustAccountIdentities | redundant with the `@aws-cdk/aws-kms:defaultKeyPolicies` feature flag | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​ANDROID_​JAVA8_​24_​4_​1 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​ANDROID_​JAVA8_​26_​1_​1 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​BASE | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​DOCKER_​17_​09_​0 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​DOCKER_​18_​09_​0 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​DOTNET_​CORE_​1_​1 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​DOTNET_​CORE_​2_​0 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​DOTNET_​CORE_​2_​1 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​GOLANG_​1_​10 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​GOLANG_​1_​11 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​NODEJS_​10_​1_​0 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​NODEJS_​10_​14_​1 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​NODEJS_​6_​3_​1 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​NODEJS_​8_​11_​0 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​OPEN_​JDK_​11 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​OPEN_​JDK_​8 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​OPEN_​JDK_​9 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​PHP_​5_​6 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​PHP_​7_​0 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​PHP_​7_​1 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​PYTHON_​2_​7_​12 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​PYTHON_​3_​3_​6 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​PYTHON_​3_​4_​5 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​PYTHON_​3_​5_​2 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​PYTHON_​3_​6_​5 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​PYTHON_​3_​7_​1 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​RUBY_​2_​2_​5 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​RUBY_​2_​3_​1 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​RUBY_​2_​5_​1 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | LinuxBuildImage.​UBUNTU_​14_​04_​RUBY_​2_​5_​3 | Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section | +| @aws-cdk/aws-codebuild | WindowsBuildImage.​WIN_​SERVER_​CORE_​2016_​BASE | `WindowsBuildImage.WINDOWS_BASE_2_0` should be used instead. | +| @aws-cdk/aws-cloudwatch | CreateAlarmOptions.​period | Use `metric.with({ period: ... })` to encode the period into the Metric object | +| @aws-cdk/aws-cloudwatch | CreateAlarmOptions.​statistic | Use `metric.with({ statistic: ... })` to encode the period into the Metric object | +| @aws-cdk/aws-cloudwatch | IMetric.​toAlarmConfig() | Use `toMetricsConfig()` instead. | +| @aws-cdk/aws-cloudwatch | IMetric.​toGraphConfig() | Use `toMetricsConfig()` instead. | +| @aws-cdk/aws-cloudwatch | MathExpression.​toAlarmConfig() | use toMetricConfig() | +| @aws-cdk/aws-cloudwatch | MathExpression.​toGraphConfig() | use toMetricConfig() | +| @aws-cdk/aws-cloudwatch | Metric.​toAlarmConfig() | use toMetricConfig() | +| @aws-cdk/aws-cloudwatch | Metric.​toGraphConfig() | use toMetricConfig() | +| @aws-cdk/aws-cloudwatch | MetricAlarmConfig | Replaced by MetricConfig | +| @aws-cdk/aws-cloudwatch | MetricAlarmConfig.​metricName | Replaced by MetricConfig | +| @aws-cdk/aws-cloudwatch | MetricAlarmConfig.​namespace | Replaced by MetricConfig | +| @aws-cdk/aws-cloudwatch | MetricAlarmConfig.​period | Replaced by MetricConfig | +| @aws-cdk/aws-cloudwatch | MetricAlarmConfig.​dimensions | Replaced by MetricConfig | +| @aws-cdk/aws-cloudwatch | MetricAlarmConfig.​extendedStatistic | Replaced by MetricConfig | +| @aws-cdk/aws-cloudwatch | MetricAlarmConfig.​statistic | Replaced by MetricConfig | +| @aws-cdk/aws-cloudwatch | MetricAlarmConfig.​unit | Replaced by MetricConfig | +| @aws-cdk/aws-cloudwatch | MetricGraphConfig | Replaced by MetricConfig | +| @aws-cdk/aws-cloudwatch | MetricGraphConfig.​metricName | Replaced by MetricConfig | +| @aws-cdk/aws-cloudwatch | MetricGraphConfig.​namespace | Replaced by MetricConfig | +| @aws-cdk/aws-cloudwatch | MetricGraphConfig.​period | Use `period` in `renderingProperties` | +| @aws-cdk/aws-cloudwatch | MetricGraphConfig.​renderingProperties | Replaced by MetricConfig | +| @aws-cdk/aws-cloudwatch | MetricGraphConfig.​color | Use `color` in `renderingProperties` | +| @aws-cdk/aws-cloudwatch | MetricGraphConfig.​dimensions | Replaced by MetricConfig | +| @aws-cdk/aws-cloudwatch | MetricGraphConfig.​label | Use `label` in `renderingProperties` | +| @aws-cdk/aws-cloudwatch | MetricGraphConfig.​statistic | Use `stat` in `renderingProperties` | +| @aws-cdk/aws-cloudwatch | MetricGraphConfig.​unit | not used in dashboard widgets | +| @aws-cdk/aws-cloudwatch | MetricRenderingProperties | Replaced by MetricConfig. | +| @aws-cdk/aws-cloudwatch | MetricRenderingProperties.​period | Replaced by MetricConfig. | +| @aws-cdk/aws-cloudwatch | MetricRenderingProperties.​color | Replaced by MetricConfig. | +| @aws-cdk/aws-cloudwatch | MetricRenderingProperties.​label | Replaced by MetricConfig. | +| @aws-cdk/aws-cloudwatch | MetricRenderingProperties.​stat | Replaced by MetricConfig. | +| @aws-cdk/aws-events | EventBus.​grantPutEvents() | use grantAllPutEvents instead | +| @aws-cdk/aws-events | RuleTargetConfig.​id | no replacement. we will always use an autogenerated id. | +| @aws-cdk/aws-ec2 | InterfaceVpcEndpoint.​securityGroupId | use the `connections` object | +| @aws-cdk/aws-ec2 | InterfaceVpcEndpointAttributes.​securityGroupId | use `securityGroups` instead | +| @aws-cdk/aws-ec2 | NatInstanceProps.​allowAllTraffic | Use `defaultAllowedTraffic`. | +| @aws-cdk/aws-ec2 | SubnetSelection.​subnetName | Use `subnetGroupName` instead | +| @aws-cdk/aws-ec2 | Vpc.​natDependencies | This value is no longer used. | +| @aws-cdk/aws-ec2 | Vpc.​addDynamoDbEndpoint() | use `addGatewayEndpoint()` instead | +| @aws-cdk/aws-ec2 | Vpc.​addS3Endpoint() | use `addGatewayEndpoint()` instead | +| @aws-cdk/aws-ec2 | VpcEndpointService.​whitelistedPrincipals | use `allowedPrincipals` | +| @aws-cdk/aws-ec2 | VpcEndpointServiceProps.​vpcEndpointServiceName | This property is not used | +| @aws-cdk/aws-ec2 | VpcEndpointServiceProps.​whitelistedPrincipals | use `allowedPrincipals` | +| @aws-cdk/aws-ec2 | WindowsVersion.​WINDOWS_​SERVER_​2016_​GERMAL_​FULL_​BASE | use WINDOWS_SERVER_2016_GERMAN_FULL_BASE | +| @aws-cdk/aws-ec2 | WindowsVersion.​WINDOWS_​SERVER_​2012_​R2_​SP1_​PORTUGESE_​BRAZIL_​64BIT_​CORE | use WINDOWS_SERVER_2012_R2_SP1_PORTUGUESE_BRAZIL_64BIT_CORE | +| @aws-cdk/aws-ec2 | WindowsVersion.​WINDOWS_​SERVER_​2016_​PORTUGESE_​PORTUGAL_​FULL_​BASE | use WINDOWS_SERVER_2016_PORTUGUESE_PORTUGAL_FULL_BASE | +| @aws-cdk/aws-ec2 | WindowsVersion.​WINDOWS_​SERVER_​2012_​R2_​RTM_​PORTUGESE_​BRAZIL_​64BIT_​BASE | use WINDOWS_SERVER_2012_R2_RTM_PORTUGUESE_BRAZIL_64BIT_BASE | +| @aws-cdk/aws-ec2 | WindowsVersion.​WINDOWS_​SERVER_​2012_​R2_​RTM_​PORTUGESE_​PORTUGAL_​64BIT_​BASE | use WINDOWS_SERVER_2012_R2_RTM_PORTUGUESE_PORTUGAL_64BIT_BASE | +| @aws-cdk/aws-ec2 | WindowsVersion.​WINDOWS_​SERVER_​2016_​PORTUGESE_​BRAZIL_​FULL_​BASE | use WINDOWS_SERVER_2016_PORTUGUESE_BRAZIL_FULL_BASE | +| @aws-cdk/aws-ec2 | WindowsVersion.​WINDOWS_​SERVER_​2012_​SP2_​PORTUGESE_​BRAZIL_​64BIT_​BASE | use WINDOWS_SERVER_2012_SP2_PORTUGUESE_BRAZIL_64BIT_BASE | +| @aws-cdk/aws-ec2 | WindowsVersion.​WINDOWS_​SERVER_​2012_​RTM_​PORTUGESE_​BRAZIL_​64BIT_​BASE | use WINDOWS_SERVER_2012_RTM_PORTUGUESE_BRAZIL_64BIT_BASE | +| @aws-cdk/aws-ec2 | WindowsVersion.​WINDOWS_​SERVER_​2008_​R2_​SP1_​PORTUGESE_​BRAZIL_​64BIT_​BASE | use WINDOWS_SERVER_2008_R2_SP1_PORTUGUESE_BRAZIL_64BIT_BASE | +| @aws-cdk/aws-ec2 | WindowsVersion.​WINDOWS_​SERVER_​2008_​SP2_​PORTUGESE_​BRAZIL_​32BIT_​BASE | use WINDOWS_SERVER_2008_SP2_PORTUGUESE_BRAZIL_32BIT_BASE | +| @aws-cdk/aws-ec2 | WindowsVersion.​WINDOWS_​SERVER_​2012_​RTM_​PORTUGESE_​PORTUGAL_​64BIT_​BASE | use WINDOWS_SERVER_2012_RTM_PORTUGUESE_PORTUGAL_64BIT_BASE | +| @aws-cdk/aws-ec2 | WindowsVersion.​WINDOWS_​SERVER_​2019_​PORTUGESE_​BRAZIL_​FULL_​BASE | use WINDOWS_SERVER_2019_PORTUGUESE_BRAZIL_FULL_BASE | +| @aws-cdk/aws-ec2 | WindowsVersion.​WINDOWS_​SERVER_​2019_​PORTUGESE_​PORTUGAL_​FULL_​BASE | use WINDOWS_SERVER_2019_PORTUGUESE_PORTUGAL_FULL_BASE | +| @aws-cdk/aws-s3-assets | Asset.​s3Url | use `httpUrl` | +| @aws-cdk/aws-s3-assets | Asset.​sourceHash | see `assetHash` | +| @aws-cdk/aws-s3-assets | AssetOptions.​sourceHash | see `assetHash` and `assetHashType` | +| @aws-cdk/aws-ecr-assets | DockerImageAsset.​sourceHash | use assetHash | +| @aws-cdk/aws-ecr-assets | DockerImageAssetOptions.​repositoryName | to control the location of docker image assets, please override `Stack.addDockerImageAsset`. this feature will be removed in future releases. | +| @aws-cdk/aws-secretsmanager | AttachedSecretOptions | use `secret.attach()` instead | +| @aws-cdk/aws-secretsmanager | AttachedSecretOptions.​target | use `secret.attach()` instead | +| @aws-cdk/aws-secretsmanager | AttachmentTargetType.​INSTANCE | use RDS_DB_INSTANCE instead | +| @aws-cdk/aws-secretsmanager | AttachmentTargetType.​CLUSTER | use RDS_DB_CLUSTER instead | +| @aws-cdk/aws-secretsmanager | Secret.​fromSecretArn() | use `fromSecretCompleteArn` or `fromSecretPartialArn` | +| @aws-cdk/aws-secretsmanager | Secret.​fromSecretName() | use `fromSecretNameV2` | +| @aws-cdk/aws-secretsmanager | Secret.​addTargetAttachment() | use `attach()` instead | +| @aws-cdk/aws-secretsmanager | SecretAttributes.​secretArn | use `secretCompleteArn` or `secretPartialArn` instead. | +| @aws-cdk/aws-lambda | Code.​isInline | this value is ignored since inline is now determined based on the the `inlineCode` field of `CodeConfig` returned from `bind()`. | +| @aws-cdk/aws-lambda | Code.​asset() | use `fromAsset` | +| @aws-cdk/aws-lambda | Code.​bucket() | use `fromBucket` | +| @aws-cdk/aws-lambda | Code.​cfnParameters() | use `fromCfnParameters` | +| @aws-cdk/aws-lambda | Code.​inline() | use `fromInline` | +| @aws-cdk/aws-lambda | Function.​addVersion() | This method will create an AWS::Lambda::Version resource which snapshots the AWS Lambda function *at the time of its creation* and it won't get updated when the function changes. Instead, use `this.currentVersion` to obtain a reference to a version resource that gets automatically recreated when the function configuration (or code) changes. | +| @aws-cdk/aws-lambda | FunctionAttributes.​securityGroupId | use `securityGroup` instead | +| @aws-cdk/aws-lambda | FunctionOptions.​securityGroup | This property is deprecated, use securityGroups instead | +| @aws-cdk/aws-lambda | LogRetention | use `LogRetention` from ' | +| @aws-cdk/aws-lambda | LogRetentionProps | use `LogRetentionProps` from ' | +| @aws-cdk/aws-lambda | Runtime.​bundlingDockerImage | use `bundlingImage` | +| @aws-cdk/aws-apigateway | CfnApiMappingV2 | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiMappingV2.​CFN_​RESOURCE_​TYPE_​NAME | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiMappingV2.​cfnProperties | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiMappingV2.​apiId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiMappingV2.​domainName | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiMappingV2.​stage | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiMappingV2.​apiMappingKey | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiMappingV2.​inspect() | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiMappingV2.​renderProperties() | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiMappingV2Props | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiMappingV2Props.​apiId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiMappingV2Props.​domainName | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiMappingV2Props.​stage | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiMappingV2Props.​apiMappingKey | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2 | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2.​CFN_​RESOURCE_​TYPE_​NAME | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2.​cfnProperties | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2.​tags | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2.​body | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2.​apiKeySelectionExpression | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2.​basePath | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2.​bodyS3Location | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2.​corsConfiguration | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2.​credentialsArn | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2.​description | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2.​disableSchemaValidation | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2.​failOnWarnings | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2.​name | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2.​protocolType | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2.​routeKey | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2.​routeSelectionExpression | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2.​target | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2.​version | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2.​inspect() | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2.​renderProperties() | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | BodyS3LocationProperty | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | BodyS3LocationProperty.​bucket | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | BodyS3LocationProperty.​etag | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | BodyS3LocationProperty.​key | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | BodyS3LocationProperty.​version | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CorsProperty | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CorsProperty.​allowCredentials | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CorsProperty.​allowHeaders | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CorsProperty.​allowMethods | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CorsProperty.​allowOrigins | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CorsProperty.​exposeHeaders | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CorsProperty.​maxAge | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2Props | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2Props.​apiKeySelectionExpression | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2Props.​basePath | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2Props.​body | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2Props.​bodyS3Location | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2Props.​corsConfiguration | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2Props.​credentialsArn | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2Props.​description | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2Props.​disableSchemaValidation | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2Props.​failOnWarnings | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2Props.​name | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2Props.​protocolType | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2Props.​routeKey | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2Props.​routeSelectionExpression | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2Props.​tags | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2Props.​target | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnApiV2Props.​version | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnAuthorizerV2 | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnAuthorizerV2.​CFN_​RESOURCE_​TYPE_​NAME | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnAuthorizerV2.​cfnProperties | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnAuthorizerV2.​apiId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnAuthorizerV2.​authorizerType | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnAuthorizerV2.​identitySource | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnAuthorizerV2.​name | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnAuthorizerV2.​authorizerCredentialsArn | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnAuthorizerV2.​authorizerResultTtlInSeconds | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnAuthorizerV2.​authorizerUri | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnAuthorizerV2.​identityValidationExpression | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnAuthorizerV2.​jwtConfiguration | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnAuthorizerV2.​inspect() | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnAuthorizerV2.​renderProperties() | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | JWTConfigurationProperty | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | JWTConfigurationProperty.​audience | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | JWTConfigurationProperty.​issuer | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnAuthorizerV2Props | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnAuthorizerV2Props.​apiId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnAuthorizerV2Props.​authorizerType | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnAuthorizerV2Props.​identitySource | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnAuthorizerV2Props.​name | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnAuthorizerV2Props.​authorizerCredentialsArn | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnAuthorizerV2Props.​authorizerResultTtlInSeconds | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnAuthorizerV2Props.​authorizerUri | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnAuthorizerV2Props.​identityValidationExpression | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnAuthorizerV2Props.​jwtConfiguration | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnDeploymentV2 | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnDeploymentV2.​CFN_​RESOURCE_​TYPE_​NAME | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnDeploymentV2.​cfnProperties | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnDeploymentV2.​apiId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnDeploymentV2.​description | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnDeploymentV2.​stageName | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnDeploymentV2.​inspect() | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnDeploymentV2.​renderProperties() | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnDeploymentV2Props | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnDeploymentV2Props.​apiId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnDeploymentV2Props.​description | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnDeploymentV2Props.​stageName | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnDomainNameV2 | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnDomainNameV2.​CFN_​RESOURCE_​TYPE_​NAME | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnDomainNameV2.​attrRegionalDomainName | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnDomainNameV2.​attrRegionalHostedZoneId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnDomainNameV2.​cfnProperties | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnDomainNameV2.​tags | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnDomainNameV2.​domainName | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnDomainNameV2.​domainNameConfigurations | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnDomainNameV2.​inspect() | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnDomainNameV2.​renderProperties() | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | DomainNameConfigurationProperty | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | DomainNameConfigurationProperty.​certificateArn | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | DomainNameConfigurationProperty.​certificateName | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | DomainNameConfigurationProperty.​endpointType | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnDomainNameV2Props | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnDomainNameV2Props.​domainName | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnDomainNameV2Props.​domainNameConfigurations | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnDomainNameV2Props.​tags | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationResponseV2 | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationResponseV2.​CFN_​RESOURCE_​TYPE_​NAME | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationResponseV2.​cfnProperties | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationResponseV2.​apiId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationResponseV2.​integrationId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationResponseV2.​integrationResponseKey | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationResponseV2.​responseParameters | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationResponseV2.​responseTemplates | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationResponseV2.​contentHandlingStrategy | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationResponseV2.​templateSelectionExpression | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationResponseV2.​inspect() | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationResponseV2.​renderProperties() | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationResponseV2Props | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationResponseV2Props.​apiId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationResponseV2Props.​integrationId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationResponseV2Props.​integrationResponseKey | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationResponseV2Props.​contentHandlingStrategy | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationResponseV2Props.​responseParameters | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationResponseV2Props.​responseTemplates | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationResponseV2Props.​templateSelectionExpression | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2 | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2.​CFN_​RESOURCE_​TYPE_​NAME | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2.​cfnProperties | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2.​apiId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2.​integrationType | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2.​requestParameters | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2.​requestTemplates | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2.​connectionType | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2.​contentHandlingStrategy | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2.​credentialsArn | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2.​description | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2.​integrationMethod | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2.​integrationUri | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2.​passthroughBehavior | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2.​payloadFormatVersion | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2.​templateSelectionExpression | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2.​timeoutInMillis | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2.​inspect() | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2.​renderProperties() | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2Props | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2Props.​apiId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2Props.​integrationType | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2Props.​connectionType | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2Props.​contentHandlingStrategy | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2Props.​credentialsArn | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2Props.​description | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2Props.​integrationMethod | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2Props.​integrationUri | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2Props.​passthroughBehavior | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2Props.​payloadFormatVersion | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2Props.​requestParameters | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2Props.​requestTemplates | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2Props.​templateSelectionExpression | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnIntegrationV2Props.​timeoutInMillis | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnModelV2 | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnModelV2.​CFN_​RESOURCE_​TYPE_​NAME | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnModelV2.​cfnProperties | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnModelV2.​apiId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnModelV2.​name | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnModelV2.​schema | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnModelV2.​contentType | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnModelV2.​description | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnModelV2.​inspect() | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnModelV2.​renderProperties() | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnModelV2Props | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnModelV2Props.​apiId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnModelV2Props.​name | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnModelV2Props.​schema | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnModelV2Props.​contentType | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnModelV2Props.​description | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteResponseV2 | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteResponseV2.​CFN_​RESOURCE_​TYPE_​NAME | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteResponseV2.​cfnProperties | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteResponseV2.​apiId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteResponseV2.​responseModels | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteResponseV2.​responseParameters | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteResponseV2.​routeId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteResponseV2.​routeResponseKey | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteResponseV2.​modelSelectionExpression | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteResponseV2.​inspect() | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteResponseV2.​renderProperties() | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | ParameterConstraintsProperty | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | ParameterConstraintsProperty.​required | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteResponseV2Props | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteResponseV2Props.​apiId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteResponseV2Props.​routeId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteResponseV2Props.​routeResponseKey | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteResponseV2Props.​modelSelectionExpression | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteResponseV2Props.​responseModels | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteResponseV2Props.​responseParameters | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2 | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2.​CFN_​RESOURCE_​TYPE_​NAME | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2.​cfnProperties | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2.​apiId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2.​requestModels | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2.​requestParameters | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2.​routeKey | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2.​apiKeyRequired | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2.​authorizationScopes | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2.​authorizationType | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2.​authorizerId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2.​modelSelectionExpression | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2.​operationName | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2.​routeResponseSelectionExpression | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2.​target | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2.​inspect() | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2.​renderProperties() | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | ParameterConstraintsProperty | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | ParameterConstraintsProperty.​required | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2Props | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2Props.​apiId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2Props.​routeKey | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2Props.​apiKeyRequired | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2Props.​authorizationScopes | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2Props.​authorizationType | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2Props.​authorizerId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2Props.​modelSelectionExpression | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2Props.​operationName | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2Props.​requestModels | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2Props.​requestParameters | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2Props.​routeResponseSelectionExpression | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnRouteV2Props.​target | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2 | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2.​CFN_​RESOURCE_​TYPE_​NAME | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2.​cfnProperties | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2.​tags | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2.​apiId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2.​routeSettings | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2.​stageName | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2.​stageVariables | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2.​accessLogSettings | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2.​autoDeploy | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2.​clientCertificateId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2.​defaultRouteSettings | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2.​deploymentId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2.​description | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2.​inspect() | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2.​renderProperties() | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | AccessLogSettingsProperty | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | AccessLogSettingsProperty.​destinationArn | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | AccessLogSettingsProperty.​format | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | RouteSettingsProperty | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | RouteSettingsProperty.​dataTraceEnabled | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | RouteSettingsProperty.​detailedMetricsEnabled | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | RouteSettingsProperty.​loggingLevel | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | RouteSettingsProperty.​throttlingBurstLimit | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | RouteSettingsProperty.​throttlingRateLimit | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2Props | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2Props.​apiId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2Props.​stageName | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2Props.​accessLogSettings | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2Props.​autoDeploy | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2Props.​clientCertificateId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2Props.​defaultRouteSettings | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2Props.​deploymentId | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2Props.​description | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2Props.​routeSettings | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2Props.​stageVariables | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | CfnStageV2Props.​tags | moved to package aws-apigatewayv2 | +| @aws-cdk/aws-apigateway | EmptyModel | You should use | +| @aws-cdk/aws-apigateway | EmptyModel.​modelId | You should use | +| @aws-cdk/aws-apigateway | ErrorModel | You should use | +| @aws-cdk/aws-apigateway | ErrorModel.​modelId | You should use | +| @aws-cdk/aws-apigateway | IResource.​restApi | Throws an error if this Resource is not associated with an instance of `RestApi`. Use `api` instead. | +| @aws-cdk/aws-apigateway | LambdaRestApiProps.​options | the `LambdaRestApiProps` now extends `RestApiProps`, so all options are just available here. Note that the options specified in `options` will be overridden by any props specified at the root level. | +| @aws-cdk/aws-apigateway | Method.​restApi | Throws an error if this Resource is not associated with an instance of `RestApi`. Use `api` instead. | +| @aws-cdk/aws-apigateway | Resource.​restApi | Throws an error if this Resource is not associated with an instance of `RestApi`. Use `api` instead. | +| @aws-cdk/aws-apigateway | ResourceBase.​restApi | Throws an error if this Resource is not associated with an instance of `RestApi`. Use `api` instead. | +| @aws-cdk/aws-apigateway | ResourceBase.​url | Throws error in some use cases that have been enabled since this deprecation notice. Use `RestApi.urlForPath()` instead. | +| @aws-cdk/aws-apigateway | RestApiBase.​configureCloudWatchRole() | This method will be made internal. No replacement | +| @aws-cdk/aws-apigateway | RestApiBase.​configureDeployment() | This method will be made internal. No replacement | +| @aws-cdk/aws-apigateway | RestApiOptions | superseded by `RestApiBaseProps` | +| @aws-cdk/aws-apigateway | UsagePlanProps.​apiKey | use `addApiKey()` | +| @aws-cdk/aws-certificatemanager | CertificateProps.​validationDomains | use `validation` instead. | +| @aws-cdk/aws-certificatemanager | CertificateProps.​validationMethod | use `validation` instead. | +| @aws-cdk/aws-route53 | AddressRecordTarget | Use RecordTarget | +| @aws-cdk/custom-resources | Provider.​bind() | use `provider.serviceToken` instead | +| @aws-cdk/aws-cloudformation | CloudFormationCapabilities | use `core.CfnCapabilities` | +| @aws-cdk/aws-cloudformation | CloudFormationCapabilities.​NONE | use `core.CfnCapabilities` | +| @aws-cdk/aws-cloudformation | CloudFormationCapabilities.​ANONYMOUS_​IAM | use `core.CfnCapabilities` | +| @aws-cdk/aws-cloudformation | CloudFormationCapabilities.​NAMED_​IAM | use `core.CfnCapabilities` | +| @aws-cdk/aws-cloudformation | CloudFormationCapabilities.​AUTO_​EXPAND | use `core.CfnCapabilities` | +| @aws-cdk/aws-cloudformation | CustomResource | use `core.CustomResource` | +| @aws-cdk/aws-cloudformation | CustomResourceProps | use `core.CustomResourceProps` | +| @aws-cdk/aws-cloudformation | CustomResourceProps.​provider | use `core.CustomResourceProps` | +| @aws-cdk/aws-cloudformation | CustomResourceProps.​properties | use `core.CustomResourceProps` | +| @aws-cdk/aws-cloudformation | CustomResourceProps.​removalPolicy | use `core.CustomResourceProps` | +| @aws-cdk/aws-cloudformation | CustomResourceProps.​resourceType | use `core.CustomResourceProps` | +| @aws-cdk/aws-cloudformation | CustomResourceProvider | use core.CustomResource instead | +| @aws-cdk/aws-cloudformation | CustomResourceProvider.​serviceToken | use core.CustomResource instead | +| @aws-cdk/aws-cloudformation | CustomResourceProvider.​fromLambda() | use core.CustomResource instead | +| @aws-cdk/aws-cloudformation | CustomResourceProvider.​fromTopic() | use core.CustomResource instead | +| @aws-cdk/aws-cloudformation | CustomResourceProvider.​lambda() | use `fromLambda` | +| @aws-cdk/aws-cloudformation | CustomResourceProvider.​topic() | use `fromTopic` | +| @aws-cdk/aws-cloudformation | CustomResourceProvider.​bind() | use core.CustomResource instead | +| @aws-cdk/aws-cloudformation | CustomResourceProviderConfig | used in {@link ICustomResourceProvider} which is now deprecated | +| @aws-cdk/aws-cloudformation | CustomResourceProviderConfig.​serviceToken | used in {@link ICustomResourceProvider} which is now deprecated | +| @aws-cdk/aws-cloudformation | ICustomResourceProvider | use `core.ICustomResourceProvider` | +| @aws-cdk/aws-cloudformation | ICustomResourceProvider.​bind() | use `core.ICustomResourceProvider` | +| @aws-cdk/aws-cloudformation | NestedStack | use core.NestedStack instead | +| @aws-cdk/aws-cloudformation | NestedStackProps | use core.NestedStackProps instead | +| @aws-cdk/aws-cloudformation | NestedStackProps.​notifications | use core.NestedStackProps instead | +| @aws-cdk/aws-cloudformation | NestedStackProps.​parameters | use core.NestedStackProps instead | +| @aws-cdk/aws-cloudformation | NestedStackProps.​timeout | use core.NestedStackProps instead | +| @aws-cdk/aws-sns | NumericConditions.​whitelist | use `allowlist` | +| @aws-cdk/aws-sns | StringConditions.​blacklist | use `denylist` | +| @aws-cdk/aws-sns | StringConditions.​whitelist | use `allowlist` | +| @aws-cdk/aws-elasticloadbalancingv2 | AddFixedResponseProps | Use `ApplicationListener.addAction` instead. | +| @aws-cdk/aws-elasticloadbalancingv2 | AddRedirectResponseProps | Use `ApplicationListener.addAction` instead. | +| @aws-cdk/aws-elasticloadbalancingv2 | AddRuleProps.​hostHeader | Use `conditions` instead. | +| @aws-cdk/aws-elasticloadbalancingv2 | AddRuleProps.​pathPattern | Use `conditions` instead. | +| @aws-cdk/aws-elasticloadbalancingv2 | AddRuleProps.​pathPatterns | Use `conditions` instead. | +| @aws-cdk/aws-elasticloadbalancingv2 | ApplicationListener.​addCertificateArns() | Use `addCertificates` instead. | +| @aws-cdk/aws-elasticloadbalancingv2 | ApplicationListener.​addFixedResponse() | Use `addAction()` instead | +| @aws-cdk/aws-elasticloadbalancingv2 | ApplicationListener.​addRedirectResponse() | Use `addAction()` instead | +| @aws-cdk/aws-elasticloadbalancingv2 | ApplicationListenerAttributes.​securityGroupAllowsAllOutbound | use `securityGroup` instead | +| @aws-cdk/aws-elasticloadbalancingv2 | ApplicationListenerAttributes.​securityGroupId | use `securityGroup` instead | +| @aws-cdk/aws-elasticloadbalancingv2 | ApplicationListenerCertificateProps.​certificateArns | Use `certificates` instead. | +| @aws-cdk/aws-elasticloadbalancingv2 | ApplicationListenerRule.​addFixedResponse() | Use configureAction instead | +| @aws-cdk/aws-elasticloadbalancingv2 | ApplicationListenerRule.​addRedirectResponse() | Use configureAction instead | +| @aws-cdk/aws-elasticloadbalancingv2 | ApplicationListenerRule.​addTargetGroup() | Use configureAction instead | +| @aws-cdk/aws-elasticloadbalancingv2 | ApplicationListenerRule.​setCondition() | use `addCondition` instead. | +| @aws-cdk/aws-elasticloadbalancingv2 | ApplicationTargetGroup.​import() | Use `fromTargetGroupAttributes` instead | +| @aws-cdk/aws-elasticloadbalancingv2 | BaseApplicationListenerProps.​certificateArns | Use the `certificates` property instead | +| @aws-cdk/aws-elasticloadbalancingv2 | BaseApplicationListenerRuleProps.​fixedResponse | Use `action` instead. | +| @aws-cdk/aws-elasticloadbalancingv2 | BaseApplicationListenerRuleProps.​hostHeader | Use `conditions` instead. | +| @aws-cdk/aws-elasticloadbalancingv2 | BaseApplicationListenerRuleProps.​pathPattern | Use `conditions` instead. | +| @aws-cdk/aws-elasticloadbalancingv2 | BaseApplicationListenerRuleProps.​pathPatterns | Use `conditions` instead. | +| @aws-cdk/aws-elasticloadbalancingv2 | BaseApplicationListenerRuleProps.​redirectResponse | Use `action` instead. | +| @aws-cdk/aws-elasticloadbalancingv2 | ContentType | superceded by `FixedResponseOptions`. | +| @aws-cdk/aws-elasticloadbalancingv2 | ContentType.​TEXT_​PLAIN | superceded by `FixedResponseOptions`. | +| @aws-cdk/aws-elasticloadbalancingv2 | ContentType.​TEXT_​CSS | superceded by `FixedResponseOptions`. | +| @aws-cdk/aws-elasticloadbalancingv2 | ContentType.​TEXT_​HTML | superceded by `FixedResponseOptions`. | +| @aws-cdk/aws-elasticloadbalancingv2 | ContentType.​APPLICATION_​JAVASCRIPT | superceded by `FixedResponseOptions`. | +| @aws-cdk/aws-elasticloadbalancingv2 | ContentType.​APPLICATION_​JSON | superceded by `FixedResponseOptions`. | +| @aws-cdk/aws-elasticloadbalancingv2 | FixedResponse | superceded by `ListenerAction.fixedResponse()`. | +| @aws-cdk/aws-elasticloadbalancingv2 | FixedResponse.​statusCode | superceded by `ListenerAction.fixedResponse()`. | +| @aws-cdk/aws-elasticloadbalancingv2 | FixedResponse.​contentType | superceded by `ListenerAction.fixedResponse()`. | +| @aws-cdk/aws-elasticloadbalancingv2 | FixedResponse.​messageBody | superceded by `ListenerAction.fixedResponse()`. | +| @aws-cdk/aws-elasticloadbalancingv2 | IApplicationListener.​addCertificateArns() | use `addCertificates()` | +| @aws-cdk/aws-elasticloadbalancingv2 | INetworkListenerCertificateProps | Use IListenerCertificate instead | +| @aws-cdk/aws-elasticloadbalancingv2 | InstanceTarget | Use IpTarget from the | +| @aws-cdk/aws-elasticloadbalancingv2 | InstanceTarget.​attachToApplicationTargetGroup() | Use IpTarget from the | +| @aws-cdk/aws-elasticloadbalancingv2 | InstanceTarget.​attachToNetworkTargetGroup() | Use IpTarget from the | +| @aws-cdk/aws-elasticloadbalancingv2 | IpTarget | Use IpTarget from the | +| @aws-cdk/aws-elasticloadbalancingv2 | IpTarget.​attachToApplicationTargetGroup() | Use IpTarget from the | +| @aws-cdk/aws-elasticloadbalancingv2 | IpTarget.​attachToNetworkTargetGroup() | Use IpTarget from the | +| @aws-cdk/aws-elasticloadbalancingv2 | NetworkLoadBalancer.​metricHealthyHostCount() | use ``NetworkTargetGroup.metricHealthyHostCount`` instead | +| @aws-cdk/aws-elasticloadbalancingv2 | NetworkLoadBalancer.​metricUnHealthyHostCount() | use ``NetworkTargetGroup.metricUnHealthyHostCount`` instead | +| @aws-cdk/aws-elasticloadbalancingv2 | NetworkTargetGroup.​import() | Use `fromTargetGroupAttributes` instead | +| @aws-cdk/aws-elasticloadbalancingv2 | RedirectResponse | superceded by `ListenerAction.redirect()`. | +| @aws-cdk/aws-elasticloadbalancingv2 | RedirectResponse.​statusCode | superceded by `ListenerAction.redirect()`. | +| @aws-cdk/aws-elasticloadbalancingv2 | RedirectResponse.​host | superceded by `ListenerAction.redirect()`. | +| @aws-cdk/aws-elasticloadbalancingv2 | RedirectResponse.​path | superceded by `ListenerAction.redirect()`. | +| @aws-cdk/aws-elasticloadbalancingv2 | RedirectResponse.​port | superceded by `ListenerAction.redirect()`. | +| @aws-cdk/aws-elasticloadbalancingv2 | RedirectResponse.​protocol | superceded by `ListenerAction.redirect()`. | +| @aws-cdk/aws-elasticloadbalancingv2 | RedirectResponse.​query | superceded by `ListenerAction.redirect()`. | +| @aws-cdk/aws-elasticloadbalancingv2 | TargetGroupAttributes.​defaultPort | This property is unused and the wrong type. No need to use it. | +| @aws-cdk/aws-elasticloadbalancingv2 | TargetGroupImportProps | Use TargetGroupAttributes instead | +| @aws-cdk/aws-apigatewayv2 | IHttpApi.​httpApiId | use apiId instead | +| @aws-cdk/aws-dynamodb | ITable.​metricSystemErrors() | use `metricSystemErrorsForOperations` | +| @aws-cdk/aws-dynamodb | Table.​grantListStreams() | Use {@link #grantTableListStreams} for more granular permission | +| @aws-cdk/aws-dynamodb | Table.​metricSystemErrors() | use `metricSystemErrorsForOperations`. | +| @aws-cdk/aws-dynamodb | TableOptions.​serverSideEncryption | This property is deprecated. In order to obtain the same behavior as enabling this, set the `encryption` property to `TableEncryption.AWS_MANAGED` instead. | +| @aws-cdk/aws-rds | Credentials.​fromUsername() | use `fromGeneratedSecret()` or `fromPassword()` for new Clusters and Instances. Note that switching from `fromUsername()` to `fromGeneratedSecret()` or `fromPassword()` for already deployed Clusters or Instances will result in their replacement! | +| @aws-cdk/aws-rds | CredentialsFromUsernameOptions | supporting API `fromUsername()` has been deprecated. See deprecation notice of the API. | +| @aws-cdk/aws-rds | CredentialsFromUsernameOptions.​password | supporting API `fromUsername()` has been deprecated. See deprecation notice of the API. | +| @aws-cdk/aws-rds | DatabaseInstanceEngine.​MARIADB | using unversioned engines is an availability risk. We recommend using versioned engines created using the {@link mariaDb()} method | +| @aws-cdk/aws-rds | DatabaseInstanceEngine.​MYSQL | using unversioned engines is an availability risk. We recommend using versioned engines created using the {@link mysql()} method | +| @aws-cdk/aws-rds | DatabaseInstanceEngine.​ORACLE_​EE | using unversioned engines is an availability risk. We recommend using versioned engines created using the {@link oracleEe()} method | +| @aws-cdk/aws-rds | DatabaseInstanceEngine.​ORACLE_​SE | instances can no longer be created with this engine. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | DatabaseInstanceEngine.​ORACLE_​SE1 | instances can no longer be created with this engine. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | DatabaseInstanceEngine.​ORACLE_​SE2 | using unversioned engines is an availability risk. We recommend using versioned engines created using the {@link oracleSe2()} method | +| @aws-cdk/aws-rds | DatabaseInstanceEngine.​POSTGRES | using unversioned engines is an availability risk. We recommend using versioned engines created using the {@link postgres()} method | +| @aws-cdk/aws-rds | DatabaseInstanceEngine.​SQL_​SERVER_​EE | using unversioned engines is an availability risk. We recommend using versioned engines created using the {@link sqlServerEe()} method | +| @aws-cdk/aws-rds | DatabaseInstanceEngine.​SQL_​SERVER_​EX | using unversioned engines is an availability risk. We recommend using versioned engines created using the {@link sqlServerEx()} method | +| @aws-cdk/aws-rds | DatabaseInstanceEngine.​SQL_​SERVER_​SE | using unversioned engines is an availability risk. We recommend using versioned engines created using the {@link sqlServerSe()} method | +| @aws-cdk/aws-rds | DatabaseInstanceEngine.​SQL_​SERVER_​WEB | using unversioned engines is an availability risk. We recommend using versioned engines created using the {@link sqlServerWeb()} method | +| @aws-cdk/aws-rds | DatabaseInstanceEngine.​oracleSe() | instances can no longer be created with this engine. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | DatabaseInstanceEngine.​oracleSe1() | instances can no longer be created with this engine. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | DatabaseInstanceNewProps.​vpcPlacement | use `vpcSubnets` | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​VER_​11_​2 | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​VER_​11_​2_​0_​2_​V2 | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​VER_​11_​2_​0_​4_​V1 | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​VER_​11_​2_​0_​4_​V10 | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​VER_​11_​2_​0_​4_​V11 | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​VER_​11_​2_​0_​4_​V12 | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​VER_​11_​2_​0_​4_​V13 | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​VER_​11_​2_​0_​4_​V14 | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​VER_​11_​2_​0_​4_​V15 | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​VER_​11_​2_​0_​4_​V16 | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​VER_​11_​2_​0_​4_​V17 | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​VER_​11_​2_​0_​4_​V18 | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​VER_​11_​2_​0_​4_​V19 | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​VER_​11_​2_​0_​4_​V20 | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​VER_​11_​2_​0_​4_​V21 | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​VER_​11_​2_​0_​4_​V22 | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​VER_​11_​2_​0_​4_​V23 | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​VER_​11_​2_​0_​4_​V24 | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​VER_​11_​2_​0_​4_​V25 | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​VER_​11_​2_​0_​4_​V3 | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​VER_​11_​2_​0_​4_​V4 | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​VER_​11_​2_​0_​4_​V5 | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​VER_​11_​2_​0_​4_​V6 | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​VER_​11_​2_​0_​4_​V7 | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​VER_​11_​2_​0_​4_​V8 | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​VER_​11_​2_​0_​4_​V9 | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​oracleLegacyFullVersion | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleLegacyEngineVersion.​oracleLegacyMajorVersion | instances can no longer be created with these engine versions. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleSe1InstanceEngineProps | instances can no longer be created with this engine. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleSe1InstanceEngineProps.​version | instances can no longer be created with this engine. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleSeInstanceEngineProps | instances can no longer be created with this engine. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | OracleSeInstanceEngineProps.​version | instances can no longer be created with this engine. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​5 | PostgreSQL 9.5 will reach end of life on February 16, 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​5_​10 | PostgreSQL 9.5 will reach end of life on February 16, 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​5_​12 | PostgreSQL 9.5 will reach end of life on February 16, 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​5_​13 | PostgreSQL 9.5 will reach end of life on February 16, 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​5_​14 | PostgreSQL 9.5 will reach end of life on February 16, 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​5_​15 | PostgreSQL 9.5 will reach end of life on February 16, 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​5_​16 | PostgreSQL 9.5 will reach end of life on February 16, 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​5_​18 | PostgreSQL 9.5 will reach end of life on February 16, 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​5_​19 | PostgreSQL 9.5 will reach end of life on February 16, 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​5_​2 | PostgreSQL 9.5 will reach end of life on February 16, 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​5_​20 | PostgreSQL 9.5 will reach end of life on February 16, 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​5_​21 | PostgreSQL 9.5 will reach end of life on February 16, 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​5_​22 | PostgreSQL 9.5 will reach end of life on February 16, 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​5_​23 | PostgreSQL 9.5 will reach end of life on February 16, 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​5_​4 | PostgreSQL 9.5 will reach end of life on February 16, 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​5_​6 | PostgreSQL 9.5 will reach end of life on February 16, 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​5_​7 | PostgreSQL 9.5 will reach end of life on February 16, 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​5_​9 | PostgreSQL 9.5 will reach end of life on February 16, 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​6 | PostgreSQL 9.6 will reach end of life in November 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​6_​1 | PostgreSQL 9.6 will reach end of life in November 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​6_​10 | PostgreSQL 9.6 will reach end of life in November 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​6_​11 | PostgreSQL 9.6 will reach end of life in November 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​6_​12 | PostgreSQL 9.6 will reach end of life in November 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​6_​14 | PostgreSQL 9.6 will reach end of life in November 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​6_​15 | PostgreSQL 9.6 will reach end of life in November 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​6_​16 | PostgreSQL 9.6 will reach end of life in November 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​6_​17 | PostgreSQL 9.6 will reach end of life in November 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​6_​18 | PostgreSQL 9.6 will reach end of life in November 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​6_​19 | PostgreSQL 9.6 will reach end of life in November 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​6_​2 | PostgreSQL 9.6 will reach end of life in November 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​6_​3 | PostgreSQL 9.6 will reach end of life in November 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​6_​5 | PostgreSQL 9.6 will reach end of life in November 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​6_​6 | PostgreSQL 9.6 will reach end of life in November 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​6_​8 | PostgreSQL 9.6 will reach end of life in November 2021 | +| @aws-cdk/aws-rds | PostgresEngineVersion.​VER_​9_​6_​9 | PostgreSQL 9.6 will reach end of life in November 2021 | +| @aws-cdk/aws-rds | SnapshotCredentials.​fromGeneratedPassword() | use `fromGeneratedSecret()` for new Clusters and Instances. Note that switching from `fromGeneratedPassword()` to `fromGeneratedSecret()` for already deployed Clusters or Instances will update their master password. | +| @aws-cdk/aws-autoscaling | BlockDevice.​mappingEnabled | use `BlockDeviceVolume.noDevice()` as the volume to supress a mapping. | +| @aws-cdk/aws-autoscaling | CommonAutoScalingGroupProps.​notificationsTopic | use `notifications` | +| @aws-cdk/aws-autoscaling | CommonAutoScalingGroupProps.​replacingUpdateMinSuccessfulInstancesPercent | Use `signals` instead | +| @aws-cdk/aws-autoscaling | CommonAutoScalingGroupProps.​resourceSignalCount | Use `signals` instead. | +| @aws-cdk/aws-autoscaling | CommonAutoScalingGroupProps.​resourceSignalTimeout | Use `signals` instead. | +| @aws-cdk/aws-autoscaling | CommonAutoScalingGroupProps.​rollingUpdateConfiguration | Use `updatePolicy` instead | +| @aws-cdk/aws-autoscaling | CommonAutoScalingGroupProps.​updateType | Use `updatePolicy` instead | +| @aws-cdk/aws-autoscaling | RequestCountScalingProps.​targetRequestsPerSecond | Use 'targetRequestsPerMinute' instead | +| @aws-cdk/aws-autoscaling | RollingUpdateConfiguration | use `UpdatePolicy.rollingUpdate()` | +| @aws-cdk/aws-autoscaling | RollingUpdateConfiguration.​maxBatchSize | use `UpdatePolicy.rollingUpdate()` | +| @aws-cdk/aws-autoscaling | RollingUpdateConfiguration.​minInstancesInService | use `UpdatePolicy.rollingUpdate()` | +| @aws-cdk/aws-autoscaling | RollingUpdateConfiguration.​minSuccessfulInstancesPercent | use `UpdatePolicy.rollingUpdate()` | +| @aws-cdk/aws-autoscaling | RollingUpdateConfiguration.​pauseTime | use `UpdatePolicy.rollingUpdate()` | +| @aws-cdk/aws-autoscaling | RollingUpdateConfiguration.​suspendProcesses | use `UpdatePolicy.rollingUpdate()` | +| @aws-cdk/aws-autoscaling | RollingUpdateConfiguration.​waitOnResourceSignals | use `UpdatePolicy.rollingUpdate()` | +| @aws-cdk/aws-autoscaling | UpdateType | Use UpdatePolicy instead | +| @aws-cdk/aws-autoscaling | UpdateType.​NONE | Use UpdatePolicy instead | +| @aws-cdk/aws-autoscaling | UpdateType.​REPLACING_​UPDATE | Use UpdatePolicy instead | +| @aws-cdk/aws-autoscaling | UpdateType.​ROLLING_​UPDATE | Use UpdatePolicy instead | +| @aws-cdk/aws-elasticloadbalancing | LoadBalancerListener.​sslCertificateId | use sslCertificateArn instead | +| @aws-cdk/aws-ecs | BaseService.​configureAwsVpcNetworking() | use configureAwsVpcNetworkingWithSecurityGroups instead. | +| @aws-cdk/aws-ecs | Ec2ServiceProps.​propagateTaskTagsFrom | Use `propagateTags` instead. | +| @aws-cdk/aws-ecs | Ec2ServiceProps.​securityGroup | use securityGroups instead. | +| @aws-cdk/aws-ecs | EcsOptimizedAmi | see {@link EcsOptimizedImage#amazonLinux}, {@link EcsOptimizedImage#amazonLinux} and {@link EcsOptimizedImage#windows} | +| @aws-cdk/aws-ecs | EcsOptimizedAmi.​getImage() | see {@link EcsOptimizedImage#amazonLinux}, {@link EcsOptimizedImage#amazonLinux} and {@link EcsOptimizedImage#windows} | +| @aws-cdk/aws-ecs | EcsOptimizedAmiProps | see {@link EcsOptimizedImage} | +| @aws-cdk/aws-ecs | EcsOptimizedAmiProps.​generation | see {@link EcsOptimizedImage} | +| @aws-cdk/aws-ecs | EcsOptimizedAmiProps.​hardwareType | see {@link EcsOptimizedImage} | +| @aws-cdk/aws-ecs | EcsOptimizedAmiProps.​windowsVersion | see {@link EcsOptimizedImage} | +| @aws-cdk/aws-ecs | FargateServiceProps.​propagateTaskTagsFrom | Use `propagateTags` instead. | +| @aws-cdk/aws-ecs | FargateServiceProps.​securityGroup | use securityGroups instead. | +| @aws-cdk/aws-cloudfront | AliasConfiguration | see {@link CloudFrontWebDistributionProps#viewerCertificate} with {@link ViewerCertificate#acmCertificate} | +| @aws-cdk/aws-cloudfront | AliasConfiguration.​acmCertRef | see {@link CloudFrontWebDistributionProps#viewerCertificate} with {@link ViewerCertificate#acmCertificate} | +| @aws-cdk/aws-cloudfront | AliasConfiguration.​names | see {@link CloudFrontWebDistributionProps#viewerCertificate} with {@link ViewerCertificate#acmCertificate} | +| @aws-cdk/aws-cloudfront | AliasConfiguration.​securityPolicy | see {@link CloudFrontWebDistributionProps#viewerCertificate} with {@link ViewerCertificate#acmCertificate} | +| @aws-cdk/aws-cloudfront | AliasConfiguration.​sslMethod | see {@link CloudFrontWebDistributionProps#viewerCertificate} with {@link ViewerCertificate#acmCertificate} | +| @aws-cdk/aws-cloudfront | Behavior.​trustedSigners | We recommend using trustedKeyGroups instead of trustedSigners. | +| @aws-cdk/aws-cloudfront | CloudFrontWebDistribution.​domainName | Use `distributionDomainName` instead. | +| @aws-cdk/aws-cloudfront | CloudFrontWebDistributionProps.​aliasConfiguration | see {@link CloudFrontWebDistributionProps#viewerCertificate} with {@link ViewerCertificate#acmCertificate} | +| @aws-cdk/aws-cloudfront | GeoRestriction.​blacklist() | use `denylist` | +| @aws-cdk/aws-cloudfront | GeoRestriction.​whitelist() | use `allowlist` | +| @aws-cdk/aws-cloudfront | IDistribution.​domainName | Use `distributionDomainName` instead. | +| @aws-cdk/aws-cloudfront | SourceConfiguration.​originHeaders | Use originHeaders on s3OriginSource or customOriginSource | +| @aws-cdk/aws-cloudfront | SourceConfiguration.​originPath | Use originPath on s3OriginSource or customOriginSource | +| @aws-cdk/aws-cloudtrail | Trail.​onCloudTrailEvent() | use Trail.onEvent() | +| @aws-cdk/aws-cloudtrail | TrailProps.​kmsKey | use encryptionKey instead. | +| @aws-cdk/aws-codepipeline-actions | BitBucketSourceAction | use CodeStarConnectionsSourceAction instead | +| @aws-cdk/aws-codepipeline-actions | BitBucketSourceAction.​actionProperties | use CodeStarConnectionsSourceAction instead | +| @aws-cdk/aws-codepipeline-actions | BitBucketSourceAction.​bind() | use CodeStarConnectionsSourceAction instead | +| @aws-cdk/aws-codepipeline-actions | BitBucketSourceAction.​onStateChange() | use CodeStarConnectionsSourceAction instead | +| @aws-cdk/aws-codepipeline-actions | BitBucketSourceActionProps | use CodeStarConnectionsSourceActionProps instead | +| @aws-cdk/aws-codepipeline-actions | CloudFormationCreateReplaceChangeSetActionProps.​capabilities | use {@link cfnCapabilities} instead | +| @aws-cdk/aws-codepipeline-actions | CloudFormationCreateUpdateStackActionProps.​capabilities | use {@link cfnCapabilities} instead | +| @aws-cdk/aws-codepipeline-actions | CloudFormationDeleteStackActionProps.​capabilities | use {@link cfnCapabilities} instead | +| @aws-cdk/aws-events-targets | EcsTask.​securityGroup | use securityGroups instead. | +| @aws-cdk/aws-events-targets | EcsTaskProps.​securityGroup | use securityGroups instead | +| @aws-cdk/aws-stepfunctions | Context | replaced by `JsonPath` | +| @aws-cdk/aws-stepfunctions | Context.​entireContext | replaced by `JsonPath` | +| @aws-cdk/aws-stepfunctions | Context.​taskToken | replaced by `JsonPath` | +| @aws-cdk/aws-stepfunctions | Context.​numberAt() | replaced by `JsonPath` | +| @aws-cdk/aws-stepfunctions | Context.​stringAt() | replaced by `JsonPath` | +| @aws-cdk/aws-stepfunctions | Data | replaced by `JsonPath` | +| @aws-cdk/aws-stepfunctions | Data.​entirePayload | replaced by `JsonPath` | +| @aws-cdk/aws-stepfunctions | Data.​isJsonPathString() | replaced by `JsonPath` | +| @aws-cdk/aws-stepfunctions | Data.​listAt() | replaced by `JsonPath` | +| @aws-cdk/aws-stepfunctions | Data.​numberAt() | replaced by `JsonPath` | +| @aws-cdk/aws-stepfunctions | Data.​stringAt() | replaced by `JsonPath` | +| @aws-cdk/aws-stepfunctions | IStepFunctionsTask | replaced by `TaskStateBase`. | +| @aws-cdk/aws-stepfunctions | IStepFunctionsTask.​bind() | replaced by `TaskStateBase`. | +| @aws-cdk/aws-stepfunctions | StepFunctionsTaskConfig | used by `IStepFunctionsTask`. `IStepFunctionsTask` is deprecated and replaced by `TaskStateBase`. | +| @aws-cdk/aws-stepfunctions | StepFunctionsTaskConfig.​resourceArn | used by `IStepFunctionsTask`. `IStepFunctionsTask` is deprecated and replaced by `TaskStateBase`. | +| @aws-cdk/aws-stepfunctions | StepFunctionsTaskConfig.​heartbeat | used by `IStepFunctionsTask`. `IStepFunctionsTask` is deprecated and replaced by `TaskStateBase`. | +| @aws-cdk/aws-stepfunctions | StepFunctionsTaskConfig.​metricDimensions | used by `IStepFunctionsTask`. `IStepFunctionsTask` is deprecated and replaced by `TaskStateBase`. | +| @aws-cdk/aws-stepfunctions | StepFunctionsTaskConfig.​metricPrefixPlural | used by `IStepFunctionsTask`. `IStepFunctionsTask` is deprecated and replaced by `TaskStateBase`. | +| @aws-cdk/aws-stepfunctions | StepFunctionsTaskConfig.​metricPrefixSingular | used by `IStepFunctionsTask`. `IStepFunctionsTask` is deprecated and replaced by `TaskStateBase`. | +| @aws-cdk/aws-stepfunctions | StepFunctionsTaskConfig.​parameters | used by `IStepFunctionsTask`. `IStepFunctionsTask` is deprecated and replaced by `TaskStateBase`. | +| @aws-cdk/aws-stepfunctions | StepFunctionsTaskConfig.​policyStatements | used by `IStepFunctionsTask`. `IStepFunctionsTask` is deprecated and replaced by `TaskStateBase`. | +| @aws-cdk/aws-stepfunctions | Task | replaced by service integration specific classes (i.e. LambdaInvoke, SnsPublish) | +| @aws-cdk/aws-stepfunctions | Task.​endStates | replaced by service integration specific classes (i.e. LambdaInvoke, SnsPublish) | +| @aws-cdk/aws-stepfunctions | Task.​addCatch() | replaced by service integration specific classes (i.e. LambdaInvoke, SnsPublish) | +| @aws-cdk/aws-stepfunctions | Task.​addRetry() | replaced by service integration specific classes (i.e. LambdaInvoke, SnsPublish) | +| @aws-cdk/aws-stepfunctions | Task.​metric() | replaced by service integration specific classes (i.e. LambdaInvoke, SnsPublish) | +| @aws-cdk/aws-stepfunctions | Task.​metricFailed() | replaced by service integration specific classes (i.e. LambdaInvoke, SnsPublish) | +| @aws-cdk/aws-stepfunctions | Task.​metricHeartbeatTimedOut() | replaced by service integration specific classes (i.e. LambdaInvoke, SnsPublish) | +| @aws-cdk/aws-stepfunctions | Task.​metricRunTime() | replaced by service integration specific classes (i.e. LambdaInvoke, SnsPublish) | +| @aws-cdk/aws-stepfunctions | Task.​metricScheduled() | replaced by service integration specific classes (i.e. LambdaInvoke, SnsPublish) | +| @aws-cdk/aws-stepfunctions | Task.​metricScheduleTime() | replaced by service integration specific classes (i.e. LambdaInvoke, SnsPublish) | +| @aws-cdk/aws-stepfunctions | Task.​metricStarted() | replaced by service integration specific classes (i.e. LambdaInvoke, SnsPublish) | +| @aws-cdk/aws-stepfunctions | Task.​metricSucceeded() | replaced by service integration specific classes (i.e. LambdaInvoke, SnsPublish) | +| @aws-cdk/aws-stepfunctions | Task.​metricTime() | replaced by service integration specific classes (i.e. LambdaInvoke, SnsPublish) | +| @aws-cdk/aws-stepfunctions | Task.​metricTimedOut() | replaced by service integration specific classes (i.e. LambdaInvoke, SnsPublish) | +| @aws-cdk/aws-stepfunctions | Task.​next() | replaced by service integration specific classes (i.e. LambdaInvoke, SnsPublish) | +| @aws-cdk/aws-stepfunctions | Task.​toStateJson() | replaced by service integration specific classes (i.e. LambdaInvoke, SnsPublish) | +| @aws-cdk/aws-stepfunctions | Task.​whenBoundToGraph() | replaced by service integration specific classes (i.e. LambdaInvoke, SnsPublish) | +| @aws-cdk/aws-stepfunctions | TaskProps | replaced by service integration specific classes (i.e. LambdaInvoke, SnsPublish) | +| @aws-cdk/aws-stepfunctions | TaskProps.​task | replaced by service integration specific classes (i.e. LambdaInvoke, SnsPublish) | +| @aws-cdk/aws-stepfunctions | TaskProps.​comment | replaced by service integration specific classes (i.e. LambdaInvoke, SnsPublish) | +| @aws-cdk/aws-stepfunctions | TaskProps.​inputPath | replaced by service integration specific classes (i.e. LambdaInvoke, SnsPublish) | +| @aws-cdk/aws-stepfunctions | TaskProps.​outputPath | replaced by service integration specific classes (i.e. LambdaInvoke, SnsPublish) | +| @aws-cdk/aws-stepfunctions | TaskProps.​parameters | replaced by service integration specific classes (i.e. LambdaInvoke, SnsPublish) | +| @aws-cdk/aws-stepfunctions | TaskProps.​resultPath | replaced by service integration specific classes (i.e. LambdaInvoke, SnsPublish) | +| @aws-cdk/aws-stepfunctions | TaskProps.​timeout | replaced by service integration specific classes (i.e. LambdaInvoke, SnsPublish) | +| @aws-cdk/aws-ecs-patterns | ApplicationLoadBalancedServiceBase.​desiredCount | Use `internalDesiredCount` instead. | +| @aws-cdk/aws-ecs-patterns | ApplicationMultipleTargetGroupsServiceBase.​desiredCount | Use `internalDesiredCount` instead. | +| @aws-cdk/aws-ecs-patterns | NetworkLoadBalancedServiceBase.​desiredCount | Use `internalDesiredCount` instead. | +| @aws-cdk/aws-ecs-patterns | NetworkMultipleTargetGroupsServiceBase.​desiredCount | Use `internalDesiredCount` instead. | +| @aws-cdk/aws-ecs-patterns | QueueProcessingServiceBase.​desiredCount | Use `minCapacity` instead. | +| @aws-cdk/aws-ecs-patterns | QueueProcessingServiceBaseProps.​desiredTaskCount | Use `minScalingCapacity` or a literal object instead. | +| @aws-cdk/aws-eks | NodegroupOptions.​instanceType | Use `instanceTypes` instead. | +| @aws-cdk/aws-eks | ServiceAccount.​addToPolicy() | use `addToPrincipalPolicy()` | +| @aws-cdk/aws-s3-deployment | Expires | use core.Expiration | +| @aws-cdk/aws-s3-deployment | Expires.​value | use core.Expiration | +| @aws-cdk/aws-s3-deployment | Expires.​after() | use core.Expiration | +| @aws-cdk/aws-s3-deployment | Expires.​atDate() | use core.Expiration | +| @aws-cdk/aws-s3-deployment | Expires.​atTimestamp() | use core.Expiration | +| @aws-cdk/aws-s3-deployment | Expires.​fromString() | use core.Expiration | +| @aws-cdk/aws-ses | WhiteListReceiptFilter | use `AllowListReceiptFilter` | +| @aws-cdk/aws-ses | WhiteListReceiptFilterProps | use `AllowListReceiptFilterProps` | +| @aws-cdk/aws-stepfunctions-tasks | EcsRunTaskBase | No replacement | +| @aws-cdk/aws-stepfunctions-tasks | EcsRunTaskBase.​connections | No replacement | +| @aws-cdk/aws-stepfunctions-tasks | EcsRunTaskBase.​bind() | No replacement | +| @aws-cdk/aws-stepfunctions-tasks | EcsRunTaskBase.​configureAwsVpcNetworking() | No replacement | +| @aws-cdk/aws-stepfunctions-tasks | EcsRunTaskBaseProps | No replacement | +| @aws-cdk/aws-stepfunctions-tasks | EcsRunTaskBaseProps.​parameters | No replacement | +| @aws-cdk/aws-stepfunctions-tasks | InvocationType | use `LambdaInvocationType` | +| @aws-cdk/aws-stepfunctions-tasks | InvocationType.​REQUEST_​RESPONSE | use `LambdaInvocationType` | +| @aws-cdk/aws-stepfunctions-tasks | InvocationType.​EVENT | use `LambdaInvocationType` | +| @aws-cdk/aws-stepfunctions-tasks | InvocationType.​DRY_​RUN | use `LambdaInvocationType` | +| @aws-cdk/aws-stepfunctions-tasks | InvokeActivity | use `StepFunctionsInvokeActivity` | +| @aws-cdk/aws-stepfunctions-tasks | InvokeActivity.​bind() | use `StepFunctionsInvokeActivity` | +| @aws-cdk/aws-stepfunctions-tasks | InvokeActivityProps | use `StepFunctionsInvokeActivity` and `StepFunctionsInvokeActivityProps`. | +| @aws-cdk/aws-stepfunctions-tasks | InvokeActivityProps.​heartbeat | use `StepFunctionsInvokeActivity` and `StepFunctionsInvokeActivityProps`. | +| @aws-cdk/aws-stepfunctions-tasks | InvokeFunction | Use `LambdaInvoke` | +| @aws-cdk/aws-stepfunctions-tasks | InvokeFunction.​bind() | Use `LambdaInvoke` | +| @aws-cdk/aws-stepfunctions-tasks | InvokeFunctionProps | use `LambdaInvoke` | +| @aws-cdk/aws-stepfunctions-tasks | InvokeFunctionProps.​payload | use `LambdaInvoke` | +| @aws-cdk/aws-stepfunctions-tasks | PublishToTopic | Use `SnsPublish` | +| @aws-cdk/aws-stepfunctions-tasks | PublishToTopic.​bind() | Use `SnsPublish` | +| @aws-cdk/aws-stepfunctions-tasks | PublishToTopicProps | Use `SnsPublish` | +| @aws-cdk/aws-stepfunctions-tasks | PublishToTopicProps.​message | Use `SnsPublish` | +| @aws-cdk/aws-stepfunctions-tasks | PublishToTopicProps.​integrationPattern | Use `SnsPublish` | +| @aws-cdk/aws-stepfunctions-tasks | PublishToTopicProps.​messagePerSubscriptionType | Use `SnsPublish` | +| @aws-cdk/aws-stepfunctions-tasks | PublishToTopicProps.​subject | Use `SnsPublish` | +| @aws-cdk/aws-stepfunctions-tasks | RunBatchJob | use `BatchSubmitJob` | +| @aws-cdk/aws-stepfunctions-tasks | RunBatchJob.​bind() | use `BatchSubmitJob` | +| @aws-cdk/aws-stepfunctions-tasks | RunBatchJobProps | use `BatchSubmitJob` | +| @aws-cdk/aws-stepfunctions-tasks | RunBatchJobProps.​jobDefinitionArn | use `BatchSubmitJob` | +| @aws-cdk/aws-stepfunctions-tasks | RunBatchJobProps.​jobName | use `BatchSubmitJob` | +| @aws-cdk/aws-stepfunctions-tasks | RunBatchJobProps.​jobQueueArn | use `BatchSubmitJob` | +| @aws-cdk/aws-stepfunctions-tasks | RunBatchJobProps.​arraySize | use `BatchSubmitJob` | +| @aws-cdk/aws-stepfunctions-tasks | RunBatchJobProps.​attempts | use `BatchSubmitJob` | +| @aws-cdk/aws-stepfunctions-tasks | RunBatchJobProps.​containerOverrides | use `BatchSubmitJob` | +| @aws-cdk/aws-stepfunctions-tasks | RunBatchJobProps.​dependsOn | use `BatchSubmitJob` | +| @aws-cdk/aws-stepfunctions-tasks | RunBatchJobProps.​integrationPattern | use `BatchSubmitJob` | +| @aws-cdk/aws-stepfunctions-tasks | RunBatchJobProps.​payload | use `BatchSubmitJob` | +| @aws-cdk/aws-stepfunctions-tasks | RunBatchJobProps.​timeout | use `BatchSubmitJob` | +| @aws-cdk/aws-stepfunctions-tasks | RunEcsEc2Task | replaced by `EcsRunTask` | +| @aws-cdk/aws-stepfunctions-tasks | RunEcsEc2TaskProps | use `EcsRunTask` and `EcsRunTaskProps` | +| @aws-cdk/aws-stepfunctions-tasks | RunEcsEc2TaskProps.​placementConstraints | use `EcsRunTask` and `EcsRunTaskProps` | +| @aws-cdk/aws-stepfunctions-tasks | RunEcsEc2TaskProps.​placementStrategies | use `EcsRunTask` and `EcsRunTaskProps` | +| @aws-cdk/aws-stepfunctions-tasks | RunEcsEc2TaskProps.​securityGroup | use `EcsRunTask` and `EcsRunTaskProps` | +| @aws-cdk/aws-stepfunctions-tasks | RunEcsEc2TaskProps.​subnets | use `EcsRunTask` and `EcsRunTaskProps` | +| @aws-cdk/aws-stepfunctions-tasks | RunEcsFargateTask | replaced by `EcsRunTask` | +| @aws-cdk/aws-stepfunctions-tasks | RunEcsFargateTaskProps | replaced by `EcsRunTask` and `EcsRunTaskProps` | +| @aws-cdk/aws-stepfunctions-tasks | RunEcsFargateTaskProps.​assignPublicIp | replaced by `EcsRunTask` and `EcsRunTaskProps` | +| @aws-cdk/aws-stepfunctions-tasks | RunEcsFargateTaskProps.​platformVersion | replaced by `EcsRunTask` and `EcsRunTaskProps` | +| @aws-cdk/aws-stepfunctions-tasks | RunEcsFargateTaskProps.​securityGroup | replaced by `EcsRunTask` and `EcsRunTaskProps` | +| @aws-cdk/aws-stepfunctions-tasks | RunEcsFargateTaskProps.​subnets | replaced by `EcsRunTask` and `EcsRunTaskProps` | +| @aws-cdk/aws-stepfunctions-tasks | RunGlueJobTask | use `GlueStartJobRun` | +| @aws-cdk/aws-stepfunctions-tasks | RunGlueJobTask.​bind() | use `GlueStartJobRun` | +| @aws-cdk/aws-stepfunctions-tasks | RunGlueJobTaskProps | use `GlueStartJobRun` | +| @aws-cdk/aws-stepfunctions-tasks | RunGlueJobTaskProps.​arguments | use `GlueStartJobRun` | +| @aws-cdk/aws-stepfunctions-tasks | RunGlueJobTaskProps.​integrationPattern | use `GlueStartJobRun` | +| @aws-cdk/aws-stepfunctions-tasks | RunGlueJobTaskProps.​notifyDelayAfter | use `GlueStartJobRun` | +| @aws-cdk/aws-stepfunctions-tasks | RunGlueJobTaskProps.​securityConfiguration | use `GlueStartJobRun` | +| @aws-cdk/aws-stepfunctions-tasks | RunGlueJobTaskProps.​timeout | use `GlueStartJobRun` | +| @aws-cdk/aws-stepfunctions-tasks | RunLambdaTask | Use `LambdaInvoke` | +| @aws-cdk/aws-stepfunctions-tasks | RunLambdaTask.​bind() | Use `LambdaInvoke` | +| @aws-cdk/aws-stepfunctions-tasks | RunLambdaTaskProps | Use `LambdaInvoke` | +| @aws-cdk/aws-stepfunctions-tasks | RunLambdaTaskProps.​clientContext | Use `LambdaInvoke` | +| @aws-cdk/aws-stepfunctions-tasks | RunLambdaTaskProps.​integrationPattern | Use `LambdaInvoke` | +| @aws-cdk/aws-stepfunctions-tasks | RunLambdaTaskProps.​invocationType | Use `LambdaInvoke` | +| @aws-cdk/aws-stepfunctions-tasks | RunLambdaTaskProps.​payload | Use `LambdaInvoke` | +| @aws-cdk/aws-stepfunctions-tasks | RunLambdaTaskProps.​qualifier | Use `LambdaInvoke` | +| @aws-cdk/aws-stepfunctions-tasks | SendToQueue | Use `SqsSendMessage` | +| @aws-cdk/aws-stepfunctions-tasks | SendToQueue.​bind() | Use `SqsSendMessage` | +| @aws-cdk/aws-stepfunctions-tasks | SendToQueueProps | Use `SqsSendMessage` | +| @aws-cdk/aws-stepfunctions-tasks | SendToQueueProps.​messageBody | Use `SqsSendMessage` | +| @aws-cdk/aws-stepfunctions-tasks | SendToQueueProps.​delay | Use `SqsSendMessage` | +| @aws-cdk/aws-stepfunctions-tasks | SendToQueueProps.​integrationPattern | Use `SqsSendMessage` | +| @aws-cdk/aws-stepfunctions-tasks | SendToQueueProps.​messageDeduplicationId | Use `SqsSendMessage` | +| @aws-cdk/aws-stepfunctions-tasks | SendToQueueProps.​messageGroupId | Use `SqsSendMessage` | +| @aws-cdk/aws-stepfunctions-tasks | StartExecution | use 'StepFunctionsStartExecution' | +| @aws-cdk/aws-stepfunctions-tasks | StartExecution.​bind() | use 'StepFunctionsStartExecution' | +| @aws-cdk/aws-stepfunctions-tasks | StartExecutionProps | use 'StepFunctionsStartExecution' | +| @aws-cdk/aws-stepfunctions-tasks | StartExecutionProps.​input | use 'StepFunctionsStartExecution' | +| @aws-cdk/aws-stepfunctions-tasks | StartExecutionProps.​integrationPattern | use 'StepFunctionsStartExecution' | +| @aws-cdk/aws-stepfunctions-tasks | StartExecutionProps.​name | use 'StepFunctionsStartExecution' | +| @aws-cdk/pipelines | SimpleSynthActionProps.​buildCommand | Use `buildCommands` instead | +| @aws-cdk/pipelines | SimpleSynthActionProps.​installCommand | Use `installCommands` instead | diff --git a/README.md b/README.md index 79e66ffa1f12d..44313c65df9d4 100644 --- a/README.md +++ b/README.md @@ -133,7 +133,7 @@ You may also find help on these community resources: * Ask a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/aws-cdk) and tag it with `aws-cdk` -### Roadmap +## Roadmap The [AWS CDK Roadmap project board](https://github.com/orgs/aws/projects/7) lets developers know about our upcoming features and priorities to help them plan how to best leverage the CDK and identify opportunities to contribute to the project. See [ROADMAP.md](https://github.com/aws/aws-cdk/blob/master/ROADMAP.md) for more information and FAQs. @@ -143,6 +143,12 @@ We welcome community contributions and pull requests. See [CONTRIBUTING.md](./CONTRIBUTING.md) for information on how to set up a development environment and submit code. +## Metrics collection +This solution collects anonymous operational metrics to help AWS improve the +quality and features of the CDK. For more information, including how to disable +this capability, please see the +[developer guide](https://docs.aws.amazon.com/cdk/latest/guide/cli.html#version_reporting). + ## More Resources * [CDK Workshop](https://cdkworkshop.com/) * [Examples](https://github.com/aws-samples/aws-cdk-examples) diff --git a/allowed-breaking-changes.txt b/allowed-breaking-changes.txt index 0f5c6dc507097..47f19a6719d17 100644 --- a/allowed-breaking-changes.txt +++ b/allowed-breaking-changes.txt @@ -61,3 +61,16 @@ weakened:@aws-cdk/cloud-assembly-schema.FileSource # These are fine, since they shouldn't be widely used. weakened:@aws-cdk/core.FileAssetLocation weakened:@aws-cdk/aws-events.RuleTargetConfig + +# replace interface with untyped properties to order to break stable to experimental dependencies +removed:@aws-cdk/aws-stepfunctions-tasks.CallApiGatewayHttpApiEndpointProps.api +strengthened:@aws-cdk/aws-stepfunctions-tasks.CallApiGatewayHttpApiEndpointProps +removed:@aws-cdk/aws-route53-targets.ApiGatewayv2Domain +removed:@aws-cdk/aws-stepfunctions-tasks.RunBatchJobProps.jobDefinition +removed:@aws-cdk/aws-stepfunctions-tasks.RunBatchJobProps.jobDefinition +removed:@aws-cdk/aws-stepfunctions-tasks.RunBatchJobProps.jobQueue +removed:@aws-cdk/aws-stepfunctions-tasks.BatchSubmitJobProps.jobQueue +removed:@aws-cdk/aws-stepfunctions-tasks.BatchSubmitJobProps.jobDefinition +strengthened:@aws-cdk/aws-stepfunctions-tasks.BatchSubmitJobProps +removed:@aws-cdk/aws-lambda-event-sources.ManagedKafkaEventSourceProps.cluster +strengthened:@aws-cdk/aws-lambda-event-sources.ManagedKafkaEventSourceProps diff --git a/design/aws-ecs/aws-ecs-scheduled-ecs-task-construct.md b/design/aws-ecs/aws-ecs-scheduled-ecs-task-construct.md index 921196c3c1bf7..dad04821f9742 100644 --- a/design/aws-ecs/aws-ecs-scheduled-ecs-task-construct.md +++ b/design/aws-ecs/aws-ecs-scheduled-ecs-task-construct.md @@ -112,7 +112,7 @@ export interface ScheduledEc2TaskProps { The `ScheduledEc2Task` construct will use the following existing constructs: * Ec2TaskDefinition - To create a Task Definition for the container to start -* Ec2EventRuleTarget - The target of the aws event +* Ec2EventRuleTarget - The target of the AWS event * EventRule - To describe the event trigger (in this case, a scheduled run) An example use case to create a task that is scheduled to run every minute: diff --git a/pack.sh b/pack.sh index b85c92f3e68a5..d270fb28271c5 100755 --- a/pack.sh +++ b/pack.sh @@ -4,7 +4,7 @@ # later read by bundle-beta.sh. set -eu export PATH=$PWD/node_modules/.bin:$PATH -export NODE_OPTIONS="--max-old-space-size=4096 ${NODE_OPTIONS:-}" +export NODE_OPTIONS="--max-old-space-size=8192 ${NODE_OPTIONS:-}" root=$PWD # Get version and changelog file name (these require that .versionrc.json would have been generated) diff --git a/package.json b/package.json index f82766ba1d48f..3084c5a4bc032 100644 --- a/package.json +++ b/package.json @@ -7,25 +7,30 @@ }, "scripts": { "pkglint": "lerna --scope pkglint run build && lerna run pkglint", + "prebuild": "node ./scripts/check-yarn-lock.js", "build": "./build.sh", "pack": "./pack.sh", "compat": "./scripts/check-api-compatibility.sh", "bump": "./bump.sh", - "build-all": "tsc -b" + "build-all": "tsc -b", + "postinstall": "patch-package --error-on-fail" }, "devDependencies": { + "@yarnpkg/lockfile": "^1.1.0", "conventional-changelog-cli": "^2.1.1", "fs-extra": "^9.1.0", "graceful-fs": "^4.2.6", "jest-junit": "^12.0.0", - "jsii-diff": "^1.25.0", - "jsii-pacmak": "^1.25.0", - "jsii-rosetta": "^1.25.0", - "lerna": "^3.22.1", - "standard-version": "^9.1.1", + "jsii-diff": "^1.29.0", + "jsii-pacmak": "^1.29.0", + "jsii-reflect": "^1.29.0", + "jsii-rosetta": "^1.29.0", + "lerna": "^4.0.0", + "patch-package": "^6.4.7", + "standard-version": "^9.3.0", "typescript": "~3.9.9" }, - "resolutions-comment": "should be removed or reviewed when nodeunit dependency is dropped or adjusted", + "tap-mocha-reporter-resolutions-comment": "should be removed or reviewed when nodeunit dependency is dropped or adjusted", "resolutions": { "tap-mocha-reporter": "^5.0.1" }, @@ -38,6 +43,21 @@ "name": "Amazon Web Services", "url": "https://aws.amazon.com" }, + "nozem": { + "$comment": [ + "these files are read by pkglint and cdk-build-tools tests for almost every package.", + "Rather than add them to each package.json individually, do it globally here." + ], + "globalNonPackageFiles": [ + "package.json", + "release.json", + "scripts/resolve-version.js", + "scripts/resolve-version-lib.js", + "version.v1.json" + ], + "cacheBucket": "nozem-artifacts-eu", + "cacheBucketRegion": "eu-west-1" + }, "workspaces": { "packages": [ "packages/*", @@ -51,6 +71,8 @@ "nohoist": [ "**/jszip", "**/jszip/**", + "@aws-cdk/aws-codebuild/yaml", + "@aws-cdk/aws-codebuild/yaml/**", "@aws-cdk/aws-codepipeline-actions/case", "@aws-cdk/aws-codepipeline-actions/case/**", "@aws-cdk/aws-cognito/punycode", @@ -63,6 +85,8 @@ "@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/@balena/dockerignore", "@aws-cdk/core/@balena/dockerignore/**", "@aws-cdk/core/fs-extra", diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/environment.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/environment.ts index d83c286f0cdd6..85247062cde7b 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/environment.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/environment.ts @@ -8,18 +8,19 @@ import { EnvironmentCapacityType } from './extensions/extension-interfaces'; import { Construct } from '@aws-cdk/core'; /** - * Settings for the environment you want to deploy. - * services within. + * Settings for the environment where you want to deploy your services. */ export interface EnvironmentProps { /** - * The VPC used by the service for networking + * The VPC used by the service for networking. + * * @default - Create a new VPC */ readonly vpc?: ec2.IVpc, /** * The ECS cluster which provides compute capacity to this service. + * * [disable-awslint:ref-via-interface] * @default - Create a new cluster */ @@ -27,6 +28,7 @@ export interface EnvironmentProps { /** * The type of capacity to use for this environment. + * * @default - EnvironmentCapacityType.FARGATE */ readonly capacityType?: EnvironmentCapacityType @@ -64,8 +66,8 @@ export interface IEnvironment { /** * An environment into which to deploy a service. This environment - * can either be instantiated with a preexisting AWS VPC and ECS cluster, - * or it can create it's own VPC and cluster. By default it will create + * can either be instantiated with a pre-existing AWS VPC and ECS cluster, + * or it can create its own VPC and cluster. By default, it will create * a cluster with Fargate capacity. */ export class Environment extends Construct implements IEnvironment { @@ -82,7 +84,7 @@ export class Environment extends Construct implements IEnvironment { public readonly id: string; /** - * The VPC into which environment services should be placed. + * The VPC where environment services should be placed. */ public readonly vpc: ec2.IVpc; @@ -159,10 +161,10 @@ export class ImportedEnvironment extends Construct implements IEnvironment { } /** - * Refuses to add a default cloudmap namespace to the cluster as we don't + * Adding a default cloudmap namespace to the cluster will throw an error, as we don't * own it. */ addDefaultCloudMapNamespace(_options: ecs.CloudMapNamespaceOptions) { throw new Error('the cluster environment is immutable when imported'); } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/appmesh.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/appmesh.ts index 95220dc1ea3b4..5442cb4fd6d15 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/appmesh.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/appmesh.ts @@ -21,7 +21,7 @@ const APP_MESH_ENVOY_SIDECAR_VERSION = 'v1.15.1.0-prod'; */ export interface MeshProps { /** - * The service mesh into which to register the service + * The service mesh into which to register the service. */ readonly mesh: appmesh.Mesh; @@ -39,9 +39,9 @@ export interface MeshProps { * to the container in a service mesh. * * The service will then be available to other App Mesh services at the - * address `.`. For example a service called + * address `.`. For example, a service called * `orders` deploying in an environment called `production` would be accessible - * to other App Mesh enabled services at the address `http://orders.production` + * to other App Mesh enabled services at the address `http://orders.production`. */ export class AppMeshExtension extends ServiceExtension { protected virtualNode!: appmesh.VirtualNode; @@ -249,7 +249,7 @@ export class AppMeshExtension extends ServiceExtension { } as ServiceBuild; } - // Now that the service is defined we can create the AppMesh virtual service + // Now that the service is defined, we can create the AppMesh virtual service // and virtual node for the real service public useService(service: ecs.Ec2Service | ecs.FargateService) { const containerextension = this.parentService.serviceDescription.get('service-container') as Container; diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/cloudwatch-agent.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/cloudwatch-agent.ts index ceed938e995cb..9096b43aabd3a 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/cloudwatch-agent.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/cloudwatch-agent.ts @@ -11,7 +11,7 @@ const CLOUDWATCH_AGENT_IMAGE = 'amazon/cloudwatch-agent:latest'; /** * This extension adds a CloudWatch agent to the task definition and - * configures the task to be able to publish metrics to CloudWatch + * configures the task to be able to publish metrics to CloudWatch. */ export class CloudwatchAgentExtension extends ServiceExtension { private CW_CONFIG_CONTENT = { diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/container.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/container.ts index 1bbc61ff4f8f7..10c61401e90d3 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/container.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/container.ts @@ -7,32 +7,33 @@ import { ServiceExtension } from './extension-interfaces'; import { Construct } from '@aws-cdk/core'; /** - * Setting for the main application container of a service + * Setting for the main application container of a service. */ export interface ContainerExtensionProps { /** - * How much CPU the container requires + * How much CPU the container requires. */ readonly cpu: number, /** - * How much memory in megabytes the container requires + * How much memory in megabytes the container requires. */ readonly memoryMiB: number, /** - * The image to run + * The image to run. */ readonly image: ecs.ContainerImage, /** - * What port the image listen for traffic on + * What port the image listen for traffic on. */ readonly trafficPort: number, /** - * Environment variables to pass into the container - * @default - No environment variables + * Environment variables to pass into the container. + * + * @default - No environment variables. */ readonly environment?: { [key: string]: string, @@ -51,7 +52,7 @@ export class Container extends ServiceExtension { public readonly trafficPort: number; /** - * The settings for the container + * The settings for the container. */ private props: ContainerExtensionProps; diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/extension-interfaces.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/extension-interfaces.ts index fa0d42602c563..8e70a53a59d8e 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/extension-interfaces.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/extension-interfaces.ts @@ -7,77 +7,83 @@ import { Service } from '../service'; import { Construct } from '@aws-cdk/core'; /** - * A list of the capacity types that are supported. These - * capacity types may change the behavior of an extension. + * The types of capacity that are supported. These capacity types may change the + * behavior of an extension. */ export enum EnvironmentCapacityType { /** * Specify that the environment should use AWS Fargate for - * hosting containers + * hosting containers. */ FARGATE = 'fargate', /** * Specify that the environment should launch containers onto - * EC2 instances + * EC2 instances. */ EC2 = 'ec2' } /** - * A service props that is in the process of being assembled - * Eventually to be assigned to a ecs.Ec2ServiceProps - * or ecs.FargateServiceProps depending on the environment's - * capacity type. + * A set of mutable service props in the process of being assembled using a + * builder pattern. They will eventually to be translated into an + * ecs.Ec2ServiceProps or ecs.FargateServiceProps interface, depending on the + * environment's capacity type. */ export interface ServiceBuild { /** - * The cluster in which to add the service + * The cluster in which to launch the service. */ readonly cluster: ecs.ICluster, /** - * The task definition registered to this service + * The task definition registered to this service. */ readonly taskDefinition: ecs.TaskDefinition, /** - * Specifies whether the task's elastic network interface receives a public IP address. + * Specifies whether the task's elastic network interface receives a public IP + * address. * * If true, each task will receive a public IP address. * - * @default false + * @default - false */ readonly assignPublicIp?: boolean; /** - * Configuration for how to register the service in service discovery + * Configuration for how to register the service in service discovery. + * * @default - No Cloud Map configured */ readonly cloudMapOptions?: ecs.CloudMapOptions /** - * During initial task startup how long the healthcheck can fail before + * How long the healthcheck can fail during initial task startup before * the task is considered unhealthy. This is used to give the task more - * time to start passing healthchecks + * time to start passing healthchecks. + * * @default - No grace period */ readonly healthCheckGracePeriod?: cdk.Duration, /** - * How many tasks to run + * How many tasks to run. + * * @default - 1 */ readonly desiredCount?: number; /** - * Minimum healthy task percentage + * Minimum healthy task percentage. + * * @default - 100 */ readonly minHealthyPercent?: number; /** - * Maximum percentage of tasks that can be launched + * Maximum percentage of tasks that can be launched. + * * @default - 200 */ readonly maxHealthyPercent?: number; @@ -85,27 +91,27 @@ export interface ServiceBuild { /** * The shape of a service extension. This abstract class is implemented - * by other extensions which extend the hooks to implement their own - * logic that they want to run during each step of preparing the service + * by other extensions that extend the hooks to implement any custom + * logic that they want to run during each step of preparing the service. */ export abstract class ServiceExtension { /** - * The name of the extension + * The name of the extension. */ public name: string; /** - * The container of this extension. Most extensions have a container, but not - * every extension is required to have a container, some extensions may just + * The container for this extension. Most extensions have a container, but not + * every extension is required to have a container. Some extensions may just * modify the properties of the service, or create external resources - * connected to the service + * connected to the service. */ public container?: ecs.ContainerDefinition; /** - * The service which this extension is applying itself to. - * Initially extensions are added to a ServiceDescription, but no service - * exists yet. Later when the ServiceDescription is used to create a service, + * The service which this extension is being added to. + * Initially, extensions are collected into a ServiceDescription, but no service + * exists yet. Later, when the ServiceDescription is used to create a service, * the extension is told what Service it is now working on. */ protected parentService!: Service; @@ -121,16 +127,17 @@ export abstract class ServiceExtension { /** * A hook that allows the extension to add hooks to other - * extensions that are registered + * extensions that are registered. */ public addHooks() { } // tslint:disable-line /** * This hook allows another service extension to register a mutating hook for * changing the primary container of this extension. This is primarily used - * for the application extension. For example the Firelens extension wants to + * for the application extension. For example, the Firelens extension wants to * be able to modify the settings of the application container to * route logs through Firelens. + * * @param hook */ public addContainerMutatingHook(hook: ContainerMutatingHook) { @@ -139,10 +146,11 @@ export abstract class ServiceExtension { /** * This is a hook which allows extensions to modify the settings of the - * task definition prior to it being created. For example App Mesh + * task definition prior to it being created. For example, the App Mesh * extension needs to configure an Envoy proxy in the task definition, - * or the application extension wants to set the overall resource for + * or the Application extension wants to set the overall resource for * the task. + * * @param props - Properties of the task definition to be created */ public modifyTaskDefinitionProps(props: ecs.TaskDefinitionProps): ecs.TaskDefinitionProps { @@ -152,9 +160,10 @@ export abstract class ServiceExtension { } /** - * A hook that is called for each extension adhead of time to - * let it do any initial setup, such as creating resources in + * A hook that is called for each extension ahead of time to + * allow for any initial setup, such as creating resources in * advance. + * * @param parent - The parent service which this extension has been added to * @param scope - The scope that this extension should create resources in */ @@ -166,7 +175,8 @@ export abstract class ServiceExtension { /** * Once the task definition is created, this hook is called for each * extension to give it a chance to add containers to the task definition, - * change the task definition's role to add permissions, etc + * change the task definition's role to add permissions, etc. + * * @param taskDefinition - The created task definition to add containers to */ public useTaskDefinition(taskDefinition: ecs.TaskDefinition) { @@ -174,20 +184,21 @@ export abstract class ServiceExtension { } /** - * Once all containers are added to the task definition this hook is + * Once all containers are added to the task definition, this hook is * called for each extension to give it a chance to resolve its dependency * graph so that its container starts in the right order based on the - * other extensions that were enabled + * other extensions that were enabled. */ public resolveContainerDependencies() { return; } /** - * Prior to launching the task definition as a service this hook + * Prior to launching the task definition as a service, this hook * is called on each extension to give it a chance to mutate the properties - * of the service to be created - * @param props - The service properties to mutate + * of the service to be created. + * + * @param props - The service properties to mutate. */ public modifyServiceProps(props: ServiceBuild): ServiceBuild { return { @@ -196,10 +207,11 @@ export abstract class ServiceExtension { } /** - * When this hook is implemented by extension it allows the extension + * When this hook is implemented by extension, it allows the extension * to use the service which has been created. It is generally used to - * create any final resources which might depend on the service itself - * @param service - The generated service + * create any final resources which might depend on the service itself. + * + * @param service - The generated service. */ public useService(service: ecs.Ec2Service | ecs.FargateService) { service = service; @@ -210,7 +222,8 @@ export abstract class ServiceExtension { * extensions from another service. Usually used for things like * allowing one service to talk to the load balancer or service mesh * proxy for another service. - * @param service - The other service to connect to + * + * @param service - The other service to connect to. */ public connectToService(service: Service) { service = service; @@ -224,10 +237,11 @@ export abstract class ServiceExtension { export abstract class ContainerMutatingHook { /** * This is a hook for modifying the container definition of any upstream - * containers. This is primarily used for the application extension. - * For example the Firelens extension wants to be able to modify the logging + * containers. This is primarily used for the main application container. + * For example, the Firelens extension wants to be able to modify the logging * settings of the application container. - * @param props - The container definition to mutate + * + * @param props - The container definition to mutate. */ public mutateContainerDefinition(props: ecs.ContainerDefinitionOptions): ecs.ContainerDefinitionOptions { return { diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/firelens.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/firelens.ts index 1dfc8e1f1b0b0..2e5f31c7af3d2 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/firelens.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/firelens.ts @@ -11,23 +11,23 @@ import { Construct } from '@aws-cdk/core'; /** * Settings for the hook which mutates the application container - * to route logs through FireLens + * to route logs through FireLens. */ export interface FirelensProps { /** - * The parent service that is being mutated + * The parent service that is being mutated. */ readonly parentService: Service; /** - * The log group into which logs should be routed + * The log group into which logs should be routed. */ readonly logGroup: awslogs.LogGroup; } /** * This hook modifies the application container's settings so that - * it routes logs using FireLens + * it routes logs using FireLens. */ export class FirelensMutatingHook extends ContainerMutatingHook { private parentService: Service; @@ -58,7 +58,7 @@ export class FirelensMutatingHook extends ContainerMutatingHook { /** * This extension adds a FluentBit log router to the task definition * and does all the configuration necessarily to enable log routing - * for the task using FireLens + * for the task using FireLens. */ export class FireLensExtension extends ServiceExtension { private logGroup!: awslogs.LogGroup; @@ -127,4 +127,4 @@ export class FireLensExtension extends ServiceExtension { }); } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/http-load-balancer.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/http-load-balancer.ts index 884477b4d38db..e0390c0ab617c 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/http-load-balancer.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/http-load-balancer.ts @@ -10,7 +10,7 @@ import { Construct } from '@aws-cdk/core'; /** * This extension add a public facing load balancer for sending traffic - * to one or more replicas of the application container + * to one or more replicas of the application container. */ export class HttpLoadBalancerExtension extends ServiceExtension { private loadBalancer!: alb.IApplicationLoadBalancer; @@ -20,7 +20,7 @@ export class HttpLoadBalancerExtension extends ServiceExtension { super('load-balancer'); } - // Before the service is created go ahead and create the load balancer itself. + // Before the service is created, go ahead and create the load balancer itself. public prehook(service: Service, scope: Construct) { this.parentService = service; diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/scale-on-cpu-utilization.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/scale-on-cpu-utilization.ts index c0ee8b0e12ac0..ec6ce9662535f 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/scale-on-cpu-utilization.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/scale-on-cpu-utilization.ts @@ -3,41 +3,47 @@ import * as cdk from '@aws-cdk/core'; import { ServiceExtension, ServiceBuild } from './extension-interfaces'; /** - * The autoscaling settings + * The autoscaling settings. */ export interface CpuScalingProps { /** - * How many tasks to launch initially + * How many tasks to launch initially. + * * @default - 2 */ readonly initialTaskCount?: number; /** - * The minimum number of tasks when scaling in + * The minimum number of tasks when scaling in. + * * @default - 2 */ readonly minTaskCount?: number; /** - * The maximum number of tasks when scaling out + * The maximum number of tasks when scaling out. + * * @default - 8 */ readonly maxTaskCount?: number; /** - * The CPU utilization to try ot maintain + * The CPU utilization to try ot maintain. + * * @default - 50% */ readonly targetCpuUtilization?: number; /** - * How long to wait between scale out actions + * How long to wait between scale out actions. + * * @default - 60 seconds */ readonly scaleOutCooldown?: cdk.Duration; /** - * How long to wait between scale in actions + * How long to wait between scale in actions. + * * @default - 60 seconds */ readonly scaleInCooldown?: cdk.Duration; @@ -54,36 +60,36 @@ const cpuScalingPropsDefault = { }; /** - * This extension helps you scale your service according to CPU utilization + * This extension helps you scale your service according to CPU utilization. */ export class ScaleOnCpuUtilization extends ServiceExtension { /** - * How many tasks to launch initially + * How many tasks to launch initially. */ public readonly initialTaskCount: number; /** - * The minimum number of tasks when scaling in + * The minimum number of tasks when scaling in. */ public readonly minTaskCount: number; /** - * The maximum number of tasks when scaling out + * The maximum number of tasks when scaling out. */ public readonly maxTaskCount: number; /** - * The CPU utilization to try ot maintain + * The CPU utilization to try ot maintain. */ public readonly targetCpuUtilization: number; /** - * How long to wait between scale out actions + * How long to wait between scale out actions. */ public readonly scaleOutCooldown: cdk.Duration; /** - * How long to wait between scale in actions + * How long to wait between scale in actions. */ public readonly scaleInCooldown: cdk.Duration; @@ -118,7 +124,7 @@ export class ScaleOnCpuUtilization extends ServiceExtension { } // This hook utilizes the resulting service construct - // once it is created + // once it is created. public useService(service: ecs.Ec2Service | ecs.FargateService) { const scalingTarget = service.autoScaleTaskCount({ minCapacity: this.minTaskCount, @@ -131,4 +137,4 @@ export class ScaleOnCpuUtilization extends ServiceExtension { scaleOutCooldown: this.scaleOutCooldown, }); } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/xray.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/xray.ts index 5e9affe0ffa3a..6b902a8c004d8 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/xray.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/xray.ts @@ -11,7 +11,7 @@ import { Construct } from '@aws-cdk/core'; const XRAY_DAEMON_IMAGE = 'amazon/aws-xray-daemon:latest'; /** - * This extension adds an X-Ray daemon inside the task definition, for + * This extension adds an X-Ray daemon inside the task definition for * capturing application trace spans and submitting them to the AWS * X-Ray service. */ @@ -67,4 +67,4 @@ export class XRayExtension extends ServiceExtension { }); } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/service-description.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/service-description.ts index 597b6ac6fe5d0..eb26905a5baa9 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/service-description.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/service-description.ts @@ -1,11 +1,10 @@ import { ServiceExtension } from './extensions/extension-interfaces'; /** - * A description of a service to construct. This construct collects - * all of the extensions that a user wants to add to their Service. - * It is used as a shared collection of all the extensions, allowing - * extensions to query the full list of extensions to determine - * information about how to self configure. + * A ServiceDescription is a wrapper for all of the extensions that a user wants + * to add to an ECS Service. It collects all of the extensions that are added + * to a service, allowing each extension to query the full list of extensions + * added to a service to determine information about how to self-configure. */ export class ServiceDescription { /** @@ -16,7 +15,8 @@ export class ServiceDescription { /** * Adds a new extension to the service. The extensions mutate a service - * to add resources or features to the service + * to add resources to or configure properties for the service. + * * @param extension - The extension that you wish to add */ public add(extension: ServiceExtension) { @@ -30,11 +30,12 @@ export class ServiceDescription { } /** - * Get the extension with a specific name. This is generally used for - * extensions to discover each other's existence. + * Get the extension with a specific name. This is generally used by + * extensions in order to discover each other. + * * @param name */ public get(name: string) { return this.extensions[name]; } -}; \ No newline at end of file +}; diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/service.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/service.ts index c988c0592b6bf..03c79528ab5d4 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/service.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/service.ts @@ -10,69 +10,71 @@ import { ServiceDescription } from './service-description'; import { Construct } from '@aws-cdk/core'; /** - * The settings for an ECS Service + * The settings for an ECS Service. */ export interface ServiceProps { /** - * A service description to use in building out the service + * The ServiceDescription used to build the service. */ readonly serviceDescription: ServiceDescription; /** - * The environment to launch the service in + * The environment to launch the service in. */ readonly environment: IEnvironment } /** - * A service builder class. This construct support various extensions - * which can construct an ECS service progressively. + * This Service construct serves as a Builder class for an ECS service. It + * supports various extensions and keeps track of any mutating state, allowing + * it to build up an ECS service progressively. */ export class Service extends Construct { /** - * The underlying ECS service that was created + * The underlying ECS service that was created. */ public ecsService!: ecs.Ec2Service | ecs.FargateService; /** - * The name of this service + * The name of the service. */ public readonly id: string; /** - * The VPC into which this service should be placed + * The VPC where this service should be placed. */ public readonly vpc: ec2.IVpc; /** - * The cluster that is providing capacity for this service + * The cluster that is providing capacity for this service. * [disable-awslint:ref-via-interface] */ public readonly cluster: ecs.ICluster; /** - * The capacity type that this service will use + * The capacity type that this service will use. + * Valid values are EC2 or FARGATE. */ public readonly capacityType: EnvironmentCapacityType; /** - * The service description used to build this service + * The ServiceDescription used to build this service. */ public readonly serviceDescription: ServiceDescription; /** - * The environment this service was launched in + * The environment where this service was launched. */ public readonly environment: IEnvironment; /** - * The generated task definition for this service, is only - * generated once .prepare() has been executed + * The generated task definition for this service. It is only + * generated after .prepare() has been executed. */ protected taskDefinition!: ecs.TaskDefinition; /** - * The list of URL's associated with this service + * The list of URLs associated with this service. */ private urls: Record = {}; @@ -215,7 +217,8 @@ export class Service extends Construct { /** * Tell extensions from one service to connect to extensions from - * another sevice if they have implemented a hook for that. + * another sevice if they have implemented a hook for it. + * * @param service */ public connectTo(service: Service) { @@ -227,9 +230,10 @@ export class Service extends Construct { } /** - * This method adds a new URL for the service. This allows extensions - * to submit a URL for the service, for example LB might add its URL - * or App Mesh can add its DNS name for the service. + * This method adds a new URL for the service. This allows extensions to + * submit a URL for the service. For example, a load balancer might add its + * URL, or App Mesh can add its DNS name for the service. + * * @param urlName - The identifier name for this URL * @param url - The URL itself. */ @@ -240,6 +244,7 @@ export class Service extends Construct { /** * Retrieve a URL for the service. The URL must have previously been * stored by one of the URL providing extensions. + * * @param urlName - The URL to look up. */ public getURL(urlName: string) { @@ -249,4 +254,4 @@ export class Service extends Construct { return this.urls[urlName]; } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/package.json b/packages/@aws-cdk-containers/ecs-service-extensions/package.json index 05781b7cc3750..5f4683eb92881 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/package.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/package.json @@ -35,14 +35,14 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "jest": "^26.6.3", "nodeunit": "^0.11.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-applicationautoscaling": "0.0.0", @@ -66,7 +66,7 @@ "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", "@aws-cdk/region-info": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -91,7 +91,7 @@ "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", "@aws-cdk/region-info": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json index 9193f8c5f76a4..2ed4b9bb1fe3e 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json @@ -1190,7 +1190,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3Bucket65227904" + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3Bucket4DD075F7" }, "S3Key": { "Fn::Join": [ @@ -1203,7 +1203,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF" + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7" } ] } @@ -1216,7 +1216,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF" + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7" } ] } @@ -1266,17 +1266,17 @@ "Type": "String", "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" }, - "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3Bucket65227904": { + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3Bucket4DD075F7": { "Type": "String", - "Description": "S3 bucket for asset \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\"" + "Description": "S3 bucket for asset \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" }, - "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF": { + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7": { "Type": "String", - "Description": "S3 key for asset version \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\"" + "Description": "S3 key for asset version \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" }, - "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343ArtifactHash0C561FF5": { + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98ArtifactHash35A756EB": { "Type": "String", - "Description": "Artifact hash for asset \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\"" + "Description": "Artifact hash for asset \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" } }, "Outputs": { diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.ts b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.ts index c7464cd28b671..ffd17d2e6bacf 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.ts @@ -1,3 +1,4 @@ +/// !cdk-integ pragma:ignore-assets import { SubnetType, Vpc } from '@aws-cdk/aws-ec2'; import { ContainerImage } from '@aws-cdk/aws-ecs'; import { CnameRecord, PublicHostedZone } from '@aws-cdk/aws-route53'; diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/test.appmesh.ts b/packages/@aws-cdk-containers/ecs-service-extensions/test/test.appmesh.ts index a221b9d31933e..c38447ac912bb 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/test.appmesh.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/test.appmesh.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; import * as appmesh from '@aws-cdk/aws-appmesh'; import * as ecs from '@aws-cdk/aws-ecs'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/test.assign-public-ip.ts b/packages/@aws-cdk-containers/ecs-service-extensions/test/test.assign-public-ip.ts index 92a36dd1d788b..2f4f926e1746b 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/test.assign-public-ip.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/test.assign-public-ip.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; import * as route53 from '@aws-cdk/aws-route53'; diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/test.cloudwatch-agent.ts b/packages/@aws-cdk-containers/ecs-service-extensions/test/test.cloudwatch-agent.ts index a8d94c3dc8e25..0b9ad5a09e647 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/test.cloudwatch-agent.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/test.cloudwatch-agent.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as ecs from '@aws-cdk/aws-ecs'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/test.environment.ts b/packages/@aws-cdk-containers/ecs-service-extensions/test/test.environment.ts index d029f81e34bc6..f1362695ac535 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/test.environment.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/test.environment.ts @@ -1,4 +1,4 @@ -import { countResources, expect, haveResource } from '@aws-cdk/assert'; +import { countResources, expect, haveResource } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/test.firelens.ts b/packages/@aws-cdk-containers/ecs-service-extensions/test/test.firelens.ts index e4ceb68444dd7..a6011a2caabf6 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/test.firelens.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/test.firelens.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as ecs from '@aws-cdk/aws-ecs'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/test.http-load-balancer.ts b/packages/@aws-cdk-containers/ecs-service-extensions/test/test.http-load-balancer.ts index 2cc26be97ddcf..2e977e19ee889 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/test.http-load-balancer.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/test.http-load-balancer.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as ecs from '@aws-cdk/aws-ecs'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/test.scale-on-cpu-utilization.ts b/packages/@aws-cdk-containers/ecs-service-extensions/test/test.scale-on-cpu-utilization.ts index 305655129eb1a..6d3e6ce715b1d 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/test.scale-on-cpu-utilization.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/test.scale-on-cpu-utilization.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; import * as ecs from '@aws-cdk/aws-ecs'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/test.service.ts b/packages/@aws-cdk-containers/ecs-service-extensions/test/test.service.ts index 23b30f59afe3d..4fa8c80657cd0 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/test.service.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/test.service.ts @@ -1,4 +1,4 @@ -import { countResources, expect, haveResource } from '@aws-cdk/assert'; +import { countResources, expect, haveResource } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/test.xray.ts b/packages/@aws-cdk-containers/ecs-service-extensions/test/test.xray.ts index 36443123e8719..c591b5c6dd012 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/test.xray.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/test.xray.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as ecs from '@aws-cdk/aws-ecs'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk/alexa-ask/package.json b/packages/@aws-cdk/alexa-ask/package.json index 48b5fa2b1e003..c4ed29f9a533a 100644 --- a/packages/@aws-cdk/alexa-ask/package.json +++ b/packages/@aws-cdk/alexa-ask/package.json @@ -72,18 +72,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/alexa-ask/test/ask.test.ts b/packages/@aws-cdk/alexa-ask/test/ask.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/alexa-ask/test/ask.test.ts +++ b/packages/@aws-cdk/alexa-ask/test/ask.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/app-delivery/package.json b/packages/@aws-cdk/app-delivery/package.json index de59545369bfd..990a4dd376c50 100644 --- a/packages/@aws-cdk/app-delivery/package.json +++ b/packages/@aws-cdk/app-delivery/package.json @@ -55,17 +55,17 @@ "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "devDependencies": { - "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "fast-check": "^2.14.0", "nodeunit": "^0.11.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "repository": { "type": "git", @@ -93,7 +93,7 @@ "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/app-delivery/test/test.pipeline-deploy-stack-action.ts b/packages/@aws-cdk/app-delivery/test/test.pipeline-deploy-stack-action.ts index d63ddbf6acb50..e4611adf570f6 100644 --- a/packages/@aws-cdk/app-delivery/test/test.pipeline-deploy-stack-action.ts +++ b/packages/@aws-cdk/app-delivery/test/test.pipeline-deploy-stack-action.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike, isSuperObject } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike, isSuperObject } from '@aws-cdk/assert-internal'; import * as cfn from '@aws-cdk/aws-cloudformation'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; diff --git a/packages/@aws-cdk/assert-internal/.eslintrc.js b/packages/@aws-cdk/assert-internal/.eslintrc.js new file mode 100644 index 0000000000000..61dd8dd001f63 --- /dev/null +++ b/packages/@aws-cdk/assert-internal/.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/assert-internal/.gitignore b/packages/@aws-cdk/assert-internal/.gitignore new file mode 100644 index 0000000000000..c9b9bcc8658a1 --- /dev/null +++ b/packages/@aws-cdk/assert-internal/.gitignore @@ -0,0 +1,16 @@ +*.js +*.js.map +*.d.ts +node_modules +dist + +.LAST_BUILD +.nyc_output +coverage +nyc.config.js +.LAST_PACKAGE +*.snk +!.eslintrc.js +!jest.config.js + +junit.xml \ No newline at end of file diff --git a/packages/@aws-cdk/assert-internal/.npmignore b/packages/@aws-cdk/assert-internal/.npmignore new file mode 100644 index 0000000000000..6f149ce45fddd --- /dev/null +++ b/packages/@aws-cdk/assert-internal/.npmignore @@ -0,0 +1,22 @@ +# Don't include original .ts files when doing `npm pack` +*.ts +!*.d.ts +coverage +.nyc_output +*.tgz + +dist +.LAST_PACKAGE +.LAST_BUILD +*.snk + +*.tsbuildinfo + +tsconfig.json +.eslintrc.js +jest.config.js + +# exclude cdk artifacts +**/cdk.out +junit.xml +test/ \ No newline at end of file diff --git a/packages/@aws-cdk/assert-internal/LICENSE b/packages/@aws-cdk/assert-internal/LICENSE new file mode 100644 index 0000000000000..28e4bdcec77ec --- /dev/null +++ b/packages/@aws-cdk/assert-internal/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-2021 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/assert-internal/NOTICE b/packages/@aws-cdk/assert-internal/NOTICE new file mode 100644 index 0000000000000..5fc3826926b5b --- /dev/null +++ b/packages/@aws-cdk/assert-internal/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/assert/README.md b/packages/@aws-cdk/assert-internal/README.md similarity index 100% rename from packages/@aws-cdk/assert/README.md rename to packages/@aws-cdk/assert-internal/README.md diff --git a/packages/@aws-cdk/assert-internal/jest.config.js b/packages/@aws-cdk/assert-internal/jest.config.js new file mode 100644 index 0000000000000..ac8c47076506a --- /dev/null +++ b/packages/@aws-cdk/assert-internal/jest.config.js @@ -0,0 +1,10 @@ +const baseConfig = require('cdk-build-tools/config/jest.config'); +module.exports = { + ...baseConfig, + coverageThreshold: { + global: { + statements: 75, + branches: 65, + }, + }, +}; diff --git a/packages/@aws-cdk/assert/jest.ts b/packages/@aws-cdk/assert-internal/jest.ts similarity index 100% rename from packages/@aws-cdk/assert/jest.ts rename to packages/@aws-cdk/assert-internal/jest.ts diff --git a/packages/@aws-cdk/assert/lib/assertion.ts b/packages/@aws-cdk/assert-internal/lib/assertion.ts similarity index 100% rename from packages/@aws-cdk/assert/lib/assertion.ts rename to packages/@aws-cdk/assert-internal/lib/assertion.ts diff --git a/packages/@aws-cdk/assert/lib/assertions/and-assertion.ts b/packages/@aws-cdk/assert-internal/lib/assertions/and-assertion.ts similarity index 100% rename from packages/@aws-cdk/assert/lib/assertions/and-assertion.ts rename to packages/@aws-cdk/assert-internal/lib/assertions/and-assertion.ts diff --git a/packages/@aws-cdk/assert/lib/assertions/count-resources.ts b/packages/@aws-cdk/assert-internal/lib/assertions/count-resources.ts similarity index 100% rename from packages/@aws-cdk/assert/lib/assertions/count-resources.ts rename to packages/@aws-cdk/assert-internal/lib/assertions/count-resources.ts diff --git a/packages/@aws-cdk/assert/lib/assertions/exist.ts b/packages/@aws-cdk/assert-internal/lib/assertions/exist.ts similarity index 100% rename from packages/@aws-cdk/assert/lib/assertions/exist.ts rename to packages/@aws-cdk/assert-internal/lib/assertions/exist.ts diff --git a/packages/@aws-cdk/assert/lib/assertions/have-output.ts b/packages/@aws-cdk/assert-internal/lib/assertions/have-output.ts similarity index 100% rename from packages/@aws-cdk/assert/lib/assertions/have-output.ts rename to packages/@aws-cdk/assert-internal/lib/assertions/have-output.ts diff --git a/packages/@aws-cdk/assert/lib/assertions/have-resource-matchers.ts b/packages/@aws-cdk/assert-internal/lib/assertions/have-resource-matchers.ts similarity index 100% rename from packages/@aws-cdk/assert/lib/assertions/have-resource-matchers.ts rename to packages/@aws-cdk/assert-internal/lib/assertions/have-resource-matchers.ts diff --git a/packages/@aws-cdk/assert/lib/assertions/have-resource.ts b/packages/@aws-cdk/assert-internal/lib/assertions/have-resource.ts similarity index 100% rename from packages/@aws-cdk/assert/lib/assertions/have-resource.ts rename to packages/@aws-cdk/assert-internal/lib/assertions/have-resource.ts diff --git a/packages/@aws-cdk/assert/lib/assertions/have-type.ts b/packages/@aws-cdk/assert-internal/lib/assertions/have-type.ts similarity index 100% rename from packages/@aws-cdk/assert/lib/assertions/have-type.ts rename to packages/@aws-cdk/assert-internal/lib/assertions/have-type.ts diff --git a/packages/@aws-cdk/assert/lib/assertions/match-template.ts b/packages/@aws-cdk/assert-internal/lib/assertions/match-template.ts similarity index 100% rename from packages/@aws-cdk/assert/lib/assertions/match-template.ts rename to packages/@aws-cdk/assert-internal/lib/assertions/match-template.ts diff --git a/packages/@aws-cdk/assert/lib/assertions/negated-assertion.ts b/packages/@aws-cdk/assert-internal/lib/assertions/negated-assertion.ts similarity index 100% rename from packages/@aws-cdk/assert/lib/assertions/negated-assertion.ts rename to packages/@aws-cdk/assert-internal/lib/assertions/negated-assertion.ts diff --git a/packages/@aws-cdk/assert/lib/canonicalize-assets.ts b/packages/@aws-cdk/assert-internal/lib/canonicalize-assets.ts similarity index 100% rename from packages/@aws-cdk/assert/lib/canonicalize-assets.ts rename to packages/@aws-cdk/assert-internal/lib/canonicalize-assets.ts diff --git a/packages/@aws-cdk/assert/lib/expect.ts b/packages/@aws-cdk/assert-internal/lib/expect.ts similarity index 100% rename from packages/@aws-cdk/assert/lib/expect.ts rename to packages/@aws-cdk/assert-internal/lib/expect.ts diff --git a/packages/@aws-cdk/assert/lib/index.ts b/packages/@aws-cdk/assert-internal/lib/index.ts similarity index 100% rename from packages/@aws-cdk/assert/lib/index.ts rename to packages/@aws-cdk/assert-internal/lib/index.ts diff --git a/packages/@aws-cdk/assert/lib/inspector.ts b/packages/@aws-cdk/assert-internal/lib/inspector.ts similarity index 100% rename from packages/@aws-cdk/assert/lib/inspector.ts rename to packages/@aws-cdk/assert-internal/lib/inspector.ts diff --git a/packages/@aws-cdk/assert/lib/synth-utils.ts b/packages/@aws-cdk/assert-internal/lib/synth-utils.ts similarity index 95% rename from packages/@aws-cdk/assert/lib/synth-utils.ts rename to packages/@aws-cdk/assert-internal/lib/synth-utils.ts index bb8d9a437afd9..d8dc73aff881a 100644 --- a/packages/@aws-cdk/assert/lib/synth-utils.ts +++ b/packages/@aws-cdk/assert-internal/lib/synth-utils.ts @@ -18,7 +18,7 @@ export class SynthUtils { */ public static toCloudFormation(stack: core.Stack, options: core.SynthesisOptions = { }): any { const synth = this._synthesizeWithNested(stack, options); - if (synth instanceof cxapi.CloudFormationStackArtifact) { + if (isStackArtifact(synth)) { return synth.template; } else { return synth; @@ -85,3 +85,7 @@ export interface SubsetOptions { */ resourceTypes?: string[]; } + +function isStackArtifact(x: object): x is cxapi.CloudFormationStackArtifact { + return 'template' in x; +} \ No newline at end of file diff --git a/packages/@aws-cdk/assert-internal/package.json b/packages/@aws-cdk/assert-internal/package.json new file mode 100644 index 0000000000000..b280034b25dab --- /dev/null +++ b/packages/@aws-cdk/assert-internal/package.json @@ -0,0 +1,67 @@ +{ + "name": "@aws-cdk/assert-internal", + "private": true, + "version": "0.0.0", + "description": "An assertion library for use with CDK Apps", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "scripts": { + "build": "cdk-build", + "watch": "cdk-watch", + "lint": "cdk-lint", + "test": "cdk-test", + "pkglint": "pkglint -f", + "package": "cdk-package", + "build+test+package": "yarn build+test && yarn package", + "build+test": "yarn build && yarn test" + }, + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@types/jest": "^26.0.23", + "cdk-build-tools": "0.0.0", + "jest": "^26.6.3", + "pkglint": "0.0.0", + "ts-jest": "^26.5.5" + }, + "dependencies": { + "@aws-cdk/cloud-assembly-schema": "0.0.0", + "@aws-cdk/cloudformation-diff": "0.0.0", + "@aws-cdk/core": "0.0.0", + "@aws-cdk/cx-api": "0.0.0", + "constructs": "^3.3.69" + }, + "peerDependencies": { + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69", + "jest": "^26.6.3" + }, + "repository": { + "url": "https://github.com/aws/aws-cdk.git", + "type": "git", + "directory": "packages/@aws-cdk/assert-internal" + }, + "keywords": [ + "aws", + "cdk" + ], + "homepage": "https://github.com/aws/aws-cdk", + "engines": { + "node": ">= 10.13.0 <13 || >=13.7.0" + }, + "stability": "experimental", + "maturity": "experimental", + "cdk-build": { + "jest": true + }, + "publishConfig": { + "tag": "latest" + }, + "ubergen": { + "exclude": true + } +} diff --git a/packages/@aws-cdk/assert/test/assertions.test.ts b/packages/@aws-cdk/assert-internal/test/assertions.test.ts similarity index 100% rename from packages/@aws-cdk/assert/test/assertions.test.ts rename to packages/@aws-cdk/assert-internal/test/assertions.test.ts diff --git a/packages/@aws-cdk/assert/test/canonicalize-assets.test.ts b/packages/@aws-cdk/assert-internal/test/canonicalize-assets.test.ts similarity index 100% rename from packages/@aws-cdk/assert/test/canonicalize-assets.test.ts rename to packages/@aws-cdk/assert-internal/test/canonicalize-assets.test.ts diff --git a/packages/@aws-cdk/assert/test/have-output.test.ts b/packages/@aws-cdk/assert-internal/test/have-output.test.ts similarity index 100% rename from packages/@aws-cdk/assert/test/have-output.test.ts rename to packages/@aws-cdk/assert-internal/test/have-output.test.ts diff --git a/packages/@aws-cdk/assert/test/have-resource.test.ts b/packages/@aws-cdk/assert-internal/test/have-resource.test.ts similarity index 100% rename from packages/@aws-cdk/assert/test/have-resource.test.ts rename to packages/@aws-cdk/assert-internal/test/have-resource.test.ts diff --git a/packages/@aws-cdk/assert/test/synth-utils.test.ts b/packages/@aws-cdk/assert-internal/test/synth-utils.test.ts similarity index 100% rename from packages/@aws-cdk/assert/test/synth-utils.test.ts rename to packages/@aws-cdk/assert-internal/test/synth-utils.test.ts diff --git a/packages/@aws-cdk/assert-internal/tsconfig.json b/packages/@aws-cdk/assert-internal/tsconfig.json new file mode 100644 index 0000000000000..6aae954779f33 --- /dev/null +++ b/packages/@aws-cdk/assert-internal/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "target":"es2018", + "lib": ["es2016", "es2017.object", "es2017.string"], + "module": "commonjs", + "composite": true, + "declaration": true, + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "noImplicitThis": true, + "alwaysStrict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": false, + "inlineSourceMap": true, + "inlineSources": true, + "strictPropertyInitialization": false, + "experimentalDecorators": true + }, + "include": ["**/*.ts" ], + "exclude": ["node_modules"], + "references": [ + { "path": "../core" }, + { "path": "../cx-api" }, + { "path": "../cfnspec" }, + { "path": "../cloudformation-diff" } + ] +} diff --git a/packages/@aws-cdk/assert/.gitignore b/packages/@aws-cdk/assert/.gitignore index c9b9bcc8658a1..f18f865e5fb57 100644 --- a/packages/@aws-cdk/assert/.gitignore +++ b/packages/@aws-cdk/assert/.gitignore @@ -1,16 +1,27 @@ +lib/ +test/ +README.md +LICENSE +NOTICE +node_modules +jest.ts +.npmignore + *.js -*.js.map *.d.ts -node_modules -dist +dist +.LAST_PACKAGE .LAST_BUILD +*.snk .nyc_output coverage nyc.config.js -.LAST_PACKAGE -*.snk !.eslintrc.js !jest.config.js -junit.xml \ No newline at end of file +junit.xml +./lib +./test +README.md +jest.ts diff --git a/packages/@aws-cdk/assert/BUILD.md b/packages/@aws-cdk/assert/BUILD.md new file mode 100644 index 0000000000000..b7770fdee296e --- /dev/null +++ b/packages/@aws-cdk/assert/BUILD.md @@ -0,0 +1,15 @@ +# How this package is built + +This package is built by copying the sources from `assert-internal`, +and if on the v2 branch transforming the imports to depend on the v2 library, +`aws-cdk-lib`. + +We don't use this package for the CDK build itself. Instead, for the +individual packages that make up the monopackage, we build and test against +the `assert-internal` package and its dependency on `@aws-cdk/core`. + +We then build and publish this package for our users to consume. + +* For v1, this is just a straight-up copy of `assert-internal` with its + dependency on `@aws-cdk/core`. +* For v2, we rewrite to depend on `aws-cdk-lib` instead. \ No newline at end of file diff --git a/packages/@aws-cdk/assert/clone.sh b/packages/@aws-cdk/assert/clone.sh new file mode 100755 index 0000000000000..c8d6c6e82af9f --- /dev/null +++ b/packages/@aws-cdk/assert/clone.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# clones tools/assert-internal into here +scriptdir=$(cd $(dirname $0) && pwd) +cd $scriptdir +set -euo pipefail +src="../assert-internal" + +# Don't copy .d.ts and .js files -- otherwise tsc might not recreate +# those files after we have rewritten the .ts files (probably due to timestamps) +rsync -av $src/lib/ lib/ +rsync -av $src/test/ test/ + +majorversion=$(node -p 'require("../../../release.json").majorVersion') + +files="README.md LICENSE NOTICE .npmignore jest.ts" + +for file in ${files}; do + cp $src/$file . +done + +if [[ "$majorversion" = "2" ]]; then + echo "Rewriting TS files..." + npx rewrite-imports-v2 "**/*.ts" + + # This forces a recompile even if this file already exists + rm -f tsconfig.tsbuildinfo + + echo "Done." +fi diff --git a/packages/@aws-cdk/assert/jest.config.js b/packages/@aws-cdk/assert/jest.config.js index ac8c47076506a..582b2b3040eb0 100644 --- a/packages/@aws-cdk/assert/jest.config.js +++ b/packages/@aws-cdk/assert/jest.config.js @@ -4,7 +4,7 @@ module.exports = { coverageThreshold: { global: { statements: 75, - branches: 65, + branches: 60, }, }, }; diff --git a/packages/@aws-cdk/assert/package.json b/packages/@aws-cdk/assert/package.json index 50b7b2a9becba..1b4c8f07bd6c7 100644 --- a/packages/@aws-cdk/assert/package.json +++ b/packages/@aws-cdk/assert/package.json @@ -14,6 +14,18 @@ "build+test+package": "yarn build+test && yarn package", "build+test": "yarn build && yarn test" }, + "cdk-build": { + "jest": true, + "pre": [ + "./clone.sh" + ], + "eslint": { + "disable": true + }, + "pkglint": { + "disable": true + } + }, "author": { "name": "Amazon Web Services", "url": "https://aws.amazon.com", @@ -21,22 +33,24 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.21", + "aws-cdk-migration": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", + "constructs": "^3.3.69", "jest": "^26.6.3", "pkglint": "0.0.0", - "ts-jest": "^26.5.4" + "@aws-cdk/assert-internal": "0.0.0", + "ts-jest": "^26.5.5" }, "dependencies": { - "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/cloudformation-diff": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0", + "constructs": "^3.3.69", "jest": "^26.6.3" }, "repository": { @@ -52,11 +66,12 @@ "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, - "stability": "experimental", - "maturity": "experimental", - "cdk-build": { - "jest": true + "ubergen": { + "exclude": true }, + "nozem": false, + "stability": "experimental", + "maturity": "developer-preview", "publishConfig": { "tag": "latest" } diff --git a/packages/@aws-cdk/assert/tsconfig.json b/packages/@aws-cdk/assert/tsconfig.json index 6aae954779f33..b426f95fcb96a 100644 --- a/packages/@aws-cdk/assert/tsconfig.json +++ b/packages/@aws-cdk/assert/tsconfig.json @@ -1,9 +1,8 @@ { "compilerOptions": { - "target":"es2018", - "lib": ["es2016", "es2017.object", "es2017.string"], - "module": "commonjs", - "composite": true, + "target":"ES2018", + "lib": ["es2018"], + "module": "CommonJS", "declaration": true, "strict": true, "noImplicitAny": true, @@ -17,14 +16,13 @@ "inlineSourceMap": true, "inlineSources": true, "strictPropertyInitialization": false, - "experimentalDecorators": true + "experimentalDecorators": true, + "composite": true, + "incremental": true }, "include": ["**/*.ts" ], "exclude": ["node_modules"], "references": [ - { "path": "../core" }, - { "path": "../cx-api" }, - { "path": "../cfnspec" }, - { "path": "../cloudformation-diff" } + { "path": "../../@aws-cdk/cloudformation-diff" } ] } diff --git a/packages/@aws-cdk/assets/lib/fs/options.ts b/packages/@aws-cdk/assets/lib/fs/options.ts index 3ccc107d3700d..548fa4bda42ee 100644 --- a/packages/@aws-cdk/assets/lib/fs/options.ts +++ b/packages/@aws-cdk/assets/lib/fs/options.ts @@ -10,6 +10,7 @@ export interface CopyOptions { * A strategy for how to handle symlinks. * * @default Never + * @deprecated use `followSymlinks` instead */ readonly follow?: FollowMode; diff --git a/packages/@aws-cdk/assets/package.json b/packages/@aws-cdk/assets/package.json index b19a88d4a9c12..e962ce96ebf94 100644 --- a/packages/@aws-cdk/assets/package.json +++ b/packages/@aws-cdk/assets/package.json @@ -67,7 +67,6 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", "@types/sinon": "^9.0.11", "aws-cdk": "0.0.0", @@ -76,18 +75,19 @@ "nodeunit": "^0.11.3", "pkglint": "0.0.0", "sinon": "^9.2.4", - "ts-mock-imports": "^1.3.3" + "ts-mock-imports": "^1.3.4", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" @@ -97,6 +97,9 @@ "awscdkio": { "announce": false }, + "nozem": { + "ostools": ["rm", "tar", "gzip"] + }, "publishConfig": { "tag": "latest" } diff --git a/packages/@aws-cdk/aws-accessanalyzer/package.json b/packages/@aws-cdk/aws-accessanalyzer/package.json index 85c2a0d682662..62e09ba13324c 100644 --- a/packages/@aws-cdk/aws-accessanalyzer/package.json +++ b/packages/@aws-cdk/aws-accessanalyzer/package.json @@ -73,18 +73,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-accessanalyzer/test/accessanalyzer.test.ts b/packages/@aws-cdk/aws-accessanalyzer/test/accessanalyzer.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-accessanalyzer/test/accessanalyzer.test.ts +++ b/packages/@aws-cdk/aws-accessanalyzer/test/accessanalyzer.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-acmpca/README.md b/packages/@aws-cdk/aws-acmpca/README.md index 04d167836539c..66f15be5be271 100644 --- a/packages/@aws-cdk/aws-acmpca/README.md +++ b/packages/@aws-cdk/aws-acmpca/README.md @@ -1,21 +1,12 @@ # AWS::ACMPCA 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]) are always stable and safe to use. -> -> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib - -![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. +![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge) --- @@ -26,3 +17,51 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aw ```ts import * as acmpca from '@aws-cdk/aws-acmpca'; ``` + +## Certificate Authority + +This package contains a `CertificateAuthority` class. +At the moment, you cannot create new Authorities using it, +but you can import existing ones using the `fromCertificateAuthorityArn` static method: + +```ts +const certificateAuthority = acmpca.CertificateAuthority.fromCertificateAuthorityArn(this, 'CA', + 'arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/023077d8-2bfa-4eb0-8f22-05c96deade77'); +``` + +## Low-level `Cfn*` classes + +You can always use the low-level classes +(starting with `Cfn*`) to create resources like the Certificate Authority: + +```ts +const cfnCertificateAuthority = new acmpca.CfnCertificateAuthority(this, 'CA', { + type: 'ROOT', + keyAlgorithm: 'RSA_2048', + signingAlgorithm: 'SHA256WITHRSA', + subject: { + country: 'US', + organization: 'string', + organizationalUnit: 'string', + distinguishedNameQualifier: 'string', + state: 'string', + commonName: '123', + serialNumber: 'string', + locality: 'string', + title: 'string', + surname: 'string', + givenName: 'string', + initials: 'DG', + pseudonym: 'string', + generationQualifier: 'DBG', + }, +}); +``` + +If you need to pass the higher-level `ICertificateAuthority` somewhere, +you can get it from the lower-level `CfnCertificateAuthority` using the same `fromCertificateAuthorityArn` method: + +```ts +const certificateAuthority = acmpca.CertificateAuthority.fromCertificateAuthorityArn(this, 'CertificateAuthority', + cfnCertificateAuthority.attrArn); +``` diff --git a/packages/@aws-cdk/aws-acmpca/package.json b/packages/@aws-cdk/aws-acmpca/package.json index e0956bffbf2c6..f6f5480861408 100644 --- a/packages/@aws-cdk/aws-acmpca/package.json +++ b/packages/@aws-cdk/aws-acmpca/package.json @@ -73,24 +73,25 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, - "stability": "experimental", - "maturity": "experimental", + "stability": "stable", + "maturity": "stable", "awscdkio": { "announce": false }, diff --git a/packages/@aws-cdk/aws-acmpca/test/acmpca.test.ts b/packages/@aws-cdk/aws-acmpca/test/acmpca.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-acmpca/test/acmpca.test.ts +++ b/packages/@aws-cdk/aws-acmpca/test/acmpca.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-amazonmq/package.json b/packages/@aws-cdk/aws-amazonmq/package.json index c9d6412f5effa..c3c54803650df 100644 --- a/packages/@aws-cdk/aws-amazonmq/package.json +++ b/packages/@aws-cdk/aws-amazonmq/package.json @@ -72,18 +72,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-amazonmq/test/amazonmq.test.ts b/packages/@aws-cdk/aws-amazonmq/test/amazonmq.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-amazonmq/test/amazonmq.test.ts +++ b/packages/@aws-cdk/aws-amazonmq/test/amazonmq.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-amplify/README.md b/packages/@aws-cdk/aws-amplify/README.md index b8e3bd91c2306..a706cb73bb39b 100644 --- a/packages/@aws-cdk/aws-amplify/README.md +++ b/packages/@aws-cdk/aws-amplify/README.md @@ -38,7 +38,7 @@ const amplifyApp = new amplify.App(this, 'MyApp', { repository: '', oauthToken: cdk.SecretValue.secretsManager('my-github-token') }), - buildSpec: codebuild.BuildSpec.fromObject({ // Alternatively add a `amplify.yml` to the repo + buildSpec: codebuild.BuildSpec.fromObjectToYaml({ // Alternatively add a `amplify.yml` to the repo version: '1.0', frontend: { phases: { diff --git a/packages/@aws-cdk/aws-amplify/package.json b/packages/@aws-cdk/aws-amplify/package.json index ea1abbde2ba37..24aa0753df720 100644 --- a/packages/@aws-cdk/aws-amplify/package.json +++ b/packages/@aws-cdk/aws-amplify/package.json @@ -73,11 +73,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", @@ -86,7 +87,7 @@ "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/aws-iam": "0.0.0", @@ -95,7 +96,7 @@ "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-amplify/test/app.test.ts b/packages/@aws-cdk/aws-amplify/test/app.test.ts index 8cff8e3d5b66d..9c7dcb4689fcb 100644 --- a/packages/@aws-cdk/aws-amplify/test/app.test.ts +++ b/packages/@aws-cdk/aws-amplify/test/app.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codecommit from '@aws-cdk/aws-codecommit'; import { SecretValue, Stack } from '@aws-cdk/core'; @@ -17,7 +17,7 @@ test('create an app connected to a GitHub repository', () => { repository: 'aws-cdk', oauthToken: SecretValue.plainText('secret'), }), - buildSpec: codebuild.BuildSpec.fromObject({ + buildSpec: codebuild.BuildSpec.fromObjectToYaml({ version: '1.0', frontend: { phases: { @@ -34,7 +34,7 @@ test('create an app connected to a GitHub repository', () => { // THEN expect(stack).toHaveResource('AWS::Amplify::App', { Name: 'App', - BuildSpec: '{\n \"version\": \"1.0\",\n \"frontend\": {\n \"phases\": {\n \"build\": {\n \"commands\": [\n \"npm run build\"\n ]\n }\n }\n }\n}', + BuildSpec: 'version: \"1.0\"\nfrontend:\n phases:\n build:\n commands:\n - npm run build\n', IAMServiceRole: { 'Fn::GetAtt': [ 'AppRole1AF9B530', diff --git a/packages/@aws-cdk/aws-amplify/test/branch.test.ts b/packages/@aws-cdk/aws-amplify/test/branch.test.ts index 41695cb33df5e..6844d9f952d10 100644 --- a/packages/@aws-cdk/aws-amplify/test/branch.test.ts +++ b/packages/@aws-cdk/aws-amplify/test/branch.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { SecretValue, Stack } from '@aws-cdk/core'; import * as amplify from '../lib'; diff --git a/packages/@aws-cdk/aws-amplify/test/domain.test.ts b/packages/@aws-cdk/aws-amplify/test/domain.test.ts index 7b0f28f75837d..13311a93abaec 100644 --- a/packages/@aws-cdk/aws-amplify/test/domain.test.ts +++ b/packages/@aws-cdk/aws-amplify/test/domain.test.ts @@ -1,5 +1,5 @@ import * as iam from '@aws-cdk/aws-iam'; -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { App, SecretValue, Stack } from '@aws-cdk/core'; import * as amplify from '../lib'; diff --git a/packages/@aws-cdk/aws-apigateway/README.md b/packages/@aws-cdk/aws-apigateway/README.md index 926f45daf1436..4607442308138 100644 --- a/packages/@aws-cdk/aws-apigateway/README.md +++ b/packages/@aws-cdk/aws-apigateway/README.md @@ -24,7 +24,7 @@ running on AWS Lambda, or any web application. - [Breaking up Methods and Resources across Stacks](#breaking-up-methods-and-resources-across-stacks) - [AWS Lambda-backed APIs](#aws-lambda-backed-apis) - [Integration Targets](#integration-targets) -- [API Keys](#api-keys) +- [Usage Plan & API Keys](#usage-plan--api-keys) - [Working with models](#working-with-models) - [Default Integration and Method Options](#default-integration-and-method-options) - [Proxy Routes](#proxy-routes) @@ -168,34 +168,36 @@ const getMessageIntegration = new apigateway.AwsIntegration({ }); ``` -## API Keys +## Usage Plan & API Keys -The following example shows how to use an API Key with a usage plan: +A usage plan specifies who can access one or more deployed API stages and methods, and the rate at which they can be +accessed. The plan uses API keys to identify API clients and meters access to the associated API stages for each key. +Usage plans also allow configuring throttling limits and quota limits that are enforced on individual client API keys. -```ts -const hello = new lambda.Function(this, 'hello', { - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'hello.handler', - code: lambda.Code.fromAsset('lambda') -}); +The following example shows how to create and asscociate a usage plan and an API key: -const api = new apigateway.RestApi(this, 'hello-api', { }); -const integration = new apigateway.LambdaIntegration(hello); +```ts +const api = new apigateway.RestApi(this, 'hello-api'); const v1 = api.root.addResource('v1'); const echo = v1.addResource('echo'); const echoMethod = echo.addMethod('GET', integration, { apiKeyRequired: true }); -const key = api.addApiKey('ApiKey'); const plan = api.addUsagePlan('UsagePlan', { name: 'Easy', - apiKey: key, throttle: { rateLimit: 10, burstLimit: 2 } }); +const key = api.addApiKey('ApiKey'); +plan.addApiKey(key); +``` + +To associate a plan to a given RestAPI stage: + +```ts plan.addApiStage({ stage: api.deploymentStage, throttle: [ @@ -233,26 +235,36 @@ following code provides read permission to an API key. importedKey.grantRead(lambda); ``` -In scenarios where you need to create a single api key and configure rate limiting for it, you can use `RateLimitedApiKey`. -This construct lets you specify rate limiting properties which should be applied only to the api key being created. -The API key created has the specified rate limits, such as quota and throttles, applied. +### ⚠️ Multiple API Keys -The following example shows how to use a rate limited api key : +It is possible to specify multiple API keys for a given Usage Plan, by calling `usagePlan.addApiKey()`. + +When using multiple API keys, a past bug of the CDK prevents API key associations to a Usage Plan to be deleted. +If the CDK app had the [feature flag] - `@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId` - enabled when the API +keys were created, then the app will not be affected by this bug. + +If this is not the case, you will need to ensure that the CloudFormation [logical ids] of the API keys that are not +being deleted remain unchanged. +Make note of the logical ids of these API keys before removing any, and set it as part of the `addApiKey()` method: ```ts -const hello = new lambda.Function(this, 'hello', { - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'hello.handler', - code: lambda.Code.fromAsset('lambda') +usageplan.addApiKey(apiKey, { + overrideLogicalId: '...', }); +``` -const api = new apigateway.RestApi(this, 'hello-api', { }); -const integration = new apigateway.LambdaIntegration(hello); +[feature flag]: https://docs.aws.amazon.com/cdk/latest/guide/featureflags.html +[logical ids]: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html -const v1 = api.root.addResource('v1'); -const echo = v1.addResource('echo'); -const echoMethod = echo.addMethod('GET', integration, { apiKeyRequired: true }); +### Rate Limited API Key + +In scenarios where you need to create a single api key and configure rate limiting for it, you can use `RateLimitedApiKey`. +This construct lets you specify rate limiting properties which should be applied only to the api key being created. +The API key created has the specified rate limits, such as quota and throttles, applied. +The following example shows how to use a rate limited api key : + +```ts const key = new apigateway.RateLimitedApiKey(this, 'rate-limited-api-key', { customerId: 'hello-customer', resources: [api], @@ -261,7 +273,6 @@ const key = new apigateway.RateLimitedApiKey(this, 'rate-limited-api-key', { period: apigateway.Period.MONTH } }); - ``` ## Working with models diff --git a/packages/@aws-cdk/aws-apigateway/lib/api-definition.ts b/packages/@aws-cdk/aws-apigateway/lib/api-definition.ts index 01be9ebd17c59..7b138cfcf23d1 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/api-definition.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/api-definition.ts @@ -7,12 +7,10 @@ import { Construct } from '@aws-cdk/core'; /** * Represents an OpenAPI definition asset. - * @experimental */ export abstract class ApiDefinition { /** * Creates an API definition from a specification file in an S3 bucket - * @experimental */ public static fromBucket(bucket: s3.IBucket, key: string, objectVersion?: string): S3ApiDefinition { return new S3ApiDefinition(bucket, key, objectVersion); @@ -70,7 +68,6 @@ export abstract class ApiDefinition { /** * Loads the API specification from a local disk asset. - * @experimental */ public static fromAsset(file: string, options?: s3_assets.AssetOptions): AssetApiDefinition { return new AssetApiDefinition(file, options); @@ -88,7 +85,6 @@ export abstract class ApiDefinition { /** * S3 location of the API definition file - * @experimental */ export interface ApiDefinitionS3Location { /** The S3 bucket */ @@ -104,7 +100,6 @@ export interface ApiDefinitionS3Location { /** * Post-Binding Configuration for a CDK construct - * @experimental */ export interface ApiDefinitionConfig { /** @@ -124,7 +119,6 @@ export interface ApiDefinitionConfig { /** * OpenAPI specification from an S3 archive. - * @experimental */ export class S3ApiDefinition extends ApiDefinition { private bucketName: string; @@ -152,7 +146,6 @@ export class S3ApiDefinition extends ApiDefinition { /** * OpenAPI specification from an inline JSON object. - * @experimental */ export class InlineApiDefinition extends ApiDefinition { constructor(private definition: any) { @@ -176,7 +169,6 @@ export class InlineApiDefinition extends ApiDefinition { /** * OpenAPI specification from a local file. - * @experimental */ export class AssetApiDefinition extends ApiDefinition { private asset?: s3_assets.Asset; diff --git a/packages/@aws-cdk/aws-apigateway/lib/apigatewayv2.ts b/packages/@aws-cdk/aws-apigateway/lib/apigatewayv2.ts index 98ee1ba04acbf..e9394f5ade6ed 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/apigatewayv2.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/apigatewayv2.ts @@ -318,7 +318,6 @@ export class CfnApiV2 extends cdk.CfnResource implements cdk.IInspectable { * * @param inspector - tree inspector to collect and process attributes * - * @stability experimental */ public inspect(inspector: cdk.TreeInspector) { inspector.addAttribute('aws:cdk:cloudformation:type', CfnApiV2.CFN_RESOURCE_TYPE_NAME); @@ -637,7 +636,6 @@ export class CfnApiMappingV2 extends cdk.CfnResource implements cdk.IInspectable * * @param inspector - tree inspector to collect and process attributes * - * @stability experimental */ public inspect(inspector: cdk.TreeInspector) { inspector.addAttribute('aws:cdk:cloudformation:type', CfnApiMappingV2.CFN_RESOURCE_TYPE_NAME); @@ -869,7 +867,6 @@ export class CfnAuthorizerV2 extends cdk.CfnResource implements cdk.IInspectable * * @param inspector - tree inspector to collect and process attributes * - * @stability experimental */ public inspect(inspector: cdk.TreeInspector) { inspector.addAttribute('aws:cdk:cloudformation:type', CfnAuthorizerV2.CFN_RESOURCE_TYPE_NAME); @@ -1065,7 +1062,6 @@ export class CfnDeploymentV2 extends cdk.CfnResource implements cdk.IInspectable * * @param inspector - tree inspector to collect and process attributes * - * @stability experimental */ public inspect(inspector: cdk.TreeInspector) { inspector.addAttribute('aws:cdk:cloudformation:type', CfnDeploymentV2.CFN_RESOURCE_TYPE_NAME); @@ -1212,7 +1208,6 @@ export class CfnDomainNameV2 extends cdk.CfnResource implements cdk.IInspectable * * @param inspector - tree inspector to collect and process attributes * - * @stability experimental */ public inspect(inspector: cdk.TreeInspector) { inspector.addAttribute('aws:cdk:cloudformation:type', CfnDomainNameV2.CFN_RESOURCE_TYPE_NAME); @@ -1576,7 +1571,6 @@ export class CfnIntegrationV2 extends cdk.CfnResource implements cdk.IInspectabl * * @param inspector - tree inspector to collect and process attributes * - * @stability experimental */ public inspect(inspector: cdk.TreeInspector) { inspector.addAttribute('aws:cdk:cloudformation:type', CfnIntegrationV2.CFN_RESOURCE_TYPE_NAME); @@ -1786,7 +1780,6 @@ export class CfnIntegrationResponseV2 extends cdk.CfnResource implements cdk.IIn * * @param inspector - tree inspector to collect and process attributes * - * @stability experimental */ public inspect(inspector: cdk.TreeInspector) { inspector.addAttribute('aws:cdk:cloudformation:type', CfnIntegrationResponseV2.CFN_RESOURCE_TYPE_NAME); @@ -1959,7 +1952,6 @@ export class CfnModelV2 extends cdk.CfnResource implements cdk.IInspectable { * * @param inspector - tree inspector to collect and process attributes * - * @stability experimental */ public inspect(inspector: cdk.TreeInspector) { inspector.addAttribute('aws:cdk:cloudformation:type', CfnModelV2.CFN_RESOURCE_TYPE_NAME); @@ -2233,7 +2225,6 @@ export class CfnRouteV2 extends cdk.CfnResource implements cdk.IInspectable { * * @param inspector - tree inspector to collect and process attributes * - * @stability experimental */ public inspect(inspector: cdk.TreeInspector) { inspector.addAttribute('aws:cdk:cloudformation:type', CfnRouteV2.CFN_RESOURCE_TYPE_NAME); @@ -2475,7 +2466,6 @@ export class CfnRouteResponseV2 extends cdk.CfnResource implements cdk.IInspecta * * @param inspector - tree inspector to collect and process attributes * - * @stability experimental */ public inspect(inspector: cdk.TreeInspector) { inspector.addAttribute('aws:cdk:cloudformation:type', CfnRouteResponseV2.CFN_RESOURCE_TYPE_NAME); @@ -2784,7 +2774,6 @@ export class CfnStageV2 extends cdk.CfnResource implements cdk.IInspectable { * * @param inspector - tree inspector to collect and process attributes * - * @stability experimental */ public inspect(inspector: cdk.TreeInspector) { inspector.addAttribute('aws:cdk:cloudformation:type', CfnStageV2.CFN_RESOURCE_TYPE_NAME); diff --git a/packages/@aws-cdk/aws-apigateway/lib/integration.ts b/packages/@aws-cdk/aws-apigateway/lib/integration.ts index 475358d672540..4ff6a28c76a63 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/integration.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/integration.ts @@ -1,5 +1,5 @@ import * as iam from '@aws-cdk/aws-iam'; -import { Lazy } from '@aws-cdk/core'; +import { Lazy, Duration } from '@aws-cdk/core'; import { Method } from './method'; import { IVpcLink, VpcLink } from './vpc-link'; @@ -80,6 +80,14 @@ export interface IntegrationOptions { */ readonly requestTemplates?: { [contentType: string]: string }; + /** + * The maximum amount of time an integration will run before it returns without a response. + * Must be between 50 milliseconds and 29 seconds. + * + * @default Duration.seconds(29) + */ + readonly timeout?: Duration; + /** * The response that API Gateway provides after a method's backend completes * processing a request. API Gateway intercepts the response from the @@ -193,6 +201,10 @@ export class Integration { if (options.connectionType === ConnectionType.INTERNET && options.vpcLink !== undefined) { throw new Error('cannot set \'vpcLink\' where \'connectionType\' is INTERNET'); } + + if (options.timeout && !options.timeout.isUnresolved() && (options.timeout.toMilliseconds() < 50 || options.timeout.toMilliseconds() > 29000)) { + throw new Error('Integration timeout must be between 50 milliseconds and 29 seconds.'); + } } /** diff --git a/packages/@aws-cdk/aws-apigateway/lib/method.ts b/packages/@aws-cdk/aws-apigateway/lib/method.ts index e4cfa78c0584e..ff9c4aaef47dd 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/method.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/method.ts @@ -289,6 +289,7 @@ export class Method extends Resource { connectionType: options.connectionType, connectionId: options.vpcLink ? options.vpcLink.vpcLinkId : undefined, credentials, + timeoutInMillis: options.timeout?.toMilliseconds(), }; } diff --git a/packages/@aws-cdk/aws-apigateway/lib/restapi.ts b/packages/@aws-cdk/aws-apigateway/lib/restapi.ts index 1afd9f7e9d090..9d74e2a1ec7a9 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/restapi.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/restapi.ts @@ -236,7 +236,6 @@ export interface RestApiProps extends RestApiOptions { /** * Props to instantiate a new SpecRestApi - * @experimental */ export interface SpecRestApiProps extends RestApiBaseProps { /** @@ -587,7 +586,6 @@ export abstract class RestApiBase extends Resource implements IRestApi { * By default, the API will automatically be deployed and accessible from a * public endpoint. * - * @experimental * * @resource AWS::ApiGateway::RestApi */ @@ -680,7 +678,6 @@ export class RestApi extends RestApiBase { /** * Import an existing RestApi that can be configured with additional Methods and Resources. - * @experimental */ public static fromRestApiAttributes(scope: Construct, id: string, attrs: RestApiAttributes): IRestApi { class Import extends RestApiBase { diff --git a/packages/@aws-cdk/aws-apigateway/lib/usage-plan.ts b/packages/@aws-cdk/aws-apigateway/lib/usage-plan.ts index 49b3ee19cd017..82f45bc538db6 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/usage-plan.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/usage-plan.ts @@ -1,4 +1,5 @@ -import { Lazy, Names, Resource, Token } from '@aws-cdk/core'; +import { FeatureFlags, Lazy, Names, Resource, Token } from '@aws-cdk/core'; +import { APIGATEWAY_USAGEPLANKEY_ORDERINSENSITIVE_ID } from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; import { IApiKey } from './api-key'; import { CfnUsagePlan, CfnUsagePlanKey } from './apigateway.generated'; @@ -139,10 +140,22 @@ export interface UsagePlanProps { /** * ApiKey to be associated with the usage plan. * @default none + * @deprecated use `addApiKey()` */ readonly apiKey?: IApiKey; } +/** + * Options to the UsagePlan.addApiKey() method + */ +export interface AddApiKeyOptions { + /** + * Override the CloudFormation logical id of the AWS::ApiGateway::UsagePlanKey resource + * @default - autogenerated by the CDK + */ + readonly overrideLogicalId?: string; +} + export class UsagePlan extends Resource { /** * @attribute @@ -176,19 +189,28 @@ export class UsagePlan extends Resource { /** * Adds an ApiKey. * - * @param apiKey + * @param apiKey the api key to associate with this usage plan + * @param options options that control the behaviour of this method */ - public addApiKey(apiKey: IApiKey): void { + public addApiKey(apiKey: IApiKey, options?: AddApiKeyOptions): void { + let id: string; const prefix = 'UsagePlanKeyResource'; - // Postfixing apikey id only from the 2nd child, to keep physicalIds of UsagePlanKey for existing CDK apps unmodified. - const id = this.node.tryFindChild(prefix) ? `${prefix}:${Names.nodeUniqueId(apiKey.node)}` : prefix; + if (FeatureFlags.of(this).isEnabled(APIGATEWAY_USAGEPLANKEY_ORDERINSENSITIVE_ID)) { + id = `${prefix}:${Names.nodeUniqueId(apiKey.node)}`; + } else { + // Postfixing apikey id only from the 2nd child, to keep physicalIds of UsagePlanKey for existing CDK apps unmodified. + id = this.node.tryFindChild(prefix) ? `${prefix}:${Names.nodeUniqueId(apiKey.node)}` : prefix; + } - new CfnUsagePlanKey(this, id, { + const resource = new CfnUsagePlanKey(this, id, { keyId: apiKey.keyId, keyType: UsagePlanKeyType.API_KEY, usagePlanId: this.usagePlanId, }); + if (options?.overrideLogicalId) { + resource.overrideLogicalId(options?.overrideLogicalId); + } } /** diff --git a/packages/@aws-cdk/aws-apigateway/package.json b/packages/@aws-cdk/aws-apigateway/package.json index 7465b7d45a6bd..ba8b777cf68ba 100644 --- a/packages/@aws-cdk/aws-apigateway/package.json +++ b/packages/@aws-cdk/aws-apigateway/package.json @@ -71,11 +71,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", @@ -90,7 +91,7 @@ "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -106,7 +107,7 @@ "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-apigateway/test/access-log.test.ts b/packages/@aws-cdk/aws-apigateway/test/access-log.test.ts index e7993ba7c287e..6509cc24b614b 100644 --- a/packages/@aws-cdk/aws-apigateway/test/access-log.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/access-log.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as apigateway from '../lib'; describe('access log', () => { diff --git a/packages/@aws-cdk/aws-apigateway/test/api-definition.test.ts b/packages/@aws-cdk/aws-apigateway/test/api-definition.test.ts index aee6c954f2b90..709900b36c71d 100644 --- a/packages/@aws-cdk/aws-apigateway/test/api-definition.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/api-definition.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as path from 'path'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-apigateway/test/api-key.test.ts b/packages/@aws-cdk/aws-apigateway/test/api-key.test.ts index 18db74d841d04..f4f348a2a3d23 100644 --- a/packages/@aws-cdk/aws-apigateway/test/api-key.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/api-key.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert/jest'; -import { ResourcePart } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +import { ResourcePart } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import * as apigateway from '../lib'; diff --git a/packages/@aws-cdk/aws-apigateway/test/authorizers/cognito.test.ts b/packages/@aws-cdk/aws-apigateway/test/authorizers/cognito.test.ts index e59339177d5d4..1956c69dbb149 100644 --- a/packages/@aws-cdk/aws-apigateway/test/authorizers/cognito.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/authorizers/cognito.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cognito from '@aws-cdk/aws-cognito'; import { Duration, Stack } from '@aws-cdk/core'; import { AuthorizationType, CognitoUserPoolsAuthorizer, RestApi } from '../../lib'; diff --git a/packages/@aws-cdk/aws-apigateway/test/authorizers/lambda.test.ts b/packages/@aws-cdk/aws-apigateway/test/authorizers/lambda.test.ts index fd0be26e030df..fdaa20af10cd3 100644 --- a/packages/@aws-cdk/aws-apigateway/test/authorizers/lambda.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/authorizers/lambda.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert/jest'; -import { ResourcePart } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +import { ResourcePart } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import * as lambda from '@aws-cdk/aws-lambda'; import { Duration, Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-apigateway/test/base-path-mapping.test.ts b/packages/@aws-cdk/aws-apigateway/test/base-path-mapping.test.ts index 49dc8e50759f8..6e57ce68d1394 100644 --- a/packages/@aws-cdk/aws-apigateway/test/base-path-mapping.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/base-path-mapping.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as acm from '@aws-cdk/aws-certificatemanager'; import * as cdk from '@aws-cdk/core'; import * as apigw from '../lib'; diff --git a/packages/@aws-cdk/aws-apigateway/test/cors.test.ts b/packages/@aws-cdk/aws-apigateway/test/cors.test.ts index 46fe8e1756443..42879b562df18 100644 --- a/packages/@aws-cdk/aws-apigateway/test/cors.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/cors.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as lambda from '@aws-cdk/aws-lambda'; import { Duration, Stack } from '@aws-cdk/core'; import * as apigw from '../lib'; diff --git a/packages/@aws-cdk/aws-apigateway/test/deployment.test.ts b/packages/@aws-cdk/aws-apigateway/test/deployment.test.ts index 55e5ab8859734..3f431bfb29f2a 100644 --- a/packages/@aws-cdk/aws-apigateway/test/deployment.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/deployment.test.ts @@ -1,6 +1,6 @@ import * as path from 'path'; -import '@aws-cdk/assert/jest'; -import { ResourcePart, SynthUtils } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +import { ResourcePart, SynthUtils } from '@aws-cdk/assert-internal'; import * as lambda from '@aws-cdk/aws-lambda'; import { CfnResource, Lazy, Stack } from '@aws-cdk/core'; import * as apigateway from '../lib'; diff --git a/packages/@aws-cdk/aws-apigateway/test/domains.test.ts b/packages/@aws-cdk/aws-apigateway/test/domains.test.ts index 2b7f49f9a3977..7ad0f4224d70b 100644 --- a/packages/@aws-cdk/aws-apigateway/test/domains.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/domains.test.ts @@ -1,5 +1,5 @@ -import { ABSENT } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { ABSENT } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as acm from '@aws-cdk/aws-certificatemanager'; import { Bucket } from '@aws-cdk/aws-s3'; import { Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-apigateway/test/gateway-response.test.ts b/packages/@aws-cdk/aws-apigateway/test/gateway-response.test.ts index 3c96d86c1410d..7a02ca17b6ca0 100644 --- a/packages/@aws-cdk/aws-apigateway/test/gateway-response.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/gateway-response.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert/jest'; -import { ABSENT } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +import { ABSENT } from '@aws-cdk/assert-internal'; import { Stack } from '@aws-cdk/core'; import { ResponseType, RestApi } from '../lib'; diff --git a/packages/@aws-cdk/aws-apigateway/test/http.test.ts b/packages/@aws-cdk/aws-apigateway/test/http.test.ts index c0f58e828d271..15714ca988087 100644 --- a/packages/@aws-cdk/aws-apigateway/test/http.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/http.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import * as apigateway from '../lib'; diff --git a/packages/@aws-cdk/aws-apigateway/test/integ.restapi.expected.json b/packages/@aws-cdk/aws-apigateway/test/integ.restapi.expected.json index 91af3471593eb..a0fb6357db3c7 100644 --- a/packages/@aws-cdk/aws-apigateway/test/integ.restapi.expected.json +++ b/packages/@aws-cdk/aws-apigateway/test/integ.restapi.expected.json @@ -602,7 +602,7 @@ "UsagePlanName": "Basic" } }, - "myapiUsagePlanUsagePlanKeyResource050D133F": { + "myapiUsagePlanUsagePlanKeyResourcetestapigatewayrestapimyapiApiKeyC43601CB600D112D": { "Type": "AWS::ApiGateway::UsagePlanKey", "Properties": { "KeyId": { diff --git a/packages/@aws-cdk/aws-apigateway/test/integ.usage-plan.multikey.expected.json b/packages/@aws-cdk/aws-apigateway/test/integ.usage-plan.multikey.expected.json index 8e761f40e2a26..9dee2e7aa07b0 100644 --- a/packages/@aws-cdk/aws-apigateway/test/integ.usage-plan.multikey.expected.json +++ b/packages/@aws-cdk/aws-apigateway/test/integ.usage-plan.multikey.expected.json @@ -3,7 +3,7 @@ "myusageplan4B391740": { "Type": "AWS::ApiGateway::UsagePlan" }, - "myusageplanUsagePlanKeyResource095B4EA9": { + "myusageplanUsagePlanKeyResourcetestapigatewayusageplanmultikeymyapikey1DDABC389A2809A73": { "Type": "AWS::ApiGateway::UsagePlanKey", "Properties": { "KeyId": { diff --git a/packages/@aws-cdk/aws-apigateway/test/integration.test.ts b/packages/@aws-cdk/aws-apigateway/test/integration.test.ts index 3c8990247d74e..f89a1fdf042ed 100644 --- a/packages/@aws-cdk/aws-apigateway/test/integration.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/integration.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert/jest'; -import { ABSENT } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +import { ABSENT } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import * as iam from '@aws-cdk/aws-iam'; @@ -184,4 +184,50 @@ describe('integration', () => { }, }); }); + + test('validates timeout is valid', () => { + + expect(() => new apigw.Integration({ + type: apigw.IntegrationType.HTTP_PROXY, + integrationHttpMethod: 'ANY', + options: { + timeout: cdk.Duration.millis(2), + }, + })).toThrow(/Integration timeout must be between 50 milliseconds and 29 seconds/); + + expect(() => new apigw.Integration({ + type: apigw.IntegrationType.HTTP_PROXY, + integrationHttpMethod: 'ANY', + options: { + timeout: cdk.Duration.seconds(50), + }, + })).toThrow(/Integration timeout must be between 50 milliseconds and 29 seconds/); + }); + + test('sets timeout', () => { + + // GIVEN + const stack = new cdk.Stack(); + const api = new apigw.RestApi(stack, 'restapi'); + + // WHEN + const integration = new apigw.Integration({ + type: apigw.IntegrationType.HTTP_PROXY, + integrationHttpMethod: 'ANY', + options: { + timeout: cdk.Duration.seconds(1), + }, + }); + api.root.addMethod('ANY', integration); + + // THEN + expect(stack).toHaveResourceLike('AWS::ApiGateway::Method', { + HttpMethod: 'ANY', + Integration: { + TimeoutInMillis: 1000, + }, + }); + + }); + }); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apigateway/test/integrations/lambda.test.ts b/packages/@aws-cdk/aws-apigateway/test/integrations/lambda.test.ts index 862b9b64266f9..76ef808c4999e 100644 --- a/packages/@aws-cdk/aws-apigateway/test/integrations/lambda.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/integrations/lambda.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as lambda from '@aws-cdk/aws-lambda'; import * as cdk from '@aws-cdk/core'; import * as apigateway from '../../lib'; diff --git a/packages/@aws-cdk/aws-apigateway/test/lambda-api.test.ts b/packages/@aws-cdk/aws-apigateway/test/lambda-api.test.ts index 6850cf4e8ba06..0babe3d5671e3 100644 --- a/packages/@aws-cdk/aws-apigateway/test/lambda-api.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/lambda-api.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as lambda from '@aws-cdk/aws-lambda'; import * as cdk from '@aws-cdk/core'; import * as apigw from '../lib'; diff --git a/packages/@aws-cdk/aws-apigateway/test/method.test.ts b/packages/@aws-cdk/aws-apigateway/test/method.test.ts index 3fb5c580bc541..fdddb91777755 100644 --- a/packages/@aws-cdk/aws-apigateway/test/method.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/method.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert/jest'; -import { ABSENT } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +import { ABSENT } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import * as lambda from '@aws-cdk/aws-lambda'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-apigateway/test/model.test.ts b/packages/@aws-cdk/aws-apigateway/test/model.test.ts index cb741f77e2d83..62602ef353959 100644 --- a/packages/@aws-cdk/aws-apigateway/test/model.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/model.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import * as apigw from '../lib'; diff --git a/packages/@aws-cdk/aws-apigateway/test/requestvalidator.test.ts b/packages/@aws-cdk/aws-apigateway/test/requestvalidator.test.ts index 0838db161f8db..ec29752b47b6a 100644 --- a/packages/@aws-cdk/aws-apigateway/test/requestvalidator.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/requestvalidator.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import * as apigateway from '../lib'; diff --git a/packages/@aws-cdk/aws-apigateway/test/resource.test.ts b/packages/@aws-cdk/aws-apigateway/test/resource.test.ts index 0a20483f4261c..36d3fff2ccdab 100644 --- a/packages/@aws-cdk/aws-apigateway/test/resource.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/resource.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Stack } from '@aws-cdk/core'; import * as apigw from '../lib'; diff --git a/packages/@aws-cdk/aws-apigateway/test/restapi.test.ts b/packages/@aws-cdk/aws-apigateway/test/restapi.test.ts index d8d0fdbcfd030..8a213ca5b8569 100644 --- a/packages/@aws-cdk/aws-apigateway/test/restapi.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/restapi.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert/jest'; -import { ResourcePart, SynthUtils } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +import { ResourcePart, SynthUtils } from '@aws-cdk/assert-internal'; import { GatewayVpcEndpoint } from '@aws-cdk/aws-ec2'; import { App, CfnElement, CfnResource, Stack } from '@aws-cdk/core'; import * as apigw from '../lib'; diff --git a/packages/@aws-cdk/aws-apigateway/test/stage.test.ts b/packages/@aws-cdk/aws-apigateway/test/stage.test.ts index a2575edbaa07b..d419a3190639f 100644 --- a/packages/@aws-cdk/aws-apigateway/test/stage.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/stage.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as logs from '@aws-cdk/aws-logs'; import * as cdk from '@aws-cdk/core'; import * as apigateway from '../lib'; diff --git a/packages/@aws-cdk/aws-apigateway/test/usage-plan.test.ts b/packages/@aws-cdk/aws-apigateway/test/usage-plan.test.ts index f183d08796388..88df6f2a04506 100644 --- a/packages/@aws-cdk/aws-apigateway/test/usage-plan.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/usage-plan.test.ts @@ -1,6 +1,8 @@ -import '@aws-cdk/assert/jest'; -import { ResourcePart } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +import { ResourcePart } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; +import * as cxapi from '@aws-cdk/cx-api'; +import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; import * as apigateway from '../lib'; const RESOURCE_TYPE = 'AWS::ApiGateway::UsagePlan'; @@ -149,60 +151,112 @@ describe('usage plan', () => { }, ResourcePart.Properties); }); - test('UsagePlanKey', () => { - // GIVEN - const stack = new cdk.Stack(); - const usagePlan: apigateway.UsagePlan = new apigateway.UsagePlan(stack, 'my-usage-plan', { - name: 'Basic', + describe('UsagePlanKey', () => { + + test('default', () => { + // GIVEN + const stack = new cdk.Stack(); + const usagePlan: apigateway.UsagePlan = new apigateway.UsagePlan(stack, 'my-usage-plan', { + name: 'Basic', + }); + const apiKey: apigateway.ApiKey = new apigateway.ApiKey(stack, 'my-api-key'); + + // WHEN + usagePlan.addApiKey(apiKey); + + // THEN + expect(stack).toHaveResource('AWS::ApiGateway::UsagePlanKey', { + KeyId: { + Ref: 'myapikey1B052F70', + }, + KeyType: 'API_KEY', + UsagePlanId: { + Ref: 'myusageplan23AA1E32', + }, + }, ResourcePart.Properties); }); - const apiKey: apigateway.ApiKey = new apigateway.ApiKey(stack, 'my-api-key'); - // WHEN - usagePlan.addApiKey(apiKey); + test('multiple keys', () => { + // GIVEN + const stack = new cdk.Stack(); + const usagePlan = new apigateway.UsagePlan(stack, 'my-usage-plan'); + const apiKey1 = new apigateway.ApiKey(stack, 'my-api-key-1', { + apiKeyName: 'my-api-key-1', + }); + const apiKey2 = new apigateway.ApiKey(stack, 'my-api-key-2', { + apiKeyName: 'my-api-key-2', + }); - // THEN - expect(stack).toHaveResource('AWS::ApiGateway::UsagePlanKey', { - KeyId: { - Ref: 'myapikey1B052F70', - }, - KeyType: 'API_KEY', - UsagePlanId: { - Ref: 'myusageplan23AA1E32', - }, - }, ResourcePart.Properties); - }); + // WHEN + usagePlan.addApiKey(apiKey1); + usagePlan.addApiKey(apiKey2); - test('UsagePlan can have multiple keys', () => { - // GIVEN - const stack = new cdk.Stack(); - const usagePlan = new apigateway.UsagePlan(stack, 'my-usage-plan'); - const apiKey1 = new apigateway.ApiKey(stack, 'my-api-key-1', { - apiKeyName: 'my-api-key-1', + // THEN + expect(stack).toHaveResource('AWS::ApiGateway::ApiKey', { + Name: 'my-api-key-1', + }, ResourcePart.Properties); + expect(stack).toHaveResource('AWS::ApiGateway::ApiKey', { + Name: 'my-api-key-2', + }, ResourcePart.Properties); + expect(stack).toHaveResource('AWS::ApiGateway::UsagePlanKey', { + KeyId: { + Ref: 'myapikey11F723FC7', + }, + }, ResourcePart.Properties); + expect(stack).toHaveResource('AWS::ApiGateway::UsagePlanKey', { + KeyId: { + Ref: 'myapikey2ABDEF012', + }, + }, ResourcePart.Properties); }); - const apiKey2 = new apigateway.ApiKey(stack, 'my-api-key-2', { - apiKeyName: 'my-api-key-2', + + test('overrideLogicalId', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app); + const usagePlan: apigateway.UsagePlan = new apigateway.UsagePlan(stack, 'my-usage-plan', { name: 'Basic' }); + const apiKey: apigateway.ApiKey = new apigateway.ApiKey(stack, 'my-api-key'); + + // WHEN + usagePlan.addApiKey(apiKey, { overrideLogicalId: 'mylogicalid' }); + + // THEN + const template = app.synth().getStackByName(stack.stackName).template; + const logicalIds = Object.entries(template.Resources) + .filter(([_, v]) => (v as any).Type === 'AWS::ApiGateway::UsagePlanKey') + .map(([k, _]) => k); + expect(logicalIds).toEqual(['mylogicalid']); }); - // WHEN - usagePlan.addApiKey(apiKey1); - usagePlan.addApiKey(apiKey2); + describe('future flag: @aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId', () => { + const flags = { [cxapi.APIGATEWAY_USAGEPLANKEY_ORDERINSENSITIVE_ID]: true }; - // THEN - expect(stack).toHaveResource('AWS::ApiGateway::ApiKey', { - Name: 'my-api-key-1', - }, ResourcePart.Properties); - expect(stack).toHaveResource('AWS::ApiGateway::ApiKey', { - Name: 'my-api-key-2', - }, ResourcePart.Properties); - expect(stack).toHaveResource('AWS::ApiGateway::UsagePlanKey', { - KeyId: { - Ref: 'myapikey11F723FC7', - }, - }, ResourcePart.Properties); - expect(stack).toHaveResource('AWS::ApiGateway::UsagePlanKey', { - KeyId: { - Ref: 'myapikey2ABDEF012', - }, - }, ResourcePart.Properties); + testFutureBehavior('UsagePlanKeys have unique logical ids', flags, cdk.App, (app) => { + // GIVEN + const stack = new cdk.Stack(app, 'my-stack'); + const usagePlan = new apigateway.UsagePlan(stack, 'my-usage-plan'); + const apiKey1 = new apigateway.ApiKey(stack, 'my-api-key-1', { + apiKeyName: 'my-api-key-1', + }); + const apiKey2 = new apigateway.ApiKey(stack, 'my-api-key-2', { + apiKeyName: 'my-api-key-2', + }); + + // WHEN + usagePlan.addApiKey(apiKey1); + usagePlan.addApiKey(apiKey2); + + // THEN + const template = app.synth().getStackByName(stack.stackName).template; + const logicalIds = Object.entries(template.Resources) + .filter(([_, v]) => (v as any).Type === 'AWS::ApiGateway::UsagePlanKey') + .map(([k, _]) => k); + + expect(logicalIds).toEqual([ + 'myusageplanUsagePlanKeyResourcemystackmyapikey1EE9AA1B359121274', + 'myusageplanUsagePlanKeyResourcemystackmyapikey2B4E8EB1456DC88E9', + ]); + }); + }); }); }); diff --git a/packages/@aws-cdk/aws-apigateway/test/util.test.ts b/packages/@aws-cdk/aws-apigateway/test/util.test.ts index 18352d21f5b0f..07c8a2cef379d 100644 --- a/packages/@aws-cdk/aws-apigateway/test/util.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/util.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { JsonSchema, JsonSchemaType } from '../lib'; import { JsonSchemaMapper, parseAwsApiCall, parseMethodOptionsPath } from '../lib/util'; diff --git a/packages/@aws-cdk/aws-apigateway/test/vpc-link.test.ts b/packages/@aws-cdk/aws-apigateway/test/vpc-link.test.ts index b7a023966d1fb..ba2b82464141d 100644 --- a/packages/@aws-cdk/aws-apigateway/test/vpc-link.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/vpc-link.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json b/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json index f21b19c75f329..c70e7a5dd8115 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json @@ -71,24 +71,25 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "@aws-cdk/aws-apigatewayv2-integrations": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-apigatewayv2": "0.0.0", "@aws-cdk/aws-cognito": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/aws-apigatewayv2": "0.0.0", "@aws-cdk/aws-cognito": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/jwt.test.ts b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/jwt.test.ts index 8b27dc312a1a3..469a0d6aa4ece 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/jwt.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/jwt.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { HttpApi, HttpIntegrationType, HttpRouteIntegrationBindOptions, IHttpRouteIntegration, PayloadFormatVersion } from '@aws-cdk/aws-apigatewayv2'; import { Stack } from '@aws-cdk/core'; import { HttpJwtAuthorizer } from '../../lib'; diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/user-pool.test.ts b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/user-pool.test.ts index c12e00a342acd..33086eab5ff4a 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/user-pool.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/user-pool.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { HttpApi, HttpIntegrationType, HttpRouteIntegrationBindOptions, IHttpRouteIntegration, PayloadFormatVersion } from '@aws-cdk/aws-apigatewayv2'; import { UserPool } from '@aws-cdk/aws-cognito'; import { Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/websocket/lambda.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/websocket/lambda.ts index 85e199a71c3d7..8dedb470ce6af 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/websocket/lambda.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/websocket/lambda.ts @@ -36,9 +36,16 @@ export class LambdaWebSocketIntegration implements IWebSocketRouteIntegration { }), }); + const integrationUri = Stack.of(route).formatArn({ + service: 'apigateway', + account: 'lambda', + resource: 'path/2015-03-31/functions', + resourceName: `${this.props.handler.functionArn}/invocations`, + }); + return { type: WebSocketIntegrationType.AWS_PROXY, - uri: this.props.handler.functionArn, + uri: integrationUri, }; } } diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json b/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json index c4a3e3039b9a3..b3f98aa94a520 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json @@ -69,12 +69,13 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "nodeunit": "^0.11.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-apigatewayv2": "0.0.0", @@ -84,7 +85,7 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-servicediscovery": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/aws-apigatewayv2": "0.0.0", @@ -94,7 +95,7 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-servicediscovery": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/alb.test.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/alb.test.ts index aa2c2fe3e4c4c..cf852751692f7 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/alb.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/alb.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { HttpApi, HttpMethod, HttpRoute, HttpRouteKey, VpcLink } from '@aws-cdk/aws-apigatewayv2'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/http-proxy.test.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/http-proxy.test.ts index 8a0eb5830a7f4..9c3b09ddcfbd6 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/http-proxy.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/http-proxy.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { HttpApi, HttpIntegration, HttpIntegrationType, HttpMethod, HttpRoute, HttpRouteKey, PayloadFormatVersion } from '@aws-cdk/aws-apigatewayv2'; import { Stack } from '@aws-cdk/core'; import { HttpProxyIntegration } from '../../lib'; diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/lambda.test.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/lambda.test.ts index 6272095194db6..6414869f66f66 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/lambda.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/lambda.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { HttpApi, HttpRoute, HttpRouteKey, PayloadFormatVersion } from '@aws-cdk/aws-apigatewayv2'; import { Code, Function, Runtime } from '@aws-cdk/aws-lambda'; import { App, Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/nlb.test.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/nlb.test.ts index 13d25f0cd896f..176e511214e77 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/nlb.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/nlb.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { HttpApi, HttpMethod, HttpRoute, HttpRouteKey, VpcLink } from '@aws-cdk/aws-apigatewayv2'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/private/integration.test.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/private/integration.test.ts index ce5f269f648a0..fb6c4ab082b53 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/private/integration.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/private/integration.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { HttpApi, HttpRoute, HttpRouteIntegrationBindOptions, HttpRouteIntegrationConfig, HttpRouteKey } from '@aws-cdk/aws-apigatewayv2'; import { Stack } from '@aws-cdk/core'; import { HttpPrivateIntegration } from '../../../lib/http/private/integration'; diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/service-discovery.test.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/service-discovery.test.ts index ebd491e2c2ab8..43294f35fb12f 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/service-discovery.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/service-discovery.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { HttpApi, HttpMethod, HttpRoute, HttpRouteKey, VpcLink } from '@aws-cdk/aws-apigatewayv2'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as servicediscovery from '@aws-cdk/aws-servicediscovery'; diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/integ.lambda.expected.json b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/integ.lambda.expected.json index 48bf164ada435..54a0f51203342 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/integ.lambda.expected.json +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/integ.lambda.expected.json @@ -245,7 +245,7 @@ } } }, - "mywsapiconnectRouteWebSocketIntegration50b017444a02be00a0b575d123314581176017EE": { + "mywsapiconnectRouteWebSocketIntegration3025fc0297cc8d73dae555b46106edcd38569D62": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { @@ -253,9 +253,26 @@ }, "IntegrationType": "AWS_PROXY", "IntegrationUri": { - "Fn::GetAtt": [ - "ConnectHandler2FFD52D8", - "Arn" + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:", + { + "Ref": "AWS::Region" + }, + ":lambda:path/2015-03-31/functions/", + { + "Fn::GetAtt": [ + "ConnectHandler2FFD52D8", + "Arn" + ] + }, + "/invocations" + ] ] } } @@ -273,7 +290,7 @@ [ "integrations/", { - "Ref": "mywsapiconnectRouteWebSocketIntegration50b017444a02be00a0b575d123314581176017EE" + "Ref": "mywsapiconnectRouteWebSocketIntegration3025fc0297cc8d73dae555b46106edcd38569D62" } ] ] @@ -317,7 +334,7 @@ } } }, - "mywsapidisconnectRouteWebSocketIntegrationcd3bacb451e82549501e141cc094d7ba1F7F68BC": { + "mywsapidisconnectRouteWebSocketIntegrationfc84ffd6c52488b90783abae35d28ebdAE5C6063": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { @@ -325,9 +342,26 @@ }, "IntegrationType": "AWS_PROXY", "IntegrationUri": { - "Fn::GetAtt": [ - "DisconnectHandlerCB7ED6F7", - "Arn" + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:", + { + "Ref": "AWS::Region" + }, + ":lambda:path/2015-03-31/functions/", + { + "Fn::GetAtt": [ + "DisconnectHandlerCB7ED6F7", + "Arn" + ] + }, + "/invocations" + ] ] } } @@ -345,7 +379,7 @@ [ "integrations/", { - "Ref": "mywsapidisconnectRouteWebSocketIntegrationcd3bacb451e82549501e141cc094d7ba1F7F68BC" + "Ref": "mywsapidisconnectRouteWebSocketIntegrationfc84ffd6c52488b90783abae35d28ebdAE5C6063" } ] ] @@ -389,7 +423,7 @@ } } }, - "mywsapidefaultRouteWebSocketIntegration640ac0772c157aa8b9a56aa99adbd9d7A2B7F2FA": { + "mywsapidefaultRouteWebSocketIntegrationa07b7cec9837e31a8c70446e1e1f1fd5055B3083": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { @@ -397,9 +431,26 @@ }, "IntegrationType": "AWS_PROXY", "IntegrationUri": { - "Fn::GetAtt": [ - "DefaultHandler604DF7AC", - "Arn" + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:", + { + "Ref": "AWS::Region" + }, + ":lambda:path/2015-03-31/functions/", + { + "Fn::GetAtt": [ + "DefaultHandler604DF7AC", + "Arn" + ] + }, + "/invocations" + ] ] } } @@ -417,7 +468,7 @@ [ "integrations/", { - "Ref": "mywsapidefaultRouteWebSocketIntegration640ac0772c157aa8b9a56aa99adbd9d7A2B7F2FA" + "Ref": "mywsapidefaultRouteWebSocketIntegrationa07b7cec9837e31a8c70446e1e1f1fd5055B3083" } ] ] @@ -461,7 +512,7 @@ } } }, - "mywsapisendmessageRouteWebSocketIntegrationcf58a195e318f43f52c4d9ac6d6d2430786B6471": { + "mywsapisendmessageRouteWebSocketIntegrationeb46e3593c10ed57eb0ca9ef3247823d74153661": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { @@ -469,9 +520,26 @@ }, "IntegrationType": "AWS_PROXY", "IntegrationUri": { - "Fn::GetAtt": [ - "MessageHandlerDFBBCD6B", - "Arn" + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:", + { + "Ref": "AWS::Region" + }, + ":lambda:path/2015-03-31/functions/", + { + "Fn::GetAtt": [ + "MessageHandlerDFBBCD6B", + "Arn" + ] + }, + "/invocations" + ] ] } } @@ -489,7 +557,7 @@ [ "integrations/", { - "Ref": "mywsapisendmessageRouteWebSocketIntegrationcf58a195e318f43f52c4d9ac6d6d2430786B6471" + "Ref": "mywsapisendmessageRouteWebSocketIntegrationeb46e3593c10ed57eb0ca9ef3247823d74153661" } ] ] diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/lambda.test.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/lambda.test.ts index 5f431ca28fc49..d5d7e4079db2d 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/lambda.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/lambda.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { WebSocketApi } from '@aws-cdk/aws-apigatewayv2'; import { Code, Function, Runtime } from '@aws-cdk/aws-lambda'; import { Stack } from '@aws-cdk/core'; @@ -21,7 +21,29 @@ describe('LambdaWebSocketIntegration', () => { // THEN expect(stack).toHaveResource('AWS::ApiGatewayV2::Integration', { IntegrationType: 'AWS_PROXY', - IntegrationUri: stack.resolve(fooFn.functionArn), + IntegrationUri: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':apigateway:', + { + Ref: 'AWS::Region', + }, + ':lambda:path/2015-03-31/functions/', + { + 'Fn::GetAtt': [ + 'Fn9270CBC0', + 'Arn', + ], + }, + '/invocations', + ], + ], + }, }); }); }); diff --git a/packages/@aws-cdk/aws-apigatewayv2/README.md b/packages/@aws-cdk/aws-apigatewayv2/README.md index 7a71fc00491a1..0d4d7849fd8df 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/README.md +++ b/packages/@aws-cdk/aws-apigatewayv2/README.md @@ -133,7 +133,7 @@ The `corsPreflight` option lets you specify a CORS configuration for an API. new HttpApi(stack, 'HttpProxyApi', { corsPreflight: { allowHeaders: ['Authorization'], - allowMethods: [HttpMethod.GET, HttpMethod.HEAD, HttpMethod.OPTIONS, HttpMethod.POST], + allowMethods: [CorsHttpMethod.GET, CorsHttpMethod.HEAD, CorsHttpMethod.OPTIONS, CorsHttpMethod.POST], allowOrigins: ['*'], maxAge: Duration.days(10), }, diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/common/api.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/common/api.ts index c632e6309083d..8e6089d3cf419 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/common/api.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/common/api.ts @@ -23,49 +23,4 @@ export interface IApi extends IResource { * @default - average over 5 minutes */ metric(metricName: string, props?: cloudwatch.MetricOptions): cloudwatch.Metric; - - /** - * Metric for the number of client-side errors captured in a given period. - * - * @default - sum over 5 minutes - */ - metricClientError(props?: cloudwatch.MetricOptions): cloudwatch.Metric; - - /** - * Metric for the number of server-side errors captured in a given period. - * - * @default - sum over 5 minutes - */ - metricServerError(props?: cloudwatch.MetricOptions): cloudwatch.Metric; - - /** - * Metric for the amount of data processed in bytes. - * - * @default - sum over 5 minutes - */ - metricDataProcessed(props?: cloudwatch.MetricOptions): cloudwatch.Metric; - - /** - * Metric for the total number API requests in a given period. - * - * @default - SampleCount over 5 minutes - */ - metricCount(props?: cloudwatch.MetricOptions): cloudwatch.Metric; - - /** - * Metric for the time between when API Gateway relays a request to the backend - * and when it receives a response from the backend. - * - * @default - no statistic - */ - metricIntegrationLatency(props?: cloudwatch.MetricOptions): cloudwatch.Metric; - - /** - * The time between when API Gateway receives a request from a client - * and when it returns a response to the client. - * The latency includes the integration latency and other API Gateway overhead. - * - * @default - no statistic - */ - metricLatency(props?: cloudwatch.MetricOptions): cloudwatch.Metric; } diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/common/base.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/common/base.ts index 542fcfb16f8f4..cd88fceba46b8 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/common/base.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/common/base.ts @@ -25,30 +25,6 @@ export abstract class ApiBase extends Resource implements IApi { ...props, }).attachTo(this); } - - public metricClientError(props?: cloudwatch.MetricOptions): cloudwatch.Metric { - return this.metric('4XXError', { statistic: 'Sum', ...props }); - } - - public metricServerError(props?: cloudwatch.MetricOptions): cloudwatch.Metric { - return this.metric('5XXError', { statistic: 'Sum', ...props }); - } - - public metricDataProcessed(props?: cloudwatch.MetricOptions): cloudwatch.Metric { - return this.metric('DataProcessed', { statistic: 'Sum', ...props }); - } - - public metricCount(props?: cloudwatch.MetricOptions): cloudwatch.Metric { - return this.metric('Count', { statistic: 'SampleCount', ...props }); - } - - public metricIntegrationLatency(props?: cloudwatch.MetricOptions): cloudwatch.Metric { - return this.metric('IntegrationLatency', props); - } - - public metricLatency(props?: cloudwatch.MetricOptions): cloudwatch.Metric { - return this.metric('Latency', props); - } } @@ -84,28 +60,4 @@ export abstract class StageBase extends Resource implements IStage { dimensions: { ApiId: this.baseApi.apiId, Stage: this.stageName }, }).attachTo(this); } - - public metricClientError(props?: cloudwatch.MetricOptions): cloudwatch.Metric { - return this.metric('4XXError', { statistic: 'Sum', ...props }); - } - - public metricServerError(props?: cloudwatch.MetricOptions): cloudwatch.Metric { - return this.metric('5XXError', { statistic: 'Sum', ...props }); - } - - public metricDataProcessed(props?: cloudwatch.MetricOptions): cloudwatch.Metric { - return this.metric('DataProcessed', { statistic: 'Sum', ...props }); - } - - public metricCount(props?: cloudwatch.MetricOptions): cloudwatch.Metric { - return this.metric('Count', { statistic: 'SampleCount', ...props }); - } - - public metricIntegrationLatency(props?: cloudwatch.MetricOptions): cloudwatch.Metric { - return this.metric('IntegrationLatency', props); - } - - public metricLatency(props?: cloudwatch.MetricOptions): cloudwatch.Metric { - return this.metric('Latency', props); - } } diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/common/stage.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/common/stage.ts index 40b7832418633..69f84a40da5e4 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/common/stage.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/common/stage.ts @@ -23,51 +23,6 @@ export interface IStage extends IResource { * @default - average over 5 minutes */ metric(metricName: string, props?: MetricOptions): Metric - - /** - * Metric for the number of client-side errors captured in a given period. - * - * @default - sum over 5 minutes - */ - metricClientError(props?: MetricOptions): Metric - - /** - * Metric for the number of server-side errors captured in a given period. - * - * @default - sum over 5 minutes - */ - metricServerError(props?: MetricOptions): Metric - - /** - * Metric for the amount of data processed in bytes. - * - * @default - sum over 5 minutes - */ - metricDataProcessed(props?: MetricOptions): Metric - - /** - * Metric for the total number API requests in a given period. - * - * @default - SampleCount over 5 minutes - */ - metricCount(props?: MetricOptions): Metric - - /** - * Metric for the time between when API Gateway relays a request to the backend - * and when it receives a response from the backend. - * - * @default - no statistic - */ - metricIntegrationLatency(props?: MetricOptions): Metric - - /** - * The time between when API Gateway receives a request from a client - * and when it returns a response to the client. - * The latency includes the integration latency and other API Gateway overhead. - * - * @default - no statistic - */ - metricLatency(props?: MetricOptions): Metric } /** diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts index 24d250dfd6eda..73abc83c16111 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts @@ -1,3 +1,4 @@ +import { Metric, MetricOptions } from '@aws-cdk/aws-cloudwatch'; import { Duration } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { CfnApi, CfnApiProps } from '../apigatewayv2.generated'; @@ -21,6 +22,51 @@ export interface IHttpApi extends IApi { */ readonly httpApiId: string; + /** + * Metric for the number of client-side errors captured in a given period. + * + * @default - sum over 5 minutes + */ + metricClientError(props?: MetricOptions): Metric; + + /** + * Metric for the number of server-side errors captured in a given period. + * + * @default - sum over 5 minutes + */ + metricServerError(props?: MetricOptions): Metric; + + /** + * Metric for the amount of data processed in bytes. + * + * @default - sum over 5 minutes + */ + metricDataProcessed(props?: MetricOptions): Metric; + + /** + * Metric for the total number API requests in a given period. + * + * @default - SampleCount over 5 minutes + */ + metricCount(props?: MetricOptions): Metric; + + /** + * Metric for the time between when API Gateway relays a request to the backend + * and when it receives a response from the backend. + * + * @default - no statistic + */ + metricIntegrationLatency(props?: MetricOptions): Metric; + + /** + * The time between when API Gateway receives a request from a client + * and when it returns a response to the client. + * The latency includes the integration latency and other API Gateway overhead. + * + * @default - no statistic + */ + metricLatency(props?: MetricOptions): Metric; + /** * Add a new VpcLink */ @@ -99,6 +145,28 @@ export interface HttpApiProps { readonly defaultAuthorizationScopes?: string[]; } +/** + * Supported CORS HTTP methods + */ +export enum CorsHttpMethod{ + /** HTTP ANY */ + ANY = '*', + /** HTTP DELETE */ + DELETE = 'DELETE', + /** HTTP GET */ + GET = 'GET', + /** HTTP HEAD */ + HEAD = 'HEAD', + /** HTTP OPTIONS */ + OPTIONS = 'OPTIONS', + /** HTTP PATCH */ + PATCH = 'PATCH', + /** HTTP POST */ + POST = 'POST', + /** HTTP PUT */ + PUT = 'PUT', +} + /** * Options for the CORS Configuration */ @@ -119,7 +187,7 @@ export interface CorsPreflightOptions { * Represents a collection of allowed HTTP methods. * @default - No Methods are allowed. */ - readonly allowMethods?: HttpMethod[]; + readonly allowMethods?: CorsHttpMethod[]; /** * Represents a collection of allowed origins. @@ -182,6 +250,30 @@ abstract class HttpApiBase extends ApiBase implements IHttpApi { // note that th public abstract readonly apiEndpoint: string; private vpcLinks: Record = {}; + public metricClientError(props?: MetricOptions): Metric { + return this.metric('4xx', { statistic: 'Sum', ...props }); + } + + public metricServerError(props?: MetricOptions): Metric { + return this.metric('5xx', { statistic: 'Sum', ...props }); + } + + public metricDataProcessed(props?: MetricOptions): Metric { + return this.metric('DataProcessed', { statistic: 'Sum', ...props }); + } + + public metricCount(props?: MetricOptions): Metric { + return this.metric('Count', { statistic: 'SampleCount', ...props }); + } + + public metricIntegrationLatency(props?: MetricOptions): Metric { + return this.metric('IntegrationLatency', props); + } + + public metricLatency(props?: MetricOptions): Metric { + return this.metric('Latency', props); + } + public addVpcLink(options: VpcLinkProps): VpcLink { const { vpcId } = options.vpc; if (vpcId in this.vpcLinks) { diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/route.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/route.ts index c3ef630abbbb5..2252630930c27 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/route.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/route.ts @@ -61,7 +61,7 @@ export class HttpRouteKey { if (path !== '/' && (!path.startsWith('/') || path.endsWith('/'))) { throw new Error('path must always start with a "/" and not end with a "/"'); } - return new HttpRouteKey(`${method ?? 'ANY'} ${path}`, path); + return new HttpRouteKey(`${method ?? HttpMethod.ANY} ${path}`, path); } /** diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/stage.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/stage.ts index d6a5f96320e3b..3ad58eea4364b 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/stage.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/stage.ts @@ -1,3 +1,4 @@ +import { Metric, MetricOptions } from '@aws-cdk/aws-cloudwatch'; import { Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { CfnStage } from '../apigatewayv2.generated'; @@ -16,6 +17,51 @@ export interface IHttpStage extends IStage { * The API this stage is associated to. */ readonly api: IHttpApi; + + /** + * Metric for the number of client-side errors captured in a given period. + * + * @default - sum over 5 minutes + */ + metricClientError(props?: MetricOptions): Metric + + /** + * Metric for the number of server-side errors captured in a given period. + * + * @default - sum over 5 minutes + */ + metricServerError(props?: MetricOptions): Metric + + /** + * Metric for the amount of data processed in bytes. + * + * @default - sum over 5 minutes + */ + metricDataProcessed(props?: MetricOptions): Metric + + /** + * Metric for the total number API requests in a given period. + * + * @default - SampleCount over 5 minutes + */ + metricCount(props?: MetricOptions): Metric + + /** + * Metric for the time between when API Gateway relays a request to the backend + * and when it receives a response from the backend. + * + * @default - no statistic + */ + metricIntegrationLatency(props?: MetricOptions): Metric + + /** + * The time between when API Gateway receives a request from a client + * and when it returns a response to the client. + * The latency includes the integration latency and other API Gateway overhead. + * + * @default - no statistic + */ + metricLatency(props?: MetricOptions): Metric } /** @@ -49,16 +95,44 @@ export interface HttpStageAttributes extends StageAttributes { readonly api: IHttpApi; } +abstract class HttpStageBase extends StageBase implements IHttpStage { + public abstract readonly api: IHttpApi; + + public metricClientError(props?: MetricOptions): Metric { + return this.metric('4xx', { statistic: 'Sum', ...props }); + } + + public metricServerError(props?: MetricOptions): Metric { + return this.metric('5xx', { statistic: 'Sum', ...props }); + } + + public metricDataProcessed(props?: MetricOptions): Metric { + return this.metric('DataProcessed', { statistic: 'Sum', ...props }); + } + + public metricCount(props?: MetricOptions): Metric { + return this.metric('Count', { statistic: 'SampleCount', ...props }); + } + + public metricIntegrationLatency(props?: MetricOptions): Metric { + return this.metric('IntegrationLatency', props); + } + + public metricLatency(props?: MetricOptions): Metric { + return this.metric('Latency', props); + } +} + /** * Represents a stage where an instance of the API is deployed. * @resource AWS::ApiGatewayV2::Stage */ -export class HttpStage extends StageBase implements IHttpStage { +export class HttpStage extends HttpStageBase { /** * Import an existing stage into this CDK app. */ public static fromHttpStageAttributes(scope: Construct, id: string, attrs: HttpStageAttributes): IHttpStage { - class Import extends StageBase implements IHttpStage { + class Import extends HttpStageBase { protected readonly baseApi = attrs.api; public readonly stageName = attrs.stageName; public readonly api = attrs.api; diff --git a/packages/@aws-cdk/aws-apigatewayv2/package.json b/packages/@aws-cdk/aws-apigatewayv2/package.json index b1dd874b85f9e..d53dfdede8aa5 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2/package.json @@ -76,11 +76,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", @@ -88,7 +89,7 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/aws-ec2": "0.0.0", @@ -96,7 +97,7 @@ "@aws-cdk/aws-certificatemanager": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/common/api-mapping.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/common/api-mapping.test.ts index b917f19513a57..705f3ca6a4371 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/common/api-mapping.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/common/api-mapping.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Certificate } from '@aws-cdk/aws-certificatemanager'; import { Stack } from '@aws-cdk/core'; import { DomainName, HttpApi, ApiMapping, WebSocketApi } from '../../lib'; diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/http/api.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/http/api.test.ts index 348d8dec9aeb4..25b0a5bca3189 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/http/api.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/http/api.test.ts @@ -1,9 +1,10 @@ -import '@aws-cdk/assert/jest'; -import { ABSENT } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +import { ABSENT } from '@aws-cdk/assert-internal'; import { Metric } from '@aws-cdk/aws-cloudwatch'; import * as ec2 from '@aws-cdk/aws-ec2'; import { Duration, Stack } from '@aws-cdk/core'; import { + CorsHttpMethod, HttpApi, HttpAuthorizer, HttpAuthorizerType, HttpIntegrationType, HttpMethod, HttpRouteAuthorizerBindOptions, HttpRouteAuthorizerConfig, HttpRouteIntegrationBindOptions, HttpRouteIntegrationConfig, IHttpRouteAuthorizer, IHttpRouteIntegration, HttpNoneAuthorizer, PayloadFormatVersion, } from '../../lib'; @@ -106,7 +107,7 @@ describe('HttpApi', () => { new HttpApi(stack, 'HttpApi', { corsPreflight: { allowHeaders: ['Authorization'], - allowMethods: [HttpMethod.GET, HttpMethod.HEAD, HttpMethod.OPTIONS, HttpMethod.POST], + allowMethods: [CorsHttpMethod.GET, CorsHttpMethod.HEAD, CorsHttpMethod.OPTIONS, CorsHttpMethod.POST, CorsHttpMethod.ANY], allowOrigins: ['*'], maxAge: Duration.seconds(36400), }, @@ -115,7 +116,7 @@ describe('HttpApi', () => { expect(stack).toHaveResource('AWS::ApiGatewayV2::Api', { CorsConfiguration: { AllowHeaders: ['Authorization'], - AllowMethods: ['GET', 'HEAD', 'OPTIONS', 'POST'], + AllowMethods: ['GET', 'HEAD', 'OPTIONS', 'POST', '*'], AllowOrigins: ['*'], MaxAge: 36400, }, @@ -147,7 +148,7 @@ describe('HttpApi', () => { const api = new HttpApi(stack, 'test-api', { createDefaultStage: false, }); - const metricName = '4xxError'; + const metricName = '4xx'; const statistic = 'Sum'; const apiId = api.apiId; @@ -184,6 +185,8 @@ describe('HttpApi', () => { expect(metric.dimensions).toEqual({ ApiId: apiId }); expect(metric.color).toEqual(color); } + const metricNames = metrics.map(m => m.metricName); + expect(metricNames).toEqual(['4xx', '5xx', 'DataProcessed', 'Latency', 'IntegrationLatency', 'Count']); }); test('Metrics from imported resource', () => { @@ -191,7 +194,7 @@ describe('HttpApi', () => { const stack = new Stack(); const apiId = 'importedId'; const api = HttpApi.fromHttpApiAttributes(stack, 'test-api', { httpApiId: apiId }); - const metricName = '4xxError'; + const metricName = '4xx'; const statistic = 'Sum'; // WHEN diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/http/authorizer.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/http/authorizer.test.ts index afb98fe733f19..9f99ccb9f7691 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/http/authorizer.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/http/authorizer.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Stack } from '@aws-cdk/core'; import { HttpApi, HttpAuthorizer, HttpAuthorizerType, diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/http/domain-name.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/http/domain-name.test.ts index f0a355c42f746..c0074ac464d63 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/http/domain-name.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/http/domain-name.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert/jest'; -// import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +// import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; import { Certificate } from '@aws-cdk/aws-certificatemanager'; import { Stack } from '@aws-cdk/core'; import { DomainName, HttpApi } from '../../lib'; diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/http/route.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/http/route.test.ts index 41af3121dc893..044d278e086e4 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/http/route.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/http/route.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Stack, App } from '@aws-cdk/core'; import { HttpApi, HttpAuthorizer, HttpAuthorizerType, HttpConnectionType, HttpIntegrationType, HttpMethod, HttpRoute, HttpRouteAuthorizerBindOptions, diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/http/stage.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/http/stage.test.ts index ff70ea026acb6..e3758183c68ff 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/http/stage.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/http/stage.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Metric } from '@aws-cdk/aws-cloudwatch'; import { Stack } from '@aws-cdk/core'; import { HttpApi, HttpStage } from '../../lib'; @@ -67,7 +67,7 @@ describe('HttpStage', () => { const stage = new HttpStage(stack, 'Stage', { httpApi: api, }); - const metricName = '4xxError'; + const metricName = '4xx'; const statistic = 'Sum'; const apiId = api.apiId; @@ -113,5 +113,7 @@ describe('HttpStage', () => { }); expect(metric.color).toEqual(color); } + const metricNames = metrics.map(m => m.metricName); + expect(metricNames).toEqual(['4xx', '5xx', 'DataProcessed', 'Latency', 'IntegrationLatency', 'Count']); }); }); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/http/vpc-link.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/http/vpc-link.test.ts index c6b68d7477bd7..134c70b653ce6 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/http/vpc-link.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/http/vpc-link.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import { Stack } from '@aws-cdk/core'; import { VpcLink } from '../../lib'; diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/websocket/api.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/websocket/api.test.ts index fcc65d4e18207..8a387941cad6f 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/websocket/api.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/websocket/api.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Stack } from '@aws-cdk/core'; import { IWebSocketRouteIntegration, WebSocketApi, WebSocketIntegrationType, diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/websocket/route.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/websocket/route.test.ts index 04e8e5fc7efac..ae73fd7e6cba0 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/websocket/route.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/websocket/route.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Stack } from '@aws-cdk/core'; import { IWebSocketRouteIntegration, WebSocketApi, WebSocketIntegrationType, diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/websocket/stage.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/websocket/stage.test.ts index 5ebdf0c61a980..4ff13cd6bb8d0 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/websocket/stage.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/websocket/stage.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Stack } from '@aws-cdk/core'; import { WebSocketApi, WebSocketStage } from '../../lib'; diff --git a/packages/@aws-cdk/aws-appconfig/package.json b/packages/@aws-cdk/aws-appconfig/package.json index 0836a936f672c..9baceaa0b44dd 100644 --- a/packages/@aws-cdk/aws-appconfig/package.json +++ b/packages/@aws-cdk/aws-appconfig/package.json @@ -73,18 +73,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-appconfig/test/appconfig.test.ts b/packages/@aws-cdk/aws-appconfig/test/appconfig.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-appconfig/test/appconfig.test.ts +++ b/packages/@aws-cdk/aws-appconfig/test/appconfig.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-appflow/package.json b/packages/@aws-cdk/aws-appflow/package.json index 6d047b697b394..3e11ac670e7b5 100644 --- a/packages/@aws-cdk/aws-appflow/package.json +++ b/packages/@aws-cdk/aws-appflow/package.json @@ -70,10 +70,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-appflow/test/appflow.test.ts b/packages/@aws-cdk/aws-appflow/test/appflow.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-appflow/test/appflow.test.ts +++ b/packages/@aws-cdk/aws-appflow/test/appflow.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-appintegrations/.eslintrc.js b/packages/@aws-cdk/aws-appintegrations/.eslintrc.js new file mode 100644 index 0000000000000..61dd8dd001f63 --- /dev/null +++ b/packages/@aws-cdk/aws-appintegrations/.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-appintegrations/.gitignore b/packages/@aws-cdk/aws-appintegrations/.gitignore new file mode 100644 index 0000000000000..62ebc95d75ce6 --- /dev/null +++ b/packages/@aws-cdk/aws-appintegrations/.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-appintegrations/.npmignore b/packages/@aws-cdk/aws-appintegrations/.npmignore new file mode 100644 index 0000000000000..e4486030fcb17 --- /dev/null +++ b/packages/@aws-cdk/aws-appintegrations/.npmignore @@ -0,0 +1,28 @@ +# 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 +test/ diff --git a/packages/@aws-cdk/aws-appintegrations/LICENSE b/packages/@aws-cdk/aws-appintegrations/LICENSE new file mode 100644 index 0000000000000..28e4bdcec77ec --- /dev/null +++ b/packages/@aws-cdk/aws-appintegrations/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-2021 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-appintegrations/NOTICE b/packages/@aws-cdk/aws-appintegrations/NOTICE new file mode 100644 index 0000000000000..5fc3826926b5b --- /dev/null +++ b/packages/@aws-cdk/aws-appintegrations/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/aws-appintegrations/README.md b/packages/@aws-cdk/aws-appintegrations/README.md new file mode 100644 index 0000000000000..67455ee5e4fe6 --- /dev/null +++ b/packages/@aws-cdk/aws-appintegrations/README.md @@ -0,0 +1,20 @@ +# AWS::AppIntegrations 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]) are always stable and safe to use. +> +> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib + +--- + + + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts +import appintegrations = require('@aws-cdk/aws-appintegrations'); +``` diff --git a/packages/@aws-cdk/aws-appintegrations/jest.config.js b/packages/@aws-cdk/aws-appintegrations/jest.config.js new file mode 100644 index 0000000000000..54e28beb9798b --- /dev/null +++ b/packages/@aws-cdk/aws-appintegrations/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-appintegrations/lib/index.ts b/packages/@aws-cdk/aws-appintegrations/lib/index.ts new file mode 100644 index 0000000000000..c62e3d98b2398 --- /dev/null +++ b/packages/@aws-cdk/aws-appintegrations/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::AppIntegrations CloudFormation Resources: +export * from './appintegrations.generated'; diff --git a/packages/@aws-cdk/aws-appintegrations/package.json b/packages/@aws-cdk/aws-appintegrations/package.json new file mode 100644 index 0000000000000..70068025c4f6b --- /dev/null +++ b/packages/@aws-cdk/aws-appintegrations/package.json @@ -0,0 +1,101 @@ +{ + "name": "@aws-cdk/aws-appintegrations", + "version": "0.0.0", + "description": "The CDK Construct Library for AWS::AppIntegrations", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "projectReferences": true, + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.AppIntegrations", + "packageId": "Amazon.CDK.AWS.AppIntegrations", + "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.appintegrations", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "appintegrations" + } + }, + "python": { + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 1" + ], + "distName": "aws-cdk.aws-appintegrations", + "module": "aws_cdk.aws_appintegrations" + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-appintegrations" + }, + "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": "yarn build && yarn test", + "build+test+package": "yarn build+test && yarn package", + "compat": "cdk-compat", + "gen": "cfn2ts", + "rosetta:extract": "yarn --silent jsii-rosetta extract" + }, + "cdk-build": { + "cloudformation": "AWS::AppIntegrations", + "jest": true, + "env": { + "AWSLINT_BASE_CONSTRUCT": "true" + } + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::AppIntegrations", + "aws-appintegrations" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@types/jest": "^26.0.23", + "@aws-cdk/assert-internal": "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 + }, + "publishConfig": { + "tag": "latest" + } +} diff --git a/packages/@aws-cdk/yaml-cfn/test/yaml.test.ts b/packages/@aws-cdk/aws-appintegrations/test/appintegrations.test.ts similarity index 57% rename from packages/@aws-cdk/yaml-cfn/test/yaml.test.ts rename to packages/@aws-cdk/aws-appintegrations/test/appintegrations.test.ts index f8ce8131c4de7..c4505ad966984 100644 --- a/packages/@aws-cdk/yaml-cfn/test/yaml.test.ts +++ b/packages/@aws-cdk/aws-appintegrations/test/appintegrations.test.ts @@ -1,4 +1,5 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; +import {} from '../lib'; test('No tests are specified for this package', () => { expect(true).toBe(true); diff --git a/packages/@aws-cdk/aws-applicationautoscaling/lib/schedule.ts b/packages/@aws-cdk/aws-applicationautoscaling/lib/schedule.ts index cdeb00be9a426..3bd74c1e4f681 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/lib/schedule.ts +++ b/packages/@aws-cdk/aws-applicationautoscaling/lib/schedule.ts @@ -17,11 +17,11 @@ export abstract class Schedule { * Construct a schedule from an interval and a time unit */ public static rate(duration: Duration): Schedule { - const validDurationUnit = ['minute', 'minutes', 'hour', 'hours', 'day', 'days']; - if (!validDurationUnit.includes(duration.unitLabel())) { - throw new Error("Allowed unit for scheduling is: 'minute', 'minutes', 'hour', 'hours', 'day' or 'days'"); - } if (duration.isUnresolved()) { + const validDurationUnit = ['minute', 'minutes', 'hour', 'hours', 'day', 'days']; + if (!validDurationUnit.includes(duration.unitLabel())) { + throw new Error("Allowed units for scheduling are: 'minute', 'minutes', 'hour', 'hours', 'day' or 'days'"); + } return new LiteralSchedule(`rate(${duration.formatTokenToNumber()})`); } if (duration.toSeconds() === 0) { diff --git a/packages/@aws-cdk/aws-applicationautoscaling/package.json b/packages/@aws-cdk/aws-applicationautoscaling/package.json index e9566094b344a..ed475aefa0b72 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/package.json +++ b/packages/@aws-cdk/aws-applicationautoscaling/package.json @@ -70,20 +70,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "fast-check": "^2.14.0", "nodeunit": "^0.11.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-autoscaling-common": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -91,7 +91,7 @@ "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-applicationautoscaling/test/test.cron.ts b/packages/@aws-cdk/aws-applicationautoscaling/test/test.cron.ts index ca0fb69812b10..324b2f8243c97 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/test/test.cron.ts +++ b/packages/@aws-cdk/aws-applicationautoscaling/test/test.cron.ts @@ -20,10 +20,16 @@ export = { test.done(); }, - 'rate must not be in seconds'(test: Test) { + 'rate can be in seconds'(test: Test) { + const duration = appscaling.Schedule.rate(Duration.seconds(120)); + test.equal('rate(2 minutes)', duration.expressionString); + test.done(); + }, + + 'rate must not be in seconds when specified as a token'(test: Test) { test.throws(() => { - appscaling.Schedule.rate(Duration.seconds(1)); - }, /Allowed unit for scheduling is: 'minute', 'minutes', 'hour', 'hours', 'day' or 'days'/); + appscaling.Schedule.rate(Duration.seconds(Lazy.number({ produce: () => 5 }))); + }, /Allowed units for scheduling/); test.done(); }, diff --git a/packages/@aws-cdk/aws-applicationautoscaling/test/test.scalable-target.ts b/packages/@aws-cdk/aws-applicationautoscaling/test/test.scalable-target.ts index 68622c2f60181..8c48f8b844a84 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/test/test.scalable-target.ts +++ b/packages/@aws-cdk/aws-applicationautoscaling/test/test.scalable-target.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk/aws-applicationautoscaling/test/test.step-scaling-policy.ts b/packages/@aws-cdk/aws-applicationautoscaling/test/test.step-scaling-policy.ts index fbcf70eb49f75..bb585daeb6eae 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/test/test.step-scaling-policy.ts +++ b/packages/@aws-cdk/aws-applicationautoscaling/test/test.step-scaling-policy.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike, SynthUtils } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike, SynthUtils } from '@aws-cdk/assert-internal'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as cdk from '@aws-cdk/core'; import * as fc from 'fast-check'; diff --git a/packages/@aws-cdk/aws-applicationautoscaling/test/test.target-tracking.ts b/packages/@aws-cdk/aws-applicationautoscaling/test/test.target-tracking.ts index 023678ec5076d..cbd67cbe9c330 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/test/test.target-tracking.ts +++ b/packages/@aws-cdk/aws-applicationautoscaling/test/test.target-tracking.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk/aws-applicationinsights/package.json b/packages/@aws-cdk/aws-applicationinsights/package.json index edef6de6de7f0..e24079e01a95c 100644 --- a/packages/@aws-cdk/aws-applicationinsights/package.json +++ b/packages/@aws-cdk/aws-applicationinsights/package.json @@ -73,10 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-applicationinsights/test/applicationinsights.test.ts b/packages/@aws-cdk/aws-applicationinsights/test/applicationinsights.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-applicationinsights/test/applicationinsights.test.ts +++ b/packages/@aws-cdk/aws-applicationinsights/test/applicationinsights.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-appmesh/README.md b/packages/@aws-cdk/aws-appmesh/README.md index 678bbe22a2c20..0adcc52901ba2 100644 --- a/packages/@aws-cdk/aws-appmesh/README.md +++ b/packages/@aws-cdk/aws-appmesh/README.md @@ -279,6 +279,65 @@ const gateway = new appmesh.VirtualGateway(this, 'gateway', { }); ``` +## Adding outlier detection to a Virtual Node listener + +The `outlierDetection` property can be added to a Virtual Node listener to add outlier detection. The 4 parameters +(`baseEjectionDuration`, `interval`, `maxEjectionPercent`, `maxServerErrors`) are required. + +```typescript +// Cloud Map service discovery is currently required for host ejection by outlier detection +const vpc = new ec2.Vpc(stack, 'vpc'); +const namespace = new servicediscovery.PrivateDnsNamespace(this, 'test-namespace', { + vpc, + name: 'domain.local', +}); +const service = namespace.createService('Svc'); + +const node = mesh.addVirtualNode('virtual-node', { + serviceDiscovery: appmesh.ServiceDiscovery.cloudMap({ + service: service, + }), + outlierDetection: { + baseEjectionDuration: cdk.Duration.seconds(10), + interval: cdk.Duration.seconds(30), + maxEjectionPercent: 50, + maxServerErrors: 5, + }, +}); +``` + +## Adding a connection pool to a listener + +The `connectionPool` property can be added to a Virtual Node listener or Virtual Gateway listener to add a request connection pool. There are different +connection pool properties per listener protocol types. + +```typescript +// A Virtual Node with a gRPC listener with a connection pool set +const node = new appmesh.VirtualNode(stack, 'node', { + mesh, + dnsHostName: 'node', + listeners: [appmesh.VirtualNodeListener.http({ + port: 80, + connectionPool: { + maxConnections: 100, + maxPendingRequests: 10, + }, + })], +}); + +// A Virtual Gateway with a gRPC listener with a connection pool set +const gateway = new appmesh.VirtualGateway(this, 'gateway', { + mesh: mesh, + listeners: [appmesh.VirtualGatewayListener.grpc({ + port: 8080, + connectionPool: { + maxRequests: 10, + }, + })], + virtualGatewayName: 'gateway', +}); +``` + ## Adding a Route A `route` is associated with a virtual router, and it's used to match requests for a virtual router and distribute traffic accordingly to its associated virtual nodes. diff --git a/packages/@aws-cdk/aws-appmesh/lib/private/utils.ts b/packages/@aws-cdk/aws-appmesh/lib/private/utils.ts index 0f63fdaf05253..7b5cfe620de1c 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/private/utils.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/private/utils.ts @@ -38,4 +38,30 @@ const HEALTH_CHECK_PROPERTY_THRESHOLDS: {[key in (keyof AppMeshHealthCheck)]?: [ port: [1, 65535], timeoutMillis: [2000, 60000], unhealthyThreshold: [2, 10], -}; \ No newline at end of file +}; + +/** + * Generated Connection pool config + */ +export interface ConnectionPoolConfig { + /** + * The maximum connections in the pool + * + * @default - none + */ + readonly maxConnections?: number; + + /** + * The maximum pending requests in the pool + * + * @default - none + */ + readonly maxPendingRequests?: number; + + /** + * The maximum requests in the pool + * + * @default - none + */ + readonly maxRequests?: number; +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-appmesh/lib/shared-interfaces.ts b/packages/@aws-cdk/aws-appmesh/lib/shared-interfaces.ts index 007f67c4a7a9b..5fb77b8cc4145 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/shared-interfaces.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/shared-interfaces.ts @@ -124,6 +124,32 @@ export interface HealthCheck { readonly unhealthyThreshold?: number; } +/** + * Represents the outlier detection for a listener. + */ +export interface OutlierDetection { + /** + * The base amount of time for which a host is ejected. + */ + readonly baseEjectionDuration: cdk.Duration; + + /** + * The time interval between ejection sweep analysis. + */ + readonly interval: cdk.Duration; + + /** + * Maximum percentage of hosts in load balancing pool for upstream service that can be ejected. Will eject at + * least one host regardless of the value. + */ + readonly maxEjectionPercent: number; + + /** + * Number of consecutive 5xx errors required for ejection. + */ + readonly maxServerErrors: number; +} + /** * All Properties for Envoy Access logs for mesh endpoints */ @@ -273,3 +299,58 @@ class VirtualServiceBackend extends Backend { }; } } + +/** + * Connection pool properties for HTTP listeners + */ +export interface HttpConnectionPool { + /** + * The maximum connections in the pool + * + * @default - none + */ + readonly maxConnections: number; + + /** + * The maximum pending requests in the pool + * + * @default - none + */ + readonly maxPendingRequests: number; +} + +/** + * Connection pool properties for TCP listeners + */ +export interface TcpConnectionPool { + /** + * The maximum connections in the pool + * + * @default - none + */ + readonly maxConnections: number; +} + +/** + * Connection pool properties for gRPC listeners + */ +export interface GrpcConnectionPool { + /** + * The maximum requests in the pool + * + * @default - none + */ + readonly maxRequests: number; +} + +/** + * Connection pool properties for HTTP2 listeners + */ +export interface Http2ConnectionPool { + /** + * The maximum requests in the pool + * + * @default - none + */ + readonly maxRequests: number; +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-appmesh/lib/virtual-gateway-listener.ts b/packages/@aws-cdk/aws-appmesh/lib/virtual-gateway-listener.ts index 9f081ffdefd60..f4a083e3ea35e 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/virtual-gateway-listener.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/virtual-gateway-listener.ts @@ -1,7 +1,13 @@ import * as cdk from '@aws-cdk/core'; import { CfnVirtualGateway } from './appmesh.generated'; -import { validateHealthChecks } from './private/utils'; -import { HealthCheck, Protocol } from './shared-interfaces'; +import { validateHealthChecks, ConnectionPoolConfig } from './private/utils'; +import { + GrpcConnectionPool, + HealthCheck, + Http2ConnectionPool, + HttpConnectionPool, + Protocol, +} from './shared-interfaces'; import { TlsCertificate, TlsCertificateConfig } from './tls-certificate'; // keep this import separate from other imports to reduce chance for merge conflicts with v2-main @@ -9,9 +15,9 @@ import { TlsCertificate, TlsCertificateConfig } from './tls-certificate'; import { Construct } from '@aws-cdk/core'; /** - * Represents the properties needed to define HTTP Listeners for a VirtualGateway + * Represents the properties needed to define a Listeners for a VirtualGateway */ -export interface HttpGatewayListenerOptions { +interface VirtualGatewayListenerCommonOptions { /** * Port to listen for connections on * @@ -35,29 +41,39 @@ export interface HttpGatewayListenerOptions { } /** - * Represents the properties needed to define GRPC Listeners for a VirtualGateway + * Represents the properties needed to define HTTP Listeners for a VirtualGateway */ -export interface GrpcGatewayListenerOptions { +export interface HttpGatewayListenerOptions extends VirtualGatewayListenerCommonOptions { /** - * Port to listen for connections on + * Connection pool for http listeners * - * @default - 8080 + * @default - None */ - readonly port?: number + readonly connectionPool?: HttpConnectionPool; +} +/** + * Represents the properties needed to define HTTP2 Listeners for a VirtualGateway + */ +export interface Http2GatewayListenerOptions extends VirtualGatewayListenerCommonOptions { /** - * The health check information for the listener + * Connection pool for http listeners * - * @default - no healthcheck + * @default - None */ - readonly healthCheck?: HealthCheck; + readonly connectionPool?: Http2ConnectionPool; +} +/** + * Represents the properties needed to define GRPC Listeners for a VirtualGateway + */ +export interface GrpcGatewayListenerOptions extends VirtualGatewayListenerCommonOptions { /** - * Represents the listener certificate + * Connection pool for http listeners * - * @default - none + * @default - None */ - readonly tlsCertificate?: TlsCertificate; + readonly connectionPool?: GrpcConnectionPool; } /** @@ -78,21 +94,21 @@ export abstract class VirtualGatewayListener { * Returns an HTTP Listener for a VirtualGateway */ public static http(options: HttpGatewayListenerOptions = {}): VirtualGatewayListener { - return new VirtualGatewayListenerImpl(Protocol.HTTP, options.healthCheck, options.port, options.tlsCertificate); + return new VirtualGatewayListenerImpl(Protocol.HTTP, options.healthCheck, options.port, options.tlsCertificate, options.connectionPool); } /** * Returns an HTTP2 Listener for a VirtualGateway */ - public static http2(options: HttpGatewayListenerOptions = {}): VirtualGatewayListener { - return new VirtualGatewayListenerImpl(Protocol.HTTP2, options.healthCheck, options.port, options.tlsCertificate); + public static http2(options: Http2GatewayListenerOptions = {}): VirtualGatewayListener { + return new VirtualGatewayListenerImpl(Protocol.HTTP2, options.healthCheck, options.port, options.tlsCertificate, options.connectionPool); } /** * Returns a GRPC Listener for a VirtualGateway */ public static grpc(options: GrpcGatewayListenerOptions = {}): VirtualGatewayListener { - return new VirtualGatewayListenerImpl(Protocol.GRPC, options.healthCheck, options.port, options.tlsCertificate); + return new VirtualGatewayListenerImpl(Protocol.GRPC, options.healthCheck, options.port, options.tlsCertificate, options.connectionPool); } /** @@ -110,7 +126,8 @@ class VirtualGatewayListenerImpl extends VirtualGatewayListener { constructor(private readonly protocol: Protocol, private readonly healthCheck: HealthCheck | undefined, private readonly port: number = 8080, - private readonly tlsCertificate: TlsCertificate | undefined) { + private readonly tlsCertificate: TlsCertificate | undefined, + private readonly connectionPool: ConnectionPoolConfig | undefined) { super(); } @@ -128,6 +145,7 @@ class VirtualGatewayListenerImpl extends VirtualGatewayListener { }, healthCheck: this.healthCheck ? renderHealthCheck(this.healthCheck, this.protocol, this.port): undefined, tls: tlsConfig ? renderTls(tlsConfig) : undefined, + connectionPool: this.connectionPool ? renderConnectionPool(this.connectionPool, this.protocol) : undefined, }, }; } @@ -171,3 +189,14 @@ function renderHealthCheck(hc: HealthCheck, listenerProtocol: Protocol, return healthCheck; } + +function renderConnectionPool(connectionPool: ConnectionPoolConfig, listenerProtocol: Protocol): +CfnVirtualGateway.VirtualGatewayConnectionPoolProperty { + return ({ + [listenerProtocol]: { + maxRequests: connectionPool?.maxRequests !== undefined ? connectionPool.maxRequests : undefined, + maxConnections: connectionPool?.maxConnections !== undefined ? connectionPool.maxConnections : undefined, + maxPendingRequests: connectionPool?.maxPendingRequests !== undefined ? connectionPool.maxPendingRequests : undefined, + }, + }); +} diff --git a/packages/@aws-cdk/aws-appmesh/lib/virtual-node-listener.ts b/packages/@aws-cdk/aws-appmesh/lib/virtual-node-listener.ts index 883d05583d5c7..7a046a138c3ca 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/virtual-node-listener.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/virtual-node-listener.ts @@ -1,7 +1,10 @@ import * as cdk from '@aws-cdk/core'; import { CfnVirtualNode } from './appmesh.generated'; -import { validateHealthChecks } from './private/utils'; -import { HealthCheck, Protocol, HttpTimeout, GrpcTimeout, TcpTimeout } from './shared-interfaces'; +import { validateHealthChecks, ConnectionPoolConfig } from './private/utils'; +import { + GrpcConnectionPool, GrpcTimeout, HealthCheck, Http2ConnectionPool, HttpConnectionPool, + HttpTimeout, OutlierDetection, Protocol, TcpConnectionPool, TcpTimeout, +} from './shared-interfaces'; import { TlsCertificate, TlsCertificateConfig } from './tls-certificate'; // keep this import separate from other imports to reduce chance for merge conflicts with v2-main @@ -42,18 +45,47 @@ interface VirtualNodeListenerCommonOptions { * @default - none */ readonly tlsCertificate?: TlsCertificate; + + /** + * Represents the configuration for enabling outlier detection + * + * @default - none + */ + readonly outlierDetection?: OutlierDetection; +} + +interface CommonHttpVirtualNodeListenerOptions extends VirtualNodeListenerCommonOptions { + /** + * Timeout for HTTP protocol + * + * @default - None + */ + readonly timeout?: HttpTimeout; } /** * Represent the HTTP Node Listener prorperty */ -export interface HttpVirtualNodeListenerOptions extends VirtualNodeListenerCommonOptions { +export interface HttpVirtualNodeListenerOptions extends CommonHttpVirtualNodeListenerOptions { + /** - * Timeout for HTTP protocol + * Connection pool for http listeners * * @default - None */ - readonly timeout?: HttpTimeout; + readonly connectionPool?: HttpConnectionPool; +} + +/** + * Represent the HTTP2 Node Listener prorperty + */ +export interface Http2VirtualNodeListenerOptions extends CommonHttpVirtualNodeListenerOptions { + /** + * Connection pool for http2 listeners + * + * @default - None + */ + readonly connectionPool?: Http2ConnectionPool; } /** @@ -66,6 +98,13 @@ export interface GrpcVirtualNodeListenerOptions extends VirtualNodeListenerCommo * @default - None */ readonly timeout?: GrpcTimeout; + + /** + * Connection pool for http listeners + * + * @default - None + */ + readonly connectionPool?: GrpcConnectionPool; } /** @@ -78,6 +117,13 @@ export interface TcpVirtualNodeListenerOptions extends VirtualNodeListenerCommon * @default - None */ readonly timeout?: TcpTimeout; + + /** + * Connection pool for http listeners + * + * @default - None + */ + readonly connectionPool?: TcpConnectionPool; } /** @@ -88,35 +134,38 @@ export abstract class VirtualNodeListener { * Returns an HTTP Listener for a VirtualNode */ public static http(props: HttpVirtualNodeListenerOptions = {}): VirtualNodeListener { - return new VirtualNodeListenerImpl(Protocol.HTTP, props.healthCheck, props.timeout, props.port, props.tlsCertificate); + return new VirtualNodeListenerImpl(Protocol.HTTP, props.healthCheck, props.timeout, props.port, props.tlsCertificate, props.outlierDetection, + props.connectionPool); } /** * Returns an HTTP2 Listener for a VirtualNode */ - public static http2(props: HttpVirtualNodeListenerOptions = {}): VirtualNodeListener { - return new VirtualNodeListenerImpl(Protocol.HTTP2, props.healthCheck, props.timeout, props.port, props.tlsCertificate); + public static http2(props: Http2VirtualNodeListenerOptions = {}): VirtualNodeListener { + return new VirtualNodeListenerImpl(Protocol.HTTP2, props.healthCheck, props.timeout, props.port, props.tlsCertificate, props.outlierDetection, + props.connectionPool); } /** * Returns an GRPC Listener for a VirtualNode */ public static grpc(props: GrpcVirtualNodeListenerOptions = {}): VirtualNodeListener { - return new VirtualNodeListenerImpl(Protocol.GRPC, props.healthCheck, props.timeout, props.port, props.tlsCertificate); + return new VirtualNodeListenerImpl(Protocol.GRPC, props.healthCheck, props.timeout, props.port, props.tlsCertificate, props.outlierDetection, + props.connectionPool); } /** * Returns an TCP Listener for a VirtualNode */ public static tcp(props: TcpVirtualNodeListenerOptions = {}): VirtualNodeListener { - return new VirtualNodeListenerImpl(Protocol.TCP, props.healthCheck, props.timeout, props.port, props.tlsCertificate); + return new VirtualNodeListenerImpl(Protocol.TCP, props.healthCheck, props.timeout, props.port, props.tlsCertificate, props.outlierDetection, + props.connectionPool); } /** * Binds the current object when adding Listener to a VirtualNode */ public abstract bind(scope: Construct): VirtualNodeListenerConfig; - } class VirtualNodeListenerImpl extends VirtualNodeListener { @@ -124,7 +173,9 @@ class VirtualNodeListenerImpl extends VirtualNodeListener { private readonly healthCheck: HealthCheck | undefined, private readonly timeout: HttpTimeout | undefined, private readonly port: number = 8080, - private readonly tlsCertificate: TlsCertificate | undefined) { super(); } + private readonly tlsCertificate: TlsCertificate | undefined, + private readonly outlierDetection: OutlierDetection | undefined, + private readonly connectionPool: ConnectionPoolConfig | undefined) { super(); } public bind(scope: Construct): VirtualNodeListenerConfig { const tlsConfig = this.tlsCertificate?.bind(scope); @@ -137,6 +188,8 @@ class VirtualNodeListenerImpl extends VirtualNodeListener { healthCheck: this.healthCheck ? this.renderHealthCheck(this.healthCheck) : undefined, timeout: this.timeout ? this.renderTimeout(this.timeout) : undefined, tls: tlsConfig ? this.renderTls(tlsConfig) : undefined, + outlierDetection: this.outlierDetection ? this.renderOutlierDetection(this.outlierDetection) : undefined, + connectionPool: this.connectionPool ? this.renderConnectionPool(this.connectionPool) : undefined, }, }; } @@ -191,5 +244,30 @@ class VirtualNodeListenerImpl extends VirtualNodeListener { }, }); } + + private renderOutlierDetection(outlierDetection: OutlierDetection): CfnVirtualNode.OutlierDetectionProperty { + return { + baseEjectionDuration: { + unit: 'ms', + value: outlierDetection.baseEjectionDuration.toMilliseconds(), + }, + interval: { + unit: 'ms', + value: outlierDetection.interval.toMilliseconds(), + }, + maxEjectionPercent: outlierDetection.maxEjectionPercent, + maxServerErrors: outlierDetection.maxServerErrors, + }; + } + + private renderConnectionPool(connectionPool: ConnectionPoolConfig): CfnVirtualNode.VirtualNodeConnectionPoolProperty { + return ({ + [this.protocol]: { + maxRequests: connectionPool?.maxRequests !== undefined ? connectionPool.maxRequests : undefined, + maxConnections: connectionPool?.maxConnections !== undefined ? connectionPool.maxConnections : undefined, + maxPendingRequests: connectionPool?.maxPendingRequests !== undefined ? connectionPool.maxPendingRequests : undefined, + }, + }); + } } diff --git a/packages/@aws-cdk/aws-appmesh/package.json b/packages/@aws-cdk/aws-appmesh/package.json index 32176758bd410..9549425e15202 100644 --- a/packages/@aws-cdk/aws-appmesh/package.json +++ b/packages/@aws-cdk/aws-appmesh/package.json @@ -75,13 +75,13 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "nodeunit": "^0.11.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-acmpca": "0.0.0", @@ -90,7 +90,7 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-servicediscovery": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/aws-acmpca": "0.0.0", @@ -99,7 +99,7 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-servicediscovery": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-appmesh/test/test.gateway-route.ts b/packages/@aws-cdk/aws-appmesh/test/test.gateway-route.ts index fed290d36a3e2..6b636507e718c 100644 --- a/packages/@aws-cdk/aws-appmesh/test/test.gateway-route.ts +++ b/packages/@aws-cdk/aws-appmesh/test/test.gateway-route.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk/aws-appmesh/test/test.mesh.ts b/packages/@aws-cdk/aws-appmesh/test/test.mesh.ts index 5c9c1cea7a9a1..ac71a80017d0a 100644 --- a/packages/@aws-cdk/aws-appmesh/test/test.mesh.ts +++ b/packages/@aws-cdk/aws-appmesh/test/test.mesh.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cloudmap from '@aws-cdk/aws-servicediscovery'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-appmesh/test/test.route.ts b/packages/@aws-cdk/aws-appmesh/test/test.route.ts index b3c1ae674a6f4..05cbd1dd04f4c 100644 --- a/packages/@aws-cdk/aws-appmesh/test/test.route.ts +++ b/packages/@aws-cdk/aws-appmesh/test/test.route.ts @@ -1,4 +1,4 @@ -import { ABSENT, expect, haveResourceLike } from '@aws-cdk/assert'; +import { ABSENT, expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk/aws-appmesh/test/test.virtual-gateway.ts b/packages/@aws-cdk/aws-appmesh/test/test.virtual-gateway.ts index 25b7974983f2a..96d3c7cba9210 100644 --- a/packages/@aws-cdk/aws-appmesh/test/test.virtual-gateway.ts +++ b/packages/@aws-cdk/aws-appmesh/test/test.virtual-gateway.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as acm from '@aws-cdk/aws-certificatemanager'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; @@ -423,6 +423,131 @@ export = { }, }, + 'Can add an http connection pool to listener'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const mesh = new appmesh.Mesh(stack, 'mesh', { + meshName: 'test-mesh', + }); + + new appmesh.VirtualGateway(stack, 'virtual-gateway', { + virtualGatewayName: 'virtual-gateway', + mesh: mesh, + listeners: [ + appmesh.VirtualGatewayListener.http({ + port: 80, + connectionPool: { + maxConnections: 100, + maxPendingRequests: 10, + }, + }), + ], + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::AppMesh::VirtualGateway', { + VirtualGatewayName: 'virtual-gateway', + Spec: { + Listeners: [ + { + ConnectionPool: { + HTTP: { + MaxConnections: 100, + MaxPendingRequests: 10, + }, + }, + }, + ], + }, + })); + + test.done(); + }, + + 'Can add an grpc connection pool to listener'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const mesh = new appmesh.Mesh(stack, 'mesh', { + meshName: 'test-mesh', + }); + + new appmesh.VirtualGateway(stack, 'virtual-gateway', { + virtualGatewayName: 'virtual-gateway', + mesh: mesh, + listeners: [ + appmesh.VirtualGatewayListener.grpc({ + port: 80, + connectionPool: { + maxRequests: 10, + }, + }), + ], + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::AppMesh::VirtualGateway', { + VirtualGatewayName: 'virtual-gateway', + Spec: { + Listeners: [ + { + ConnectionPool: { + GRPC: { + MaxRequests: 10, + }, + }, + }, + ], + }, + })); + + test.done(); + }, + + 'Can add an http2 connection pool to listener'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const mesh = new appmesh.Mesh(stack, 'mesh', { + meshName: 'test-mesh', + }); + + new appmesh.VirtualGateway(stack, 'virtual-gateway', { + virtualGatewayName: 'virtual-gateway', + mesh: mesh, + listeners: [ + appmesh.VirtualGatewayListener.http2({ + port: 80, + connectionPool: { + maxRequests: 10, + }, + }), + ], + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::AppMesh::VirtualGateway', { + VirtualGatewayName: 'virtual-gateway', + Spec: { + Listeners: [ + { + ConnectionPool: { + HTTP2: { + MaxRequests: 10, + }, + }, + }, + ], + }, + })); + + test.done(); + }, + 'Can import VirtualGateways using an ARN'(test: Test) { const app = new cdk.App(); // GIVEN diff --git a/packages/@aws-cdk/aws-appmesh/test/test.virtual-node.ts b/packages/@aws-cdk/aws-appmesh/test/test.virtual-node.ts index c09bdef5badbd..f143b0025c1db 100644 --- a/packages/@aws-cdk/aws-appmesh/test/test.virtual-node.ts +++ b/packages/@aws-cdk/aws-appmesh/test/test.virtual-node.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as acmpca from '@aws-cdk/aws-acmpca'; import * as acm from '@aws-cdk/aws-certificatemanager'; import * as cdk from '@aws-cdk/core'; @@ -257,6 +257,61 @@ export = { }, }, + 'when a listener is added with outlier detection with user defined props': { + 'should add a listener outlier detection to the resource'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const mesh = new appmesh.Mesh(stack, 'mesh', { + meshName: 'test-mesh', + }); + + const node = new appmesh.VirtualNode(stack, 'test-node', { + mesh, + serviceDiscovery: appmesh.ServiceDiscovery.dns('test'), + }); + + node.addListener(appmesh.VirtualNodeListener.tcp({ + port: 80, + outlierDetection: { + baseEjectionDuration: cdk.Duration.seconds(10), + interval: cdk.Duration.seconds(30), + maxEjectionPercent: 50, + maxServerErrors: 5, + }, + })); + + // THEN + expect(stack).to(haveResourceLike('AWS::AppMesh::VirtualNode', { + Spec: { + Listeners: [ + { + OutlierDetection: { + BaseEjectionDuration: { + Unit: 'ms', + Value: 10000, + }, + Interval: { + Unit: 'ms', + Value: 30000, + }, + MaxEjectionPercent: 50, + MaxServerErrors: 5, + }, + PortMapping: { + Port: 80, + Protocol: 'tcp', + }, + }, + ], + }, + })); + + test.done(); + }, + }, + 'when a default backend is added': { 'should add a backend default to the resource'(test: Test) { // GIVEN @@ -502,6 +557,164 @@ export = { test.done(); }, }, + + 'Can add an http connection pool to listener'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const mesh = new appmesh.Mesh(stack, 'mesh', { + meshName: 'test-mesh', + }); + + new appmesh.VirtualNode(stack, 'test-node', { + mesh, + listeners: [ + appmesh.VirtualNodeListener.http({ + port: 80, + connectionPool: { + maxConnections: 100, + maxPendingRequests: 10, + }, + }), + ], + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::AppMesh::VirtualNode', { + Spec: { + Listeners: [ + { + ConnectionPool: { + HTTP: { + MaxConnections: 100, + MaxPendingRequests: 10, + }, + }, + }, + ], + }, + })); + + test.done(); + }, + + 'Can add an tcp connection pool to listener'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const mesh = new appmesh.Mesh(stack, 'mesh', { + meshName: 'test-mesh', + }); + + new appmesh.VirtualNode(stack, 'test-node', { + mesh, + listeners: [ + appmesh.VirtualNodeListener.tcp({ + port: 80, + connectionPool: { + maxConnections: 100, + }, + }), + ], + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::AppMesh::VirtualNode', { + Spec: { + Listeners: [ + { + ConnectionPool: { + TCP: { + MaxConnections: 100, + }, + }, + }, + ], + }, + })); + + test.done(); + }, + + 'Can add an grpc connection pool to listener'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const mesh = new appmesh.Mesh(stack, 'mesh', { + meshName: 'test-mesh', + }); + + new appmesh.VirtualNode(stack, 'test-node', { + mesh, + listeners: [ + appmesh.VirtualNodeListener.grpc({ + port: 80, + connectionPool: { + maxRequests: 10, + }, + }), + ], + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::AppMesh::VirtualNode', { + Spec: { + Listeners: [ + { + ConnectionPool: { + GRPC: { + MaxRequests: 10, + }, + }, + }, + ], + }, + })); + + test.done(); + }, + + 'Can add an http2 connection pool to listener'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const mesh = new appmesh.Mesh(stack, 'mesh', { + meshName: 'test-mesh', + }); + + new appmesh.VirtualNode(stack, 'test-node', { + mesh, + listeners: [ + appmesh.VirtualNodeListener.http2({ + port: 80, + connectionPool: { + maxRequests: 10, + }, + }), + ], + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::AppMesh::VirtualNode', { + Spec: { + Listeners: [ + { + ConnectionPool: { + HTTP2: { + MaxRequests: 10, + }, + }, + }, + ], + }, + })); + + test.done(); + }, }, 'Can import Virtual Nodes using an ARN'(test: Test) { diff --git a/packages/@aws-cdk/aws-appmesh/test/test.virtual-router.ts b/packages/@aws-cdk/aws-appmesh/test/test.virtual-router.ts index fef86e6bd7e7a..c9c94add0c402 100644 --- a/packages/@aws-cdk/aws-appmesh/test/test.virtual-router.ts +++ b/packages/@aws-cdk/aws-appmesh/test/test.virtual-router.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk/aws-appmesh/test/test.virtual-service.ts b/packages/@aws-cdk/aws-appmesh/test/test.virtual-service.ts index c60c98f8e7b94..404cb5481141e 100644 --- a/packages/@aws-cdk/aws-appmesh/test/test.virtual-service.ts +++ b/packages/@aws-cdk/aws-appmesh/test/test.virtual-service.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk/aws-appstream/package.json b/packages/@aws-cdk/aws-appstream/package.json index e9655519ab834..027cf8919899e 100644 --- a/packages/@aws-cdk/aws-appstream/package.json +++ b/packages/@aws-cdk/aws-appstream/package.json @@ -72,18 +72,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-appstream/test/appstream.test.ts b/packages/@aws-cdk/aws-appstream/test/appstream.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-appstream/test/appstream.test.ts +++ b/packages/@aws-cdk/aws-appstream/test/appstream.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-appsync/README.md b/packages/@aws-cdk/aws-appsync/README.md index d15051d191a25..e0a636217f38b 100644 --- a/packages/@aws-cdk/aws-appsync/README.md +++ b/packages/@aws-cdk/aws-appsync/README.md @@ -26,7 +26,7 @@ APIs that use GraphQL. ## Example -## DynamoDB +### DynamoDB Example of a GraphQL API with `AWS_IAM` authorization resolving into a DynamoDb backend data source. @@ -95,7 +95,7 @@ demoDS.createResolver({ }); ``` -## Aurora Serverless +### Aurora Serverless AppSync provides a data source for executing SQL commands against Amazon Aurora Serverless clusters. You can use AppSync resolvers to execute SQL statements @@ -240,13 +240,13 @@ httpDs.createResolver({ }); ``` -### Schema +## Schema Every GraphQL Api needs a schema to define the Api. CDK offers `appsync.Schema` for static convenience methods for various types of schema declaration: code-first or schema-first. -#### Code-First +### Code-First When declaring your GraphQL Api, CDK defaults to a code-first approach if the `schema` property is not configured. @@ -274,7 +274,7 @@ const api = new appsync.GraphqlApi(stack, 'api', { See the [code-first schema](#Code-First-Schema) section for more details. -#### Schema-First +### Schema-First You can define your GraphQL Schema from a file on disk. For convenience, use the `appsync.Schema.fromAsset` to specify the file representing your schema. @@ -286,7 +286,7 @@ const api = appsync.GraphqlApi(stack, 'api', { }); ``` -### Imports +## Imports Any GraphQL Api that has been created outside the stack can be imported from another stack into your CDK app. Utilizing the `fromXxx` function, you have @@ -304,7 +304,7 @@ If you don't specify `graphqlArn` in `fromXxxAttributes`, CDK will autogenerate the expected `arn` for the imported api, given the `apiId`. For creating data sources and resolvers, an `apiId` is sufficient. -### Permissions +## Permissions When using `AWS_IAM` as the authorization type for GraphQL API, an IAM Role with correct permissions must be used for access to API. @@ -358,7 +358,7 @@ const api = new appsync.GraphqlApi(stack, 'API', { api.grant(role, appsync.IamResource.custom('types/Mutation/fields/updateExample'), 'appsync:GraphQL') ``` -#### IamResource +### IamResource In order to use the `grant` functions, you need to use the class `IamResource`. @@ -368,7 +368,7 @@ In order to use the `grant` functions, you need to use the class `IamResource`. - `IamResource.all()` permits ALL resources. -#### Generic Permissions +### Generic Permissions Alternatively, you can use more generic `grant` functions to accomplish the same usage. @@ -386,7 +386,7 @@ api.grantMutation(role, 'updateExample'); api.grant(role, appsync.IamResource.ofType('Mutation', 'updateExample'), 'appsync:GraphQL'); ``` -### Pipeline Resolvers and AppSync Functions +## Pipeline Resolvers and AppSync Functions AppSync Functions are local functions that perform certain operations onto a backend data source. Developers can compose operations (Functions) and execute @@ -418,7 +418,7 @@ const pipelineResolver = new appsync.Resolver(stack, 'pipeline', { Learn more about Pipeline Resolvers and AppSync Functions [here](https://docs.aws.amazon.com/appsync/latest/devguide/pipeline-resolvers.html). -### Code-First Schema +## Code-First Schema CDK offers the ability to generate your schema in a code-first approach. A code-first approach offers a developer workflow with: @@ -429,7 +429,7 @@ A code-first approach offers a developer workflow with: The code-first approach allows for **dynamic** schema generation. You can generate your schema based on variables and templates to reduce code duplication. -#### Code-First Example +### Code-First Example To showcase the code-first approach. Let's try to model the following schema segment. @@ -545,7 +545,7 @@ create the base Object Type (i.e. Film) and from there we can generate its respe Check out a more in-depth example [here](https://github.com/BryanPan342/starwars-code-first). -#### GraphQL Types +## GraphQL Types One of the benefits of GraphQL is its strongly typed nature. We define the types within an object, query, mutation, interface, etc. as **GraphQL Types**. @@ -562,7 +562,7 @@ More concretely, GraphQL Types are simply the types appended to variables. Referencing the object type `Demo` in the previous example, the GraphQL Types is `String!` and is applied to both the names `id` and `version`. -#### Directives +### Directives `Directives` are attached to a field or type and affect the execution of queries, mutations, and types. With AppSync, we use `Directives` to configure authorization. @@ -577,12 +577,12 @@ through `Cognito User Pools` To learn more about authorization and directives, read these docs [here](https://docs.aws.amazon.com/appsync/latest/devguide/security.html). -#### Field and Resolvable Fields +### Field and Resolvable Fields While `GraphqlType` is a base implementation for GraphQL fields, we have abstractions on top of `GraphqlType` that provide finer grain support. -#### Field +### Field `Field` extends `GraphqlType` and will allow you to define arguments. [**Interface Types**](#Interface-Types) are not resolvable and this class will allow you to define arguments, but not its resolvers. @@ -609,7 +609,7 @@ const type = new appsync.InterfaceType('Node', { }); ``` -#### Resolvable Fields +### Resolvable Fields `ResolvableField` extends `Field` and will allow you to define arguments and its resolvers. [**Object Types**](#Object-Types) can have fields that resolve and perform operations on @@ -671,7 +671,7 @@ const query = new appsync.ObjectType('Query', { Learn more about fields and resolvers [here](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-mapping-template-reference-overview.html). -#### Intermediate Types +### Intermediate Types Intermediate Types are defined by Graphql Types and Fields. They have a set of defined fields, where each field corresponds to another type in the system. Intermediate @@ -703,7 +703,7 @@ const node = new appsync.InterfaceType('Node', { To learn more about **Interface Types**, read the docs [here](https://graphql.org/learn/schema/#interfaces). -##### Object Types +#### Object Types **Object Types** are types that you declare. For example, in the [code-first example](#code-first-example) the `demo` variable is an **Object Type**. **Object Types** are defined by @@ -775,7 +775,7 @@ You can create Object Types in three ways: To learn more about **Object Types**, read the docs [here](https://graphql.org/learn/schema/#object-types-and-fields). -### Enum Types +#### Enum Types **Enum Types** are a special type of Intermediate Type. They restrict a particular set of allowed values for other Intermediate Types. @@ -832,7 +832,7 @@ api.addType(review); To learn more about **Input Types**, read the docs [here](https://graphql.org/learn/schema/#input-types). -### Union Types +#### Union Types **Union Types** are a special type of Intermediate Type. They are similar to Interface Types, but they cannot specify any common fields between types. @@ -860,7 +860,7 @@ api.addType(search); To learn more about **Union Types**, read the docs [here](https://graphql.org/learn/schema/#union-types). -#### Query +### Query Every schema requires a top level Query type. By default, the schema will look for the `Object Type` named `Query`. The top level `Query` is the **only** exposed @@ -883,7 +883,7 @@ api.addQuery('allFilms', new appsync.ResolvableField({ To learn more about top level operations, check out the docs [here](https://docs.aws.amazon.com/appsync/latest/devguide/graphql-overview.html). -#### Mutation +### Mutation Every schema **can** have a top level Mutation type. By default, the schema will look for the `ObjectType` named `Mutation`. The top level `Mutation` Type is the only exposed @@ -906,7 +906,7 @@ api.addMutation('addFilm', new appsync.ResolvableField({ To learn more about top level operations, check out the docs [here](https://docs.aws.amazon.com/appsync/latest/devguide/graphql-overview.html). -#### Subscription +### Subscription Every schema **can** have a top level Subscription type. The top level `Subscription` Type is the only exposed type that users can access to invoke a response to a mutation. `Subscriptions` diff --git a/packages/@aws-cdk/aws-appsync/lib/graphqlapi.ts b/packages/@aws-cdk/aws-appsync/lib/graphqlapi.ts index 2d9addb93cf24..9dcc75719b77b 100644 --- a/packages/@aws-cdk/aws-appsync/lib/graphqlapi.ts +++ b/packages/@aws-cdk/aws-appsync/lib/graphqlapi.ts @@ -242,7 +242,6 @@ export interface GraphqlApiProps { * * @default - schema will be generated code-first (i.e. addType, addObjectType, etc.) * - * @experimental */ readonly schema?: Schema; /** @@ -583,7 +582,6 @@ export class GraphqlApi extends GraphqlApiBase { * @param delimiter the delimiter between schema and addition * @default - '' * - * @experimental */ public addToSchema(addition: string, delimiter?: string): void { this.schema.addToSchema(addition, delimiter); @@ -594,7 +592,6 @@ export class GraphqlApi extends GraphqlApiBase { * * @param type the intermediate type to add to the schema * - * @experimental */ public addType(type: IIntermediateType): IIntermediateType { return this.schema.addType(type); diff --git a/packages/@aws-cdk/aws-appsync/lib/schema-base.ts b/packages/@aws-cdk/aws-appsync/lib/schema-base.ts index b824d2b29c4e6..fa876c395bc25 100644 --- a/packages/@aws-cdk/aws-appsync/lib/schema-base.ts +++ b/packages/@aws-cdk/aws-appsync/lib/schema-base.ts @@ -186,7 +186,6 @@ interface DirectiveOptions { * * i.e. @aws_iam or @aws_subscribe * - * @experimental */ export class Directive { /** diff --git a/packages/@aws-cdk/aws-appsync/lib/schema-field.ts b/packages/@aws-cdk/aws-appsync/lib/schema-field.ts index b276644873a7d..f8cf13a698878 100644 --- a/packages/@aws-cdk/aws-appsync/lib/schema-field.ts +++ b/packages/@aws-cdk/aws-appsync/lib/schema-field.ts @@ -11,7 +11,6 @@ import { Type, IField, IIntermediateType, Directive } from './schema-base'; * @option isRequired - is this attribute non-nullable * @option isRequiredList - is this attribute a non-nullable list * - * @experimental */ export interface BaseTypeOptions { /** @@ -48,7 +47,6 @@ export interface BaseTypeOptions { * @option isRequiredList - is this attribute a non-nullable list * @option objectType - the object type linked to this attribute * - * @experimental */ export interface GraphqlTypeOptions extends BaseTypeOptions { /** diff --git a/packages/@aws-cdk/aws-appsync/lib/schema-intermediate.ts b/packages/@aws-cdk/aws-appsync/lib/schema-intermediate.ts index 5d87ba2e7f130..6236a00ce1803 100644 --- a/packages/@aws-cdk/aws-appsync/lib/schema-intermediate.ts +++ b/packages/@aws-cdk/aws-appsync/lib/schema-intermediate.ts @@ -12,7 +12,6 @@ import { BaseTypeOptions, GraphqlType, ResolvableFieldOptions, ResolvableField } * i.e. { string: GraphqlType, string: GraphqlType } * @param directives - the directives for this object type * - * @experimental */ export interface IntermediateTypeOptions { /** @@ -31,7 +30,6 @@ export interface IntermediateTypeOptions { * Interface Types are abstract types that includes a certain set of fields * that other types must include if they implement the interface. * - * @experimental */ export class InterfaceType implements IIntermediateType { /** @@ -122,7 +120,6 @@ export class InterfaceType implements IIntermediateType { * @param interfaceTypes - the interfaces that this object type implements * @param directives - the directives for this object type * - * @experimental */ export interface ObjectTypeOptions extends IntermediateTypeOptions { /** @@ -136,7 +133,6 @@ export interface ObjectTypeOptions extends IntermediateTypeOptions { /** * Object Types are types declared by you. * - * @experimental */ export class ObjectType extends InterfaceType implements IIntermediateType { /** @@ -233,7 +229,6 @@ export class ObjectType extends InterfaceType implements IIntermediateType { * Input Types are abstract types that define complex objects. * They are used in arguments to represent * - * @experimental */ export class InputType implements IIntermediateType { /** @@ -309,7 +304,6 @@ export class InputType implements IIntermediateType { /** * Properties for configuring an Union Type * - * @experimental */ export interface UnionTypeOptions { /** @@ -325,7 +319,6 @@ export interface UnionTypeOptions { * Note that fields of a union type need to be object types. In other words, * you can't create a union type out of interfaces, other unions, or inputs. * - * @experimental */ export class UnionType implements IIntermediateType { /** @@ -405,7 +398,6 @@ export class UnionType implements IIntermediateType { /** * Properties for configuring an Enum Type * - * @experimental */ export interface EnumTypeOptions { /** @@ -418,7 +410,6 @@ export interface EnumTypeOptions { * Enum Types are abstract types that includes a set of fields * that represent the strings this type can create. * - * @experimental */ export class EnumType implements IIntermediateType { /** diff --git a/packages/@aws-cdk/aws-appsync/lib/schema.ts b/packages/@aws-cdk/aws-appsync/lib/schema.ts index 1ae6964bda346..fb22204c34440 100644 --- a/packages/@aws-cdk/aws-appsync/lib/schema.ts +++ b/packages/@aws-cdk/aws-appsync/lib/schema.ts @@ -98,7 +98,6 @@ export class Schema { * @param delimiter the delimiter between schema and addition * @default - '' * - * @experimental */ public addToSchema(addition: string, delimiter?: string): void { if (this.mode !== SchemaMode.CODE) { @@ -186,7 +185,6 @@ export class Schema { * * @param type the intermediate type to add to the schema * - * @experimental */ public addType(type: IIntermediateType): IIntermediateType { if (this.mode !== SchemaMode.CODE) { diff --git a/packages/@aws-cdk/aws-appsync/package.json b/packages/@aws-cdk/aws-appsync/package.json index f6bfb64813364..61ac81e9d385c 100644 --- a/packages/@aws-cdk/aws-appsync/package.json +++ b/packages/@aws-cdk/aws-appsync/package.json @@ -71,13 +71,14 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "jest": "^26.6.3", "pkglint": "0.0.0", - "@aws-cdk/aws-stepfunctions": "0.0.0" + "@aws-cdk/aws-stepfunctions": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-cognito": "0.0.0", @@ -89,7 +90,7 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -102,7 +103,7 @@ "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-rds": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-appsync/test/appsync-auth.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync-auth.test.ts index d1ca8a57ec5a0..c0d7ce0ac8796 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync-auth.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync-auth.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as path from 'path'; import * as cognito from '@aws-cdk/aws-cognito'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-appsync/test/appsync-code-first.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync-code-first.test.ts index f23b63ef1e301..5abe04434496a 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync-code-first.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync-code-first.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import * as appsync from '../lib'; import * as t from './scalar-type-defintions'; diff --git a/packages/@aws-cdk/aws-appsync/test/appsync-directives.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync-directives.test.ts index 7c0c792be1606..1d4d211ac8289 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync-directives.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync-directives.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cognito from '@aws-cdk/aws-cognito'; import * as cdk from '@aws-cdk/core'; import * as appsync from '../lib'; diff --git a/packages/@aws-cdk/aws-appsync/test/appsync-dynamodb.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync-dynamodb.test.ts index 07565edd1fba5..ffc36ddabd276 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync-dynamodb.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync-dynamodb.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as path from 'path'; import * as db from '@aws-cdk/aws-dynamodb'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-appsync/test/appsync-enum-type.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync-enum-type.test.ts index b937a0e12217d..82551e354d1a0 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync-enum-type.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync-enum-type.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import * as appsync from '../lib'; import * as t from './scalar-type-defintions'; diff --git a/packages/@aws-cdk/aws-appsync/test/appsync-grant.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync-grant.test.ts index d59b7c5d363cb..904c19b7dafd6 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync-grant.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync-grant.test.ts @@ -1,5 +1,5 @@ import { join } from 'path'; -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import * as appsync from '../lib'; diff --git a/packages/@aws-cdk/aws-appsync/test/appsync-http.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync-http.test.ts index 6484da2013921..8023412c78a55 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync-http.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync-http.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as path from 'path'; import * as sfn from '@aws-cdk/aws-stepfunctions'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-appsync/test/appsync-input-types.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync-input-types.test.ts index 6047854eaf946..bfc391aeaf0f3 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync-input-types.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync-input-types.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import * as appsync from '../lib'; import * as t from './scalar-type-defintions'; diff --git a/packages/@aws-cdk/aws-appsync/test/appsync-interface-type.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync-interface-type.test.ts index 89a578fc0bd0b..4061a2e69a0f9 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync-interface-type.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync-interface-type.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import * as appsync from '../lib'; import * as t from './scalar-type-defintions'; diff --git a/packages/@aws-cdk/aws-appsync/test/appsync-lambda.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync-lambda.test.ts index 11190591974a8..7ad869dc6cdd6 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync-lambda.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync-lambda.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as path from 'path'; import * as lambda from '@aws-cdk/aws-lambda'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-appsync/test/appsync-none.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync-none.test.ts index 3985cebc30719..6dc1e0ad9273f 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync-none.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync-none.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as path from 'path'; import * as cdk from '@aws-cdk/core'; import * as appsync from '../lib'; diff --git a/packages/@aws-cdk/aws-appsync/test/appsync-object-type.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync-object-type.test.ts index ef05e857c8eb6..f0517b2c0c24e 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync-object-type.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync-object-type.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import * as appsync from '../lib'; import * as t from './scalar-type-defintions'; diff --git a/packages/@aws-cdk/aws-appsync/test/appsync-rds.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync-rds.test.ts index 5a1b278dfc10f..1f7c942811791 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync-rds.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync-rds.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as path from 'path'; import { Vpc, SecurityGroup, SubnetType } from '@aws-cdk/aws-ec2'; import { DatabaseSecret, DatabaseClusterEngine, AuroraMysqlEngineVersion, ServerlessCluster } from '@aws-cdk/aws-rds'; diff --git a/packages/@aws-cdk/aws-appsync/test/appsync-scalar-type.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync-scalar-type.test.ts index 312d7a3784b98..150b45e747006 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync-scalar-type.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync-scalar-type.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import * as appsync from '../lib'; import * as t from './scalar-type-defintions'; diff --git a/packages/@aws-cdk/aws-appsync/test/appsync-schema.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync-schema.test.ts index fafc4e20c2e8a..37db685807139 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync-schema.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync-schema.test.ts @@ -1,5 +1,5 @@ import { join } from 'path'; -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import * as appsync from '../lib'; import * as t from './scalar-type-defintions'; diff --git a/packages/@aws-cdk/aws-appsync/test/appsync-union-types.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync-union-types.test.ts index 7cf14b9c2f870..a2f0e6f47a41a 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync-union-types.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync-union-types.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import * as appsync from '../lib'; import * as t from './scalar-type-defintions'; diff --git a/packages/@aws-cdk/aws-appsync/test/appsync.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync.test.ts index f4ddfc3ba9da0..773b1142b0917 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync.test.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import * as appsync from '../lib'; diff --git a/packages/@aws-cdk/aws-athena/package.json b/packages/@aws-cdk/aws-athena/package.json index 2a3cd7207b97f..a1b280f9a6ac1 100644 --- a/packages/@aws-cdk/aws-athena/package.json +++ b/packages/@aws-cdk/aws-athena/package.json @@ -71,21 +71,22 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "nodeunit-shim": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-athena/test/athena.test.ts b/packages/@aws-cdk/aws-athena/test/athena.test.ts index 6cadc1a5a8310..3e954a5b6c39b 100644 --- a/packages/@aws-cdk/aws-athena/test/athena.test.ts +++ b/packages/@aws-cdk/aws-athena/test/athena.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert/jest'; -import { expect, haveResource } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { CfnWorkGroup } from '../lib'; diff --git a/packages/@aws-cdk/aws-auditmanager/package.json b/packages/@aws-cdk/aws-auditmanager/package.json index b263be5fd8c92..ae2544821a2f8 100644 --- a/packages/@aws-cdk/aws-auditmanager/package.json +++ b/packages/@aws-cdk/aws-auditmanager/package.json @@ -73,10 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-auditmanager/test/auditmanager.test.ts b/packages/@aws-cdk/aws-auditmanager/test/auditmanager.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-auditmanager/test/auditmanager.test.ts +++ b/packages/@aws-cdk/aws-auditmanager/test/auditmanager.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-autoscaling-common/README.md b/packages/@aws-cdk/aws-autoscaling-common/README.md index 83b483af43573..fdea0531620e1 100644 --- a/packages/@aws-cdk/aws-autoscaling-common/README.md +++ b/packages/@aws-cdk/aws-autoscaling-common/README.md @@ -3,13 +3,7 @@ --- -![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. +![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge) --- diff --git a/packages/@aws-cdk/aws-autoscaling-common/package.json b/packages/@aws-cdk/aws-autoscaling-common/package.json index 8a43f80c5b9c7..12709e6ccaa55 100644 --- a/packages/@aws-cdk/aws-autoscaling-common/package.json +++ b/packages/@aws-cdk/aws-autoscaling-common/package.json @@ -62,24 +62,24 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "fast-check": "^2.14.0", "nodeunit": "^0.11.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "awslint": { "exclude": [ @@ -105,8 +105,8 @@ "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, - "stability": "experimental", - "maturity": "experimental", + "stability": "stable", + "maturity": "stable", "awscdkio": { "announce": false }, diff --git a/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json b/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json index b15364996c1f3..107f83ff25370 100644 --- a/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json +++ b/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json @@ -62,13 +62,14 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "@aws-cdk/aws-ec2": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-autoscaling": "0.0.0", @@ -79,7 +80,7 @@ "@aws-cdk/aws-sns-subscriptions": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -91,7 +92,7 @@ "@aws-cdk/aws-sns-subscriptions": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-autoscaling-hooktargets/test/hooks.test.ts b/packages/@aws-cdk/aws-autoscaling-hooktargets/test/hooks.test.ts index 9fcf5b6994878..d984693280351 100644 --- a/packages/@aws-cdk/aws-autoscaling-hooktargets/test/hooks.test.ts +++ b/packages/@aws-cdk/aws-autoscaling-hooktargets/test/hooks.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert/jest'; -import { arrayWith } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +import { arrayWith } from '@aws-cdk/assert-internal'; import * as autoscaling from '@aws-cdk/aws-autoscaling'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as kms from '@aws-cdk/aws-kms'; diff --git a/packages/@aws-cdk/aws-autoscaling/README.md b/packages/@aws-cdk/aws-autoscaling/README.md index 95e1a25963afe..67e55eee91a9f 100644 --- a/packages/@aws-cdk/aws-autoscaling/README.md +++ b/packages/@aws-cdk/aws-autoscaling/README.md @@ -360,6 +360,24 @@ new autoscaling.AutoScalingGroup(stack, 'ASG', { }); ``` +## Protecting new instances from being terminated on scale-in + +By default, Auto Scaling can terminate an instance at any time after launch when +scaling in an Auto Scaling Group, subject to the group's [termination +policy](https://docs.aws.amazon.com/autoscaling/ec2/userguide/as-instance-termination.html). + +However, you may wish to protect newly-launched instances from being scaled in +if they are going to run critical applications that should not be prematurely +terminated. EC2 Capacity Providers for Amazon ECS requires this attribute be +set to `true`. + +```ts +new autoscaling.AutoScalingGroup(stack, 'ASG', { + newInstancesProtectedFromScaleIn: true, + // ... +}); +``` + ## Future work * [ ] CloudWatch Events (impossible to add currently as the AutoScalingGroup ARN is diff --git a/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts b/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts index 42ea38ab80d11..3fa71ecb9a0e9 100644 --- a/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts +++ b/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts @@ -290,6 +290,23 @@ export interface CommonAutoScalingGroupProps { */ readonly updatePolicy?: UpdatePolicy; + /** + * Whether newly-launched instances are protected from termination by Amazon + * EC2 Auto Scaling when scaling in. + * + * By default, Auto Scaling can terminate an instance at any time after launch + * when scaling in an Auto Scaling Group, subject to the group's termination + * policy. However, you may wish to protect newly-launched instances from + * being scaled in if they are going to run critical applications that should + * not be prematurely terminated. + * + * This flag must be enabled if the Auto Scaling Group will be associated with + * an ECS Capacity Provider with managed termination protection. + * + * @default false + */ + readonly newInstancesProtectedFromScaleIn?: boolean; + /** * The name of the Auto Scaling group. This name must be unique per Region per account. * @default - Auto generated by CloudFormation @@ -901,11 +918,15 @@ export class AutoScalingGroup extends AutoScalingGroupBase implements private readonly groupMetrics: GroupMetrics[] = []; private readonly notifications: NotificationConfiguration[] = []; + protected newInstancesProtectedFromScaleIn?: boolean; + constructor(scope: Construct, id: string, props: AutoScalingGroupProps) { super(scope, id, { physicalName: props.autoScalingGroupName, }); + this.newInstancesProtectedFromScaleIn = props.newInstancesProtectedFromScaleIn; + if (props.initOptions && !props.init) { throw new Error('Setting \'initOptions\' requires that \'init\' is also set'); } @@ -1021,6 +1042,7 @@ export class AutoScalingGroup extends AutoScalingGroupBase implements healthCheckType: props.healthCheck && props.healthCheck.type, healthCheckGracePeriod: props.healthCheck && props.healthCheck.gracePeriod && props.healthCheck.gracePeriod.toSeconds(), maxInstanceLifetime: this.maxInstanceLifetime ? this.maxInstanceLifetime.toSeconds() : undefined, + newInstancesProtectedFromScaleIn: Lazy.any({ produce: () => this.newInstancesProtectedFromScaleIn }), }; if (!hasPublic && props.associatePublicIpAddress) { @@ -1126,6 +1148,20 @@ export class AutoScalingGroup extends AutoScalingGroupBase implements }); } + /** + * Ensures newly-launched instances are protected from scale-in. + */ + public protectNewInstancesFromScaleIn() { + this.newInstancesProtectedFromScaleIn = true; + } + + /** + * Returns `true` if newly-launched instances are protected from scale-in. + */ + public areNewInstancesProtectedFromScaleIn(): boolean { + return this.newInstancesProtectedFromScaleIn === true; + } + /** * Apply CloudFormation update policies for the AutoScalingGroup */ @@ -1620,13 +1656,13 @@ export interface RequestCountScalingProps extends BaseTargetTrackingProps { * Target average requests/seconds on each instance * * @deprecated Use 'targetRequestsPerMinute' instead - * @default - Specify exactly one of 'targetRequestsPerSecond' and 'targetRequestsPerSecond' + * @default - Specify exactly one of 'targetRequestsPerMinute' and 'targetRequestsPerSecond' */ readonly targetRequestsPerSecond?: number; /** * Target average requests/minute on each instance - * @default - Specify exactly one of 'targetRequestsPerSecond' and 'targetRequestsPerSecond' + * @default - Specify exactly one of 'targetRequestsPerMinute' and 'targetRequestsPerSecond' */ readonly targetRequestsPerMinute?: number; } diff --git a/packages/@aws-cdk/aws-autoscaling/package.json b/packages/@aws-cdk/aws-autoscaling/package.json index 79a8b3e02b967..3a35a0ac9f860 100644 --- a/packages/@aws-cdk/aws-autoscaling/package.json +++ b/packages/@aws-cdk/aws-autoscaling/package.json @@ -71,14 +71,15 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "@aws-cdk/cx-api": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "nodeunit-shim": "0.0.0", "pkglint": "0.0.0", - "@aws-cdk/cloud-assembly-schema": "0.0.0" + "@aws-cdk/cloud-assembly-schema": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-autoscaling-common": "0.0.0", @@ -89,7 +90,7 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -101,7 +102,7 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts b/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts index ae3be33401f71..9fb5da7b46ce8 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts +++ b/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts @@ -1,4 +1,4 @@ -import { ABSENT, expect, haveResource, haveResourceLike, InspectionFailure, ResourcePart } from '@aws-cdk/assert'; +import { ABSENT, expect, haveResource, haveResourceLike, InspectionFailure, ResourcePart } from '@aws-cdk/assert-internal'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; @@ -1320,6 +1320,50 @@ nodeunitShim({ test.deepEqual(Object.values(autoscaling.ScalingEvent).length - 1, autoscaling.ScalingEvents.ALL._types.length); test.done(); }, + + 'Can protect new instances from scale-in via constructor property'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const vpc = mockVpc(stack); + + // WHEN + const asg = new autoscaling.AutoScalingGroup(stack, 'MyASG', { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.M4, ec2.InstanceSize.MICRO), + machineImage: new ec2.AmazonLinuxImage(), + vpc, + newInstancesProtectedFromScaleIn: true, + }); + + // THEN + test.strictEqual(asg.areNewInstancesProtectedFromScaleIn(), true); + expect(stack).to(haveResourceLike('AWS::AutoScaling::AutoScalingGroup', { + NewInstancesProtectedFromScaleIn: true, + })); + + test.done(); + }, + + 'Can protect new instances from scale-in via setter'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const vpc = mockVpc(stack); + + // WHEN + const asg = new autoscaling.AutoScalingGroup(stack, 'MyASG', { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.M4, ec2.InstanceSize.MICRO), + machineImage: new ec2.AmazonLinuxImage(), + vpc, + }); + asg.protectNewInstancesFromScaleIn(); + + // THEN + test.strictEqual(asg.areNewInstancesProtectedFromScaleIn(), true); + expect(stack).to(haveResourceLike('AWS::AutoScaling::AutoScalingGroup', { + NewInstancesProtectedFromScaleIn: true, + })); + + test.done(); + }, }); function mockVpc(stack: cdk.Stack) { diff --git a/packages/@aws-cdk/aws-autoscaling/test/cfn-init.test.ts b/packages/@aws-cdk/aws-autoscaling/test/cfn-init.test.ts index ac7fb951907a7..58d9bc6ec152c 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/cfn-init.test.ts +++ b/packages/@aws-cdk/aws-autoscaling/test/cfn-init.test.ts @@ -1,4 +1,4 @@ -import { anything, arrayWith, expect, haveResourceLike, ResourcePart } from '@aws-cdk/assert'; +import { anything, arrayWith, expect, haveResourceLike, ResourcePart } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import { Duration, Stack } from '@aws-cdk/core'; import * as autoscaling from '../lib'; diff --git a/packages/@aws-cdk/aws-autoscaling/test/lifecyclehooks.test.ts b/packages/@aws-cdk/aws-autoscaling/test/lifecyclehooks.test.ts index 5db2600011100..24bebc1a605d0 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/lifecyclehooks.test.ts +++ b/packages/@aws-cdk/aws-autoscaling/test/lifecyclehooks.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, ResourcePart } from '@aws-cdk/assert'; +import { expect, haveResource, ResourcePart } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-autoscaling/test/scaling.test.ts b/packages/@aws-cdk/aws-autoscaling/test/scaling.test.ts index 5c1f8947b09bd..89b137dd5267f 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/scaling.test.ts +++ b/packages/@aws-cdk/aws-autoscaling/test/scaling.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; diff --git a/packages/@aws-cdk/aws-autoscaling/test/scheduled-action.test.ts b/packages/@aws-cdk/aws-autoscaling/test/scheduled-action.test.ts index 47e2e36f4b119..e5044af33543e 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/scheduled-action.test.ts +++ b/packages/@aws-cdk/aws-autoscaling/test/scheduled-action.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, MatchStyle } from '@aws-cdk/assert'; +import { expect, haveResource, MatchStyle } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import * as constructs from 'constructs'; diff --git a/packages/@aws-cdk/aws-autoscalingplans/package.json b/packages/@aws-cdk/aws-autoscalingplans/package.json index 5674f715e2b80..902f17dfd8ab0 100644 --- a/packages/@aws-cdk/aws-autoscalingplans/package.json +++ b/packages/@aws-cdk/aws-autoscalingplans/package.json @@ -71,19 +71,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-autoscalingplans/test/autoscalingplans.test.ts b/packages/@aws-cdk/aws-autoscalingplans/test/autoscalingplans.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-autoscalingplans/test/autoscalingplans.test.ts +++ b/packages/@aws-cdk/aws-autoscalingplans/test/autoscalingplans.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-backup/README.md b/packages/@aws-cdk/aws-backup/README.md index 47b54313a8fc9..3d1e81615fc37 100644 --- a/packages/@aws-cdk/aws-backup/README.md +++ b/packages/@aws-cdk/aws-backup/README.md @@ -5,17 +5,7 @@ ![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]) are always stable and safe to use. -> -> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib - -![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. +![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge) --- diff --git a/packages/@aws-cdk/aws-backup/package.json b/packages/@aws-cdk/aws-backup/package.json index 841f29f929f36..366c7a20f72f8 100644 --- a/packages/@aws-cdk/aws-backup/package.json +++ b/packages/@aws-cdk/aws-backup/package.json @@ -73,11 +73,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-dynamodb": "0.0.0", @@ -89,7 +90,7 @@ "@aws-cdk/aws-rds": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/aws-dynamodb": "0.0.0", @@ -101,13 +102,18 @@ "@aws-cdk/aws-rds": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, - "stability": "experimental", - "maturity": "experimental", + "awslint": { + "exclude": [ + "resource-attribute:@aws-cdk/aws-backup.BackupSelection.backupSelectionId" + ] + }, + "stability": "stable", + "maturity": "stable", "awscdkio": { "announce": false }, diff --git a/packages/@aws-cdk/aws-backup/test/plan.test.ts b/packages/@aws-cdk/aws-backup/test/plan.test.ts index 9d2eef140846e..91ac4baef7e02 100644 --- a/packages/@aws-cdk/aws-backup/test/plan.test.ts +++ b/packages/@aws-cdk/aws-backup/test/plan.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as events from '@aws-cdk/aws-events'; import { App, Duration, Stack } from '@aws-cdk/core'; import { BackupPlan, BackupPlanRule, BackupVault } from '../lib'; diff --git a/packages/@aws-cdk/aws-backup/test/selection.test.ts b/packages/@aws-cdk/aws-backup/test/selection.test.ts index d801efb34894c..3c4fd6d63ee56 100644 --- a/packages/@aws-cdk/aws-backup/test/selection.test.ts +++ b/packages/@aws-cdk/aws-backup/test/selection.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as dynamodb from '@aws-cdk/aws-dynamodb'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as efs from '@aws-cdk/aws-efs'; diff --git a/packages/@aws-cdk/aws-backup/test/vault.test.ts b/packages/@aws-cdk/aws-backup/test/vault.test.ts index dd1800c5b831e..183498bae31b3 100644 --- a/packages/@aws-cdk/aws-backup/test/vault.test.ts +++ b/packages/@aws-cdk/aws-backup/test/vault.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as sns from '@aws-cdk/aws-sns'; diff --git a/packages/@aws-cdk/aws-batch/package.json b/packages/@aws-cdk/aws-batch/package.json index 0b8f4666ab077..0ab890c0c9546 100644 --- a/packages/@aws-cdk/aws-batch/package.json +++ b/packages/@aws-cdk/aws-batch/package.json @@ -71,12 +71,13 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", @@ -86,7 +87,7 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -97,7 +98,7 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-batch/test/batch.test.ts b/packages/@aws-cdk/aws-batch/test/batch.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-batch/test/batch.test.ts +++ b/packages/@aws-cdk/aws-batch/test/batch.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-batch/test/compute-environment.test.ts b/packages/@aws-cdk/aws-batch/test/compute-environment.test.ts index 607479a4ae8fb..dd18be3f1496c 100644 --- a/packages/@aws-cdk/aws-batch/test/compute-environment.test.ts +++ b/packages/@aws-cdk/aws-batch/test/compute-environment.test.ts @@ -1,6 +1,6 @@ import { throws } from 'assert'; -import { expect, haveResource, haveResourceLike, ResourcePart } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { expect, haveResource, haveResourceLike, ResourcePart } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; import * as iam from '@aws-cdk/aws-iam'; diff --git a/packages/@aws-cdk/aws-batch/test/job-definition.test.ts b/packages/@aws-cdk/aws-batch/test/job-definition.test.ts index 1658be4c8e22e..2761611e063bb 100644 --- a/packages/@aws-cdk/aws-batch/test/job-definition.test.ts +++ b/packages/@aws-cdk/aws-batch/test/job-definition.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert/jest'; -import { ResourcePart } from '@aws-cdk/assert/lib/assertions/have-resource'; +import '@aws-cdk/assert-internal/jest'; +import { ResourcePart } from '@aws-cdk/assert-internal/lib/assertions/have-resource'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecr from '@aws-cdk/aws-ecr'; import * as ecs from '@aws-cdk/aws-ecs'; diff --git a/packages/@aws-cdk/aws-batch/test/job-queue.test.ts b/packages/@aws-cdk/aws-batch/test/job-queue.test.ts index 860999d7f29e1..0bec27b20899a 100644 --- a/packages/@aws-cdk/aws-batch/test/job-queue.test.ts +++ b/packages/@aws-cdk/aws-batch/test/job-queue.test.ts @@ -1,5 +1,5 @@ -import { ResourcePart } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { ResourcePart } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import * as batch from '../lib'; diff --git a/packages/@aws-cdk/aws-budgets/package.json b/packages/@aws-cdk/aws-budgets/package.json index 3d8297269395f..4b57842332145 100644 --- a/packages/@aws-cdk/aws-budgets/package.json +++ b/packages/@aws-cdk/aws-budgets/package.json @@ -71,19 +71,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-budgets/test/budgets.test.ts b/packages/@aws-cdk/aws-budgets/test/budgets.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-budgets/test/budgets.test.ts +++ b/packages/@aws-cdk/aws-budgets/test/budgets.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-cassandra/package.json b/packages/@aws-cdk/aws-cassandra/package.json index 5b0a317a627d8..9a66b67e105fd 100644 --- a/packages/@aws-cdk/aws-cassandra/package.json +++ b/packages/@aws-cdk/aws-cassandra/package.json @@ -73,10 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-cassandra/test/cassandra.test.ts b/packages/@aws-cdk/aws-cassandra/test/cassandra.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-cassandra/test/cassandra.test.ts +++ b/packages/@aws-cdk/aws-cassandra/test/cassandra.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-ce/package.json b/packages/@aws-cdk/aws-ce/package.json index 07c5e186da907..6dea1a924c2aa 100644 --- a/packages/@aws-cdk/aws-ce/package.json +++ b/packages/@aws-cdk/aws-ce/package.json @@ -73,10 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-ce/test/ce.test.ts b/packages/@aws-cdk/aws-ce/test/ce.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-ce/test/ce.test.ts +++ b/packages/@aws-cdk/aws-ce/test/ce.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-certificatemanager/jest.config.js b/packages/@aws-cdk/aws-certificatemanager/jest.config.js index cd664e1d069e5..54e28beb9798b 100644 --- a/packages/@aws-cdk/aws-certificatemanager/jest.config.js +++ b/packages/@aws-cdk/aws-certificatemanager/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/.eslintrc.js b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/.eslintrc.js new file mode 100644 index 0000000000000..2ab6719877209 --- /dev/null +++ b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/.eslintrc.js @@ -0,0 +1,3 @@ +const baseConfig = require('cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; +module.exports = baseConfig; \ No newline at end of file diff --git a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/.eslintrc.json b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/.eslintrc.json deleted file mode 100644 index 12a6e88f4c7c3..0000000000000 --- a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/.eslintrc.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "standard", - "rules": { - "semi": ["error", "always"] - }, - "env": { - "jest": true, - "node": true - } -} diff --git a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/lib/index.js b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/lib/index.js index 866e9405b049e..d34f7922f4e7e 100644 --- a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/lib/index.js +++ b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/lib/index.js @@ -2,7 +2,7 @@ const aws = require('aws-sdk'); -const defaultSleep = function(ms) { +const defaultSleep = function (ms) { return new Promise(resolve => setTimeout(resolve, ms)); }; @@ -24,7 +24,7 @@ let maxAttempts = 10; * @param {string} [reason] reason for failure, if any, to convey to the user * @returns {Promise} Promise that is resolved on success, or rejected on connection error or HTTP error response */ -let report = function(event, context, responseStatus, physicalResourceId, responseData, reason) { +let report = function (event, context, responseStatus, physicalResourceId, responseData, reason) { return new Promise((resolve, reject) => { const https = require('https'); const { URL } = require('url'); @@ -75,12 +75,13 @@ let report = function(event, context, responseStatus, physicalResourceId, respon * @param {string} requestId the CloudFormation request ID * @param {string} domainName the Common Name (CN) field for the requested certificate * @param {string} hostedZoneId the Route53 Hosted Zone ID + * @param {map} tags Tags to add to the requested certificate * @returns {string} Validated certificate ARN */ -const requestCertificate = async function(requestId, domainName, subjectAlternativeNames, hostedZoneId, region, route53Endpoint) { +const requestCertificate = async function (requestId, domainName, subjectAlternativeNames, hostedZoneId, region, route53Endpoint, tags) { const crypto = require('crypto'); const acm = new aws.ACM({ region }); - const route53 = route53Endpoint ? new aws.Route53({endpoint: route53Endpoint}) : new aws.Route53(); + const route53 = route53Endpoint ? new aws.Route53({ endpoint: route53Endpoint }) : new aws.Route53(); if (waiter) { // Used by the test suite, since waiters aren't mockable yet route53.waitFor = acm.waitFor = waiter; @@ -97,6 +98,16 @@ const requestCertificate = async function(requestId, domainName, subjectAlternat console.log(`Certificate ARN: ${reqCertResponse.CertificateArn}`); + + if (!!tags) { + const result = Array.from(Object.entries(tags)).map(([Key, Value]) => ({ Key, Value })) + + await acm.addTagsToCertificate({ + CertificateArn: reqCertResponse.CertificateArn, + Tags: result, + }).promise(); + } + console.log('Waiting for ACM to provide DNS records for validation...'); let records; @@ -129,6 +140,7 @@ const requestCertificate = async function(requestId, domainName, subjectAlternat throw new Error(`Response from describeCertificate did not contain DomainValidationOptions after ${maxAttempts} attempts.`) } + console.log(`Upserting ${records.length} DNS records into zone ${hostedZoneId}:`); const changeBatch = await route53.changeResourceRecordSets({ @@ -180,7 +192,7 @@ const requestCertificate = async function(requestId, domainName, subjectAlternat * * @param {string} arn The certificate ARN */ -const deleteCertificate = async function(arn, region) { +const deleteCertificate = async function (arn, region) { const acm = new aws.ACM({ region }); try { @@ -224,7 +236,7 @@ const deleteCertificate = async function(arn, region) { /** * Main handler, invoked by Lambda */ -exports.certificateRequestHandler = async function(event, context) { +exports.certificateRequestHandler = async function (event, context) { var responseData = {}; var physicalResourceId; var certificateArn; @@ -240,6 +252,7 @@ exports.certificateRequestHandler = async function(event, context) { event.ResourceProperties.HostedZoneId, event.ResourceProperties.Region, event.ResourceProperties.Route53Endpoint, + event.ResourceProperties.Tags, ); responseData.Arn = physicalResourceId = certificateArn; break; @@ -267,69 +280,69 @@ exports.certificateRequestHandler = async function(event, context) { /** * @private */ -exports.withReporter = function(reporter) { +exports.withReporter = function (reporter) { report = reporter; }; /** * @private */ -exports.withDefaultResponseURL = function(url) { +exports.withDefaultResponseURL = function (url) { defaultResponseURL = url; }; /** * @private */ -exports.withWaiter = function(w) { +exports.withWaiter = function (w) { waiter = w; }; /** * @private */ -exports.resetWaiter = function() { +exports.resetWaiter = function () { waiter = undefined; }; /** * @private */ -exports.withSleep = function(s) { +exports.withSleep = function (s) { sleep = s; } /** * @private */ -exports.resetSleep = function() { +exports.resetSleep = function () { sleep = defaultSleep; } /** * @private */ -exports.withRandom = function(r) { +exports.withRandom = function (r) { random = r; } /** * @private */ -exports.resetRandom = function() { +exports.resetRandom = function () { random = Math.random; } /** * @private */ -exports.withMaxAttempts = function(ma) { +exports.withMaxAttempts = function (ma) { maxAttempts = ma; } /** * @private */ -exports.resetMaxAttempts = function() { +exports.resetMaxAttempts = function () { maxAttempts = 10; } 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 0ccfbcc561479..e3dcc7e1b26c4 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 @@ -27,9 +27,12 @@ }, "license": "Apache-2.0", "devDependencies": { + "@types/aws-lambda": "^8.10.76", + "@types/sinon": "^9.0.11", + "cdk-build-tools": "0.0.0", "aws-sdk": "^2.596.0", "aws-sdk-mock": "^5.1.0", - "eslint": "^7.22.0", + "eslint": "^7.25.0", "eslint-config-standard": "^14.1.1", "eslint-plugin-import": "^2.22.1", "eslint-plugin-node": "^11.1.0", @@ -37,7 +40,8 @@ "eslint-plugin-standard": "^4.1.0", "jest": "^26.6.3", "lambda-tester": "^3.6.0", + "sinon": "^9.2.4", "nock": "^13.0.11", - "ts-jest": "^26.5.4" + "ts-jest": "^26.5.5" } } diff --git a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/test/handler.test.js b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/test/handler.test.js index 3e93f09680a91..5b53bc0a46301 100644 --- a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/test/handler.test.js +++ b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/test/handler.test.js @@ -20,13 +20,15 @@ describe('DNS Validated Certificate Handler', () => { const testRRValue = '_x2.acm-validations.aws'; const testAltRRName = '_3639ac514e785e898d2646601fa951d5.foo.example.com'; const testAltRRValue = '_x3.acm-validations.aws'; - const spySleep = sinon.spy(function(ms) { + const testTags = { Tag1: 'Test1', Tag2: 'Test2' }; + const testTagsValue = [{ Key: 'Tag1', Value: 'Test1' }, { Key: 'Tag2', Value: 'Test2' }]; + const spySleep = sinon.spy(function (ms) { return Promise.resolve(); }); beforeEach(() => { handler.withDefaultResponseURL(ResponseURL); - handler.withWaiter(function() { + handler.withWaiter(function () { // Mock waiter is merely a self-fulfilling promise return { promise: () => { @@ -37,7 +39,7 @@ describe('DNS Validated Certificate Handler', () => { }; }); handler.withSleep(spySleep); - console.log = function() { }; + console.log = function () { }; }); afterEach(() => { // Restore waiters and logger @@ -99,6 +101,8 @@ describe('DNS Validated Certificate Handler', () => { } }); + const addTagsToCertificateFake = sinon.fake.resolves({}); + const changeResourceRecordSetsFake = sinon.fake.resolves({ ChangeInfo: { Id: 'bogus' @@ -108,6 +112,7 @@ describe('DNS Validated Certificate Handler', () => { AWS.mock('ACM', 'requestCertificate', requestCertificateFake); AWS.mock('ACM', 'describeCertificate', describeCertificateFake); AWS.mock('Route53', 'changeResourceRecordSets', changeResourceRecordSetsFake); + AWS.mock('ACM', 'addTagsToCertificate', addTagsToCertificateFake); const request = nock(ResponseURL).put('/', body => { return body.Status === 'SUCCESS'; @@ -121,6 +126,7 @@ describe('DNS Validated Certificate Handler', () => { DomainName: testDomainName, HostedZoneId: testHostedZoneId, Region: 'us-east-1', + Tags: testTags } }) .expectResolve(() => { @@ -144,6 +150,10 @@ describe('DNS Validated Certificate Handler', () => { }, HostedZoneId: testHostedZoneId })); + sinon.assert.calledWith(addTagsToCertificateFake, sinon.match({ + "CertificateArn": testCertificateArn, + "Tags": testTagsValue, + })); expect(request.isDone()).toBe(true); }); }); @@ -182,14 +192,21 @@ describe('DNS Validated Certificate Handler', () => { } }); + const addTagsToCertificateFake = sinon.fake.resolves({ + Certificate: testCertificateArn, + Tags: testTags, + }); + const changeResourceRecordSetsFake = sinon.fake.resolves({ ChangeInfo: { Id: 'bogus' } }); + AWS.mock('ACM', 'requestCertificate', requestCertificateFake); AWS.mock('ACM', 'describeCertificate', describeCertificateFake); + AWS.mock('ACM', 'addTagsToCertificate', addTagsToCertificateFake); AWS.mock('Route53', 'changeResourceRecordSets', changeResourceRecordSetsFake); const request = nock(ResponseURL).put('/', body => { @@ -205,6 +222,7 @@ describe('DNS Validated Certificate Handler', () => { SubjectAlternativeNames: [testSubjectAlternativeName], HostedZoneId: testHostedZoneId, Region: 'us-east-1', + Tags: testTags, } }) .expectResolve(() => { @@ -241,6 +259,10 @@ describe('DNS Validated Certificate Handler', () => { }, HostedZoneId: testHostedZoneId })); + sinon.assert.calledWith(addTagsToCertificateFake, sinon.match({ + "CertificateArn": testCertificateArn, + "Tags": testTagsValue, + })); expect(request.isDone()).toBe(true); }); }); @@ -286,6 +308,11 @@ describe('DNS Validated Certificate Handler', () => { } }); + const addTagsToCertificateFake = sinon.fake.resolves({ + Certificate: testCertificateArn, + Tags: testTags, + }); + const changeResourceRecordSetsFake = sinon.fake.resolves({ ChangeInfo: { Id: 'bogus' @@ -294,6 +321,7 @@ describe('DNS Validated Certificate Handler', () => { AWS.mock('ACM', 'requestCertificate', requestCertificateFake); AWS.mock('ACM', 'describeCertificate', describeCertificateFake); + AWS.mock('ACM', 'addTagsToCertificate', addTagsToCertificateFake); AWS.mock('Route53', 'changeResourceRecordSets', changeResourceRecordSetsFake); const request = nock(ResponseURL).put('/', body => { @@ -308,6 +336,7 @@ describe('DNS Validated Certificate Handler', () => { DomainName: testDomainName, HostedZoneId: testHostedZoneId, Region: 'us-east-1', + Tags: testTags, } }) .expectResolve(() => { @@ -343,6 +372,10 @@ describe('DNS Validated Certificate Handler', () => { }, HostedZoneId: testHostedZoneId })); + sinon.assert.calledWith(addTagsToCertificateFake, sinon.match({ + "CertificateArn": testCertificateArn, + "Tags": testTagsValue, + })); expect(request.isDone()).toBe(true); }); }); @@ -453,6 +486,12 @@ describe('DNS Validated Certificate Handler', () => { }); AWS.mock('ACM', 'describeCertificate', describeCertificateFake); + const addTagsToCertificateFake = sinon.fake.resolves({ + Certificate: testCertificateArn, + Tags: testTags, + }); + AWS.mock('ACM', 'addTagsToCertificate', addTagsToCertificateFake); + const changeResourceRecordSetsFake = sinon.fake.resolves({ ChangeInfo: { Id: 'bogus' @@ -472,6 +511,7 @@ describe('DNS Validated Certificate Handler', () => { DomainName: testDomainName, HostedZoneId: testHostedZoneId, Region: 'us-east-1', + Tags: testTags, } }) .expectResolve(() => { @@ -479,6 +519,93 @@ describe('DNS Validated Certificate Handler', () => { sinon.assert.calledWith(describeCertificateFake, sinon.match({ CertificateArn: testCertificateArn, })); + sinon.assert.calledWith(addTagsToCertificateFake, sinon.match({ + "CertificateArn": testCertificateArn, + "Tags": testTagsValue, + })); + expect(request.isDone()).toBe(true); + }); + }); + + test('Create operation succeeds with no tags passed', () => { + const requestCertificateFake = sinon.fake.resolves({ + CertificateArn: testCertificateArn, + }); + + const describeCertificateFake = sinon.stub(); + describeCertificateFake.onFirstCall().resolves({ + Certificate: { + CertificateArn: testCertificateArn + } + }); + describeCertificateFake.resolves({ + Certificate: { + CertificateArn: testCertificateArn, + DomainValidationOptions: [{ + ValidationStatus: 'SUCCESS', + ResourceRecord: { + Name: testRRName, + Type: 'CNAME', + Value: testRRValue + } + }] + } + }); + + const changeResourceRecordSetsFake = sinon.fake.resolves({ + ChangeInfo: { + Id: 'bogus' + } + }); + + const addTagsToCertificateFake = sinon.fake.resolves({ + Certificate: testCertificateArn, + }); + + AWS.mock('ACM', 'requestCertificate', requestCertificateFake); + AWS.mock('ACM', 'describeCertificate', describeCertificateFake); + AWS.mock('Route53', 'changeResourceRecordSets', changeResourceRecordSetsFake); + AWS.mock('ACM', 'addTagsToCertificate', addTagsToCertificateFake); + + const request = nock(ResponseURL).put('/', body => { + return body.Status === 'SUCCESS'; + }).reply(200); + + return LambdaTester(handler.certificateRequestHandler) + .event({ + RequestType: 'Create', + RequestId: testRequestId, + ResourceProperties: { + DomainName: testDomainName, + HostedZoneId: testHostedZoneId, + Region: 'us-east-1' + } + }) + .expectResolve(() => { + sinon.assert.calledWith(requestCertificateFake, sinon.match({ + DomainName: testDomainName, + ValidationMethod: 'DNS' + })); + sinon.assert.calledWith(changeResourceRecordSetsFake, sinon.match({ + ChangeBatch: { + Changes: [{ + Action: 'UPSERT', + ResourceRecordSet: { + Name: testRRName, + Type: 'CNAME', + TTL: 60, + ResourceRecords: [{ + Value: testRRValue + }] + } + }] + }, + HostedZoneId: testHostedZoneId + })); + sinon.assert.neverCalledWith(addTagsToCertificateFake, sinon.match({ + "CertificateArn": testCertificateArn, + "Tags": testTagsValue, + })); expect(request.isDone()).toBe(true); }); }); diff --git a/packages/@aws-cdk/aws-certificatemanager/lib/dns-validated-certificate.ts b/packages/@aws-cdk/aws-certificatemanager/lib/dns-validated-certificate.ts index 6bb389afea97e..2c47ad9c49d9e 100644 --- a/packages/@aws-cdk/aws-certificatemanager/lib/dns-validated-certificate.ts +++ b/packages/@aws-cdk/aws-certificatemanager/lib/dns-validated-certificate.ts @@ -9,7 +9,6 @@ import { CertificateProps, ICertificate } from './certificate'; /** * Properties to create a DNS validated certificate managed by AWS Certificate Manager * - * @experimental */ export interface DnsValidatedCertificateProps extends CertificateProps { /** @@ -46,6 +45,7 @@ export interface DnsValidatedCertificateProps extends CertificateProps { * @default - A new role will be created */ readonly customResourceRole?: iam.IRole; + } /** @@ -53,10 +53,16 @@ export interface DnsValidatedCertificateProps extends CertificateProps { * validated using DNS validation against the specified Route 53 hosted zone. * * @resource AWS::CertificateManager::Certificate - * @experimental */ -export class DnsValidatedCertificate extends cdk.Resource implements ICertificate { +export class DnsValidatedCertificate extends cdk.Resource implements ICertificate, cdk.ITaggable { public readonly certificateArn: string; + + /** + * Resource Tags. + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-certificatemanager-certificate.html#cfn-certificatemanager-certificate-tags + */ + + public readonly tags: cdk.TagManager; private normalizedZoneName: string; private hostedZoneId: string; private domainName: string; @@ -73,6 +79,7 @@ export class DnsValidatedCertificate extends cdk.Resource implements ICertificat // Remove any `/hostedzone/` prefix from the Hosted Zone ID this.hostedZoneId = props.hostedZone.hostedZoneId.replace(/^\/hostedzone\//, ''); + this.tags = new cdk.TagManager(cdk.TagType.MAP, 'AWS::CertificateManager::Certificate'); const requestorFunction = new lambda.Function(this, 'CertificateRequestorFunction', { code: lambda.Code.fromAsset(path.resolve(__dirname, '..', 'lambda-packages', 'dns_validated_certificate_handler', 'lib')), @@ -82,7 +89,7 @@ export class DnsValidatedCertificate extends cdk.Resource implements ICertificat role: props.customResourceRole, }); requestorFunction.addToRolePolicy(new iam.PolicyStatement({ - actions: ['acm:RequestCertificate', 'acm:DescribeCertificate', 'acm:DeleteCertificate'], + actions: ['acm:RequestCertificate', 'acm:DescribeCertificate', 'acm:DeleteCertificate', 'acm:AddTagsToCertificate'], resources: ['*'], })); requestorFunction.addToRolePolicy(new iam.PolicyStatement({ @@ -102,6 +109,7 @@ export class DnsValidatedCertificate extends cdk.Resource implements ICertificat HostedZoneId: this.hostedZoneId, Region: props.region, Route53Endpoint: props.route53Endpoint, + Tags: cdk.Lazy.list({ produce: () => this.tags.renderTags() }), }, }); @@ -112,8 +120,8 @@ export class DnsValidatedCertificate extends cdk.Resource implements ICertificat const errors: string[] = []; // Ensure the zone name is a parent zone of the certificate domain name if (!cdk.Token.isUnresolved(this.normalizedZoneName) && - this.domainName !== this.normalizedZoneName && - !this.domainName.endsWith('.' + this.normalizedZoneName)) { + this.domainName !== this.normalizedZoneName && + !this.domainName.endsWith('.' + this.normalizedZoneName)) { errors.push(`DNS zone ${this.normalizedZoneName} is not authoritative for certificate domain name ${this.domainName}`); } return errors; diff --git a/packages/@aws-cdk/aws-certificatemanager/package.json b/packages/@aws-cdk/aws-certificatemanager/package.json index 96e0787fb06ec..b601342654213 100644 --- a/packages/@aws-cdk/aws-certificatemanager/package.json +++ b/packages/@aws-cdk/aws-certificatemanager/package.json @@ -71,17 +71,18 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -89,7 +90,7 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-certificatemanager/test/certificate.test.ts b/packages/@aws-cdk/aws-certificatemanager/test/certificate.test.ts index ab43a486ae7d1..1fd22c2175e26 100644 --- a/packages/@aws-cdk/aws-certificatemanager/test/certificate.test.ts +++ b/packages/@aws-cdk/aws-certificatemanager/test/certificate.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as route53 from '@aws-cdk/aws-route53'; import { Lazy, Stack } from '@aws-cdk/core'; import { Certificate, CertificateValidation, ValidationMethod } from '../lib'; diff --git a/packages/@aws-cdk/aws-certificatemanager/test/dns-validated-certificate.test.ts b/packages/@aws-cdk/aws-certificatemanager/test/dns-validated-certificate.test.ts index 17e89b68e4343..1b0a667b52738 100644 --- a/packages/@aws-cdk/aws-certificatemanager/test/dns-validated-certificate.test.ts +++ b/packages/@aws-cdk/aws-certificatemanager/test/dns-validated-certificate.test.ts @@ -1,8 +1,8 @@ -import '@aws-cdk/assert/jest'; -import { SynthUtils } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +import { SynthUtils } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import { HostedZone, PublicHostedZone } from '@aws-cdk/aws-route53'; -import { App, Stack, Token } from '@aws-cdk/core'; +import { App, Stack, Token, Tags } from '@aws-cdk/core'; import { DnsValidatedCertificate } from '../lib/dns-validated-certificate'; test('creates CloudFormation Custom Resource', () => { @@ -49,6 +49,7 @@ test('creates CloudFormation Custom Resource', () => { 'acm:RequestCertificate', 'acm:DescribeCertificate', 'acm:DeleteCertificate', + 'acm:AddTagsToCertificate', ], Effect: 'Allow', Resource: '*', @@ -136,6 +137,36 @@ test('test root certificate', () => { }); }); +test('test tags are passed to customresource', () => { + const stack = new Stack(); + Tags.of(stack).add('Key1', 'Value1'); + + const exampleDotComZone = new PublicHostedZone(stack, 'ExampleDotCom', { + zoneName: 'example.com', + }); + + new DnsValidatedCertificate(stack, 'Cert', { + domainName: 'example.com', + hostedZone: exampleDotComZone, + }); + + expect(stack).toHaveResource('AWS::CloudFormation::CustomResource', { + ServiceToken: { + 'Fn::GetAtt': [ + 'CertCertificateRequestorFunction98FDF273', + 'Arn', + ], + }, + DomainName: 'example.com', + HostedZoneId: { + Ref: 'ExampleDotCom4D1B83AA', + }, + Tags: { + Key1: 'Value1', + }, + }); +}); + test('works with imported zone', () => { // GIVEN const app = new App(); diff --git a/packages/@aws-cdk/aws-certificatemanager/test/util.test.ts b/packages/@aws-cdk/aws-certificatemanager/test/util.test.ts index 2b14771c3a517..a4bdb2e05e1e0 100644 --- a/packages/@aws-cdk/aws-certificatemanager/test/util.test.ts +++ b/packages/@aws-cdk/aws-certificatemanager/test/util.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { PublicHostedZone } from '@aws-cdk/aws-route53'; import { App, Aws, Stack } from '@aws-cdk/core'; import { Certificate, DnsValidatedCertificate } from '../lib'; diff --git a/packages/@aws-cdk/aws-chatbot/README.md b/packages/@aws-cdk/aws-chatbot/README.md index 2c4cee1196900..857e2524ed784 100644 --- a/packages/@aws-cdk/aws-chatbot/README.md +++ b/packages/@aws-cdk/aws-chatbot/README.md @@ -5,17 +5,7 @@ ![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]) are always stable and safe to use. -> -> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib - -![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. +![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge) --- diff --git a/packages/@aws-cdk/aws-chatbot/package.json b/packages/@aws-cdk/aws-chatbot/package.json index ab267bf8f1c0c..b1a327c77f19a 100644 --- a/packages/@aws-cdk/aws-chatbot/package.json +++ b/packages/@aws-cdk/aws-chatbot/package.json @@ -73,11 +73,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", @@ -85,7 +86,7 @@ "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", @@ -93,13 +94,13 @@ "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, - "stability": "experimental", - "maturity": "experimental", + "stability": "stable", + "maturity": "stable", "awscdkio": { "announce": false }, diff --git a/packages/@aws-cdk/aws-chatbot/test/integ.chatbot-logretention.ts b/packages/@aws-cdk/aws-chatbot/test/integ.chatbot-logretention.ts index cbb8de485b295..c443319bd336f 100644 --- a/packages/@aws-cdk/aws-chatbot/test/integ.chatbot-logretention.ts +++ b/packages/@aws-cdk/aws-chatbot/test/integ.chatbot-logretention.ts @@ -1,3 +1,4 @@ +/// !cdk-integ pragma:ignore-assets import * as iam from '@aws-cdk/aws-iam'; import * as logs from '@aws-cdk/aws-logs'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-chatbot/test/slack-channel-configuration.test.ts b/packages/@aws-cdk/aws-chatbot/test/slack-channel-configuration.test.ts index de5a5da9a63c1..21d530bfd839a 100644 --- a/packages/@aws-cdk/aws-chatbot/test/slack-channel-configuration.test.ts +++ b/packages/@aws-cdk/aws-chatbot/test/slack-channel-configuration.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert/jest'; -import { ABSENT } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +import { ABSENT } from '@aws-cdk/assert-internal'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as iam from '@aws-cdk/aws-iam'; import * as logs from '@aws-cdk/aws-logs'; diff --git a/packages/@aws-cdk/aws-cloud9/package.json b/packages/@aws-cdk/aws-cloud9/package.json index e71b8c60f3bc0..deef42d133ecd 100644 --- a/packages/@aws-cdk/aws-cloud9/package.json +++ b/packages/@aws-cdk/aws-cloud9/package.json @@ -71,25 +71,26 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "@aws-cdk/aws-codecommit": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-cloud9/test/cloud9.environment.test.ts b/packages/@aws-cdk/aws-cloud9/test/cloud9.environment.test.ts index d2a1a43fa0755..231484ea26ffb 100644 --- a/packages/@aws-cdk/aws-cloud9/test/cloud9.environment.test.ts +++ b/packages/@aws-cdk/aws-cloud9/test/cloud9.environment.test.ts @@ -1,4 +1,4 @@ -import { expect as expectCDK, haveResource, haveResourceLike } from '@aws-cdk/assert'; +import { expect as expectCDK, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; import * as codecommit from '@aws-cdk/aws-codecommit'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-cloud9/test/cloud9.test.ts b/packages/@aws-cdk/aws-cloud9/test/cloud9.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-cloud9/test/cloud9.test.ts +++ b/packages/@aws-cdk/aws-cloud9/test/cloud9.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-cloudformation/package.json b/packages/@aws-cdk/aws-cloudformation/package.json index 550bc780b750d..9433981c2133a 100644 --- a/packages/@aws-cdk/aws-cloudformation/package.json +++ b/packages/@aws-cdk/aws-cloudformation/package.json @@ -67,19 +67,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", "@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.72", + "@types/aws-lambda": "^8.10.76", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "nodeunit": "^0.11.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", @@ -88,7 +88,7 @@ "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -98,7 +98,7 @@ "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-cloudformation/test/test.deps.ts b/packages/@aws-cdk/aws-cloudformation/test/test.deps.ts index 7917763b82666..de239daffb9a8 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/test.deps.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/test.deps.ts @@ -1,6 +1,6 @@ import * as fs from 'fs'; import * as path from 'path'; -import { expect, haveResource, ResourcePart } from '@aws-cdk/assert'; +import { expect, haveResource, ResourcePart } from '@aws-cdk/assert-internal'; import { App, CfnResource, Stack } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk/aws-cloudformation/test/test.nested-stack.ts b/packages/@aws-cdk/aws-cloudformation/test/test.nested-stack.ts index 7a443a6db19cd..8921c2722eda3 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/test.nested-stack.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/test.nested-stack.ts @@ -1,6 +1,6 @@ import * as fs from 'fs'; import * as path from 'path'; -import { expect, haveResource, matchTemplate, SynthUtils } from '@aws-cdk/assert'; +import { expect, haveResource, matchTemplate, SynthUtils } from '@aws-cdk/assert-internal'; import * as s3_assets from '@aws-cdk/aws-s3-assets'; import * as sns from '@aws-cdk/aws-sns'; import { App, CfnParameter, CfnResource, ContextProvider, LegacyStackSynthesizer, Names, Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-cloudformation/test/test.resource.ts b/packages/@aws-cdk/aws-cloudformation/test/test.resource.ts index 7015fe21bf948..387aa45240e92 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/test.resource.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/test.resource.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, ResourcePart } from '@aws-cdk/assert'; +import { expect, haveResource, ResourcePart } from '@aws-cdk/assert-internal'; import * as lambda from '@aws-cdk/aws-lambda'; import * as sns from '@aws-cdk/aws-sns'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-cloudfront-origins/package.json b/packages/@aws-cdk/aws-cloudfront-origins/package.json index d90ce2d097315..92688f9d2ce76 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/package.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/package.json @@ -69,12 +69,13 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "@aws-cdk/aws-ec2": "0.0.0", "aws-sdk": "^2.848.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-cloudfront": "0.0.0", @@ -82,12 +83,12 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0", + "constructs": "^3.3.69", "@aws-cdk/aws-cloudfront": "0.0.0", "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/http-origin.test.ts b/packages/@aws-cdk/aws-cloudfront-origins/test/http-origin.test.ts index 77b9beccea7e1..dc8c6c702fce3 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/http-origin.test.ts +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/http-origin.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cloudfront from '@aws-cdk/aws-cloudfront'; import { App, Duration, Stack } from '@aws-cdk/core'; import { HttpOrigin } from '../lib'; diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/load-balancer-origin.test.ts b/packages/@aws-cdk/aws-cloudfront-origins/test/load-balancer-origin.test.ts index 65464ea1c2b7f..8a21feb22f30e 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/load-balancer-origin.test.ts +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/load-balancer-origin.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cloudfront from '@aws-cdk/aws-cloudfront'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import { App, Duration, Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/origin-group.test.ts b/packages/@aws-cdk/aws-cloudfront-origins/test/origin-group.test.ts index 2d343b686dff9..d8f8bb10fabb2 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/origin-group.test.ts +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/origin-group.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cloudfront from '@aws-cdk/aws-cloudfront'; import * as s3 from '@aws-cdk/aws-s3'; import { Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/s3-origin.test.ts b/packages/@aws-cdk/aws-cloudfront-origins/test/s3-origin.test.ts index a502dd5cf4f46..c9e0ecb797464 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/s3-origin.test.ts +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/s3-origin.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cloudfront from '@aws-cdk/aws-cloudfront'; import * as s3 from '@aws-cdk/aws-s3'; import { App, Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-cloudfront/lib/cache-policy.ts b/packages/@aws-cdk/aws-cloudfront/lib/cache-policy.ts index e9dbf46901eda..0d851e8a886ef 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/cache-policy.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/cache-policy.ts @@ -1,4 +1,4 @@ -import { Duration, Names, Resource, Token } from '@aws-cdk/core'; +import { Duration, Names, Resource, Stack, Token } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { CfnCachePolicy } from './cloudfront.generated'; @@ -125,7 +125,7 @@ export class CachePolicy extends Resource implements ICachePolicy { physicalName: props.cachePolicyName, }); - const cachePolicyName = props.cachePolicyName ?? Names.uniqueId(this); + const cachePolicyName = props.cachePolicyName ?? `${Names.uniqueId(this)}-${Stack.of(this).region}`; if (!Token.isUnresolved(cachePolicyName) && !cachePolicyName.match(/^[\w-]+$/i)) { throw new Error(`'cachePolicyName' can only include '-', '_', and alphanumeric characters, got: '${props.cachePolicyName}'`); } @@ -231,9 +231,6 @@ export class CacheHeaderBehavior { if (headers.length === 0) { throw new Error('At least one header to allow must be provided'); } - if (headers.length > 10) { - throw new Error(`Maximum allowed headers in Cache Policy is 10; got ${headers.length}.`); - } return new CacheHeaderBehavior('whitelist', headers); } diff --git a/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts index 02e3d092295f3..3482d53e9624c 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts @@ -279,6 +279,12 @@ export class Distribution extends Resource implements IDistribution { this.certificate = props.certificate; this.errorResponses = props.errorResponses ?? []; + // Comments have an undocumented limit of 128 characters + const trimmedComment = + props.comment && props.comment.length > 128 + ? `${props.comment.substr(0, 128 - 3)}...` + : props.comment; + const distribution = new CfnDistribution(this, 'Resource', { distributionConfig: { enabled: props.enabled ?? true, @@ -287,7 +293,7 @@ export class Distribution extends Resource implements IDistribution { defaultCacheBehavior: this.defaultBehavior._renderBehavior(), aliases: props.domainNames, cacheBehaviors: Lazy.any({ produce: () => this.renderCacheBehaviors() }), - comment: props.comment, + comment: trimmedComment, customErrorResponses: this.renderErrorResponses(), defaultRootObject: props.defaultRootObject, httpVersion: props.httpVersion ?? HttpVersion.HTTP2, diff --git a/packages/@aws-cdk/aws-cloudfront/lib/experimental/edge-function.ts b/packages/@aws-cdk/aws-cloudfront/lib/experimental/edge-function.ts index b12a56fe67e80..a45bc0ce6db97 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/experimental/edge-function.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/experimental/edge-function.ts @@ -3,19 +3,16 @@ 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 * as lambda from '@aws-cdk/aws-lambda'; -// hack, as this is not exported by the Lambda module -import { calculateFunctionHash } from '@aws-cdk/aws-lambda/lib/function-hash'; import * as ssm from '@aws-cdk/aws-ssm'; import { - ConstructNode, + CfnResource, ConstructNode, CustomResource, CustomResourceProvider, CustomResourceProviderRuntime, - Resource, Stack, Stage, Token, + Lazy, Resource, Stack, Stage, Token, } from '@aws-cdk/core'; import { Construct } from 'constructs'; /** * Properties for creating a Lambda@Edge function - * @experimental */ export interface EdgeFunctionProps extends lambda.FunctionProps { /** @@ -36,7 +33,6 @@ export interface EdgeFunctionProps extends lambda.FunctionProps { * See https://docs.aws.amazon.com/cdk/latest/guide/bootstrapping.html or 'cdk bootstrap --help' for options. * * @resource AWS::Lambda::Function - * @experimental */ export class EdgeFunction extends Resource implements lambda.IVersion { @@ -148,25 +144,29 @@ export class EdgeFunction extends Resource implements lambda.IVersion { /** Create a support stack and function in us-east-1, and a SSM reader in-region */ private createCrossRegionFunction(id: string, props: EdgeFunctionProps): FunctionConfig { - const parameterNamePrefix = 'EdgeFunctionArn'; - const parameterName = `${parameterNamePrefix}${id}`; + const parameterNamePrefix = '/cdk/EdgeFunctionArn'; + if (Token.isUnresolved(this.env.region)) { + throw new Error('stacks which use EdgeFunctions must have an explicitly set region'); + } + const parameterName = `${parameterNamePrefix}/${this.env.region}/${this.node.path}`; const functionStack = this.edgeStack(props.stackId); const edgeFunction = new lambda.Function(functionStack, id, props); addEdgeLambdaToRoleTrustStatement(edgeFunction.role!); // Store the current version's ARN to be retrieved by the cross region reader below. + const version = edgeFunction.currentVersion; new ssm.StringParameter(edgeFunction, 'Parameter', { parameterName, - stringValue: edgeFunction.currentVersion.edgeArn, + stringValue: version.edgeArn, }); - const edgeArn = this.createCrossRegionArnReader(parameterNamePrefix, parameterName, edgeFunction); + const edgeArn = this.createCrossRegionArnReader(parameterNamePrefix, parameterName, version); return { edgeFunction, edgeArn }; } - private createCrossRegionArnReader(parameterNamePrefix: string, parameterName: string, edgeFunction: lambda.Function): string { + private createCrossRegionArnReader(parameterNamePrefix: string, parameterName: string, version: lambda.Version): string { // Prefix of the parameter ARN that applies to all EdgeFunctions. // This is necessary because the `CustomResourceProvider` is a singleton, and the `policyStatement` // must work for multiple EdgeFunctions. @@ -174,7 +174,8 @@ export class EdgeFunction extends Resource implements lambda.IVersion { service: 'ssm', region: EdgeFunction.EDGE_REGION, resource: 'parameter', - resourceName: parameterNamePrefix + '*', + resourceName: parameterNamePrefix + '/*', + sep: '', }); const resourceType = 'Custom::CrossRegionStringParameterReader'; @@ -194,7 +195,15 @@ export class EdgeFunction extends Resource implements lambda.IVersion { Region: EdgeFunction.EDGE_REGION, ParameterName: parameterName, // This is used to determine when the function has changed, to refresh the ARN from the custom resource. - RefreshToken: calculateFunctionHash(edgeFunction), + // + // Use the logical id of the function version. Whenever a function version changes, the logical id must be + // changed for it to take effect - a good candidate for RefreshToken. + RefreshToken: Lazy.uncachedString({ + produce: () => { + const cfn = version.node.defaultChild as CfnResource; + return this.stack.resolve(cfn.logicalId); + }, + }), }, }); @@ -206,10 +215,6 @@ export class EdgeFunction extends Resource implements lambda.IVersion { if (!stage) { throw new Error('stacks which use EdgeFunctions must be part of a CDK app or stage'); } - const region = this.env.region; - if (Token.isUnresolved(region)) { - throw new Error('stacks which use EdgeFunctions must have an explicitly set region'); - } const edgeStackId = stackId ?? `edge-lambda-stack-${this.stack.node.addr}`; let edgeStack = stage.node.tryFindChild(edgeStackId) as Stack; diff --git a/packages/@aws-cdk/aws-cloudfront/lib/geo-restriction.ts b/packages/@aws-cdk/aws-cloudfront/lib/geo-restriction.ts index 7c18b2f7ebc68..853f74b007303 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/geo-restriction.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/geo-restriction.ts @@ -4,27 +4,43 @@ export class GeoRestriction { /** - * Whitelist specific countries which you want CloudFront to distribute your content. + * Allow specific countries which you want CloudFront to distribute your content. * * @param locations Two-letter, uppercase country code for a country - * that you want to whitelist. Include one element for each country. + * that you want to allow. Include one element for each country. * See ISO 3166-1-alpha-2 code on the *International Organization for Standardization* website */ - public static whitelist(...locations: string[]) { + public static allowlist(...locations: string[]) { return new GeoRestriction('whitelist', GeoRestriction.validateLocations(locations)); } /** - * Blacklist specific countries which you don't want CloudFront to distribute your content. + * Deny specific countries which you don't want CloudFront to distribute your content. * * @param locations Two-letter, uppercase country code for a country - * that you want to blacklist. Include one element for each country. + * that you want to deny. Include one element for each country. * See ISO 3166-1-alpha-2 code on the *International Organization for Standardization* website */ - public static blacklist(...locations: string[]) { + public static denylist(...locations: string[]) { return new GeoRestriction('blacklist', GeoRestriction.validateLocations(locations)); } + /** + * DEPRECATED + * @deprecated use `allowlist` + */ + public static whitelist(...locations: string[]) { + return GeoRestriction.allowlist(...locations); + } + + /** + * DEPRECATED + * @deprecated use `denylist` + */ + public static blacklist(...locations: string[]) { + return GeoRestriction.denylist(...locations); + } + private static LOCATION_REGEX = /^[A-Z]{2}$/; private static validateLocations(locations: string[]) { @@ -43,9 +59,9 @@ export class GeoRestriction { /** * Creates an instance of GeoRestriction for internal use * - * @param restrictionType Specifies the restriction type to impose (whitelist or blacklist) + * @param restrictionType Specifies the restriction type to impose * @param locations Two-letter, uppercase country code for a country - * that you want to whitelist/blacklist. Include one element for each country. + * that you want to allow/deny. Include one element for each country. * See ISO 3166-1-alpha-2 code on the *International Organization for Standardization* website */ private constructor(readonly restrictionType: 'whitelist' | 'blacklist', readonly locations: string[]) {} diff --git a/packages/@aws-cdk/aws-cloudfront/lib/origin-access-identity.ts b/packages/@aws-cdk/aws-cloudfront/lib/origin-access-identity.ts index dbb58110c29cf..c8a9b2b17ec82 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/origin-access-identity.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/origin-access-identity.ts @@ -115,7 +115,7 @@ export class OriginAccessIdentity extends OriginAccessIdentityBase implements IO // physical id - OAI name this.originAccessIdentityName = this.getResourceNameAttribute(this.resource.ref); - // Canonical user to whitelist in S3 Bucket Policy + // Canonical user to grant access to in the S3 Bucket Policy this.cloudFrontOriginAccessIdentityS3CanonicalUserId = this.resource.attrS3CanonicalUserId; // The principal for must be either the canonical user or a special ARN // with the CloudFront Origin Access Id (see `arn()` method). For diff --git a/packages/@aws-cdk/aws-cloudfront/lib/origin-request-policy.ts b/packages/@aws-cdk/aws-cloudfront/lib/origin-request-policy.ts index 17e7894e6e84e..1bd4fde321080 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/origin-request-policy.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/origin-request-policy.ts @@ -184,9 +184,6 @@ export class OriginRequestHeaderBehavior { if (headers.length === 0) { throw new Error('At least one header to allow must be provided'); } - if (headers.length > 10) { - throw new Error(`Maximum allowed headers in Origin Request Policy is 10; got ${headers.length}.`); - } if (/Authorization/i.test(headers.join('|')) || /Accept-Encoding/i.test(headers.join('|'))) { throw new Error('you cannot pass `Authorization` or `Accept-Encoding` as header values; use a CachePolicy to forward these headers instead'); } diff --git a/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts index 87836434fa141..17aafe5e4f6fd 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts @@ -769,8 +769,14 @@ export class CloudFrontWebDistribution extends cdk.Resource implements IDistribu constructor(scope: Construct, id: string, props: CloudFrontWebDistributionProps) { super(scope, id); + // Comments have an undocumented limit of 128 characters + const trimmedComment = + props.comment && props.comment.length > 128 + ? `${props.comment.substr(0, 128 - 3)}...` + : props.comment; + let distributionConfig: CfnDistribution.DistributionConfigProperty = { - comment: props.comment, + comment: trimmedComment, enabled: true, defaultRootObject: props.defaultRootObject ?? 'index.html', httpVersion: props.httpVersion || HttpVersion.HTTP2, diff --git a/packages/@aws-cdk/aws-cloudfront/package.json b/packages/@aws-cdk/aws-cloudfront/package.json index 75b18c5b95444..7ae097b628922 100644 --- a/packages/@aws-cdk/aws-cloudfront/package.json +++ b/packages/@aws-cdk/aws-cloudfront/package.json @@ -71,13 +71,14 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "aws-sdk": "^2.848.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "nodeunit-shim": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", @@ -89,7 +90,7 @@ "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -102,7 +103,7 @@ "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" @@ -155,7 +156,8 @@ "resource-interface-extends-resource:@aws-cdk/aws-cloudfront.IOriginRequestPolicy", "resource-attribute:@aws-cdk/aws-cloudfront.OriginRequestPolicy.originRequestPolicyLastModifiedTime", "resource-attribute:@aws-cdk/aws-cloudfront.KeyGroup.keyGroupLastModifiedTime", - "resource-attribute:@aws-cdk/aws-cloudfront.PublicKey.publicKeyCreatedTime" + "resource-attribute:@aws-cdk/aws-cloudfront.PublicKey.publicKeyCreatedTime", + "resource-attribute:@aws-cdk/aws-cloudfront.OriginAccessIdentity.cloudFrontOriginAccessIdentityId" ] }, "awscdkio": { diff --git a/packages/@aws-cdk/aws-cloudfront/test/cache-policy.test.ts b/packages/@aws-cdk/aws-cloudfront/test/cache-policy.test.ts index 4f6d618c51621..84996aadccb79 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/cache-policy.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/cache-policy.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { App, Aws, Duration, Stack } from '@aws-cdk/core'; import { CachePolicy, CacheCookieBehavior, CacheHeaderBehavior, CacheQueryStringBehavior } from '../lib'; @@ -24,7 +24,7 @@ describe('CachePolicy', () => { expect(stack).toHaveResource('AWS::CloudFront::CachePolicy', { CachePolicyConfig: { - Name: 'StackCachePolicy0D6FCBC0', + Name: 'StackCachePolicy0D6FCBC0-testregion', MinTTL: 0, DefaultTTL: 86400, MaxTTL: 31536000, @@ -96,17 +96,6 @@ describe('CachePolicy', () => { expect(() => new CachePolicy(stack, 'CachePolicy6', { cachePolicyName: 'My_Policy' })).not.toThrow(); }); - test('throws if more than 10 CacheHeaderBehavior headers are being passed', () => { - const errorMessage = /Maximum allowed headers in Cache Policy is 10; got (.*?)/; - expect(() => new CachePolicy(stack, 'CachePolicy1', { - headerBehavior: CacheHeaderBehavior.allowList('Lorem', 'ipsum', 'dolor', 'sit', 'amet', 'consectetur', 'adipiscing', 'elit', 'sed', 'do', 'eiusmod'), - })).toThrow(errorMessage); - - expect(() => new CachePolicy(stack, 'CachePolicy2', { - headerBehavior: CacheHeaderBehavior.allowList('Lorem', 'ipsum', 'dolor', 'sit', 'amet', 'consectetur', 'adipiscing', 'elit', 'sed', 'do'), - })).not.toThrow(); - }); - test('does not throw if cachePolicyName is a token', () => { expect(() => new CachePolicy(stack, 'CachePolicy', { cachePolicyName: Aws.STACK_NAME, diff --git a/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts b/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts index 974d459dc0206..f6294ad1b6d08 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts @@ -1,5 +1,5 @@ -import { ABSENT, objectLike } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { ABSENT, objectLike } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as acm from '@aws-cdk/aws-certificatemanager'; import * as lambda from '@aws-cdk/aws-lambda'; import * as s3 from '@aws-cdk/aws-s3'; @@ -56,7 +56,7 @@ test('exhaustive example of props renders correctly', () => { enabled: false, enableIpv6: false, enableLogging: true, - geoRestriction: GeoRestriction.blacklist('US', 'GB'), + geoRestriction: GeoRestriction.denylist('US', 'GB'), httpVersion: HttpVersion.HTTP1_1, logFilePrefix: 'logs/', logIncludesCookies: true, @@ -107,6 +107,40 @@ test('exhaustive example of props renders correctly', () => { }); }); +test('ensure comment prop is not greater than max lenght', () => { + const origin = defaultOrigin(); + new Distribution(stack, 'MyDist', { + defaultBehavior: { origin }, + comment: `Adding a comment longer than 128 characters should be trimmed and added the +ellipsis so a user would know there was more to read and everything beyond this point should not show up`, + }); + + expect(stack).toHaveResource('AWS::CloudFront::Distribution', { + DistributionConfig: { + DefaultCacheBehavior: { + CachePolicyId: '658327ea-f89d-4fab-a63d-7e88639e58f6', + Compress: true, + TargetOriginId: 'StackMyDistOrigin1D6D5E535', + ViewerProtocolPolicy: 'allow-all', + }, + Comment: `Adding a comment longer than 128 characters should be trimmed and added the +ellipsis so a user would know there was more to ...`, + Enabled: true, + HttpVersion: 'http2', + IPV6Enabled: true, + Origins: [ + { + DomainName: 'www.example.com', + Id: 'StackMyDistOrigin1D6D5E535', + CustomOriginConfig: { + OriginProtocolPolicy: 'https-only', + }, + }, + ], + }, + }); +}); + describe('multiple behaviors', () => { test('a second behavior can\'t be specified with the catch-all path pattern', () => { diff --git a/packages/@aws-cdk/aws-cloudfront/test/experimental/edge-function.test.ts b/packages/@aws-cdk/aws-cloudfront/test/experimental/edge-function.test.ts index 55b0c2f4aeaac..4a22798eb48a1 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/experimental/edge-function.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/experimental/edge-function.test.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as iam from '@aws-cdk/aws-iam'; import * as lambda from '@aws-cdk/aws-lambda'; @@ -39,7 +39,7 @@ describe('stacks', () => { Statement: [{ Effect: 'Allow', Resource: { - 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':ssm:us-east-1:111111111111:parameter/EdgeFunctionArn*']], + 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':ssm:us-east-1:111111111111:parameter/cdk/EdgeFunctionArn/*']], }, Action: ['ssm:GetParameter'], }], @@ -57,7 +57,7 @@ describe('stacks', () => { 'Fn::GetAtt': ['CustomCrossRegionStringParameterReaderCustomResourceProviderHandler65B5F33A', 'Arn'], }, Region: 'us-east-1', - ParameterName: 'EdgeFunctionArnMyFn', + ParameterName: '/cdk/EdgeFunctionArn/testregion/Stack/MyFn', }); }); @@ -98,7 +98,7 @@ describe('stacks', () => { expect(fnStack).toHaveResource('AWS::SSM::Parameter', { Type: 'String', Value: { Ref: 'MyFnCurrentVersion309B29FC29686ce94039b6e08d1645be854b3ac9' }, - Name: 'EdgeFunctionArnMyFn', + Name: '/cdk/EdgeFunctionArn/testregion/Stack/MyFn', }); }); @@ -201,7 +201,30 @@ describe('stacks', () => { 'Fn::GetAtt': ['CustomCrossRegionStringParameterReaderCustomResourceProviderHandler65B5F33A', 'Arn'], }, Region: 'us-east-1', - ParameterName: 'EdgeFunctionArnMyFn', + ParameterName: '/cdk/EdgeFunctionArn/testregion/Stage/Stack/MyFn', + }); + }); + + test('a single EdgeFunction used in multiple stacks creates mutiple stacks in us-east-1', () => { + const firstStack = new cdk.Stack(app, 'FirstStack', { + env: { account: '111111111111', region: 'testregion' }, + }); + const secondStack = new cdk.Stack(app, 'SecondStack', { + env: { account: '111111111111', region: 'testregion' }, + }); + new cloudfront.experimental.EdgeFunction(firstStack, 'MyFn', defaultEdgeFunctionProps()); + new cloudfront.experimental.EdgeFunction(secondStack, 'MyFn', defaultEdgeFunctionProps()); + + // Two stacks in us-east-1 + const firstFnStack = app.node.findChild(`edge-lambda-stack-${firstStack.node.addr}`) as cdk.Stack; + const secondFnStack = app.node.findChild(`edge-lambda-stack-${secondStack.node.addr}`) as cdk.Stack; + + // Two SSM parameters + expect(firstFnStack).toHaveResourceLike('AWS::SSM::Parameter', { + Name: '/cdk/EdgeFunctionArn/testregion/FirstStack/MyFn', + }); + expect(secondFnStack).toHaveResourceLike('AWS::SSM::Parameter', { + Name: '/cdk/EdgeFunctionArn/testregion/SecondStack/MyFn', }); }); }); diff --git a/packages/@aws-cdk/aws-cloudfront/test/geo-restriction.test.ts b/packages/@aws-cdk/aws-cloudfront/test/geo-restriction.test.ts index 23af143c67851..c9fb509d29d1d 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/geo-restriction.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/geo-restriction.test.ts @@ -1,9 +1,9 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { GeoRestriction } from '../lib'; describe.each([ - ['whitelist', GeoRestriction.whitelist], - ['blacklist', GeoRestriction.blacklist], + ['whitelist', GeoRestriction.allowlist], + ['blacklist', GeoRestriction.denylist], ])('%s', (type, geoFn) => { test('throws is location is empty', () => { diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-lambda-cross-region.expected.json b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-lambda-cross-region.expected.json index c251765b20980..d95e038c2c890 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-lambda-cross-region.expected.json +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-lambda-cross-region.expected.json @@ -11,8 +11,8 @@ ] }, "Region": "us-east-1", - "ParameterName": "EdgeFunctionArnLambda", - "RefreshToken": "4412ddb0ae449da20173ca211c51fddc" + "ParameterName": "/cdk/EdgeFunctionArn/eu-west-1/integ-distribution-lambda-cross-region/Lambda", + "RefreshToken": "LambdaCurrentVersionDF706F6A97fb843e9bd06fcd2bb15eeace80e13e" }, "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" @@ -57,7 +57,7 @@ { "Ref": "AWS::AccountId" }, - ":parameter/EdgeFunctionArn*" + ":parameter/cdk/EdgeFunctionArn/*" ] ] }, @@ -137,8 +137,8 @@ ] }, "Region": "us-east-1", - "ParameterName": "EdgeFunctionArnLambda2", - "RefreshToken": "8f81ceb404ac454f09648e62822d9ca9" + "ParameterName": "/cdk/EdgeFunctionArn/eu-west-1/integ-distribution-lambda-cross-region/Lambda2", + "RefreshToken": "Lambda2CurrentVersion72012B74b9eef8becb98501bc795baca3c6169c4" }, "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" @@ -278,7 +278,7 @@ "Value": { "Ref": "LambdaCurrentVersionDF706F6A97fb843e9bd06fcd2bb15eeace80e13e" }, - "Name": "EdgeFunctionArnLambda" + "Name": "/cdk/EdgeFunctionArn/eu-west-1/integ-distribution-lambda-cross-region/Lambda" } }, "LambdaAliaslive79C8A712": { @@ -372,7 +372,7 @@ "Value": { "Ref": "Lambda2CurrentVersion72012B74b9eef8becb98501bc795baca3c6169c4" }, - "Name": "EdgeFunctionArnLambda2" + "Name": "/cdk/EdgeFunctionArn/eu-west-1/integ-distribution-lambda-cross-region/Lambda2" } }, "Lambda2Aliaslive77F6085F": { diff --git a/packages/@aws-cdk/aws-cloudfront/test/key-group.test.ts b/packages/@aws-cdk/aws-cloudfront/test/key-group.test.ts index f5a0ae43c0855..f27f2ad7e0e42 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/key-group.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/key-group.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert/jest'; -import { expect as expectStack } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +import { expect as expectStack } from '@aws-cdk/assert-internal'; import { App, Stack } from '@aws-cdk/core'; import { KeyGroup, PublicKey } from '../lib'; diff --git a/packages/@aws-cdk/aws-cloudfront/test/oai.test.ts b/packages/@aws-cdk/aws-cloudfront/test/oai.test.ts index ed93bad727eb0..e9e04fa6e3003 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/oai.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/oai.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import { OriginAccessIdentity } from '../lib'; diff --git a/packages/@aws-cdk/aws-cloudfront/test/origin-groups.test.ts b/packages/@aws-cdk/aws-cloudfront/test/origin-groups.test.ts index 55d9c38a8c3a0..6ffd4b5bd9e8e 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/origin-groups.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/origin-groups.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; diff --git a/packages/@aws-cdk/aws-cloudfront/test/origin-request-policy.test.ts b/packages/@aws-cdk/aws-cloudfront/test/origin-request-policy.test.ts index b342ac434e48e..92db58161cf1b 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/origin-request-policy.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/origin-request-policy.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { App, Aws, Stack } from '@aws-cdk/core'; import { OriginRequestPolicy, OriginRequestCookieBehavior, OriginRequestHeaderBehavior, OriginRequestQueryStringBehavior } from '../lib'; @@ -89,17 +89,6 @@ describe('OriginRequestPolicy', () => { expect(() => new OriginRequestPolicy(stack, 'OriginRequestPolicy7', { headerBehavior: OriginRequestHeaderBehavior.allowList('Foo', 'Bar') })).not.toThrow(); }); - test('throws if more than 10 OriginRequestHeaderBehavior headers are being passed', () => { - const errorMessage = /Maximum allowed headers in Origin Request Policy is 10; got (.*?)/; - expect(() => new OriginRequestPolicy(stack, 'OriginRequestPolicy1', { - headerBehavior: OriginRequestHeaderBehavior.allowList('Lorem', 'ipsum', 'dolor', 'sit', 'amet', 'consectetur', 'adipiscing', 'elit', 'sed', 'do', 'eiusmod'), - })).toThrow(errorMessage); - - expect(() => new OriginRequestPolicy(stack, 'OriginRequestPolicy2', { - headerBehavior: OriginRequestHeaderBehavior.allowList('Lorem', 'ipsum', 'dolor', 'sit', 'amet', 'consectetur', 'adipiscing', 'elit', 'sed', 'do'), - })).not.toThrow(); - }); - test('does not throw if originRequestPolicyName is a token', () => { expect(() => new OriginRequestPolicy(stack, 'CachePolicy', { originRequestPolicyName: Aws.STACK_NAME, diff --git a/packages/@aws-cdk/aws-cloudfront/test/origin.test.ts b/packages/@aws-cdk/aws-cloudfront/test/origin.test.ts index cbf3b32ad6f10..b2a60a2fd109d 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/origin.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/origin.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { App, Stack, Duration } from '@aws-cdk/core'; import { TestOrigin } from './test-origin'; diff --git a/packages/@aws-cdk/aws-cloudfront/test/private/cache-behavior.test.ts b/packages/@aws-cdk/aws-cloudfront/test/private/cache-behavior.test.ts index c9500b23eaddf..326b33490271e 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/private/cache-behavior.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/private/cache-behavior.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as lambda from '@aws-cdk/aws-lambda'; import { App, Stack } from '@aws-cdk/core'; import { AllowedMethods, CachedMethods, CachePolicy, KeyGroup, LambdaEdgeEventType, OriginRequestPolicy, PublicKey, ViewerProtocolPolicy } from '../../lib'; diff --git a/packages/@aws-cdk/aws-cloudfront/test/public-key.test.ts b/packages/@aws-cdk/aws-cloudfront/test/public-key.test.ts index 934b1a9dc8107..5fbd8da23ddc8 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/public-key.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/public-key.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert/jest'; -import { expect as expectStack } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +import { expect as expectStack } from '@aws-cdk/assert-internal'; import { App, Stack } from '@aws-cdk/core'; import { PublicKey } from '../lib'; diff --git a/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts b/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts index d8e12059172fa..6e10b54defc77 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts @@ -1,4 +1,4 @@ -import { ABSENT, expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; +import { ABSENT, expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; import * as certificatemanager from '@aws-cdk/aws-certificatemanager'; import * as lambda from '@aws-cdk/aws-lambda'; import * as s3 from '@aws-cdk/aws-s3'; @@ -198,6 +198,78 @@ nodeunitShim({ test.done(); }, + 'ensure long comments will not break the distribution'(test: Test) { + const stack = new cdk.Stack(); + const sourceBucket = new s3.Bucket(stack, 'Bucket'); + + new CloudFrontWebDistribution(stack, 'AnAmazingWebsiteProbably', { + comment: `Adding a comment longer than 128 characters should be trimmed and +added the ellipsis so a user would know there was more to read and everything beyond this point should not show up`, + originConfigs: [ + { + s3OriginSource: { + s3BucketSource: sourceBucket, + }, + behaviors: [ + { + isDefaultBehavior: true, + }, + ], + }, + ], + }); + + expect(stack).toMatch({ + Resources: { + Bucket83908E77: { + Type: 'AWS::S3::Bucket', + DeletionPolicy: 'Retain', + UpdateReplacePolicy: 'Retain', + }, + AnAmazingWebsiteProbablyCFDistribution47E3983B: { + Type: 'AWS::CloudFront::Distribution', + Properties: { + DistributionConfig: { + DefaultRootObject: 'index.html', + Origins: [ + { + ConnectionAttempts: 3, + ConnectionTimeout: 10, + DomainName: { + 'Fn::GetAtt': ['Bucket83908E77', 'RegionalDomainName'], + }, + Id: 'origin1', + S3OriginConfig: {}, + }, + ], + ViewerCertificate: { + CloudFrontDefaultCertificate: true, + }, + PriceClass: 'PriceClass_100', + DefaultCacheBehavior: { + AllowedMethods: ['GET', 'HEAD'], + CachedMethods: ['GET', 'HEAD'], + TargetOriginId: 'origin1', + ViewerProtocolPolicy: 'redirect-to-https', + ForwardedValues: { + QueryString: false, + Cookies: { Forward: 'none' }, + }, + Compress: true, + }, + Comment: `Adding a comment longer than 128 characters should be trimmed and +added the ellipsis so a user would know there was more to ...`, + Enabled: true, + IPV6Enabled: true, + HttpVersion: 'http2', + }, + }, + }, + }, + }); + test.done(); + }, + 'distribution with bucket and OAI'(test: Test) { const stack = new cdk.Stack(); const s3BucketSource = new s3.Bucket(stack, 'Bucket'); @@ -1097,7 +1169,7 @@ nodeunitShim({ 'geo restriction': { 'success': { - 'whitelist'(test: Test) { + 'allowlist'(test: Test) { const stack = new cdk.Stack(); const sourceBucket = new s3.Bucket(stack, 'Bucket'); @@ -1106,7 +1178,7 @@ nodeunitShim({ s3OriginSource: { s3BucketSource: sourceBucket }, behaviors: [{ isDefaultBehavior: true }], }], - geoRestriction: GeoRestriction.whitelist('US', 'UK'), + geoRestriction: GeoRestriction.allowlist('US', 'UK'), }); expect(stack).toMatch({ @@ -1173,7 +1245,7 @@ nodeunitShim({ test.done(); }, - 'blacklist'(test: Test) { + 'denylist'(test: Test) { const stack = new cdk.Stack(); const sourceBucket = new s3.Bucket(stack, 'Bucket'); @@ -1182,7 +1254,7 @@ nodeunitShim({ s3OriginSource: { s3BucketSource: sourceBucket }, behaviors: [{ isDefaultBehavior: true }], }], - geoRestriction: GeoRestriction.blacklist('US'), + geoRestriction: GeoRestriction.denylist('US'), }); expect(stack).toMatch({ @@ -1253,22 +1325,22 @@ nodeunitShim({ 'error': { 'throws if locations is empty array'(test: Test) { test.throws(() => { - GeoRestriction.whitelist(); + GeoRestriction.allowlist(); }, /Should provide at least 1 location/); test.throws(() => { - GeoRestriction.blacklist(); + GeoRestriction.denylist(); }, /Should provide at least 1 location/); test.done(); }, 'throws if locations format is wrong'(test: Test) { test.throws(() => { - GeoRestriction.whitelist('us'); + GeoRestriction.allowlist('us'); }, /Invalid location format for location: us, location should be two-letter and uppercase country ISO 3166-1-alpha-2 code/); test.throws(() => { - GeoRestriction.blacklist('us'); + GeoRestriction.denylist('us'); }, /Invalid location format for location: us, location should be two-letter and uppercase country ISO 3166-1-alpha-2 code/); test.done(); diff --git a/packages/@aws-cdk/aws-cloudtrail/package.json b/packages/@aws-cdk/aws-cloudtrail/package.json index ce2c1f2e647ed..506513079f999 100644 --- a/packages/@aws-cdk/aws-cloudtrail/package.json +++ b/packages/@aws-cdk/aws-cloudtrail/package.json @@ -71,14 +71,15 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "aws-sdk": "^2.848.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "colors": "^1.4.0", "jest": "^26.6.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-events": "0.0.0", @@ -89,7 +90,7 @@ "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -101,7 +102,7 @@ "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-cloudtrail/test/cloudtrail.test.ts b/packages/@aws-cdk/aws-cloudtrail/test/cloudtrail.test.ts index 7f777a46749af..9e17345368785 100644 --- a/packages/@aws-cdk/aws-cloudtrail/test/cloudtrail.test.ts +++ b/packages/@aws-cdk/aws-cloudtrail/test/cloudtrail.test.ts @@ -1,5 +1,5 @@ -import { ABSENT, SynthUtils } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { ABSENT, SynthUtils } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as lambda from '@aws-cdk/aws-lambda'; diff --git a/packages/@aws-cdk/aws-cloudwatch-actions/package.json b/packages/@aws-cdk/aws-cloudwatch-actions/package.json index 04ed6918384c1..881ee54c2656f 100644 --- a/packages/@aws-cdk/aws-cloudwatch-actions/package.json +++ b/packages/@aws-cdk/aws-cloudwatch-actions/package.json @@ -62,13 +62,14 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "@aws-cdk/aws-ec2": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-applicationautoscaling": "0.0.0", @@ -77,7 +78,7 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -87,7 +88,7 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-cloudwatch-actions/test/appscaling.test.ts b/packages/@aws-cdk/aws-cloudwatch-actions/test/appscaling.test.ts index 82dc972cee2b8..f355290aaa553 100644 --- a/packages/@aws-cdk/aws-cloudwatch-actions/test/appscaling.test.ts +++ b/packages/@aws-cdk/aws-cloudwatch-actions/test/appscaling.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as appscaling from '@aws-cdk/aws-applicationautoscaling'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import { Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-cloudwatch-actions/test/ec2.test.ts b/packages/@aws-cdk/aws-cloudwatch-actions/test/ec2.test.ts index 8845588d533b4..d4dd9781f8370 100644 --- a/packages/@aws-cdk/aws-cloudwatch-actions/test/ec2.test.ts +++ b/packages/@aws-cdk/aws-cloudwatch-actions/test/ec2.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import { Stack } from '@aws-cdk/core'; import * as actions from '../lib'; diff --git a/packages/@aws-cdk/aws-cloudwatch-actions/test/scaling.test.ts b/packages/@aws-cdk/aws-cloudwatch-actions/test/scaling.test.ts index 69a1fd701499d..61561cd412e15 100644 --- a/packages/@aws-cdk/aws-cloudwatch-actions/test/scaling.test.ts +++ b/packages/@aws-cdk/aws-cloudwatch-actions/test/scaling.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as autoscaling from '@aws-cdk/aws-autoscaling'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as ec2 from '@aws-cdk/aws-ec2'; diff --git a/packages/@aws-cdk/aws-cloudwatch-actions/test/sns.test.ts b/packages/@aws-cdk/aws-cloudwatch-actions/test/sns.test.ts index 272d82925bb3b..3cdc6e71ae9c2 100644 --- a/packages/@aws-cdk/aws-cloudwatch-actions/test/sns.test.ts +++ b/packages/@aws-cdk/aws-cloudwatch-actions/test/sns.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as sns from '@aws-cdk/aws-sns'; import { Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-cloudwatch/lib/alarm-base.ts b/packages/@aws-cdk/aws-cloudwatch/lib/alarm-base.ts index 996079718edba..830fa04b290e5 100644 --- a/packages/@aws-cdk/aws-cloudwatch/lib/alarm-base.ts +++ b/packages/@aws-cdk/aws-cloudwatch/lib/alarm-base.ts @@ -51,7 +51,7 @@ export abstract class AlarmBase extends Resource implements IAlarm { * AlarmRule indicating ALARM state for Alarm. */ public renderAlarmRule(): string { - return `ALARM(${this.alarmArn})`; + return `ALARM("${this.alarmArn}")`; } /** diff --git a/packages/@aws-cdk/aws-cloudwatch/lib/alarm-rule.ts b/packages/@aws-cdk/aws-cloudwatch/lib/alarm-rule.ts index 7d7a25d2e9104..939d9b0746dea 100644 --- a/packages/@aws-cdk/aws-cloudwatch/lib/alarm-rule.ts +++ b/packages/@aws-cdk/aws-cloudwatch/lib/alarm-rule.ts @@ -91,7 +91,7 @@ export class AlarmRule { public static fromAlarm(alarm: IAlarm, alarmState: AlarmState): IAlarmRule { return new class implements IAlarmRule { public renderAlarmRule(): string { - return `${alarmState}(${alarm.alarmArn})`; + return `${alarmState}("${alarm.alarmArn}")`; } }; } diff --git a/packages/@aws-cdk/aws-cloudwatch/package.json b/packages/@aws-cdk/aws-cloudwatch/package.json index 98a3281163384..cc4168d188112 100644 --- a/packages/@aws-cdk/aws-cloudwatch/package.json +++ b/packages/@aws-cdk/aws-cloudwatch/package.json @@ -70,24 +70,24 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "nodeunit": "^0.11.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "awslint": { "exclude": [ diff --git a/packages/@aws-cdk/aws-cloudwatch/test/integ.composite-alarm.expected.json b/packages/@aws-cdk/aws-cloudwatch/test/integ.composite-alarm.expected.json index 87ae41c2f517e..614707db2a7d7 100644 --- a/packages/@aws-cdk/aws-cloudwatch/test/integ.composite-alarm.expected.json +++ b/packages/@aws-cdk/aws-cloudwatch/test/integ.composite-alarm.expected.json @@ -48,6 +48,19 @@ "Threshold": 100000 } }, + "Alarm548383B2F": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "EvaluationPeriods": 3, + "AlarmName": "Alarm with space in name", + "MetricName": "Metric", + "Namespace": "CDK/Test", + "Period": 300, + "Statistic": "Average", + "Threshold": 100000 + } + }, "CompositeAlarmF4C3D082": { "Type": "AWS::CloudWatch::CompositeAlarm", "Properties": { @@ -56,35 +69,42 @@ "Fn::Join": [ "", [ - "(((ALARM(", + "(((ALARM(\"", { "Fn::GetAtt": [ "Alarm1F9009D71", "Arn" ] }, - ") OR OK(", + "\") OR OK(\"", { "Fn::GetAtt": [ "Alarm2A7122E13", "Arn" ] }, - ") OR ALARM(", + "\") OR ALARM(\"", { "Fn::GetAtt": [ "Alarm32341D8D9", "Arn" ] }, - ")) AND (NOT (INSUFFICIENT_DATA(", + "\") OR ALARM(\"", + { + "Fn::GetAtt": [ + "Alarm548383B2F", + "Arn" + ] + }, + "\")) AND (NOT (INSUFFICIENT_DATA(\"", { "Fn::GetAtt": [ "Alarm4671832C8", "Arn" ] }, - ")))) OR FALSE)" + "\")))) OR FALSE)" ] ] } diff --git a/packages/@aws-cdk/aws-cloudwatch/test/integ.composite-alarm.ts b/packages/@aws-cdk/aws-cloudwatch/test/integ.composite-alarm.ts index 7e2e215a13aab..e4ed35c19c17f 100644 --- a/packages/@aws-cdk/aws-cloudwatch/test/integ.composite-alarm.ts +++ b/packages/@aws-cdk/aws-cloudwatch/test/integ.composite-alarm.ts @@ -35,12 +35,20 @@ class CompositeAlarmIntegrationTest extends Stack { evaluationPeriods: 3, }); + const alarm5 = new Alarm(this, 'Alarm5', { + alarmName: 'Alarm with space in name', + metric: testMetric, + threshold: 100000, + evaluationPeriods: 3, + }); + const alarmRule = AlarmRule.anyOf( AlarmRule.allOf( AlarmRule.anyOf( alarm1, AlarmRule.fromAlarm(alarm2, AlarmState.OK), alarm3, + alarm5, ), AlarmRule.not(AlarmRule.fromAlarm(alarm4, AlarmState.INSUFFICIENT_DATA)), ), diff --git a/packages/@aws-cdk/aws-cloudwatch/test/test.alarm.ts b/packages/@aws-cdk/aws-cloudwatch/test/test.alarm.ts index c6a727c023c16..fbce3d9c4ef9c 100644 --- a/packages/@aws-cdk/aws-cloudwatch/test/test.alarm.ts +++ b/packages/@aws-cdk/aws-cloudwatch/test/test.alarm.ts @@ -1,4 +1,4 @@ -import { ABSENT, expect, haveResource } from '@aws-cdk/assert'; +import { ABSENT, expect, haveResource } from '@aws-cdk/assert-internal'; import { Duration, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk/aws-cloudwatch/test/test.composite-alarm.ts b/packages/@aws-cdk/aws-cloudwatch/test/test.composite-alarm.ts index 633d792f79401..87625abcd6aa6 100644 --- a/packages/@aws-cdk/aws-cloudwatch/test/test.composite-alarm.ts +++ b/packages/@aws-cdk/aws-cloudwatch/test/test.composite-alarm.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import { Stack } from '@aws-cdk/core'; import { Test } from 'nodeunit'; import { Alarm, AlarmRule, AlarmState, CompositeAlarm, Metric } from '../lib'; @@ -36,12 +36,20 @@ export = { evaluationPeriods: 3, }); + const alarm5 = new Alarm(stack, 'Alarm5', { + alarmName: 'Alarm with space in name', + metric: testMetric, + threshold: 100000, + evaluationPeriods: 3, + }); + const alarmRule = AlarmRule.anyOf( AlarmRule.allOf( AlarmRule.anyOf( alarm1, AlarmRule.fromAlarm(alarm2, AlarmState.OK), alarm3, + alarm5, ), AlarmRule.not(AlarmRule.fromAlarm(alarm4, AlarmState.INSUFFICIENT_DATA)), ), @@ -58,35 +66,42 @@ export = { 'Fn::Join': [ '', [ - '(((ALARM(', + '(((ALARM("', { 'Fn::GetAtt': [ 'Alarm1F9009D71', 'Arn', ], }, - ') OR OK(', + '") OR OK("', { 'Fn::GetAtt': [ 'Alarm2A7122E13', 'Arn', ], }, - ') OR ALARM(', + '") OR ALARM("', { 'Fn::GetAtt': [ 'Alarm32341D8D9', 'Arn', ], }, - ')) AND (NOT (INSUFFICIENT_DATA(', + '") OR ALARM("', + { + 'Fn::GetAtt': [ + 'Alarm548383B2F', + 'Arn', + ], + }, + '")) AND (NOT (INSUFFICIENT_DATA("', { 'Fn::GetAtt': [ 'Alarm4671832C8', 'Arn', ], }, - ')))) OR FALSE)', + '")))) OR FALSE)', ], ], }, diff --git a/packages/@aws-cdk/aws-cloudwatch/test/test.cross-environment.ts b/packages/@aws-cdk/aws-cloudwatch/test/test.cross-environment.ts index c38ff3455c9f1..1afb4cdca882c 100644 --- a/packages/@aws-cdk/aws-cloudwatch/test/test.cross-environment.ts +++ b/packages/@aws-cdk/aws-cloudwatch/test/test.cross-environment.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import { Stack } from '@aws-cdk/core'; import { Test } from 'nodeunit'; import { Alarm, GraphWidget, IWidget, Metric } from '../lib'; diff --git a/packages/@aws-cdk/aws-cloudwatch/test/test.dashboard.ts b/packages/@aws-cdk/aws-cloudwatch/test/test.dashboard.ts index cf62fde0403e3..4249f8675d1be 100644 --- a/packages/@aws-cdk/aws-cloudwatch/test/test.dashboard.ts +++ b/packages/@aws-cdk/aws-cloudwatch/test/test.dashboard.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, isSuperObject } from '@aws-cdk/assert'; +import { expect, haveResource, isSuperObject } from '@aws-cdk/assert-internal'; import { App, Stack } from '@aws-cdk/core'; import { Test } from 'nodeunit'; import { Dashboard, GraphWidget, PeriodOverride, TextWidget } from '../lib'; diff --git a/packages/@aws-cdk/aws-cloudwatch/test/test.metric-math.ts b/packages/@aws-cdk/aws-cloudwatch/test/test.metric-math.ts index b5eecac9ec52d..dcf65649236aa 100644 --- a/packages/@aws-cdk/aws-cloudwatch/test/test.metric-math.ts +++ b/packages/@aws-cdk/aws-cloudwatch/test/test.metric-math.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import { Duration, Stack } from '@aws-cdk/core'; import { Test } from 'nodeunit'; import { Alarm, GraphWidget, IWidget, MathExpression, Metric } from '../lib'; diff --git a/packages/@aws-cdk/aws-cloudwatch/test/test.metrics.ts b/packages/@aws-cdk/aws-cloudwatch/test/test.metrics.ts index a08c248406bad..e1dc9230e1404 100644 --- a/packages/@aws-cdk/aws-cloudwatch/test/test.metrics.ts +++ b/packages/@aws-cdk/aws-cloudwatch/test/test.metrics.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk/aws-codeartifact/package.json b/packages/@aws-cdk/aws-codeartifact/package.json index e4b8ef3ffaad6..96a62e0b4e801 100644 --- a/packages/@aws-cdk/aws-codeartifact/package.json +++ b/packages/@aws-cdk/aws-codeartifact/package.json @@ -73,10 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-codeartifact/test/codeartifact.test.ts b/packages/@aws-cdk/aws-codeartifact/test/codeartifact.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-codeartifact/test/codeartifact.test.ts +++ b/packages/@aws-cdk/aws-codeartifact/test/codeartifact.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-codebuild/NOTICE b/packages/@aws-cdk/aws-codebuild/NOTICE index 5fc3826926b5b..c84ff36099c3b 100644 --- a/packages/@aws-cdk/aws-codebuild/NOTICE +++ b/packages/@aws-cdk/aws-codebuild/NOTICE @@ -1,2 +1,23 @@ AWS Cloud Development Kit (AWS CDK) Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +------------------------------------------------------------------------------- + +The AWS CDK includes the following third-party software/licensing: + +** yaml - https://www.npmjs.com/package/yaml +Copyright 2018 Eemeli Aro + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. + +---------------- diff --git a/packages/@aws-cdk/aws-codebuild/README.md b/packages/@aws-cdk/aws-codebuild/README.md index cdc3d9f59b665..2fb82c887ba39 100644 --- a/packages/@aws-cdk/aws-codebuild/README.md +++ b/packages/@aws-cdk/aws-codebuild/README.md @@ -152,6 +152,9 @@ const project = codebuild.Project(stack, 'MyProject', { }); ``` +If you'd prefer your buildspec to be rendered as YAML in the template, +use the `fromObjectToYaml()` method instead of `fromObject()`. + Because we've not set the `name` property, this example will set the `overrideArtifactName` parameter, and produce an artifact named as defined in the Buildspec file, uploaded to an S3 bucket (`bucket`). The path will be @@ -645,3 +648,17 @@ new codebuild.Project(stack, 'MyProject', { queuedTimeout: Duration.minutes(30) }); ``` + +## Limiting concurrency + +By default if a new build is triggered it will be run even if there is a previous build already in progress. +It is possible to limit the maximum concurrent builds to value between 1 and the account specific maximum limit. +By default there is no explicit limit. + +```ts +import * as codebuild from '@aws-cdk/aws-codebuild'; + +new codebuild.Project(stack, 'MyProject', { + concurrentBuildLimit: 1 +}); +``` diff --git a/packages/@aws-cdk/aws-codebuild/lib/build-spec.ts b/packages/@aws-cdk/aws-codebuild/lib/build-spec.ts index 5f33babced96a..d4ec5fe2d951d 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/build-spec.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/build-spec.ts @@ -1,4 +1,5 @@ import { IResolveContext, Lazy, Stack } from '@aws-cdk/core'; +import * as yaml_cfn from './private/yaml-cfn'; /** * BuildSpec for CodeBuild projects @@ -8,6 +9,15 @@ export abstract class BuildSpec { return new ObjectBuildSpec(value); } + /** + * Create a buildspec from an object that will be rendered as YAML in the resulting CloudFormation template. + * + * @param value the object containing the buildspec that will be rendered as YAML + */ + public static fromObjectToYaml(value: {[key: string]: any}): BuildSpec { + return new YamlBuildSpec(value); + } + /** * Use a file from the source as buildspec * @@ -70,6 +80,21 @@ class ObjectBuildSpec extends BuildSpec { } } +/** + * BuildSpec that exports into YAML format + */ +class YamlBuildSpec extends BuildSpec { + public readonly isImmediate: boolean = true; + + constructor(public readonly spec: {[key: string]: any}) { + super(); + } + + public toBuildSpec(): string { + return yaml_cfn.serialize(this.spec); + } +} + /** * Merge two buildspecs into a new BuildSpec * diff --git a/packages/@aws-cdk/aws-codebuild/lib/private/yaml-cfn.ts b/packages/@aws-cdk/aws-codebuild/lib/private/yaml-cfn.ts new file mode 100644 index 0000000000000..fe88409f68a1e --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/lib/private/yaml-cfn.ts @@ -0,0 +1,18 @@ +import * as yaml from 'yaml'; +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; + } +} diff --git a/packages/@aws-cdk/aws-codebuild/lib/project.ts b/packages/@aws-cdk/aws-codebuild/lib/project.ts index 718f7263ada13..307db08241ff5 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/project.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/project.ts @@ -7,7 +7,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as s3 from '@aws-cdk/aws-s3'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; -import { Aws, Duration, IResource, Lazy, Names, PhysicalName, Resource, SecretValue, Stack, Tokenization } from '@aws-cdk/core'; +import { ArnComponents, Aws, Duration, IResource, Lazy, Names, PhysicalName, Resource, SecretValue, Stack, Token, TokenComparison, Tokenization } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { IArtifacts } from './artifacts'; import { BuildSpec } from './build-spec'; @@ -584,6 +584,13 @@ export interface CommonProjectProps { * @default - no queue timeout is set */ readonly queuedTimeout?: Duration + + /** + * Maximum number of concurrent builds. Minimum value is 1 and maximum is account build limit. + * + * @default - no explicit limit is set + */ + readonly concurrentBuildLimit?: number } export interface ProjectProps extends CommonProjectProps { @@ -639,14 +646,19 @@ export interface BindToCodePipelineOptions { export class Project extends ProjectBase { public static fromProjectArn(scope: Construct, id: string, projectArn: string): IProject { + const parsedArn = Stack.of(scope).parseArn(projectArn); + class Import extends ProjectBase { public readonly grantPrincipal: iam.IPrincipal; public readonly projectArn = projectArn; - public readonly projectName = Stack.of(scope).parseArn(projectArn).resourceName!; + public readonly projectName = parsedArn.resourceName!; public readonly role?: iam.Role = undefined; constructor(s: Construct, i: string) { - super(s, i); + super(s, i, { + account: parsedArn.account, + region: parsedArn.region, + }); this.grantPrincipal = new iam.UnknownPrincipal({ resource: this }); } } @@ -707,14 +719,16 @@ export class Project extends ProjectBase { validateNoPlainTextSecrets: boolean = false, principal?: iam.IGrantable): CfnProject.EnvironmentVariableProperty[] { const ret = new Array(); - const ssmVariables = new Array(); - const secretsManagerSecrets = new Array(); + const ssmIamResources = new Array(); + const secretsManagerIamResources = new Set(); + const kmsIamResources = new Set(); for (const [name, envVariable] of Object.entries(environmentVariables)) { + const envVariableValue = envVariable.value?.toString(); const cfnEnvVariable: CfnProject.EnvironmentVariableProperty = { name, type: envVariable.type || BuildEnvironmentVariableType.PLAINTEXT, - value: envVariable.value?.toString(), + value: envVariableValue, }; ret.push(cfnEnvVariable); @@ -733,10 +747,11 @@ export class Project extends ProjectBase { } if (principal) { + const stack = Stack.of(principal); + // save the SSM env variables if (envVariable.type === BuildEnvironmentVariableType.PARAMETER_STORE) { - const envVariableValue = envVariable.value.toString(); - ssmVariables.push(Stack.of(principal).formatArn({ + ssmIamResources.push(stack.formatArn({ service: 'ssm', resource: 'parameter', // If the parameter name starts with / the resource name is not separated with a double '/' @@ -749,27 +764,80 @@ export class Project extends ProjectBase { // save SecretsManager env variables if (envVariable.type === BuildEnvironmentVariableType.SECRETS_MANAGER) { - secretsManagerSecrets.push(Stack.of(principal).formatArn({ - service: 'secretsmanager', - resource: 'secret', - // we don't know the exact ARN of the Secret just from its name, but we can get close - resourceName: `${envVariable.value}-??????`, - sep: ':', - })); + if (Token.isUnresolved(envVariableValue)) { + // the value of the property can be a complex string, separated by ':'; + // see https://docs.aws.amazon.com/codebuild/latest/userguide/build-spec-ref.html#build-spec.env.secrets-manager + const secretArn = envVariableValue.split(':')[0]; + + // if we are passed a Token, we should assume it's the ARN of the Secret + // (as the name would not work anyway, because it would be the full name, which CodeBuild does not support) + secretsManagerIamResources.add(secretArn); + } else { + // check if the provided value is a full ARN of the Secret + let parsedArn: ArnComponents | undefined; + try { + parsedArn = stack.parseArn(envVariableValue, ':'); + } catch (e) {} + const secretSpecifier: string = parsedArn ? parsedArn.resourceName : envVariableValue; + + // the value of the property can be a complex string, separated by ':'; + // see https://docs.aws.amazon.com/codebuild/latest/userguide/build-spec-ref.html#build-spec.env.secrets-manager + const secretName = secretSpecifier.split(':')[0]; + const secretIamResourceName = parsedArn + // If we were given an ARN, we don't' know whether the name is full, or partial, + // as CodeBuild supports both ARN forms. + // Because of that, follow the name with a '*', which works for both + ? `${secretName}*` + // If we were given just a name, it must be partial, as CodeBuild doesn't support providing full names. + // In this case, we need to accommodate for the generated suffix in the IAM resource name + : `${secretName}-??????`; + secretsManagerIamResources.add(stack.formatArn({ + service: 'secretsmanager', + resource: 'secret', + resourceName: secretIamResourceName, + sep: ':', + // if we were given an ARN, we need to use the provided partition/account/region + partition: parsedArn?.partition, + account: parsedArn?.account, + region: parsedArn?.region, + })); + // if secret comes from another account, SecretsManager will need to access + // KMS on the other account as well to be able to get the secret + if (parsedArn && parsedArn.account && Token.compareStrings(parsedArn.account, stack.account) === TokenComparison.DIFFERENT) { + kmsIamResources.add(stack.formatArn({ + service: 'kms', + resource: 'key', + // We do not know the ID of the key, but since this is a cross-account access, + // the key policies have to allow this access, so a wildcard is safe here + resourceName: '*', + sep: '/', + // if we were given an ARN, we need to use the provided partition/account/region + partition: parsedArn.partition, + account: parsedArn.account, + region: parsedArn.region, + })); + } + } } } } - if (ssmVariables.length !== 0) { + if (ssmIamResources.length !== 0) { principal?.grantPrincipal.addToPrincipalPolicy(new iam.PolicyStatement({ actions: ['ssm:GetParameters'], - resources: ssmVariables, + resources: ssmIamResources, })); } - if (secretsManagerSecrets.length !== 0) { + if (secretsManagerIamResources.size !== 0) { principal?.grantPrincipal.addToPrincipalPolicy(new iam.PolicyStatement({ actions: ['secretsmanager:GetSecretValue'], - resources: secretsManagerSecrets, + resources: Array.from(secretsManagerIamResources), + })); + } + if (kmsIamResources.size !== 0) { + principal?.grantPrincipal.addToPrincipalPolicy(new iam.PolicyStatement({ + actions: ['kms:Decrypt'], + resources: Array.from(kmsIamResources), })); } @@ -879,6 +947,7 @@ export class Project extends ProjectBase { name: this.physicalName, timeoutInMinutes: props.timeout && props.timeout.toMinutes(), queuedTimeoutInMinutes: props.queuedTimeout && props.queuedTimeout.toMinutes(), + concurrentBuildLimit: props.concurrentBuildLimit, secondarySources: Lazy.any({ produce: () => this.renderSecondarySources() }), secondarySourceVersions: Lazy.any({ produce: () => this.renderSecondarySourceVersions() }), secondaryArtifacts: Lazy.any({ produce: () => this.renderSecondaryArtifacts() }), @@ -1831,7 +1900,10 @@ export interface BuildEnvironmentVariable { * The value of the environment variable. * For plain-text variables (the default), this is the literal value of variable. * For SSM parameter variables, pass the name of the parameter here (`parameterName` property of `IParameter`). - * For SecretsManager variables secrets, pass the secret name here (`secretName` property of `ISecret`). + * For SecretsManager variables secrets, pass either the secret name (`secretName` property of `ISecret`) + * or the secret ARN (`secretArn` property of `ISecret`) here, + * along with optional SecretsManager qualifiers separated by ':', like the JSON key, or the version or stage + * (see https://docs.aws.amazon.com/codebuild/latest/userguide/build-spec-ref.html#build-spec.env.secrets-manager for details). */ readonly value: any; } diff --git a/packages/@aws-cdk/aws-codebuild/package.json b/packages/@aws-cdk/aws-codebuild/package.json index 7b268062d474f..d2b3a23a1a356 100644 --- a/packages/@aws-cdk/aws-codebuild/package.json +++ b/packages/@aws-cdk/aws-codebuild/package.json @@ -74,7 +74,6 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@types/nodeunit": "^0.0.31", @@ -83,7 +82,8 @@ "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "nodeunit": "^0.11.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", @@ -100,10 +100,15 @@ "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/region-info": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69", + "yaml": "1.10.2" }, + "bundledDependencies": [ + "yaml" + ], "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { + "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", @@ -118,7 +123,7 @@ "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/region-info": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts b/packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts index 806ec437c20c6..fb28c29a1185d 100644 --- a/packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts +++ b/packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts @@ -1,4 +1,4 @@ -import { ABSENT, expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; +import { ABSENT, expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; import * as codecommit from '@aws-cdk/aws-codecommit'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as kms from '@aws-cdk/aws-kms'; diff --git a/packages/@aws-cdk/aws-codebuild/test/test.linux-gpu-build-image.ts b/packages/@aws-cdk/aws-codebuild/test/test.linux-gpu-build-image.ts index b3063b0cf0f01..60d3b17ca3043 100644 --- a/packages/@aws-cdk/aws-codebuild/test/test.linux-gpu-build-image.ts +++ b/packages/@aws-cdk/aws-codebuild/test/test.linux-gpu-build-image.ts @@ -1,4 +1,4 @@ -import { arrayWith, expect, haveResourceLike, objectLike } from '@aws-cdk/assert'; +import { arrayWith, expect, haveResourceLike, objectLike } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; import * as codebuild from '../lib'; diff --git a/packages/@aws-cdk/aws-codebuild/test/test.project.ts b/packages/@aws-cdk/aws-codebuild/test/test.project.ts index 159511589ead7..7ed5fafccbbd3 100644 --- a/packages/@aws-cdk/aws-codebuild/test/test.project.ts +++ b/packages/@aws-cdk/aws-codebuild/test/test.project.ts @@ -1,4 +1,4 @@ -import { countResources, expect, haveResource, haveResourceLike, objectLike, not, ResourcePart, arrayWith } from '@aws-cdk/assert'; +import { countResources, expect, haveResource, haveResourceLike, objectLike, not, ResourcePart, arrayWith } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as logs from '@aws-cdk/aws-logs'; @@ -53,6 +53,34 @@ export = { test.done(); }, + 'can use yamlbuildspec literal'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + buildSpec: codebuild.BuildSpec.fromObjectToYaml({ + text: 'text', + decimal: 10, + list: ['say hi'], + obj: { + text: 'text', + decimal: 10, + list: ['say hi'], + }, + }), + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { + Source: { + BuildSpec: 'text: text\ndecimal: 10\nlist:\n - say hi\nobj:\n text: text\n decimal: 10\n list:\n - say hi\n', + }, + })); + + test.done(); + }, + 'must supply buildspec when using nosource'(test: Test) { // GIVEN const stack = new cdk.Stack(); @@ -737,192 +765,707 @@ export = { }, 'EnvironmentVariables': { - 'can use environment variables from parameter store'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); + 'from SSM': { + 'can use environment variables'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + environment: { + buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage'), + }, + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.PARAMETER_STORE, + value: '/params/param1', + }, + }, + }); - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - environment: { - buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage'), - }, - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.PARAMETER_STORE, - value: '/params/param1', + // THEN + expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { + Environment: objectLike({ + EnvironmentVariables: [{ + Name: 'ENV_VAR1', + Type: 'PARAMETER_STORE', + Value: '/params/param1', + }], + }), + })); + + test.done(); + }, + + 'grants the correct read permissions'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + environment: { + buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage'), }, - }, - }); + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.PARAMETER_STORE, + value: '/params/param1', + }, + 'ENV_VAR2': { + type: codebuild.BuildEnvironmentVariableType.PARAMETER_STORE, + value: 'params/param2', + }, + }, + }); - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Environment: objectLike({ - EnvironmentVariables: [{ - Name: 'ENV_VAR1', - Type: 'PARAMETER_STORE', - Value: '/params/param1', - }], - }), - })); + // THEN + expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith(objectLike({ + 'Action': 'ssm:GetParameters', + 'Effect': 'Allow', + 'Resource': [{ + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':ssm:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':parameter/params/param1', + ], + ], + }, + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':ssm:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':parameter/params/param2', + ], + ], + }], + })), + }, + })); - test.done(); - }, + test.done(); + }, - 'grant read permission for parameter store variables'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); + 'does not grant read permissions when variables are not from parameter store'(test: Test) { - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - environment: { - buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage'), - }, - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.PARAMETER_STORE, - value: '/params/param1', + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + environment: { + buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage'), }, - 'ENV_VAR2': { - type: codebuild.BuildEnvironmentVariableType.PARAMETER_STORE, - value: 'params/param2', + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.PLAINTEXT, + value: 'var1-value', + }, }, - }, - }); + }); - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith(objectLike({ - 'Action': 'ssm:GetParameters', - 'Effect': 'Allow', - 'Resource': [{ - 'Fn::Join': [ - '', - [ + // THEN + expect(stack).notTo(haveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith(objectLike({ + 'Action': 'ssm:GetParameters', + 'Effect': 'Allow', + })), + }, + })); + + test.done(); + }, + }, + + 'from SecretsManager': { + 'can be provided as a verbatim secret name'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: 'my-secret', + }, + }, + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': 'my-secret', + }, + ], + }, + })); + + // THEN + expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': ['', [ 'arn:', - { - Ref: 'AWS::Partition', - }, - ':ssm:', - { - Ref: 'AWS::Region', - }, + { Ref: 'AWS::Partition' }, + ':secretsmanager:', + { Ref: 'AWS::Region' }, ':', - { - Ref: 'AWS::AccountId', - }, - ':parameter/params/param1', - ], - ], + { Ref: 'AWS::AccountId' }, + ':secret:my-secret-??????', + ]], + }, + }), + }, + })); + + test.done(); + }, + + 'can be provided as a verbatim secret name followed by a JSON key'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: 'my-secret:json-key', }, - { - 'Fn::Join': [ - '', - [ + }, + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': 'my-secret:json-key', + }, + ], + }, + })); + + // THEN + expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': ['', [ 'arn:', - { - Ref: 'AWS::Partition', - }, - ':ssm:', - { - Ref: 'AWS::Region', - }, + { Ref: 'AWS::Partition' }, + ':secretsmanager:', + { Ref: 'AWS::Region' }, ':', - { - Ref: 'AWS::AccountId', - }, - ':parameter/params/param2', - ], - ], - }], - })), - }, - })); + { Ref: 'AWS::AccountId' }, + ':secret:my-secret-??????', + ]], + }, + }), + }, + })); + test.done(); + }, - test.done(); - }, + 'can be provided as a verbatim full secret ARN followed by a JSON key'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); - 'should not grant read permission when variables are not from parameter store'(test: Test) { + // WHEN + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: 'arn:aws:secretsmanager:us-west-2:123456789012:secret:my-secret-123456:json-key', + }, + }, + }); - // GIVEN - const stack = new cdk.Stack(); + // THEN + expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:my-secret-123456:json-key', + }, + ], + }, + })); + + // THEN + expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:my-secret-123456*', + }), + }, + })); + + // THEN + expect(stack).to(not(haveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'kms:Decrypt', + 'Effect': 'Allow', + 'Resource': 'arn:aws:kms:us-west-2:123456789012:key/*', + }), + }, + }))); - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - environment: { - buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage'), - }, - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.PLAINTEXT, - value: 'var1-value', + test.done(); + }, + + 'can be provided as a verbatim partial secret ARN'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret', + }, }, - }, - }); + }); - // THEN - expect(stack).notTo(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith(objectLike({ - 'Action': 'ssm:GetParameters', - 'Effect': 'Allow', - })), - }, - })); + // THEN + expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret', + }, + ], + }, + })); + + // THEN + expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret*', + }), + }, + })); + + // THEN + expect(stack).to(not(haveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'kms:Decrypt', + 'Effect': 'Allow', + 'Resource': 'arn:aws:kms:us-west-2:123456789012:key/*', + }), + }, + }))); - test.done(); - }, + test.done(); + }, - "grants the Project's Role read permissions to the SecretsManager environment variables"(test: Test) { - // GIVEN - const stack = new cdk.Stack(); + "when provided as a verbatim partial secret ARN from another account, adds permission to decrypt keys in the Secret's account"(test: Test) { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'ProjectStack', { + env: { account: '123456789012' }, + }); - // WHEN - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: 'my-secret', + // WHEN + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: 'arn:aws:secretsmanager:us-west-2:901234567890:secret:mysecret', + }, }, - }, - }); + }); - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': { - 'Fn::Join': ['', [ - 'arn:', - { Ref: 'AWS::Partition' }, - ':secretsmanager:', - { Ref: 'AWS::Region' }, - ':', - { Ref: 'AWS::AccountId' }, - ':secret:my-secret-??????', - ]], + // THEN + expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'kms:Decrypt', + 'Effect': 'Allow', + 'Resource': 'arn:aws:kms:us-west-2:901234567890:key/*', + }), + }, + })); + + test.done(); + }, + + 'when two secrets from another account are provided as verbatim partial secret ARNs, adds only one permission for decrypting'(test: Test) { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'ProjectStack', { + env: { account: '123456789012' }, + }); + + // WHEN + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: 'arn:aws:secretsmanager:us-west-2:901234567890:secret:mysecret', }, - }), - }, - })); + 'ENV_VAR2': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: 'arn:aws:secretsmanager:us-west-2:901234567890:secret:other-secret', + }, + }, + }); - test.done(); + // THEN + expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'kms:Decrypt', + 'Effect': 'Allow', + 'Resource': 'arn:aws:kms:us-west-2:901234567890:key/*', + }), + }, + })); + + test.done(); + }, + + 'can be provided as the ARN attribute of a new Secret'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const secret = new secretsmanager.Secret(stack, 'Secret'); + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: secret.secretArn, + }, + }, + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': { 'Ref': 'SecretA720EF05' }, + }, + ], + }, + })); + + // THEN + expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': { 'Ref': 'SecretA720EF05' }, + }), + }, + })); + + test.done(); + }, + + 'when the same new secret is provided with different JSON keys, only adds the resource once'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const secret = new secretsmanager.Secret(stack, 'Secret'); + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: `${secret.secretArn}:json-key1`, + }, + 'ENV_VAR2': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: `${secret.secretArn}:json-key2`, + }, + }, + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': { 'Fn::Join': ['', [{ 'Ref': 'SecretA720EF05' }, ':json-key1']] }, + }, + { + 'Name': 'ENV_VAR2', + 'Type': 'SECRETS_MANAGER', + 'Value': { 'Fn::Join': ['', [{ 'Ref': 'SecretA720EF05' }, ':json-key2']] }, + }, + ], + }, + })); + + // THEN + expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': { 'Ref': 'SecretA720EF05' }, + }), + }, + })); + + test.done(); + }, + + 'can be provided as the ARN attribute of a new Secret, followed by a JSON key'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const secret = new secretsmanager.Secret(stack, 'Secret'); + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: `${secret.secretArn}:json-key:version-stage`, + }, + }, + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': { + 'Fn::Join': ['', [ + { 'Ref': 'SecretA720EF05' }, + ':json-key:version-stage', + ]], + }, + }, + ], + }, + })); + + // THEN + expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': { 'Ref': 'SecretA720EF05' }, + }), + }, + })); + + test.done(); + }, + + 'can be provided as the name attribute of a Secret imported by name'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const secret = secretsmanager.Secret.fromSecretNameV2(stack, 'Secret', 'mysecret'); + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: secret.secretName, + }, + }, + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': 'mysecret', + }, + ], + }, + })); + + // THEN + expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': ['', [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':secretsmanager:', + { 'Ref': 'AWS::Region' }, + ':', + { 'Ref': 'AWS::AccountId' }, + ':secret:mysecret-??????', + ]], + }, + }), + }, + })); + + test.done(); + }, + + 'can be provided as the ARN attribute of a Secret imported by partial ARN, followed by a JSON key'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const secret = secretsmanager.Secret.fromSecretPartialArn(stack, 'Secret', + 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret'); + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: `${secret.secretArn}:json-key`, + }, + }, + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret:json-key', + }, + ], + }, + })); + + // THEN + expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret*', + }), + }, + })); + + test.done(); + }, + + 'can be provided as the ARN attribute of a Secret imported by complete ARN, followed by a JSON key'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const secret = secretsmanager.Secret.fromSecretCompleteArn(stack, 'Secret', + 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret-123456'); + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: `${secret.secretArn}:json-key`, + }, + }, + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret-123456:json-key', + }, + ], + }, + })); + + // THEN + expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret-123456*', + }), + }, + })); + + test.done(); + }, }, 'should fail creating when using a secret value in a plaintext variable'(test: Test) { @@ -982,6 +1525,7 @@ export = { test.done(); }, + 'can override build timeout'(test: Test) { // GIVEN const stack = new cdk.Stack(); @@ -1003,4 +1547,41 @@ export = { test.done(); }, }, + + 'Maximum concurrency': { + 'can limit maximum concurrency'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + concurrentBuildLimit: 1, + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { + ConcurrentBuildLimit: 1, + })); + + test.done(); + }, + }, + + 'can be imported': { + 'by ARN'(test: Test) { + const stack = new cdk.Stack(); + const project = codebuild.Project.fromProjectArn(stack, 'Project', + 'arn:aws:codebuild:us-west-2:123456789012:project/My-Project'); + + test.equal(project.projectName, 'My-Project'); + test.equal(project.env.account, '123456789012'); + test.equal(project.env.region, 'us-west-2'); + + test.done(); + }, + }, }; diff --git a/packages/@aws-cdk/aws-codebuild/test/test.report-group.ts b/packages/@aws-cdk/aws-codebuild/test/test.report-group.ts index 01cdd4f0d07b3..9ea5441aeb5df 100644 --- a/packages/@aws-cdk/aws-codebuild/test/test.report-group.ts +++ b/packages/@aws-cdk/aws-codebuild/test/test.report-group.ts @@ -1,4 +1,4 @@ -import { ABSENT, expect, haveResourceLike, ResourcePart } from '@aws-cdk/assert'; +import { ABSENT, expect, haveResourceLike, ResourcePart } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as s3 from '@aws-cdk/aws-s3'; diff --git a/packages/@aws-cdk/aws-codebuild/test/test.untrusted-code-boundary.ts b/packages/@aws-cdk/aws-codebuild/test/test.untrusted-code-boundary.ts index 04196e631f5c8..e806e48b58edb 100644 --- a/packages/@aws-cdk/aws-codebuild/test/test.untrusted-code-boundary.ts +++ b/packages/@aws-cdk/aws-codebuild/test/test.untrusted-code-boundary.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike, arrayWith } from '@aws-cdk/assert'; +import { expect, haveResourceLike, arrayWith } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk/aws-codecommit/package.json b/packages/@aws-cdk/aws-codecommit/package.json index 0580fab198c85..1b295a70524bc 100644 --- a/packages/@aws-cdk/aws-codecommit/package.json +++ b/packages/@aws-cdk/aws-codecommit/package.json @@ -75,7 +75,6 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@types/nodeunit": "^0.0.31", "aws-sdk": "^2.848.0", @@ -83,20 +82,21 @@ "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "nodeunit": "^0.11.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-codecommit/test/test.codecommit.ts b/packages/@aws-cdk/aws-codecommit/test/test.codecommit.ts index 1f49f852b1e57..899be7482ff19 100644 --- a/packages/@aws-cdk/aws-codecommit/test/test.codecommit.ts +++ b/packages/@aws-cdk/aws-codecommit/test/test.codecommit.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import { Role, ServicePrincipal } from '@aws-cdk/aws-iam'; import { Stack } from '@aws-cdk/core'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk/aws-codedeploy/.gitignore b/packages/@aws-cdk/aws-codedeploy/.gitignore index 018c65919d67c..7fb7303ad5bf6 100644 --- a/packages/@aws-cdk/aws-codedeploy/.gitignore +++ b/packages/@aws-cdk/aws-codedeploy/.gitignore @@ -15,4 +15,5 @@ nyc.config.js *.snk !.eslintrc.js -junit.xml \ No newline at end of file +junit.xml +!test/lambda/*/*.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codedeploy/lib/server/deployment-group.ts b/packages/@aws-cdk/aws-codedeploy/lib/server/deployment-group.ts index ce93f699537c7..4e1a436ef9b77 100644 --- a/packages/@aws-cdk/aws-codedeploy/lib/server/deployment-group.ts +++ b/packages/@aws-cdk/aws-codedeploy/lib/server/deployment-group.ts @@ -269,7 +269,9 @@ export class ServerDeploymentGroup extends ServerDeploymentGroupBase { physicalName: props.deploymentGroupName, }); - this.application = props.application || new ServerApplication(this, 'Application'); + this.application = props.application || new ServerApplication(this, 'Application', { + applicationName: props.deploymentGroupName === cdk.PhysicalName.GENERATE_IF_NEEDED ? cdk.PhysicalName.GENERATE_IF_NEEDED : undefined, + }); this.role = props.role || new iam.Role(this, 'Role', { assumedBy: new iam.ServicePrincipal('codedeploy.amazonaws.com'), @@ -354,7 +356,7 @@ export class ServerDeploymentGroup extends ServerDeploymentGroupBase { 'if [ -z "$PKG_CMD" ]; then', 'PKG_CMD=apt-get', 'else', - 'PKG=CMD=yum', + 'PKG_CMD=yum', 'fi', '$PKG_CMD update -y', 'set +e', // make sure we don't exit on the next command failing (we check its exit code below) @@ -365,8 +367,7 @@ export class ServerDeploymentGroup extends ServerDeploymentGroupBase { '$PKG_CMD install -y ruby', 'fi', 'AWS_CLI_PACKAGE_NAME=awscli', - 'if [[ "$PKG_CMD" = "yum" ]];', - 'then', + 'if [ "$PKG_CMD" = "yum" ]; then', 'AWS_CLI_PACKAGE_NAME=aws-cli', 'fi', '$PKG_CMD install -y $AWS_CLI_PACKAGE_NAME', diff --git a/packages/@aws-cdk/aws-codedeploy/package.json b/packages/@aws-cdk/aws-codedeploy/package.json index 257e001f0fdbe..b658ac39da8bb 100644 --- a/packages/@aws-cdk/aws-codedeploy/package.json +++ b/packages/@aws-cdk/aws-codedeploy/package.json @@ -73,13 +73,13 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "nodeunit": "^0.11.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-autoscaling": "0.0.0", @@ -92,7 +92,7 @@ "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -106,7 +106,7 @@ "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-codedeploy/test/ecs/test.application.ts b/packages/@aws-cdk/aws-codedeploy/test/ecs/test.application.ts index 14c4811407f34..de45dc0bd58e9 100644 --- a/packages/@aws-cdk/aws-codedeploy/test/ecs/test.application.ts +++ b/packages/@aws-cdk/aws-codedeploy/test/ecs/test.application.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; import * as codedeploy from '../../lib'; diff --git a/packages/@aws-cdk/aws-codedeploy/test/lambda/test.application.ts b/packages/@aws-cdk/aws-codedeploy/test/lambda/test.application.ts index cf335cca66aec..f3f79115d0165 100644 --- a/packages/@aws-cdk/aws-codedeploy/test/lambda/test.application.ts +++ b/packages/@aws-cdk/aws-codedeploy/test/lambda/test.application.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; import * as codedeploy from '../../lib'; diff --git a/packages/@aws-cdk/aws-codedeploy/test/lambda/test.custom-deployment-config.ts b/packages/@aws-cdk/aws-codedeploy/test/lambda/test.custom-deployment-config.ts index fdd8ba0c56be6..9ba58b043aebd 100644 --- a/packages/@aws-cdk/aws-codedeploy/test/lambda/test.custom-deployment-config.ts +++ b/packages/@aws-cdk/aws-codedeploy/test/lambda/test.custom-deployment-config.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike, ResourcePart } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike, ResourcePart } from '@aws-cdk/assert-internal'; import * as lambda from '@aws-cdk/aws-lambda'; import * as cdk from '@aws-cdk/core'; import { ICallbackFunction, Test } from 'nodeunit'; 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 267cdc193a602..6274fd6ca3457 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 @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike, ResourcePart } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike, ResourcePart } from '@aws-cdk/assert-internal'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as iam from '@aws-cdk/aws-iam'; import * as lambda from '@aws-cdk/aws-lambda'; diff --git a/packages/@aws-cdk/aws-codedeploy/test/server/integ.deployment-group.expected.json b/packages/@aws-cdk/aws-codedeploy/test/server/integ.deployment-group.expected.json index 1f5d3d109128d..c5ae20b9ac145 100644 --- a/packages/@aws-cdk/aws-codedeploy/test/server/integ.deployment-group.expected.json +++ b/packages/@aws-cdk/aws-codedeploy/test/server/integ.deployment-group.expected.json @@ -659,7 +659,7 @@ "Fn::Join": [ "", [ - "#!/bin/bash\nset +e\nPKG_CMD=`which yum 2>/dev/null`\nset -e\nif [ -z \"$PKG_CMD\" ]; then\nPKG_CMD=apt-get\nelse\nPKG=CMD=yum\nfi\n$PKG_CMD update -y\nset +e\n$PKG_CMD install -y ruby2.0\nRUBY2_INSTALL=$?\nset -e\nif [ $RUBY2_INSTALL -ne 0 ]; then\n$PKG_CMD install -y ruby\nfi\nAWS_CLI_PACKAGE_NAME=awscli\nif [[ \"$PKG_CMD\" = \"yum\" ]];\nthen\nAWS_CLI_PACKAGE_NAME=aws-cli\nfi\n$PKG_CMD install -y $AWS_CLI_PACKAGE_NAME\nTMP_DIR=`mktemp -d`\ncd $TMP_DIR\naws s3 cp s3://aws-codedeploy-", + "#!/bin/bash\nset +e\nPKG_CMD=`which yum 2>/dev/null`\nset -e\nif [ -z \"$PKG_CMD\" ]; then\nPKG_CMD=apt-get\nelse\nPKG_CMD=yum\nfi\n$PKG_CMD update -y\nset +e\n$PKG_CMD install -y ruby2.0\nRUBY2_INSTALL=$?\nset -e\nif [ $RUBY2_INSTALL -ne 0 ]; then\n$PKG_CMD install -y ruby\nfi\nAWS_CLI_PACKAGE_NAME=awscli\nif [ \"$PKG_CMD\" = \"yum\" ]; then\nAWS_CLI_PACKAGE_NAME=aws-cli\nfi\n$PKG_CMD install -y $AWS_CLI_PACKAGE_NAME\nTMP_DIR=`mktemp -d`\ncd $TMP_DIR\naws s3 cp s3://aws-codedeploy-", { "Ref": "AWS::Region" }, @@ -884,4 +884,4 @@ "Default": "/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codedeploy/test/server/test.deployment-config.ts b/packages/@aws-cdk/aws-codedeploy/test/server/test.deployment-config.ts index 7b8c43a1ae0d5..0108122030276 100644 --- a/packages/@aws-cdk/aws-codedeploy/test/server/test.deployment-config.ts +++ b/packages/@aws-cdk/aws-codedeploy/test/server/test.deployment-config.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; import * as codedeploy from '../../lib'; diff --git a/packages/@aws-cdk/aws-codedeploy/test/server/test.deployment-group.ts b/packages/@aws-cdk/aws-codedeploy/test/server/test.deployment-group.ts index 8d2dbe44cd604..4bd4da6192380 100644 --- a/packages/@aws-cdk/aws-codedeploy/test/server/test.deployment-group.ts +++ b/packages/@aws-cdk/aws-codedeploy/test/server/test.deployment-group.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, SynthUtils } from '@aws-cdk/assert'; +import { expect, haveOutput, haveResource, SynthUtils } from '@aws-cdk/assert-internal'; import * as autoscaling from '@aws-cdk/aws-autoscaling'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as ec2 from '@aws-cdk/aws-ec2'; @@ -28,6 +28,25 @@ export = { test.done(); }, + 'creating an application with physical name if needed'(test: Test) { + const stack = new cdk.Stack(undefined, undefined, { env: { account: '12345', region: 'us-test-1' } }); + const stack2 = new cdk.Stack(undefined, undefined, { env: { account: '12346', region: 'us-test-2' } }); + const serverDeploymentGroup = new codedeploy.ServerDeploymentGroup(stack, 'MyDG', { + deploymentGroupName: cdk.PhysicalName.GENERATE_IF_NEEDED, + }); + + new cdk.CfnOutput(stack2, 'Output', { + value: serverDeploymentGroup.application.applicationName, + }); + + expect(stack2).to(haveOutput({ + outputName: 'Output', + outputValue: 'defaultmydgapplication78dba0bb0c7580b32033', + })); + + test.done(); + }, + 'can be imported'(test: Test) { const stack = new cdk.Stack(); @@ -62,7 +81,7 @@ export = { 'Fn::Join': [ '', [ - '#!/bin/bash\nset +e\nPKG_CMD=`which yum 2>/dev/null`\nset -e\nif [ -z "$PKG_CMD" ]; then\nPKG_CMD=apt-get\nelse\nPKG=CMD=yum\nfi\n$PKG_CMD update -y\nset +e\n$PKG_CMD install -y ruby2.0\nRUBY2_INSTALL=$?\nset -e\nif [ $RUBY2_INSTALL -ne 0 ]; then\n$PKG_CMD install -y ruby\nfi\nAWS_CLI_PACKAGE_NAME=awscli\nif [[ "$PKG_CMD" = "yum" ]];\nthen\nAWS_CLI_PACKAGE_NAME=aws-cli\nfi\n$PKG_CMD install -y $AWS_CLI_PACKAGE_NAME\nTMP_DIR=`mktemp -d`\ncd $TMP_DIR\naws s3 cp s3://aws-codedeploy-', + '#!/bin/bash\nset +e\nPKG_CMD=`which yum 2>/dev/null`\nset -e\nif [ -z "$PKG_CMD" ]; then\nPKG_CMD=apt-get\nelse\nPKG_CMD=yum\nfi\n$PKG_CMD update -y\nset +e\n$PKG_CMD install -y ruby2.0\nRUBY2_INSTALL=$?\nset -e\nif [ $RUBY2_INSTALL -ne 0 ]; then\n$PKG_CMD install -y ruby\nfi\nAWS_CLI_PACKAGE_NAME=awscli\nif [ "$PKG_CMD" = "yum" ]; then\nAWS_CLI_PACKAGE_NAME=aws-cli\nfi\n$PKG_CMD install -y $AWS_CLI_PACKAGE_NAME\nTMP_DIR=`mktemp -d`\ncd $TMP_DIR\naws s3 cp s3://aws-codedeploy-', { 'Ref': 'AWS::Region', }, diff --git a/packages/@aws-cdk/aws-codeguruprofiler/package.json b/packages/@aws-cdk/aws-codeguruprofiler/package.json index dd7c44d1a3527..8eac7b8a18af5 100644 --- a/packages/@aws-cdk/aws-codeguruprofiler/package.json +++ b/packages/@aws-cdk/aws-codeguruprofiler/package.json @@ -73,21 +73,22 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-codeguruprofiler/test/codeguruprofiler.test.ts b/packages/@aws-cdk/aws-codeguruprofiler/test/codeguruprofiler.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-codeguruprofiler/test/codeguruprofiler.test.ts +++ b/packages/@aws-cdk/aws-codeguruprofiler/test/codeguruprofiler.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-codeguruprofiler/test/profiling-group.test.ts b/packages/@aws-cdk/aws-codeguruprofiler/test/profiling-group.test.ts index 27dc281589172..00212902bbec6 100644 --- a/packages/@aws-cdk/aws-codeguruprofiler/test/profiling-group.test.ts +++ b/packages/@aws-cdk/aws-codeguruprofiler/test/profiling-group.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import { AccountRootPrincipal, Role } from '@aws-cdk/aws-iam'; import { Stack } from '@aws-cdk/core'; import { ProfilingGroup, ComputePlatform } from '../lib'; diff --git a/packages/@aws-cdk/aws-codegurureviewer/package.json b/packages/@aws-cdk/aws-codegurureviewer/package.json index 1b75ae00b4682..d7e411d99ee3f 100644 --- a/packages/@aws-cdk/aws-codegurureviewer/package.json +++ b/packages/@aws-cdk/aws-codegurureviewer/package.json @@ -73,10 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-codegurureviewer/test/codegurureviewer.test.ts b/packages/@aws-cdk/aws-codegurureviewer/test/codegurureviewer.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-codegurureviewer/test/codegurureviewer.test.ts +++ b/packages/@aws-cdk/aws-codegurureviewer/test/codegurureviewer.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-codepipeline-actions/README.md b/packages/@aws-cdk/aws-codepipeline-actions/README.md index 559a111f2f18c..89a94d4918697 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/README.md +++ b/packages/@aws-cdk/aws-codepipeline-actions/README.md @@ -168,7 +168,7 @@ the connection has already been created. ```ts const sourceOutput = new codepipeline.Artifact(); -const sourceAction = new codepipeline_actions.BitBucketSourceAction({ +const sourceAction = new codepipeline_actions.CodeStarConnectionsSourceAction({ actionName: 'BitBucket_Source', owner: 'aws', repo: 'aws-cdk', @@ -177,9 +177,8 @@ const sourceAction = new codepipeline_actions.BitBucketSourceAction({ }); ``` -**Note**: as this feature is still in Beta in CodePipeline, -the above class `BitBucketSourceAction` is experimental - -we reserve the right to make breaking changes to it. +You can also use the `CodeStarConnectionsSourceAction` to connect to GitHub, in the same way +(you just have to select GitHub as the source when creating the connection in the console). ### AWS S3 Source @@ -232,7 +231,10 @@ import * as cloudtrail from '@aws-cdk/aws-cloudtrail'; const key = 'some/key.zip'; const trail = new cloudtrail.Trail(this, 'CloudTrail'); -trail.addS3EventSelector([sourceBucket.arnForObjects(key)], { +trail.addS3EventSelector([{ + bucket: sourceBucket, + objectPrefix: key, +}], { readWriteType: cloudtrail.ReadWriteType.WRITE_ONLY, }); const sourceAction = new codepipeline_actions.S3SourceAction({ @@ -826,24 +828,16 @@ new codepipeline_actions.AlexaSkillDeployAction({ ### AWS Service Catalog -You can deploy a CloudFormation template to an existing Service Catalog product with the following action: +You can deploy a CloudFormation template to an existing Service Catalog product with the following Action: ```ts -new codepipeline.Pipeline(this, 'Pipeline', { - stages: [ - { - stageName: 'ServiceCatalogDeploy', - actions: [ - new codepipeline_actions.ServiceCatalogDeployAction({ - actionName: 'ServiceCatalogDeploy', - templatePath: cdkBuildOutput.atPath("Sample.template.json"), - productVersionName: "Version - " + Date.now.toString, - productType: "CLOUD_FORMATION_TEMPLATE", - productVersionDescription: "This is a version from the pipeline with a new description.", - productId: "prod-XXXXXXXX", - }), - }, - ], +const serviceCatalogDeployAction = new codepipeline_actions.ServiceCatalogDeployActionBeta1({ + actionName: 'ServiceCatalogDeploy', + templatePath: cdkBuildOutput.atPath("Sample.template.json"), + productVersionName: "Version - " + Date.now.toString, + productType: "CLOUD_FORMATION_TEMPLATE", + productVersionDescription: "This is a version from the pipeline with a new description.", + productId: "prod-XXXXXXXX", }); ``` diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/action.ts index c2f7ca5ca5305..f6e8a58d27329 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/action.ts @@ -1,125 +1,15 @@ import * as codepipeline from '@aws-cdk/aws-codepipeline'; -import * as events from '@aws-cdk/aws-events'; -import { Lazy } from '@aws-cdk/core'; - -// keep this import separate from other imports to reduce chance for merge conflicts with v2-main -// eslint-disable-next-line no-duplicate-imports, import/order -import { Construct } from '@aws-cdk/core'; /** * Low-level class for generic CodePipeline Actions. - * - * WARNING: this class should not be externally exposed, but is currently visible - * because of a limitation of jsii (https://github.com/aws/jsii/issues/524). - * - * This class will disappear in a future release and should not be used. - * - * @experimental + * If you're implementing your own IAction, + * prefer to use the Action class from the codepipeline module. */ -export abstract class Action implements codepipeline.IAction { - public readonly actionProperties: codepipeline.ActionProperties; - private _pipeline?: codepipeline.IPipeline; - private _stage?: codepipeline.IStage; - private _scope?: Construct; - private readonly customerProvidedNamespace?: string; - private readonly namespaceOrToken: string; - private actualNamespace?: string; - private variableReferenced = false; +export abstract class Action extends codepipeline.Action { + protected readonly providedActionProperties: codepipeline.ActionProperties; protected constructor(actionProperties: codepipeline.ActionProperties) { - this.customerProvidedNamespace = actionProperties.variablesNamespace; - this.namespaceOrToken = Lazy.string({ - produce: () => { - // make sure the action was bound (= added to a pipeline) - if (this.actualNamespace !== undefined) { - return this.customerProvidedNamespace !== undefined - // if a customer passed a namespace explicitly, always use that - ? this.customerProvidedNamespace - // otherwise, only return a namespace if any variable was referenced - : (this.variableReferenced ? this.actualNamespace : undefined); - } else { - throw new Error(`Cannot reference variables of action '${this.actionProperties.actionName}', ` + - 'as that action was never added to a pipeline'); - } - }, - }); - this.actionProperties = { - ...actionProperties, - variablesNamespace: this.namespaceOrToken, - }; - } - - public bind(scope: Construct, stage: codepipeline.IStage, options: codepipeline.ActionBindOptions): - codepipeline.ActionConfig { - this._pipeline = stage.pipeline; - this._stage = stage; - this._scope = scope; - - this.actualNamespace = this.customerProvidedNamespace === undefined - // default a namespace name, based on the stage and action names - ? `${stage.stageName}_${this.actionProperties.actionName}_NS` - : this.customerProvidedNamespace; - - return this.bound(scope, stage, options); - } - - public onStateChange(name: string, target?: events.IRuleTarget, options?: events.RuleProps) { - const rule = new events.Rule(this.scope, name, options); - rule.addTarget(target); - rule.addEventPattern({ - detailType: ['CodePipeline Action Execution State Change'], - source: ['aws.codepipeline'], - resources: [this.pipeline.pipelineArn], - detail: { - stage: [this.stage.stageName], - action: [this.actionProperties.actionName], - }, - }); - return rule; - } - - protected variableExpression(variableName: string): string { - this.variableReferenced = true; - return `#{${this.namespaceOrToken}.${variableName}}`; - } - - /** - * The method called when an Action is attached to a Pipeline. - * This method is guaranteed to be called only once for each Action instance. - * - * @param options an instance of the {@link ActionBindOptions} class, - * that contains the necessary information for the Action - * to configure itself, like a reference to the Role, etc. - */ - protected abstract bound(scope: Construct, stage: codepipeline.IStage, options: codepipeline.ActionBindOptions): - codepipeline.ActionConfig; - - private get pipeline(): codepipeline.IPipeline { - if (this._pipeline) { - return this._pipeline; - } else { - throw new Error('Action must be added to a stage that is part of a pipeline before using onStateChange'); - } - } - - private get stage(): codepipeline.IStage { - if (this._stage) { - return this._stage; - } else { - throw new Error('Action must be added to a stage that is part of a pipeline before using onStateChange'); - } - } - - /** - * Retrieves the Construct scope of this Action. - * Only available after the Action has been added to a Stage, - * and that Stage to a Pipeline. - */ - private get scope(): Construct { - if (this._scope) { - return this._scope; - } else { - throw new Error('Action must be added to a stage that is part of a pipeline first'); - } + super(); + this.providedActionProperties = actionProperties; } } diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/bitbucket/source-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/bitbucket/source-action.ts index 7d7625ab4fca4..585ebf33e80eb 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/bitbucket/source-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/bitbucket/source-action.ts @@ -1,8 +1,6 @@ import * as codepipeline from '@aws-cdk/aws-codepipeline'; -import * as iam from '@aws-cdk/aws-iam'; - -import { Action } from '../action'; -import { sourceArtifactBounds } from '../common'; +import * as events from '@aws-cdk/aws-events'; +import { CodeStarConnectionsSourceAction, CodeStarConnectionsSourceActionProps } from '../codestar-connections/source-action'; // keep this import separate from other imports to reduce chance for merge conflicts with v2-main // eslint-disable-next-line no-duplicate-imports, import/order @@ -11,120 +9,32 @@ import { Construct } from '@aws-cdk/core'; /** * Construction properties for {@link BitBucketSourceAction}. * - * @experimental + * @deprecated use CodeStarConnectionsSourceActionProps instead */ -export interface BitBucketSourceActionProps extends codepipeline.CommonAwsActionProps { - /** - * The output artifact that this action produces. - * Can be used as input for further pipeline actions. - */ - readonly output: codepipeline.Artifact; - - /** - * The ARN of the CodeStar Connection created in the AWS console - * that has permissions to access this BitBucket repository. - * - * @example 'arn:aws:codestar-connections:us-east-1:123456789012:connection/12345678-abcd-12ab-34cdef5678gh' - * @see https://docs.aws.amazon.com/codepipeline/latest/userguide/connections-create.html - */ - readonly connectionArn: string; - - /** - * The owning user or organization of the repository. - * - * @example 'aws' - */ - readonly owner: string; - - /** - * The name of the repository. - * - * @example 'aws-cdk' - */ - readonly repo: string; - - /** - * The branch to build. - * - * @default 'master' - */ - readonly branch?: string; - - // long URL in @see - /** - * Whether the output should be the contents of the repository - * (which is the default), - * or a link that allows CodeBuild to clone the repository before building. - * - * **Note**: if this option is true, - * then only CodeBuild actions can use the resulting {@link output}. - * - * @default false - * @see https://docs.aws.amazon.com/codepipeline/latest/userguide/action-reference-CodestarConnectionSource.html#action-reference-CodestarConnectionSource-config - */ - readonly codeBuildCloneOutput?: boolean; +export interface BitBucketSourceActionProps extends CodeStarConnectionsSourceActionProps { } /** * A CodePipeline source action for BitBucket. * - * @experimental + * @deprecated use CodeStarConnectionsSourceAction instead */ -export class BitBucketSourceAction extends Action { - /** - * The name of the property that holds the ARN of the CodeStar Connection - * inside of the CodePipeline Artifact's metadata. - * - * @internal - */ - public static readonly _CONNECTION_ARN_PROPERTY = 'CodeStarConnectionArnProperty'; - - private readonly props: BitBucketSourceActionProps; +export class BitBucketSourceAction implements codepipeline.IAction { + private readonly codeStarConnectionsSourceAction: CodeStarConnectionsSourceAction; constructor(props: BitBucketSourceActionProps) { - super({ - ...props, - category: codepipeline.ActionCategory.SOURCE, - owner: 'AWS', // because props also has a (different!) owner property! - provider: 'CodeStarSourceConnection', - artifactBounds: sourceArtifactBounds(), - outputs: [props.output], - }); - - this.props = props; + this.codeStarConnectionsSourceAction = new CodeStarConnectionsSourceAction(props); } - protected bound(_scope: Construct, _stage: codepipeline.IStage, options: codepipeline.ActionBindOptions): codepipeline.ActionConfig { - // https://docs.aws.amazon.com/codepipeline/latest/userguide/security-iam.html#how-to-update-role-new-services - options.role.addToPolicy(new iam.PolicyStatement({ - actions: [ - 'codestar-connections:UseConnection', - ], - resources: [ - this.props.connectionArn, - ], - })); - - // the action needs to write the output to the pipeline bucket - options.bucket.grantReadWrite(options.role); + public get actionProperties(): codepipeline.ActionProperties { + return this.codeStarConnectionsSourceAction.actionProperties; + } - // if codeBuildCloneOutput is true, - // save the connectionArn in the Artifact instance - // to be read by the CodeBuildAction later - if (this.props.codeBuildCloneOutput === true) { - this.props.output.setMetadata(BitBucketSourceAction._CONNECTION_ARN_PROPERTY, - this.props.connectionArn); - } + public bind(scope: Construct, stage: codepipeline.IStage, options: codepipeline.ActionBindOptions): codepipeline.ActionConfig { + return this.codeStarConnectionsSourceAction.bind(scope, stage, options); + } - return { - configuration: { - ConnectionArn: this.props.connectionArn, - FullRepositoryId: `${this.props.owner}/${this.props.repo}`, - BranchName: this.props.branch ?? 'master', - OutputArtifactFormat: this.props.codeBuildCloneOutput === true - ? 'CODEBUILD_CLONE_REF' - : undefined, - }, - }; + public onStateChange(name: string, target?: events.IRuleTarget, options?: events.RuleProps): events.Rule { + return this.codeStarConnectionsSourceAction.onStateChange(name, target, options); } } diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/codebuild/build-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/codebuild/build-action.ts index 54735d4ec1d9d..c825682d16c76 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/codebuild/build-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/codebuild/build-action.ts @@ -2,7 +2,7 @@ import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; -import { BitBucketSourceAction } from '..'; +import { CodeStarConnectionsSourceAction } from '..'; import { Action } from '../action'; import { CodeCommitSourceAction } from '../codecommit/source-action'; @@ -180,10 +180,10 @@ export class CodeBuildAction extends Action { } for (const inputArtifact of this.actionProperties.inputs || []) { - // if any of the inputs come from the BitBucketSourceAction + // if any of the inputs come from the CodeStarConnectionsSourceAction // with codeBuildCloneOutput=true, // grant the Project's Role to use the connection - const connectionArn = inputArtifact.getMetadata(BitBucketSourceAction._CONNECTION_ARN_PROPERTY); + const connectionArn = inputArtifact.getMetadata(CodeStarConnectionsSourceAction._CONNECTION_ARN_PROPERTY); if (connectionArn) { this.props.project.addToRolePolicy(new iam.PolicyStatement({ actions: ['codestar-connections:UseConnection'], diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/codecommit/source-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/codecommit/source-action.ts index 602a168487830..8708410dfff18 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/codecommit/source-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/codecommit/source-action.ts @@ -2,7 +2,7 @@ import * as codecommit from '@aws-cdk/aws-codecommit'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as targets from '@aws-cdk/aws-events-targets'; import * as iam from '@aws-cdk/aws-iam'; -import { Names, Token } from '@aws-cdk/core'; +import { Names, Stack, Token, TokenComparison } from '@aws-cdk/core'; import { Action } from '../action'; import { sourceArtifactBounds } from '../common'; @@ -171,6 +171,11 @@ export class CodeCommitSourceAction extends Action { // the Action will write the contents of the Git repository to the Bucket, // so its Role needs write permissions to the Pipeline Bucket options.bucket.grantReadWrite(options.role); + // when this action is cross-account, + // the Role needs the s3:PutObjectAcl permission for some not yet fully understood reason + if (Token.compareStrings(this.props.repository.env.account, Stack.of(stage.pipeline).account) === TokenComparison.DIFFERENT) { + options.bucket.grantPutAcl(options.role); + } // https://docs.aws.amazon.com/codecommit/latest/userguide/auth-and-access-control-permissions-reference.html#aa-acp options.role.addToPrincipalPolicy(new iam.PolicyStatement({ diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/codestar-connections/source-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/codestar-connections/source-action.ts new file mode 100644 index 0000000000000..ca47af5c29c8e --- /dev/null +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/codestar-connections/source-action.ts @@ -0,0 +1,139 @@ +import * as codepipeline from '@aws-cdk/aws-codepipeline'; +import * as iam from '@aws-cdk/aws-iam'; + +import { Action } from '../action'; +import { sourceArtifactBounds } from '../common'; + +// keep this import separate from other imports to reduce chance for merge conflicts with v2-main +// eslint-disable-next-line no-duplicate-imports, import/order +import { Construct } from '@aws-cdk/core'; + +/** + * Construction properties for {@link CodeStarConnectionsSourceAction}. + */ +export interface CodeStarConnectionsSourceActionProps extends codepipeline.CommonAwsActionProps { + /** + * The output artifact that this action produces. + * Can be used as input for further pipeline actions. + */ + readonly output: codepipeline.Artifact; + + /** + * The ARN of the CodeStar Connection created in the AWS console + * that has permissions to access this GitHub or BitBucket repository. + * + * @example 'arn:aws:codestar-connections:us-east-1:123456789012:connection/12345678-abcd-12ab-34cdef5678gh' + * @see https://docs.aws.amazon.com/codepipeline/latest/userguide/connections-create.html + */ + readonly connectionArn: string; + + /** + * The owning user or organization of the repository. + * + * @example 'aws' + */ + readonly owner: string; + + /** + * The name of the repository. + * + * @example 'aws-cdk' + */ + readonly repo: string; + + /** + * The branch to build. + * + * @default 'master' + */ + readonly branch?: string; + + // long URL in @see + /** + * Whether the output should be the contents of the repository + * (which is the default), + * or a link that allows CodeBuild to clone the repository before building. + * + * **Note**: if this option is true, + * then only CodeBuild actions can use the resulting {@link output}. + * + * @default false + * @see https://docs.aws.amazon.com/codepipeline/latest/userguide/action-reference-CodestarConnectionSource.html#action-reference-CodestarConnectionSource-config + */ + readonly codeBuildCloneOutput?: boolean; + + /** + * Controls automatically starting your pipeline when a new commit + * is made on the configured repository and branch. If unspecified, + * the default value is true, and the field does not display by default. + * + * @default true + * @see https://docs.aws.amazon.com/codepipeline/latest/userguide/action-reference-CodestarConnectionSource.html + */ + readonly triggerOnPush?: boolean; +} + +/** + * A CodePipeline source action for the CodeStar Connections source, + * which allows connecting to GitHub and BitBucket. + */ +export class CodeStarConnectionsSourceAction extends Action { + /** + * The name of the property that holds the ARN of the CodeStar Connection + * inside of the CodePipeline Artifact's metadata. + * + * @internal + */ + public static readonly _CONNECTION_ARN_PROPERTY = 'CodeStarConnectionArnProperty'; + + private readonly props: CodeStarConnectionsSourceActionProps; + + constructor(props: CodeStarConnectionsSourceActionProps) { + super({ + ...props, + category: codepipeline.ActionCategory.SOURCE, + owner: 'AWS', // because props also has a (different!) owner property! + provider: 'CodeStarSourceConnection', + artifactBounds: sourceArtifactBounds(), + outputs: [props.output], + }); + + this.props = props; + } + + protected bound(_scope: Construct, _stage: codepipeline.IStage, options: codepipeline.ActionBindOptions): codepipeline.ActionConfig { + // https://docs.aws.amazon.com/codepipeline/latest/userguide/security-iam.html#how-to-update-role-new-services + options.role.addToPolicy(new iam.PolicyStatement({ + actions: [ + 'codestar-connections:UseConnection', + ], + resources: [ + this.props.connectionArn, + ], + })); + + // the action needs to write the output to the pipeline bucket + options.bucket.grantReadWrite(options.role); + options.bucket.grantPutAcl(options.role); + + // if codeBuildCloneOutput is true, + // save the connectionArn in the Artifact instance + // to be read by the CodeBuildAction later + if (this.props.codeBuildCloneOutput === true) { + this.props.output.setMetadata(CodeStarConnectionsSourceAction._CONNECTION_ARN_PROPERTY, + this.props.connectionArn); + } + + return { + configuration: { + ConnectionArn: this.props.connectionArn, + FullRepositoryId: `${this.props.owner}/${this.props.repo}`, + BranchName: this.props.branch ?? 'master', + OutputArtifactFormat: this.props.codeBuildCloneOutput === true + ? 'CODEBUILD_CLONE_REF' + : undefined, + DetectChanges: this.props.triggerOnPush, + }, + }; + } +} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/ecr/source-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/ecr/source-action.ts index 6042d701017a5..eb40c994ccd98 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/ecr/source-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/ecr/source-action.ts @@ -95,7 +95,7 @@ export class EcrSourceAction extends Action { this.props.repository.onCloudTrailImagePushed(Names.nodeUniqueId(stage.pipeline.node) + 'SourceEventRule', { target: new targets.CodePipeline(stage.pipeline), - imageTag: this.props.imageTag, + imageTag: this.props.imageTag ?? 'latest', }); // the Action Role also needs to write to the Pipeline's bucket diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/index.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/index.ts index 3cc0534bf1e11..254b2764f2684 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/index.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/index.ts @@ -1,5 +1,6 @@ export * from './alexa-ask/deploy-action'; export * from './bitbucket/source-action'; +export * from './codestar-connections/source-action'; export * from './cloudformation/pipeline-actions'; export * from './codebuild/build-action'; export * from './codecommit/source-action'; @@ -15,5 +16,5 @@ export * from './manual-approval-action'; export * from './s3/deploy-action'; export * from './s3/source-action'; export * from './stepfunctions/invoke-action'; -export * from './servicecatalog/deploy-action'; -export * from './action'; // for some reason, JSII fails building the module without exporting this class +export * from './servicecatalog/deploy-action-beta1'; +export * from './action'; diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/servicecatalog/deploy-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/servicecatalog/deploy-action-beta1.ts similarity index 86% rename from packages/@aws-cdk/aws-codepipeline-actions/lib/servicecatalog/deploy-action.ts rename to packages/@aws-cdk/aws-codepipeline-actions/lib/servicecatalog/deploy-action-beta1.ts index 9059af1ac0ba1..34b055c14735b 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/servicecatalog/deploy-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/servicecatalog/deploy-action-beta1.ts @@ -8,13 +8,9 @@ import { Action } from '../action'; import { Construct } from '@aws-cdk/core'; /** - * Construction properties of the {@link ServiceCatalogDeployAction ServiceCatalog deploy CodePipeline Action}. - * - * **Note**: this API is still experimental, and may have breaking changes in the future! - * - * @experimental + * Construction properties of the {@link ServiceCatalogDeployActionBeta1 ServiceCatalog deploy CodePipeline Action}. */ -export interface ServiceCatalogDeployActionProps extends codepipeline.CommonAwsActionProps { +export interface ServiceCatalogDeployActionBeta1Props extends codepipeline.CommonAwsActionProps { /** * The path to the cloudformation artifact. */ @@ -39,19 +35,21 @@ export interface ServiceCatalogDeployActionProps extends codepipeline.CommonAwsA /** * CodePipeline action to connect to an existing ServiceCatalog product. +<<<<<<< HEAD:packages/@aws-cdk/aws-codepipeline-actions/lib/servicecatalog/deploy-action.ts * * **Note**: this class is still experimental, and may have breaking changes in the future! * - * @experimental +======= +>>>>>>> master:packages/@aws-cdk/aws-codepipeline-actions/lib/servicecatalog/deploy-action-beta1.ts */ -export class ServiceCatalogDeployAction extends Action { +export class ServiceCatalogDeployActionBeta1 extends Action { private readonly templatePath: string; private readonly productVersionName: string; private readonly productVersionDescription?: string; private readonly productId: string; private readonly productType: string; - constructor(props: ServiceCatalogDeployActionProps) { + constructor(props: ServiceCatalogDeployActionBeta1Props) { super({ ...props, provider: 'ServiceCatalog', diff --git a/packages/@aws-cdk/aws-codepipeline-actions/package.json b/packages/@aws-cdk/aws-codepipeline-actions/package.json index 62a7868ece518..48b7c111f56f6 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/package.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/package.json @@ -66,7 +66,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "@aws-cdk/aws-cloudtrail": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@types/lodash": "^4.14.168", @@ -74,7 +74,8 @@ "cdk-integ-tools": "0.0.0", "lodash": "^4.17.21", "nodeunit-shim": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-cloudformation": "0.0.0", @@ -88,15 +89,15 @@ "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-events-targets": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", - "@aws-cdk/aws-servicecatalog": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sns-subscriptions": "0.0.0", "@aws-cdk/aws-stepfunctions": "0.0.0", "@aws-cdk/core": "0.0.0", "case": "1.6.3", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -111,14 +112,14 @@ "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-events-targets": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", - "@aws-cdk/aws-servicecatalog": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sns-subscriptions": "0.0.0", "@aws-cdk/aws-stepfunctions": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "bundledDependencies": [ "case" @@ -148,7 +149,6 @@ "props-default-doc:@aws-cdk/aws-codepipeline-actions.CloudFormationCreateUpdateStackActionProps.extraInputs", "props-default-doc:@aws-cdk/aws-codepipeline-actions.CloudFormationDeleteStackActionProps.extraInputs", "props-default-doc:@aws-cdk/aws-codepipeline-actions.CodeBuildActionProps.extraInputs", - "docs-public-apis:@aws-cdk/aws-codepipeline-actions.Action.bind", "docs-public-apis:@aws-cdk/aws-codepipeline-actions.CodeCommitSourceActionProps.branch", "docs-public-apis:@aws-cdk/aws-codepipeline-actions.EcrSourceActionProps.output", "docs-public-apis:@aws-cdk/aws-codepipeline-actions.GitHubSourceActionProps.output", diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/bitbucket/bitbucket-source-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/bitbucket/bitbucket-source-action.test.ts index 942811b94b2fd..74df86e395548 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/bitbucket/bitbucket-source-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/bitbucket/bitbucket-source-action.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { arrayWith, expect, haveResourceLike, objectLike } from '@aws-cdk/assert-internal'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import { Stack } from '@aws-cdk/core'; @@ -80,11 +80,82 @@ nodeunitShim({ }, })); + test.done(); + }, + 'grant s3 putObjectACL to the following CodeBuild Project'(test: Test) { + const stack = new Stack(); + createBitBucketAndCodeBuildPipeline(stack, { + codeBuildCloneOutput: true, + }); + expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith( + objectLike({ + 'Action': 's3:PutObjectAcl', + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': [ + '', + [ + { + 'Fn::GetAtt': [ + 'PipelineArtifactsBucket22248F97', + 'Arn', + ], + }, + '/*', + ], + ], + }, + }), + ), + }, + })); + test.done(); + }, + 'setting triggerOnPush=false reflects in the configuration'(test: Test) { + const stack = new Stack(); + + createBitBucketAndCodeBuildPipeline(stack, { + triggerOnPush: false, + }); + + expect(stack).to(haveResourceLike('AWS::CodePipeline::Pipeline', { + 'Stages': [ + { + 'Name': 'Source', + 'Actions': [ + { + 'Name': 'BitBucket', + 'ActionTypeId': { + 'Owner': 'AWS', + 'Provider': 'CodeStarSourceConnection', + }, + 'Configuration': { + 'ConnectionArn': 'arn:aws:codestar-connections:us-east-1:123456789012:connection/12345678-abcd-12ab-34cdef5678gh', + 'FullRepositoryId': 'aws/aws-cdk', + 'BranchName': 'master', + 'DetectChanges': false, + }, + }, + ], + }, + { + 'Name': 'Build', + 'Actions': [ + { + 'Name': 'CodeBuild', + }, + ], + }, + ], + })); + test.done(); }, }); -function createBitBucketAndCodeBuildPipeline(stack: Stack, props: { codeBuildCloneOutput: boolean }): void { +function createBitBucketAndCodeBuildPipeline(stack: Stack, props: Partial): void { const sourceOutput = new codepipeline.Artifact(); new codepipeline.Pipeline(stack, 'Pipeline', { stages: [ @@ -97,7 +168,7 @@ function createBitBucketAndCodeBuildPipeline(stack: Stack, props: { codeBuildClo repo: 'aws-cdk', output: sourceOutput, connectionArn: 'arn:aws:codestar-connections:us-east-1:123456789012:connection/12345678-abcd-12ab-34cdef5678gh', - codeBuildCloneOutput: props.codeBuildCloneOutput, + ...props, }), ], }, diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/cloudformation-pipeline-actions.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/cloudformation-pipeline-actions.test.ts index 7501f74bb1ff7..e478ad7a97d21 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/cloudformation-pipeline-actions.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/cloudformation-pipeline-actions.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codecommit from '@aws-cdk/aws-codecommit'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/codebuild/codebuild-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/codebuild/codebuild-action.test.ts index a451aa51dcc42..b4fec6fc9eb83 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/codebuild/codebuild-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/codebuild/codebuild-action.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codecommit from '@aws-cdk/aws-codecommit'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/codecommit/codecommit-source-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/codecommit/codecommit-source-action.test.ts index c3e2f4b9b6582..8c668be7f47d8 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/codecommit/codecommit-source-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/codecommit/codecommit-source-action.test.ts @@ -1,9 +1,11 @@ -import { arrayWith, countResources, expect, haveResourceLike, not, objectLike } from '@aws-cdk/assert'; +import { arrayWith, countResources, expect, haveResourceLike, not, objectLike } from '@aws-cdk/assert-internal'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codecommit from '@aws-cdk/aws-codecommit'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as iam from '@aws-cdk/aws-iam'; -import { Stack, Lazy } from '@aws-cdk/core'; +import * as kms from '@aws-cdk/aws-kms'; +import * as s3 from '@aws-cdk/aws-s3'; +import { Stack, Lazy, App } from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import * as cpactions from '../../lib'; @@ -429,6 +431,60 @@ nodeunitShim({ test.done(); }, + + 'grants explicit s3:PutObjectAcl permissions when the Actions is cross-account'(test: Test) { + const app = new App(); + + const repoStack = new Stack(app, 'RepoStack', { + env: { account: '123', region: 'us-east-1' }, + }); + const repoFomAnotherAccount = codecommit.Repository.fromRepositoryName(repoStack, 'Repo', 'my-repo'); + + const pipelineStack = new Stack(app, 'PipelineStack', { + env: { account: '456', region: 'us-east-1' }, + }); + new codepipeline.Pipeline(pipelineStack, 'Pipeline', { + artifactBucket: s3.Bucket.fromBucketAttributes(pipelineStack, 'PipelineBucket', { + bucketName: 'pipeline-bucket', + encryptionKey: kms.Key.fromKeyArn(pipelineStack, 'PipelineKey', + 'arn:aws:kms:us-east-1:456:key/my-key'), + }), + stages: [ + { + stageName: 'Source', + actions: [new cpactions.CodeCommitSourceAction({ + actionName: 'Source', + output: new codepipeline.Artifact(), + repository: repoFomAnotherAccount, + })], + }, + { + stageName: 'Approve', + actions: [new cpactions.ManualApprovalAction({ + actionName: 'Approve', + })], + }, + ], + }); + + expect(repoStack).to(haveResourceLike('AWS::IAM::Policy', { + PolicyDocument: { + Statement: arrayWith({ + 'Action': 's3:PutObjectAcl', + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': ['', [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':s3:::pipeline-bucket/*', + ]], + }, + }), + }, + })); + + test.done(); + }, }, }); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/codedeploy/ecs-deploy-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/codedeploy/ecs-deploy-action.test.ts index 4444ea9d409df..30a1d4827b091 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/codedeploy/ecs-deploy-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/codedeploy/ecs-deploy-action.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as codedeploy from '@aws-cdk/aws-codedeploy'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/codestar-connections/codestar-connections-source-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/codestar-connections/codestar-connections-source-action.test.ts new file mode 100644 index 0000000000000..367da1e11ed3f --- /dev/null +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/codestar-connections/codestar-connections-source-action.test.ts @@ -0,0 +1,185 @@ +import { arrayWith, expect, haveResourceLike, objectLike } from '@aws-cdk/assert-internal'; +import * as codebuild from '@aws-cdk/aws-codebuild'; +import * as codepipeline from '@aws-cdk/aws-codepipeline'; +import { Stack } from '@aws-cdk/core'; +import { nodeunitShim, Test } from 'nodeunit-shim'; +import * as cpactions from '../../lib'; + +/* eslint-disable quote-props */ + +nodeunitShim({ + 'CodeStar Connections source Action': { + 'produces the correct configuration when added to a pipeline'(test: Test) { + const stack = new Stack(); + + createBitBucketAndCodeBuildPipeline(stack, { + codeBuildCloneOutput: false, + }); + + expect(stack).to(haveResourceLike('AWS::CodePipeline::Pipeline', { + 'Stages': [ + { + 'Name': 'Source', + 'Actions': [ + { + 'Name': 'BitBucket', + 'ActionTypeId': { + 'Owner': 'AWS', + 'Provider': 'CodeStarSourceConnection', + }, + 'Configuration': { + 'ConnectionArn': 'arn:aws:codestar-connections:us-east-1:123456789012:connection/12345678-abcd-12ab-34cdef5678gh', + 'FullRepositoryId': 'aws/aws-cdk', + 'BranchName': 'master', + }, + }, + ], + }, + { + 'Name': 'Build', + 'Actions': [ + { + 'Name': 'CodeBuild', + }, + ], + }, + ], + })); + + test.done(); + }, + }, + + 'setting codeBuildCloneOutput=true adds permission to use the connection to the following CodeBuild Project'(test: Test) { + const stack = new Stack(); + + createBitBucketAndCodeBuildPipeline(stack, { + codeBuildCloneOutput: true, + }); + + expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': [ + { + 'Action': [ + 'logs:CreateLogGroup', + 'logs:CreateLogStream', + 'logs:PutLogEvents', + ], + }, + {}, + {}, + {}, + {}, + { + 'Action': 'codestar-connections:UseConnection', + 'Effect': 'Allow', + 'Resource': 'arn:aws:codestar-connections:us-east-1:123456789012:connection/12345678-abcd-12ab-34cdef5678gh', + }, + ], + }, + })); + + test.done(); + }, + + 'grant s3 putObjectACL to the following CodeBuild Project'(test: Test) { + const stack = new Stack(); + + createBitBucketAndCodeBuildPipeline(stack, { + codeBuildCloneOutput: true, + }); + + expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith( + objectLike({ + 'Action': 's3:PutObjectAcl', + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': ['', [ + { 'Fn::GetAtt': ['PipelineArtifactsBucket22248F97', 'Arn'] }, + '/*', + ]], + }, + }), + ), + }, + })); + + test.done(); + }, + + 'setting triggerOnPush=false reflects in the configuration'(test: Test) { + const stack = new Stack(); + + createBitBucketAndCodeBuildPipeline(stack, { + triggerOnPush: false, + }); + + expect(stack).to(haveResourceLike('AWS::CodePipeline::Pipeline', { + 'Stages': [ + { + 'Name': 'Source', + 'Actions': [ + { + 'Name': 'BitBucket', + 'ActionTypeId': { + 'Owner': 'AWS', + 'Provider': 'CodeStarSourceConnection', + }, + 'Configuration': { + 'ConnectionArn': 'arn:aws:codestar-connections:us-east-1:123456789012:connection/12345678-abcd-12ab-34cdef5678gh', + 'FullRepositoryId': 'aws/aws-cdk', + 'BranchName': 'master', + 'DetectChanges': false, + }, + }, + ], + }, + { + 'Name': 'Build', + 'Actions': [ + { + 'Name': 'CodeBuild', + }, + ], + }, + ], + })); + + test.done(); + }, +}); + +function createBitBucketAndCodeBuildPipeline(stack: Stack, props: Partial): void { + const sourceOutput = new codepipeline.Artifact(); + new codepipeline.Pipeline(stack, 'Pipeline', { + stages: [ + { + stageName: 'Source', + actions: [ + new cpactions.CodeStarConnectionsSourceAction({ + actionName: 'BitBucket', + owner: 'aws', + repo: 'aws-cdk', + output: sourceOutput, + connectionArn: 'arn:aws:codestar-connections:us-east-1:123456789012:connection/12345678-abcd-12ab-34cdef5678gh', + ...props, + }), + ], + }, + { + stageName: 'Build', + actions: [ + new cpactions.CodeBuildAction({ + actionName: 'CodeBuild', + project: new codebuild.PipelineProject(stack, 'MyProject'), + input: sourceOutput, + outputs: [new codepipeline.Artifact()], + }), + ], + }, + ], + }); +} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/ecr/ecr-source-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/ecr/ecr-source-action.test.ts index aacbb856e065c..aecf6cb915f04 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/ecr/ecr-source-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/ecr/ecr-source-action.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as ecr from '@aws-cdk/aws-ecr'; diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/ecs/ecs-deploy-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/ecs/ecs-deploy-action.test.ts index 841ca3948ec83..3cdc12554d501 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/ecs/ecs-deploy-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/ecs/ecs-deploy-action.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/github/github-source-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/github/github-source-action.test.ts index a73726e055459..635f7ac67780f 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/github/github-source-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/github/github-source-action.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike, SynthUtils } from '@aws-cdk/assert'; +import { expect, haveResourceLike, SynthUtils } from '@aws-cdk/assert-internal'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import { SecretValue, Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecr-source.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecr-source.expected.json index 384e784a5ca76..c200ab454d71a 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecr-source.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecr-source.expected.json @@ -348,8 +348,8 @@ }, "MyEcrRepo767466D0": { "Type": "AWS::ECR::Repository", - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "MyEcrRepoawscdkcodepipelineecrsourceMyPipeline63CF3194SourceEventRule911FDB6D": { "Type": "AWS::Events::Rule", @@ -367,6 +367,9 @@ { "Ref": "MyEcrRepo767466D0" } + ], + "imageTag": [ + "latest" ] }, "eventName": [ @@ -412,4 +415,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecr-source.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecr-source.ts index 8aadd0b5e29a7..9e6e4b497a7a7 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecr-source.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecr-source.ts @@ -15,7 +15,9 @@ const pipeline = new codepipeline.Pipeline(stack, 'MyPipeline', { artifactBucket: bucket, }); -const repository = new ecr.Repository(stack, 'MyEcrRepo'); +const repository = new ecr.Repository(stack, 'MyEcrRepo', { + removalPolicy: cdk.RemovalPolicy.DESTROY, +}); const sourceStage = pipeline.addStage({ stageName: 'Source' }); sourceStage.addAction(new cpactions.EcrSourceAction({ actionName: 'ECR_Source', diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/lambda/lambda-invoke-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/lambda/lambda-invoke-action.test.ts index 64eecdb801b1c..c3dce7754f70a 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/lambda/lambda-invoke-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/lambda/lambda-invoke-action.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as lambda from '@aws-cdk/aws-lambda'; import * as s3 from '@aws-cdk/aws-s3'; diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/manual-approval.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/manual-approval.test.ts index 121e87cd9eb4e..7a7ba4be529cf 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/manual-approval.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/manual-approval.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as sns from '@aws-cdk/aws-sns'; import { SecretValue, Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/pipeline.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/pipeline.test.ts index 0c0491d778150..331bae0db4b9e 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/pipeline.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/pipeline.test.ts @@ -1,4 +1,4 @@ -import { countResources, expect, haveResource, haveResourceLike, not, SynthUtils } from '@aws-cdk/assert'; +import { countResources, expect, haveResource, haveResourceLike, not, SynthUtils } from '@aws-cdk/assert-internal'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codecommit from '@aws-cdk/aws-codecommit'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-deploy-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-deploy-action.test.ts index 2e2b5cef98ace..aa8095678043a 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-deploy-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-deploy-action.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as s3 from '@aws-cdk/aws-s3'; import { App, Duration, SecretValue, Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-source-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-source-action.test.ts index 3ae1210dcd8f7..0fb227a9246e8 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-source-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-source-action.test.ts @@ -1,4 +1,4 @@ -import { countResources, expect, haveResourceLike, not } from '@aws-cdk/assert'; +import { countResources, expect, haveResourceLike, not } from '@aws-cdk/assert-internal'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as s3 from '@aws-cdk/aws-s3'; diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/servicecatalog/servicecatalog-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/servicecatalog/servicecatalog-deploy-action-beta1.test.ts similarity index 97% rename from packages/@aws-cdk/aws-codepipeline-actions/test/servicecatalog/servicecatalog-action.test.ts rename to packages/@aws-cdk/aws-codepipeline-actions/test/servicecatalog/servicecatalog-deploy-action-beta1.test.ts index 1415b2a084eaf..ef96441ca585e 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/servicecatalog/servicecatalog-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/servicecatalog/servicecatalog-deploy-action-beta1.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as codecommit from '@aws-cdk/aws-codecommit'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import { Stack } from '@aws-cdk/core'; @@ -12,7 +12,7 @@ nodeunitShim({ // GIVEN const stack = new TestFixture(); // WHEN - stack.deployStage.addAction(new cpactions.ServiceCatalogDeployAction({ + stack.deployStage.addAction(new cpactions.ServiceCatalogDeployActionBeta1({ actionName: 'ServiceCatalogTest', templatePath: stack.sourceOutput.atPath('template.yaml'), productVersionDescription: 'This is a description of the version.', @@ -58,7 +58,7 @@ nodeunitShim({ // GIVEN const stack = new TestFixture(); // WHEN - stack.deployStage.addAction(new cpactions.ServiceCatalogDeployAction({ + stack.deployStage.addAction(new cpactions.ServiceCatalogDeployActionBeta1({ actionName: 'ServiceCatalogTest', templatePath: stack.sourceOutput.atPath('template.yaml'), productVersionName: 'VersionName', @@ -127,4 +127,4 @@ class TestFixture extends Stack { }); this.sourceStage.addAction(source); } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/stepfunctions/stepfunctions-invoke-actions.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/stepfunctions/stepfunctions-invoke-actions.test.ts index 47e33e7d5b5d8..50f8788e8823c 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/stepfunctions/stepfunctions-invoke-actions.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/stepfunctions/stepfunctions-invoke-actions.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as s3 from '@aws-cdk/aws-s3'; import * as stepfunction from '@aws-cdk/aws-stepfunctions'; diff --git a/packages/@aws-cdk/aws-codepipeline/lib/action.ts b/packages/@aws-cdk/aws-codepipeline/lib/action.ts index 6b28bcc8a3749..2bf32ca5ee330 100644 --- a/packages/@aws-cdk/aws-codepipeline/lib/action.ts +++ b/packages/@aws-cdk/aws-codepipeline/lib/action.ts @@ -1,7 +1,7 @@ import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; import * as s3 from '@aws-cdk/aws-s3'; -import { IResource } from '@aws-cdk/core'; +import { IResource, Lazy } from '@aws-cdk/core'; import { Artifact } from './artifact'; // keep this import separate from other imports to reduce chance for merge conflicts with v2-main @@ -119,13 +119,36 @@ export interface ActionConfig { } /** - * A Pipeline Action + * A Pipeline Action. + * If you want to implement this interface, + * consider extending the {@link Action} class, + * which contains some common logic. */ export interface IAction { + /** + * The simple properties of the Action, + * like its Owner, name, etc. + * Note that this accessor will be called before the {@link bind} callback. + */ readonly actionProperties: ActionProperties; + /** + * The callback invoked when this Action is added to a Pipeline. + * + * @param scope the Construct tree scope the Action can use if it needs to create any resources + * @param stage the {@link IStage} this Action is being added to + * @param options additional options the Action can use, + * like the artifact Bucket of the pipeline it's being added to + */ bind(scope: Construct, stage: IStage, options: ActionBindOptions): ActionConfig; + /** + * Creates an Event that will be triggered whenever the state of this Action changes. + * + * @param name the name to use for the new Event + * @param target the optional target for the Event + * @param options additional options that can be used to customize the created Event + */ onStateChange(name: string, target?: events.IRuleTarget, options?: events.RuleProps): events.Rule; } @@ -234,3 +257,125 @@ export interface CommonAwsActionProps extends CommonActionProps { */ readonly role?: iam.IRole; } + +/** + * Low-level class for generic CodePipeline Actions implementing the {@link IAction} interface. + * Contains some common logic that can be re-used by all {@link IAction} implementations. + * If you're writing your own Action class, + * feel free to extend this class. + */ +export abstract class Action implements IAction { + /** + * This is a renamed version of the {@link IAction.actionProperties} property. + */ + protected abstract readonly providedActionProperties: ActionProperties; + + private __actionProperties?: ActionProperties; + private __pipeline?: IPipeline; + private __stage?: IStage; + private __scope?: Construct; + private readonly _namespaceToken: string; + private _customerProvidedNamespace?: string; + private _actualNamespace?: string; + + private _variableReferenced = false; + + protected constructor() { + this._namespaceToken = Lazy.string({ + produce: () => { + // make sure the action was bound (= added to a pipeline) + if (this._actualNamespace === undefined) { + throw new Error(`Cannot reference variables of action '${this.actionProperties.actionName}', ` + + 'as that action was never added to a pipeline'); + } else { + return this._customerProvidedNamespace !== undefined + // if a customer passed a namespace explicitly, always use that + ? this._customerProvidedNamespace + // otherwise, only return a namespace if any variable was referenced + : (this._variableReferenced ? this._actualNamespace : undefined); + } + }, + }); + } + + public get actionProperties(): ActionProperties { + if (this.__actionProperties === undefined) { + const actionProperties = this.providedActionProperties; + this._customerProvidedNamespace = actionProperties.variablesNamespace; + this.__actionProperties = { + ...actionProperties, + variablesNamespace: this._customerProvidedNamespace === undefined + ? this._namespaceToken + : this._customerProvidedNamespace, + }; + } + return this.__actionProperties; + } + + public bind(scope: Construct, stage: IStage, options: ActionBindOptions): ActionConfig { + this.__pipeline = stage.pipeline; + this.__stage = stage; + this.__scope = scope; + + this._actualNamespace = this._customerProvidedNamespace === undefined + // default a namespace name, based on the stage and action names + ? `${stage.stageName}_${this.actionProperties.actionName}_NS` + : this._customerProvidedNamespace; + + return this.bound(scope, stage, options); + } + + public onStateChange(name: string, target?: events.IRuleTarget, options?: events.RuleProps) { + const rule = new events.Rule(this._scope, name, options); + rule.addTarget(target); + rule.addEventPattern({ + detailType: ['CodePipeline Action Execution State Change'], + source: ['aws.codepipeline'], + resources: [this._pipeline.pipelineArn], + detail: { + stage: [this._stage.stageName], + action: [this.actionProperties.actionName], + }, + }); + return rule; + } + + protected variableExpression(variableName: string): string { + this._variableReferenced = true; + return `#{${this._namespaceToken}.${variableName}}`; + } + + /** + * This is a renamed version of the {@link IAction.bind} method. + */ + protected abstract bound(scope: Construct, stage: IStage, options: ActionBindOptions): ActionConfig; + + private get _pipeline(): IPipeline { + if (this.__pipeline) { + return this.__pipeline; + } else { + throw new Error('Action must be added to a stage that is part of a pipeline before using onStateChange'); + } + } + + private get _stage(): IStage { + if (this.__stage) { + return this.__stage; + } else { + throw new Error('Action must be added to a stage that is part of a pipeline before using onStateChange'); + } + } + + /** + * Retrieves the Construct scope of this Action. + * Only available after the Action has been added to a Stage, + * and that Stage to a Pipeline. + */ + private get _scope(): Construct { + if (this.__scope) { + return this.__scope; + } else { + throw new Error('Action must be added to a stage that is part of a pipeline first'); + } + } +} diff --git a/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts b/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts index 8ef8cc3dede8e..1b3ca9e0e6adc 100644 --- a/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts +++ b/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts @@ -97,7 +97,6 @@ export interface PipelineProps { * the construct will automatically create a Stack containing an S3 Bucket in that region. * * @default - None. - * @experimental */ readonly crossRegionReplicationBuckets?: { [region: string]: s3.IBucket }; @@ -386,7 +385,6 @@ export class Pipeline extends PipelineBase { * Returns all of the {@link CrossRegionSupportStack}s that were generated automatically * when dealing with Actions that reside in a different region than the Pipeline itself. * - * @experimental */ public get crossRegionSupport(): { [region: string]: CrossRegionSupport } { const ret: { [region: string]: CrossRegionSupport } = {}; @@ -662,48 +660,68 @@ export class Pipeline extends PipelineBase { * @param action the Action to return the Stack for */ private getOtherStackIfActionIsCrossAccount(action: IAction): Stack | undefined { - const pipelineStack = Stack.of(this); + const targetAccount = action.actionProperties.resource + ? action.actionProperties.resource.env.account + : action.actionProperties.account; - if (action.actionProperties.resource) { - const resourceStack = Stack.of(action.actionProperties.resource); - // check if resource is from a different account - if (pipelineStack.account === resourceStack.account) { - return undefined; - } else { - this._crossAccountSupport[resourceStack.account] = resourceStack; - return resourceStack; - } - } - - if (!action.actionProperties.account) { + if (targetAccount === undefined) { + // if the account of the Action is not specified, + // then it defaults to the same account the pipeline itself is in return undefined; } - const targetAccount = action.actionProperties.account; - // check whether the account is a static string + // check whether the action's account is a static string if (Token.isUnresolved(targetAccount)) { - throw new Error(`The 'account' property must be a concrete value (action: '${action.actionProperties.actionName}')`); + if (Token.isUnresolved(this.env.account)) { + // the pipeline is also env-agnostic, so that's fine + return undefined; + } else { + throw new Error(`The 'account' property must be a concrete value (action: '${action.actionProperties.actionName}')`); + } } - // check whether the pipeline account is a static string - if (Token.isUnresolved(pipelineStack.account)) { + + // At this point, we know that the action's account is a static string. + // In this case, the pipeline's account must also be a static string. + if (Token.isUnresolved(this.env.account)) { throw new Error('Pipeline stack which uses cross-environment actions must have an explicitly set account'); } - if (pipelineStack.account === targetAccount) { + // at this point, we know that both the Pipeline's account, + // and the action-backing resource's account are static strings + + // if they are identical - nothing to do (the action is not cross-account) + if (this.env.account === targetAccount) { return undefined; } + // at this point, we know that the action is certainly cross-account, + // so we need to return a Stack in its account to create the helper Role in + + const candidateActionResourceStack = action.actionProperties.resource + ? Stack.of(action.actionProperties.resource) + : undefined; + if (candidateActionResourceStack?.account === targetAccount) { + // we always use the "latest" action-backing resource's Stack for this account, + // even if a different one was used earlier + this._crossAccountSupport[targetAccount] = candidateActionResourceStack; + return candidateActionResourceStack; + } + let targetAccountStack: Stack | undefined = this._crossAccountSupport[targetAccount]; if (!targetAccountStack) { const stackId = `cross-account-support-stack-${targetAccount}`; const app = this.requireApp(); targetAccountStack = app.node.tryFindChild(stackId) as Stack; if (!targetAccountStack) { + const actionRegion = action.actionProperties.resource + ? action.actionProperties.resource.env.region + : action.actionProperties.region; + const pipelineStack = Stack.of(this); targetAccountStack = new Stack(app, stackId, { stackName: `${pipelineStack.stackName}-support-${targetAccount}`, env: { account: targetAccount, - region: action.actionProperties.region ? action.actionProperties.region : pipelineStack.region, + region: actionRegion ?? pipelineStack.region, }, }); } @@ -916,7 +934,6 @@ export class Pipeline extends PipelineBase { * the cross-region capabilities of CodePipeline. * You get instances of this interface from the {@link Pipeline#crossRegionSupport} property. * - * @experimental */ export interface CrossRegionSupport { /** diff --git a/packages/@aws-cdk/aws-codepipeline/package.json b/packages/@aws-cdk/aws-codepipeline/package.json index 1cc830be83ec6..0c52c95657acc 100644 --- a/packages/@aws-cdk/aws-codepipeline/package.json +++ b/packages/@aws-cdk/aws-codepipeline/package.json @@ -76,7 +76,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "@aws-cdk/cx-api": "0.0.0", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", @@ -84,7 +84,8 @@ "nodeunit-shim": "0.0.0", "cfn2ts": "0.0.0", "nodeunit": "^0.11.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-events": "0.0.0", @@ -92,7 +93,7 @@ "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -101,7 +102,7 @@ "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" @@ -154,9 +155,6 @@ "props-default-doc:@aws-cdk/aws-codepipeline.ActionProperties.runOrder", "docs-public-apis:@aws-cdk/aws-codepipeline.ActionProperties.version", "props-default-doc:@aws-cdk/aws-codepipeline.ActionProperties.version", - "docs-public-apis:@aws-cdk/aws-codepipeline.IAction.actionProperties", - "docs-public-apis:@aws-cdk/aws-codepipeline.IAction.bind", - "docs-public-apis:@aws-cdk/aws-codepipeline.IAction.onStateChange", "docs-public-apis:@aws-cdk/aws-codepipeline.IStage.pipeline", "docs-public-apis:@aws-cdk/aws-codepipeline.IStage.addAction", "docs-public-apis:@aws-cdk/aws-codepipeline.IStage.onStateChange", diff --git a/packages/@aws-cdk/aws-codepipeline/test/action.test.ts b/packages/@aws-cdk/aws-codepipeline/test/action.test.ts index 381eed2a1b7c5..8f3e81736d0b2 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/action.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; diff --git a/packages/@aws-cdk/aws-codepipeline/test/artifacts.test.ts b/packages/@aws-cdk/aws-codepipeline/test/artifacts.test.ts index c67176d1e13ae..29cda05adedf8 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/artifacts.test.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/artifacts.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import * as codepipeline from '../lib'; diff --git a/packages/@aws-cdk/aws-codepipeline/test/cross-env.test.ts b/packages/@aws-cdk/aws-codepipeline/test/cross-env.test.ts index caaab6f8378a1..f22c80e82cba1 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/cross-env.test.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/cross-env.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as iam from '@aws-cdk/aws-iam'; import * as s3 from '@aws-cdk/aws-s3'; import { Stack, App } from '@aws-cdk/core'; @@ -138,4 +138,74 @@ describe.each(['legacy', 'modern'])('with %s synthesis', (synthesisStyle: string }); }); }); -}); \ No newline at end of file +}); + +describe('cross-environment CodePipeline', function () { + test('correctly detects that an Action is cross-account from the account of the resource backing the Action', () => { + const app = new App(); + + const pipelineStack = new Stack(app, 'PipelineStack', { + env: { account: '123', region: 'my-region' }, + }); + const sourceOutput = new codepipeline.Artifact(); + const pipeline = new codepipeline.Pipeline(pipelineStack, 'Pipeline', { + stages: [ + { + stageName: 'Source', + actions: [ + new FakeSourceAction({ + actionName: 'Source', + output: sourceOutput, + }), + ], + }, + ], + }); + + // Import a resource backing the FakeBuildAction into the pipeline's Stack, + // but specify a different account for it during the import. + // This should be correctly detected by the CodePipeline construct, + // and a correct support Stack should be created. + const deployBucket = s3.Bucket.fromBucketAttributes(pipelineStack, 'DeployBucket', { + bucketName: 'my-bucket', + account: '456', + }); + pipeline.addStage({ + stageName: 'Build', + actions: [ + new FakeBuildAction({ + actionName: 'Build', + input: sourceOutput, + resource: deployBucket, + }), + ], + }); + + const asm = app.synth(); + const supportStack = asm.getStackByName(`${pipelineStack.stackName}-support-456`); + expect(supportStack).toHaveResourceLike('AWS::IAM::Role', { + RoleName: 'pipelinestack-support-456dbuildactionrole91c6f1a469fd11d52dfe', + }); + + expect(pipelineStack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Stages: [ + { Name: 'Source' }, + { + Name: 'Build', + Actions: [ + { + Name: 'Build', + RoleArn: { + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':iam::456:role/pipelinestack-support-456dbuildactionrole91c6f1a469fd11d52dfe', + ]], + }, + }, + ], + }, + ], + }); + }); +}); diff --git a/packages/@aws-cdk/aws-codepipeline/test/fake-build-action.ts b/packages/@aws-cdk/aws-codepipeline/test/fake-build-action.ts index 53cec90d55267..9f2d41b7d5252 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/fake-build-action.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/fake-build-action.ts @@ -1,4 +1,3 @@ -import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; import { IResource } from '@aws-cdk/core'; import { Construct } from 'constructs'; @@ -24,12 +23,13 @@ export interface FakeBuildActionProps extends codepipeline.CommonActionProps { resource?: IResource; } -export class FakeBuildAction implements codepipeline.IAction { - public readonly actionProperties: codepipeline.ActionProperties; +export class FakeBuildAction extends codepipeline.Action { + protected readonly providedActionProperties: codepipeline.ActionProperties; private readonly customConfigKey: string | undefined; constructor(props: FakeBuildActionProps) { - this.actionProperties = { + super(); + this.providedActionProperties = { ...props, category: codepipeline.ActionCategory.BUILD, provider: 'Fake', @@ -40,7 +40,7 @@ export class FakeBuildAction implements codepipeline.IAction { this.customConfigKey = props.customConfigKey; } - public bind(_scope: Construct, _stage: codepipeline.IStage, _options: codepipeline.ActionBindOptions): + public bound(_scope: Construct, _stage: codepipeline.IStage, _options: codepipeline.ActionBindOptions): codepipeline.ActionConfig { return { configuration: { @@ -48,8 +48,4 @@ export class FakeBuildAction implements codepipeline.IAction { }, }; } - - public onStateChange(_name: string, _target?: events.IRuleTarget, _options?: events.RuleProps): events.Rule { - throw new Error('onStateChange() is not available on FakeBuildAction'); - } } diff --git a/packages/@aws-cdk/aws-codepipeline/test/fake-source-action.ts b/packages/@aws-cdk/aws-codepipeline/test/fake-source-action.ts index 8e8c2652caa9c..13e4a21b0e77e 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/fake-source-action.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/fake-source-action.ts @@ -1,4 +1,3 @@ -import * as events from '@aws-cdk/aws-events'; import { Lazy } from '@aws-cdk/core'; import { Construct } from 'constructs'; import * as codepipeline from '../lib'; @@ -15,15 +14,15 @@ export interface FakeSourceActionProps extends codepipeline.CommonActionProps { readonly region?: string; } -export class FakeSourceAction implements codepipeline.IAction { +export class FakeSourceAction extends codepipeline.Action { public readonly inputs?: codepipeline.Artifact[]; public readonly outputs?: codepipeline.Artifact[]; public readonly variables: IFakeSourceActionVariables; - - public readonly actionProperties: codepipeline.ActionProperties; + protected readonly providedActionProperties: codepipeline.ActionProperties; constructor(props: FakeSourceActionProps) { - this.actionProperties = { + super(); + this.providedActionProperties = { ...props, category: codepipeline.ActionCategory.SOURCE, provider: 'Fake', @@ -35,12 +34,8 @@ export class FakeSourceAction implements codepipeline.IAction { }; } - public bind(_scope: Construct, _stage: codepipeline.IStage, _options: codepipeline.ActionBindOptions): + public bound(_scope: Construct, _stage: codepipeline.IStage, _options: codepipeline.ActionBindOptions): codepipeline.ActionConfig { return {}; } - - public onStateChange(_name: string, _target?: events.IRuleTarget, _options?: events.RuleProps): events.Rule { - throw new Error('onStateChange() is not available on FakeSourceAction'); - } } diff --git a/packages/@aws-cdk/aws-codepipeline/test/pipeline.test.ts b/packages/@aws-cdk/aws-codepipeline/test/pipeline.test.ts index 3b091ac8ef339..5a45459030ee7 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/pipeline.test.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/pipeline.test.ts @@ -1,5 +1,5 @@ -import { expect as ourExpect, ResourcePart, arrayWith, objectLike, haveResourceLike } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { expect as ourExpect, ResourcePart, arrayWith, objectLike, haveResourceLike } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as s3 from '@aws-cdk/aws-s3'; diff --git a/packages/@aws-cdk/aws-codepipeline/test/stages.test.ts b/packages/@aws-cdk/aws-codepipeline/test/stages.test.ts index 58b6ff1b45510..3cbb290187436 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/stages.test.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/stages.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import * as codepipeline from '../lib'; diff --git a/packages/@aws-cdk/aws-codepipeline/test/variables.test.ts b/packages/@aws-cdk/aws-codepipeline/test/variables.test.ts index a2e184a4a3c21..265ddd09b0843 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/variables.test.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/variables.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import * as codepipeline from '../lib'; diff --git a/packages/@aws-cdk/aws-codestar/package.json b/packages/@aws-cdk/aws-codestar/package.json index 01024a24b1248..c7206144de2c6 100644 --- a/packages/@aws-cdk/aws-codestar/package.json +++ b/packages/@aws-cdk/aws-codestar/package.json @@ -73,21 +73,22 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-codestar/test/codestar.test.ts b/packages/@aws-cdk/aws-codestar/test/codestar.test.ts index bc551f25a41d3..7b142a03ac221 100644 --- a/packages/@aws-cdk/aws-codestar/test/codestar.test.ts +++ b/packages/@aws-cdk/aws-codestar/test/codestar.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Bucket } from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import { GitHubRepository, RepositoryVisibility } from '../lib'; diff --git a/packages/@aws-cdk/aws-codestarconnections/package.json b/packages/@aws-cdk/aws-codestarconnections/package.json index 66ab2aab76ea6..d216451a1caa0 100644 --- a/packages/@aws-cdk/aws-codestarconnections/package.json +++ b/packages/@aws-cdk/aws-codestarconnections/package.json @@ -73,10 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-codestarconnections/test/codestarconnections.test.ts b/packages/@aws-cdk/aws-codestarconnections/test/codestarconnections.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-codestarconnections/test/codestarconnections.test.ts +++ b/packages/@aws-cdk/aws-codestarconnections/test/codestarconnections.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-codestarnotifications/package.json b/packages/@aws-cdk/aws-codestarnotifications/package.json index 18667b45db8b1..1d220f65881e4 100644 --- a/packages/@aws-cdk/aws-codestarnotifications/package.json +++ b/packages/@aws-cdk/aws-codestarnotifications/package.json @@ -73,18 +73,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-codestarnotifications/test/codestarnotifications.test.ts b/packages/@aws-cdk/aws-codestarnotifications/test/codestarnotifications.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-codestarnotifications/test/codestarnotifications.test.ts +++ b/packages/@aws-cdk/aws-codestarnotifications/test/codestarnotifications.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-cognito/README.md b/packages/@aws-cdk/aws-cognito/README.md index d3f90ff026b36..0582fbdec0f2a 100644 --- a/packages/@aws-cdk/aws-cognito/README.md +++ b/packages/@aws-cdk/aws-cognito/README.md @@ -87,9 +87,9 @@ new cognito.UserPool(this, 'myuserpool', { selfSignUpEnabled: true, userVerification: { emailSubject: 'Verify your email for our awesome app!', - emailBody: 'Hello {username}, Thanks for signing up to our awesome app! Your verification code is {####}', + emailBody: 'Thanks for signing up to our awesome app! Your verification code is {####}', emailStyle: cognito.VerificationEmailStyle.CODE, - smsMessage: 'Hello {username}, Thanks for signing up to our awesome app! Your verification code is {####}', + smsMessage: 'Thanks for signing up to our awesome app! Your verification code is {####}', } }); ``` @@ -345,7 +345,7 @@ on the construct, as so - const authChallengeFn = new lambda.Function(this, 'authChallengeFn', { runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', - code: lambda.Code.fromInline('auth challenge'), + code: lambda.Code.fromAsset(/* path to lambda asset */), }); const userpool = new cognito.UserPool(this, 'myuserpool', { @@ -359,7 +359,7 @@ const userpool = new cognito.UserPool(this, 'myuserpool', { userpool.addTrigger(cognito.UserPoolOperation.USER_MIGRATION, new lambda.Function(this, 'userMigrationFn', { runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', - code: lambda.Code.fromInline('user migration'), + code: lambda.Code.fromAsset(/* path to lambda asset */), })); ``` 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 866c11015ecfd..d1f89f188c667 100644 --- a/packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts @@ -232,7 +232,7 @@ export interface UserPoolClientOptions { readonly disableOAuth?: boolean; /** - * OAuth settings for this to client to interact with the app. + * OAuth settings for this client to interact with the app. * An error is thrown when this is specified and `disableOAuth` is set. * @default - see defaults in `OAuthSettings`. meaningless if `disableOAuth` is set. */ diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts index eff29527ab4af..28e37670b05a2 100644 --- a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts @@ -660,22 +660,39 @@ export class UserPool extends UserPoolBase { * Import an existing user pool based on its id. */ public static fromUserPoolId(scope: Construct, id: string, userPoolId: string): IUserPool { - class Import extends UserPoolBase { - public readonly userPoolId = userPoolId; - public readonly userPoolArn = Stack.of(this).formatArn({ - service: 'cognito-idp', - resource: 'userpool', - resourceName: userPoolId, - }); - } - return new Import(scope, id); + let userPoolArn = Stack.of(scope).formatArn({ + service: 'cognito-idp', + resource: 'userpool', + resourceName: userPoolId, + }); + + return UserPool.fromUserPoolArn(scope, id, userPoolArn); } /** * Import an existing user pool based on its ARN. */ public static fromUserPoolArn(scope: Construct, id: string, userPoolArn: string): IUserPool { - return UserPool.fromUserPoolId(scope, id, Stack.of(scope).parseArn(userPoolArn).resourceName!); + const arnParts = Stack.of(scope).parseArn(userPoolArn); + + if (!arnParts.resourceName) { + throw new Error('invalid user pool ARN'); + } + + const userPoolId = arnParts.resourceName; + + class ImportedUserPool extends UserPoolBase { + public readonly userPoolArn = userPoolArn; + public readonly userPoolId = userPoolId; + constructor() { + super(scope, id, { + account: arnParts.account, + region: arnParts.region, + }); + } + } + + return new ImportedUserPool(); } /** diff --git a/packages/@aws-cdk/aws-cognito/package.json b/packages/@aws-cdk/aws-cognito/package.json index 3a981167956a3..0ac87ea6ba50b 100644 --- a/packages/@aws-cdk/aws-cognito/package.json +++ b/packages/@aws-cdk/aws-cognito/package.json @@ -71,13 +71,14 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "@types/punycode": "^2.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", @@ -85,7 +86,7 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", - "constructs": "^3.2.0", + "constructs": "^3.3.69", "punycode": "^2.1.1" }, "homepage": "https://github.com/aws/aws-cdk", @@ -95,7 +96,7 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "bundledDependencies": [ "punycode" diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.expected.json index abcb9265e2bda..6d825755af54d 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.expected.json @@ -146,7 +146,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3Bucket65227904" + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3Bucket4DD075F7" }, "S3Key": { "Fn::Join": [ @@ -159,7 +159,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF" + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7" } ] } @@ -172,7 +172,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF" + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7" } ] } @@ -213,17 +213,17 @@ } }, "Parameters": { - "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3Bucket65227904": { + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3Bucket4DD075F7": { "Type": "String", - "Description": "S3 bucket for asset \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\"" + "Description": "S3 bucket for asset \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" }, - "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF": { + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7": { "Type": "String", - "Description": "S3 key for asset version \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\"" + "Description": "S3 key for asset version \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" }, - "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343ArtifactHash0C561FF5": { + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98ArtifactHash35A756EB": { "Type": "String", - "Description": "Artifact hash for asset \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\"" + "Description": "Artifact hash for asset \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cognito/test/user-pool-attr.test.ts b/packages/@aws-cdk/aws-cognito/test/user-pool-attr.test.ts index 1d5b5a7bd5d5f..38c40ff918e6f 100644 --- a/packages/@aws-cdk/aws-cognito/test/user-pool-attr.test.ts +++ b/packages/@aws-cdk/aws-cognito/test/user-pool-attr.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { CfnParameter, Stack } from '@aws-cdk/core'; import { BooleanAttribute, CustomAttributeConfig, DateTimeAttribute, ICustomAttribute, NumberAttribute, StringAttribute, ClientAttributes } from '../lib'; import { StandardAttributeNames } from '../lib/private/attr-names'; 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 02420721df344..084ea563cb477 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 @@ -1,5 +1,5 @@ -import { ABSENT, arrayWith } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { ABSENT, arrayWith } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import { Stack, Duration } from '@aws-cdk/core'; import { OAuthScope, ResourceServerScope, UserPool, UserPoolClient, UserPoolClientIdentityProvider, UserPoolIdentityProvider, ClientAttributes } from '../lib'; diff --git a/packages/@aws-cdk/aws-cognito/test/user-pool-domain.test.ts b/packages/@aws-cdk/aws-cognito/test/user-pool-domain.test.ts index b981707a90ce6..220ae84e85d08 100644 --- a/packages/@aws-cdk/aws-cognito/test/user-pool-domain.test.ts +++ b/packages/@aws-cdk/aws-cognito/test/user-pool-domain.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Certificate } from '@aws-cdk/aws-certificatemanager'; import { CfnParameter, Stack } from '@aws-cdk/core'; import { UserPool, UserPoolDomain } from '../lib'; diff --git a/packages/@aws-cdk/aws-cognito/test/user-pool-idps/amazon.test.ts b/packages/@aws-cdk/aws-cognito/test/user-pool-idps/amazon.test.ts index a6995367a3ded..b198419b90c49 100644 --- a/packages/@aws-cdk/aws-cognito/test/user-pool-idps/amazon.test.ts +++ b/packages/@aws-cdk/aws-cognito/test/user-pool-idps/amazon.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Stack } from '@aws-cdk/core'; import { ProviderAttribute, UserPool, UserPoolIdentityProviderAmazon } from '../../lib'; diff --git a/packages/@aws-cdk/aws-cognito/test/user-pool-idps/apple.ts b/packages/@aws-cdk/aws-cognito/test/user-pool-idps/apple.ts index 5f4180bce5682..8273a91da719d 100644 --- a/packages/@aws-cdk/aws-cognito/test/user-pool-idps/apple.ts +++ b/packages/@aws-cdk/aws-cognito/test/user-pool-idps/apple.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Stack } from '@aws-cdk/core'; import { ProviderAttribute, UserPool, UserPoolIdentityProviderApple } from '../../lib'; diff --git a/packages/@aws-cdk/aws-cognito/test/user-pool-idps/base.test.ts b/packages/@aws-cdk/aws-cognito/test/user-pool-idps/base.test.ts index 2bbac71068439..0497376879798 100644 --- a/packages/@aws-cdk/aws-cognito/test/user-pool-idps/base.test.ts +++ b/packages/@aws-cdk/aws-cognito/test/user-pool-idps/base.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Stack } from '@aws-cdk/core'; import { ProviderAttribute, UserPool } from '../../lib'; import { UserPoolIdentityProviderBase } from '../../lib/user-pool-idps/private/user-pool-idp-base'; diff --git a/packages/@aws-cdk/aws-cognito/test/user-pool-idps/facebook.test.ts b/packages/@aws-cdk/aws-cognito/test/user-pool-idps/facebook.test.ts index 3020bd117221f..574220cc5796b 100644 --- a/packages/@aws-cdk/aws-cognito/test/user-pool-idps/facebook.test.ts +++ b/packages/@aws-cdk/aws-cognito/test/user-pool-idps/facebook.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Stack } from '@aws-cdk/core'; import { ProviderAttribute, UserPool, UserPoolIdentityProviderFacebook } from '../../lib'; diff --git a/packages/@aws-cdk/aws-cognito/test/user-pool-idps/google.test.ts b/packages/@aws-cdk/aws-cognito/test/user-pool-idps/google.test.ts index 41700abe1c92d..8d816b6675742 100644 --- a/packages/@aws-cdk/aws-cognito/test/user-pool-idps/google.test.ts +++ b/packages/@aws-cdk/aws-cognito/test/user-pool-idps/google.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Stack } from '@aws-cdk/core'; import { ProviderAttribute, UserPool, UserPoolIdentityProviderGoogle } from '../../lib'; diff --git a/packages/@aws-cdk/aws-cognito/test/user-pool-resource-server.test.ts b/packages/@aws-cdk/aws-cognito/test/user-pool-resource-server.test.ts index 17c2045230ca5..b2126e1daafd9 100644 --- a/packages/@aws-cdk/aws-cognito/test/user-pool-resource-server.test.ts +++ b/packages/@aws-cdk/aws-cognito/test/user-pool-resource-server.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Stack } from '@aws-cdk/core'; import { UserPool, UserPoolResourceServer } from '../lib'; diff --git a/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts b/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts index 4aa6a1bf4b85a..7f1c02c786a4e 100644 --- a/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts +++ b/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert/jest'; -import { ABSENT, ResourcePart } from '@aws-cdk/assert/lib/assertions/have-resource'; +import '@aws-cdk/assert-internal/jest'; +import { ABSENT, ResourcePart } from '@aws-cdk/assert-internal/lib/assertions/have-resource'; import { Role, ServicePrincipal } from '@aws-cdk/aws-iam'; import * as lambda from '@aws-cdk/aws-lambda'; import { CfnParameter, Duration, Stack, Tags } from '@aws-cdk/core'; @@ -211,17 +211,36 @@ describe('User Pool', () => { // WHEN const pool = UserPool.fromUserPoolArn(stack, 'userpool', userPoolArn); expect(pool.userPoolId).toEqual('test-user-pool'); - expect(stack.resolve(pool.userPoolArn)).toEqual({ - 'Fn::Join': ['', [ - 'arn:', - { Ref: 'AWS::Partition' }, - ':cognito-idp:', - { Ref: 'AWS::Region' }, - ':', - { Ref: 'AWS::AccountId' }, - ':userpool/test-user-pool', - ]], + expect(stack.resolve(pool.userPoolArn)).toEqual('arn:aws:cognito-idp:us-east-1:0123456789012:userpool/test-user-pool'); + }); + + test('import using arn without resourceName fails', () => { + // GIVEN + const stack = new Stack(); + const userPoolArn = 'arn:aws:cognito-idp:us-east-1:0123456789012:*'; + + // WHEN + expect(() => { + UserPool.fromUserPoolArn(stack, 'userpool', userPoolArn); + }).toThrowError(/invalid user pool ARN/); + }); + + test('import from different account region using arn', () => { + // GIVEN + const userPoolArn = 'arn:aws:cognito-idp:us-east-1:0123456789012:userpool/test-user-pool'; + + const stack = new Stack(undefined, undefined, { + env: { + account: '111111111111', + region: 'us-east-2', + }, }); + + // WHEN + const pool = UserPool.fromUserPoolArn(stack, 'userpool', userPoolArn); + expect(pool.env.account).toEqual('0123456789012'); + expect(pool.env.region).toEqual('us-east-1'); + expect(pool.userPoolArn).toEqual('arn:aws:cognito-idp:us-east-1:0123456789012:userpool/test-user-pool'); }); test('support tags', () => { diff --git a/packages/@aws-cdk/aws-config/package.json b/packages/@aws-cdk/aws-config/package.json index 59055c7030216..e756e50422eed 100644 --- a/packages/@aws-cdk/aws-config/package.json +++ b/packages/@aws-cdk/aws-config/package.json @@ -70,14 +70,14 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-events-targets": "0.0.0", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "nodeunit": "^0.11.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-events": "0.0.0", @@ -85,7 +85,7 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -94,7 +94,7 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-config/test/test.managed-rules.ts b/packages/@aws-cdk/aws-config/test/test.managed-rules.ts index e2b5143ce0f92..76e0790be3313 100644 --- a/packages/@aws-cdk/aws-config/test/test.managed-rules.ts +++ b/packages/@aws-cdk/aws-config/test/test.managed-rules.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as sns from '@aws-cdk/aws-sns'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk/aws-config/test/test.rule.ts b/packages/@aws-cdk/aws-config/test/test.rule.ts index 1fdac054bc321..ef2398ffae689 100644 --- a/packages/@aws-cdk/aws-config/test/test.rule.ts +++ b/packages/@aws-cdk/aws-config/test/test.rule.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, ResourcePart } from '@aws-cdk/assert'; +import { expect, haveResource, ResourcePart } from '@aws-cdk/assert-internal'; import * as targets from '@aws-cdk/aws-events-targets'; import * as lambda from '@aws-cdk/aws-lambda'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-customerprofiles/.eslintrc.js b/packages/@aws-cdk/aws-customerprofiles/.eslintrc.js new file mode 100644 index 0000000000000..61dd8dd001f63 --- /dev/null +++ b/packages/@aws-cdk/aws-customerprofiles/.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-customerprofiles/.gitignore b/packages/@aws-cdk/aws-customerprofiles/.gitignore new file mode 100644 index 0000000000000..62ebc95d75ce6 --- /dev/null +++ b/packages/@aws-cdk/aws-customerprofiles/.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-customerprofiles/.npmignore b/packages/@aws-cdk/aws-customerprofiles/.npmignore new file mode 100644 index 0000000000000..e4486030fcb17 --- /dev/null +++ b/packages/@aws-cdk/aws-customerprofiles/.npmignore @@ -0,0 +1,28 @@ +# 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 +test/ diff --git a/packages/@aws-cdk/aws-customerprofiles/LICENSE b/packages/@aws-cdk/aws-customerprofiles/LICENSE new file mode 100644 index 0000000000000..28e4bdcec77ec --- /dev/null +++ b/packages/@aws-cdk/aws-customerprofiles/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-2021 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-customerprofiles/NOTICE b/packages/@aws-cdk/aws-customerprofiles/NOTICE new file mode 100644 index 0000000000000..5fc3826926b5b --- /dev/null +++ b/packages/@aws-cdk/aws-customerprofiles/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/aws-customerprofiles/README.md b/packages/@aws-cdk/aws-customerprofiles/README.md new file mode 100644 index 0000000000000..fb215d6b27201 --- /dev/null +++ b/packages/@aws-cdk/aws-customerprofiles/README.md @@ -0,0 +1,20 @@ +# AWS::CustomerProfiles 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]) are always stable and safe to use. +> +> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib + +--- + + + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts +import customerprofiles = require('@aws-cdk/aws-customerprofiles'); +``` diff --git a/packages/@aws-cdk/aws-customerprofiles/jest.config.js b/packages/@aws-cdk/aws-customerprofiles/jest.config.js new file mode 100644 index 0000000000000..54e28beb9798b --- /dev/null +++ b/packages/@aws-cdk/aws-customerprofiles/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-customerprofiles/lib/index.ts b/packages/@aws-cdk/aws-customerprofiles/lib/index.ts new file mode 100644 index 0000000000000..7c0cb8f7868a4 --- /dev/null +++ b/packages/@aws-cdk/aws-customerprofiles/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::CustomerProfiles CloudFormation Resources: +export * from './customerprofiles.generated'; diff --git a/packages/@aws-cdk/aws-customerprofiles/package.json b/packages/@aws-cdk/aws-customerprofiles/package.json new file mode 100644 index 0000000000000..17b6f9fb26612 --- /dev/null +++ b/packages/@aws-cdk/aws-customerprofiles/package.json @@ -0,0 +1,101 @@ +{ + "name": "@aws-cdk/aws-customerprofiles", + "version": "0.0.0", + "description": "The CDK Construct Library for AWS::CustomerProfiles", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "projectReferences": true, + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.CustomerProfiles", + "packageId": "Amazon.CDK.AWS.CustomerProfiles", + "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.customerprofiles", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "customerprofiles" + } + }, + "python": { + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 1" + ], + "distName": "aws-cdk.aws-customerprofiles", + "module": "aws_cdk.aws_customerprofiles" + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-customerprofiles" + }, + "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": "yarn build && yarn test", + "build+test+package": "yarn build+test && yarn package", + "compat": "cdk-compat", + "gen": "cfn2ts", + "rosetta:extract": "yarn --silent jsii-rosetta extract" + }, + "cdk-build": { + "cloudformation": "AWS::CustomerProfiles", + "jest": true, + "env": { + "AWSLINT_BASE_CONSTRUCT": "true" + } + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::CustomerProfiles", + "aws-customerprofiles" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@types/jest": "^26.0.23", + "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 + }, + "publishConfig": { + "tag": "latest" + } +} diff --git a/packages/@aws-cdk/aws-customerprofiles/test/customerprofiles.test.ts b/packages/@aws-cdk/aws-customerprofiles/test/customerprofiles.test.ts new file mode 100644 index 0000000000000..c4505ad966984 --- /dev/null +++ b/packages/@aws-cdk/aws-customerprofiles/test/customerprofiles.test.ts @@ -0,0 +1,6 @@ +import '@aws-cdk/assert-internal/jest'; +import {} from '../lib'; + +test('No tests are specified for this package', () => { + expect(true).toBe(true); +}); diff --git a/packages/@aws-cdk/aws-databrew/package.json b/packages/@aws-cdk/aws-databrew/package.json index be8bdfacf71db..eeba7990834a7 100644 --- a/packages/@aws-cdk/aws-databrew/package.json +++ b/packages/@aws-cdk/aws-databrew/package.json @@ -73,10 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-databrew/test/databrew.test.ts b/packages/@aws-cdk/aws-databrew/test/databrew.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-databrew/test/databrew.test.ts +++ b/packages/@aws-cdk/aws-databrew/test/databrew.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-datapipeline/package.json b/packages/@aws-cdk/aws-datapipeline/package.json index 2e1f552ef864a..3549f8fea9a9f 100644 --- a/packages/@aws-cdk/aws-datapipeline/package.json +++ b/packages/@aws-cdk/aws-datapipeline/package.json @@ -71,19 +71,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-datapipeline/test/datapipeline.test.ts b/packages/@aws-cdk/aws-datapipeline/test/datapipeline.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-datapipeline/test/datapipeline.test.ts +++ b/packages/@aws-cdk/aws-datapipeline/test/datapipeline.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-datasync/package.json b/packages/@aws-cdk/aws-datasync/package.json index 124d3871ae0c3..a1d18fa6f8aa3 100644 --- a/packages/@aws-cdk/aws-datasync/package.json +++ b/packages/@aws-cdk/aws-datasync/package.json @@ -73,10 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-datasync/test/datasync.test.ts b/packages/@aws-cdk/aws-datasync/test/datasync.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-datasync/test/datasync.test.ts +++ b/packages/@aws-cdk/aws-datasync/test/datasync.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-dax/package.json b/packages/@aws-cdk/aws-dax/package.json index 83fecea8535ee..69ace1acbc1a5 100644 --- a/packages/@aws-cdk/aws-dax/package.json +++ b/packages/@aws-cdk/aws-dax/package.json @@ -71,19 +71,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-dax/test/dax.test.ts b/packages/@aws-cdk/aws-dax/test/dax.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-dax/test/dax.test.ts +++ b/packages/@aws-cdk/aws-dax/test/dax.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-detective/package.json b/packages/@aws-cdk/aws-detective/package.json index 741eade5dc9e2..717be699c22ad 100644 --- a/packages/@aws-cdk/aws-detective/package.json +++ b/packages/@aws-cdk/aws-detective/package.json @@ -73,10 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-detective/test/detective.test.ts b/packages/@aws-cdk/aws-detective/test/detective.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-detective/test/detective.test.ts +++ b/packages/@aws-cdk/aws-detective/test/detective.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-devopsguru/package.json b/packages/@aws-cdk/aws-devopsguru/package.json index 7632ba1d35cea..cdab8bcc65c6a 100644 --- a/packages/@aws-cdk/aws-devopsguru/package.json +++ b/packages/@aws-cdk/aws-devopsguru/package.json @@ -73,10 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-devopsguru/test/devopsguru.test.ts b/packages/@aws-cdk/aws-devopsguru/test/devopsguru.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-devopsguru/test/devopsguru.test.ts +++ b/packages/@aws-cdk/aws-devopsguru/test/devopsguru.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-directoryservice/package.json b/packages/@aws-cdk/aws-directoryservice/package.json index 9be65b5324fff..df966366462c8 100644 --- a/packages/@aws-cdk/aws-directoryservice/package.json +++ b/packages/@aws-cdk/aws-directoryservice/package.json @@ -71,19 +71,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-directoryservice/test/directoryservice.test.ts b/packages/@aws-cdk/aws-directoryservice/test/directoryservice.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-directoryservice/test/directoryservice.test.ts +++ b/packages/@aws-cdk/aws-directoryservice/test/directoryservice.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-dlm/package.json b/packages/@aws-cdk/aws-dlm/package.json index 5829ed6a34e11..5037eaacd8232 100644 --- a/packages/@aws-cdk/aws-dlm/package.json +++ b/packages/@aws-cdk/aws-dlm/package.json @@ -72,18 +72,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-dlm/test/dlm.test.ts b/packages/@aws-cdk/aws-dlm/test/dlm.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-dlm/test/dlm.test.ts +++ b/packages/@aws-cdk/aws-dlm/test/dlm.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-dms/package.json b/packages/@aws-cdk/aws-dms/package.json index 1c6f0a473b7b3..476adefb9dbf3 100644 --- a/packages/@aws-cdk/aws-dms/package.json +++ b/packages/@aws-cdk/aws-dms/package.json @@ -71,19 +71,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-dms/test/dms.test.ts b/packages/@aws-cdk/aws-dms/test/dms.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-dms/test/dms.test.ts +++ b/packages/@aws-cdk/aws-dms/test/dms.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-docdb/README.md b/packages/@aws-cdk/aws-docdb/README.md index 530942578a090..fb1c4eeb270ee 100644 --- a/packages/@aws-cdk/aws-docdb/README.md +++ b/packages/@aws-cdk/aws-docdb/README.md @@ -5,17 +5,7 @@ ![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]) are always stable and safe to use. -> -> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib - -![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. +![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge) --- @@ -32,13 +22,11 @@ const cluster = new DatabaseCluster(this, 'Database', { masterUser: { username: 'myuser' // NOTE: 'admin' is reserved by DocumentDB }, - instanceProps: { - instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.LARGE), - vpcSubnets: { - subnetType: ec2.SubnetType.PUBLIC, - }, - vpc - } + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.LARGE), + vpcSubnets: { + subnetType: ec2.SubnetType.PUBLIC, + }, + vpc }); ``` @@ -62,6 +50,16 @@ attributes: const writeAddress = cluster.clusterEndpoint.socketAddress; // "HOSTNAME:PORT" ``` +If you have existing security groups you would like to add to the cluster, use the `addSecurityGroups` method. Security +groups added in this way will not be managed by the `Connections` object of the cluster. + +```ts +const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup', { + vpc, +}); +cluster.addSecurityGroups(securityGroup); +``` + ## Rotating credentials When the master password is generated and stored in AWS Secrets Manager, it can be rotated automatically: diff --git a/packages/@aws-cdk/aws-docdb/lib/cluster.ts b/packages/@aws-cdk/aws-docdb/lib/cluster.ts index f60a332d1b77f..f90e976db8798 100644 --- a/packages/@aws-cdk/aws-docdb/lib/cluster.ts +++ b/packages/@aws-cdk/aws-docdb/lib/cluster.ts @@ -8,7 +8,7 @@ import { DatabaseSecret } from './database-secret'; import { CfnDBCluster, CfnDBInstance, CfnDBSubnetGroup } from './docdb.generated'; import { Endpoint } from './endpoint'; import { IClusterParameterGroup } from './parameter-group'; -import { BackupProps, InstanceProps, Login, RotationMultiUserOptions } from './props'; +import { BackupProps, Login, RotationMultiUserOptions } from './props'; /** * Properties for a new database cluster @@ -82,9 +82,37 @@ export interface DatabaseClusterProps { readonly instanceIdentifierBase?: string; /** - * Settings for the individual instances that are launched + * What type of instance to start for the replicas */ - readonly instanceProps: InstanceProps; + readonly instanceType: ec2.InstanceType; + + /** + * What subnets to run the DocumentDB instances in. + * + * Must be at least 2 subnets in two different AZs. + */ + readonly vpc: ec2.IVpc; + + /** + * Where to place the instances within the VPC + * + * @default private subnets + */ + readonly vpcSubnets?: ec2.SubnetSelection; + + /** + * Security group. + * + * @default a new security group is created. + */ + readonly securityGroup?: ec2.ISecurityGroup; + + /** + * The DB parameter group to associate with the instance. + * + * @default no parameter group + */ + readonly parameterGroup?: IClusterParameterGroup; /** * A weekly time range in which maintenance should preferably execute. @@ -99,13 +127,6 @@ export interface DatabaseClusterProps { */ readonly preferredMaintenanceWindow?: string; - /** - * Additional parameters to pass to the database engine - * - * @default - No parameter group. - */ - readonly parameterGroup?: IClusterParameterGroup; - /** * The removal policy to apply when the cluster and its instances are removed * or replaced during a stack update, or when the stack is deleted. This @@ -262,6 +283,11 @@ export class DatabaseCluster extends DatabaseClusterBase { */ public readonly secret?: secretsmanager.ISecret; + /** + * The underlying CloudFormation resource for a database cluster. + */ + private readonly cluster: CfnDBCluster; + /** * The VPC where the DB subnet group is created. */ @@ -275,8 +301,8 @@ export class DatabaseCluster extends DatabaseClusterBase { constructor(scope: Construct, id: string, props: DatabaseClusterProps) { super(scope, id); - this.vpc = props.instanceProps.vpc; - this.vpcSubnets = props.instanceProps.vpcSubnets; + this.vpc = props.vpc; + this.vpcSubnets = props.vpcSubnets; // Determine the subnet(s) to deploy the DocDB cluster to const { subnetIds, internetConnectivityEstablished } = this.vpc.selectSubnets(this.vpcSubnets); @@ -295,8 +321,8 @@ export class DatabaseCluster extends DatabaseClusterBase { // Create the security group for the DB cluster let securityGroup: ec2.ISecurityGroup; - if (props.instanceProps.securityGroup) { - securityGroup = props.instanceProps.securityGroup; + if (props.securityGroup) { + securityGroup = props.securityGroup; } else { securityGroup = new ec2.SecurityGroup(this, 'SecurityGroup', { description: 'DocumentDB security group', @@ -327,7 +353,7 @@ export class DatabaseCluster extends DatabaseClusterBase { } // Create the DocDB cluster - const cluster = new CfnDBCluster(this, 'Resource', { + this.cluster = new CfnDBCluster(this, 'Resource', { // Basic engineVersion: props.engineVersion, dbClusterIdentifier: props.dbClusterName, @@ -349,16 +375,16 @@ export class DatabaseCluster extends DatabaseClusterBase { storageEncrypted, }); - cluster.applyRemovalPolicy(props.removalPolicy, { + this.cluster.applyRemovalPolicy(props.removalPolicy, { applyToUpdateReplacePolicy: true, }); - this.clusterIdentifier = cluster.ref; - this.clusterResourceIdentifier = cluster.attrClusterResourceId; + this.clusterIdentifier = this.cluster.ref; + this.clusterResourceIdentifier = this.cluster.attrClusterResourceId; - const port = Token.asNumber(cluster.attrPort); - this.clusterEndpoint = new Endpoint(cluster.attrEndpoint, port); - this.clusterReadEndpoint = new Endpoint(cluster.attrReadEndpoint, port); + const port = Token.asNumber(this.cluster.attrPort); + this.clusterEndpoint = new Endpoint(this.cluster.attrEndpoint, port); + this.clusterReadEndpoint = new Endpoint(this.cluster.attrReadEndpoint, port); if (secret) { this.secret = secret.attach(this); @@ -378,10 +404,10 @@ export class DatabaseCluster extends DatabaseClusterBase { const instance = new CfnDBInstance(this, `Instance${instanceIndex}`, { // Link to cluster - dbClusterIdentifier: cluster.ref, + dbClusterIdentifier: this.cluster.ref, dbInstanceIdentifier: instanceIdentifier, // Instance properties - dbInstanceClass: databaseInstanceType(props.instanceProps.instanceType), + dbInstanceClass: databaseInstanceType(props.instanceType), }); instance.applyRemovalPolicy(props.removalPolicy, { @@ -446,6 +472,17 @@ export class DatabaseCluster extends DatabaseClusterBase { target: this, }); } + + /** + * Adds security groups to this cluster. + * @param securityGroups The security groups to add. + */ + public addSecurityGroups(...securityGroups: ec2.ISecurityGroup[]): void { + if (this.cluster.vpcSecurityGroupIds === undefined) { + this.cluster.vpcSecurityGroupIds = []; + } + this.cluster.vpcSecurityGroupIds.push(...securityGroups.map(sg => sg.securityGroupId)); + } } /** diff --git a/packages/@aws-cdk/aws-docdb/lib/instance.ts b/packages/@aws-cdk/aws-docdb/lib/instance.ts index 3208bda7107f7..a7563cb601388 100644 --- a/packages/@aws-cdk/aws-docdb/lib/instance.ts +++ b/packages/@aws-cdk/aws-docdb/lib/instance.ts @@ -120,7 +120,7 @@ export interface DatabaseInstanceProps { /** * The name of the compute and memory capacity classes. */ - readonly instanceClass: ec2.InstanceType; + readonly instanceType: ec2.InstanceType; /** * The name of the Availability Zone where the DB instance will be located. @@ -202,7 +202,7 @@ export class DatabaseInstance extends DatabaseInstanceBase implements IDatabaseI const instance = new CfnDBInstance(this, 'Resource', { dbClusterIdentifier: props.cluster.clusterIdentifier, - dbInstanceClass: `db.${props.instanceClass}`, + dbInstanceClass: `db.${props.instanceType}`, autoMinorVersionUpgrade: props.autoMinorVersionUpgrade ?? true, availabilityZone: props.availabilityZone, dbInstanceIdentifier: props.dbInstanceName, diff --git a/packages/@aws-cdk/aws-docdb/lib/props.ts b/packages/@aws-cdk/aws-docdb/lib/props.ts index 270bc51cdc203..9cd24b1fce1bc 100644 --- a/packages/@aws-cdk/aws-docdb/lib/props.ts +++ b/packages/@aws-cdk/aws-docdb/lib/props.ts @@ -1,8 +1,6 @@ -import * as ec2 from '@aws-cdk/aws-ec2'; import * as kms from '@aws-cdk/aws-kms'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; import { Duration, SecretValue } from '@aws-cdk/core'; -import { IClusterParameterGroup } from './parameter-group'; /** * Backup configuration for DocumentDB databases @@ -57,44 +55,6 @@ export interface Login { readonly kmsKey?: kms.IKey; } -/** - * Instance properties for database instances - */ -export interface InstanceProps { - /** - * What type of instance to start for the replicas - */ - readonly instanceType: ec2.InstanceType; - - /** - * What subnets to run the DocumentDB instances in. - * - * Must be at least 2 subnets in two different AZs. - */ - readonly vpc: ec2.IVpc; - - /** - * Where to place the instances within the VPC - * - * @default private subnets - */ - readonly vpcSubnets?: ec2.SubnetSelection; - - /** - * Security group. - * - * @default a new security group is created. - */ - readonly securityGroup?: ec2.ISecurityGroup; - - /** - * The DB parameter group to associate with the instance. - * - * @default no parameter group - */ - readonly parameterGroup?: IClusterParameterGroup; -} - /** * Options to add the multi user rotation */ diff --git a/packages/@aws-cdk/aws-docdb/package.json b/packages/@aws-cdk/aws-docdb/package.json index 658583ff0d644..128a7f4904fbc 100644 --- a/packages/@aws-cdk/aws-docdb/package.json +++ b/packages/@aws-cdk/aws-docdb/package.json @@ -73,11 +73,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-efs": "0.0.0", @@ -85,7 +86,7 @@ "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/aws-efs": "0.0.0", @@ -93,7 +94,7 @@ "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" @@ -104,8 +105,8 @@ "attribute-tag:@aws-cdk/aws-docdb.DatabaseSecret.secretName" ] }, - "stability": "experimental", - "maturity": "experimental", + "stability": "stable", + "maturity": "stable", "awscdkio": { "announce": false }, diff --git a/packages/@aws-cdk/aws-docdb/test/cluster.test.ts b/packages/@aws-cdk/aws-docdb/test/cluster.test.ts index f227293310bf3..1dd057fa29653 100644 --- a/packages/@aws-cdk/aws-docdb/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-docdb/test/cluster.test.ts @@ -1,4 +1,4 @@ -import { expect as expectCDK, haveResource, ResourcePart } from '@aws-cdk/assert'; +import { expect as expectCDK, haveResource, ResourcePart, arrayWith } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as kms from '@aws-cdk/aws-kms'; import * as cdk from '@aws-cdk/core'; @@ -18,10 +18,8 @@ describe('DatabaseCluster', () => { username: 'admin', password: cdk.SecretValue.plainText('tooshort'), }, - instanceProps: { - instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), - vpc, - }, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, }); // THEN @@ -63,10 +61,8 @@ describe('DatabaseCluster', () => { username: 'admin', password: cdk.SecretValue.plainText('tooshort'), }, - instanceProps: { - instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), - vpc, - }, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, }); // THEN @@ -90,10 +86,8 @@ describe('DatabaseCluster', () => { masterUser: { username: 'admin', }, - instanceProps: { - vpc, - instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.LARGE), - }, + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.LARGE), }); }).toThrowError('At least one instance is required'); }); @@ -112,12 +106,10 @@ describe('DatabaseCluster', () => { masterUser: { username: 'admin', }, - instanceProps: { - vpc, - instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.LARGE), - vpcSubnets: { - subnetType: ec2.SubnetType.PRIVATE, - }, + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.LARGE), + vpcSubnets: { + subnetType: ec2.SubnetType.PRIVATE, }, }); }).toThrowError('Cluster requires at least 2 subnets, got 1'); @@ -134,10 +126,8 @@ describe('DatabaseCluster', () => { masterUser: { username: 'admin', }, - instanceProps: { - instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), - vpc, - }, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, }); // THEN @@ -163,11 +153,9 @@ describe('DatabaseCluster', () => { username: 'admin', password: cdk.SecretValue.plainText('tooshort'), }, - instanceProps: { - instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), - vpc, - securityGroup: sg, - }, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + securityGroup: sg, }); // THEN @@ -197,10 +185,8 @@ describe('DatabaseCluster', () => { username: 'admin', password: cdk.SecretValue.plainText('tooshort'), }, - instanceProps: { - instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), - vpc, - }, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, parameterGroup: group, }); @@ -223,10 +209,8 @@ describe('DatabaseCluster', () => { username: 'admin', password: cdk.SecretValue.plainText('tooshort'), }, - instanceProps: { - instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), - vpc, - }, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, parameterGroup: group, }); @@ -246,10 +230,8 @@ describe('DatabaseCluster', () => { masterUser: { username: 'admin', }, - instanceProps: { - instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), - vpc, - }, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, }); // THEN @@ -300,10 +282,8 @@ describe('DatabaseCluster', () => { masterUser: { username: 'admin', }, - instanceProps: { - instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), - vpc, - }, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, kmsKey: new kms.Key(stack, 'Key'), }); @@ -329,10 +309,8 @@ describe('DatabaseCluster', () => { masterUser: { username: 'admin', }, - instanceProps: { - instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), - vpc, - }, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, }); // THEN @@ -352,10 +330,8 @@ describe('DatabaseCluster', () => { masterUser: { username: 'admin', }, - instanceProps: { - instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), - vpc, - }, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, kmsKey: new kms.Key(stack, 'Key'), storageEncrypted: false, }); @@ -375,10 +351,8 @@ describe('DatabaseCluster', () => { masterUser: { username: 'admin', }, - instanceProps: { - instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), - vpc, - }, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, }); // THEN @@ -396,10 +370,8 @@ describe('DatabaseCluster', () => { masterUser: { username: 'admin', }, - instanceProps: { - vpc, - instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), - }, + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), instanceIdentifierBase, }); @@ -420,10 +392,8 @@ describe('DatabaseCluster', () => { masterUser: { username: 'admin', }, - instanceProps: { - vpc, - instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), - }, + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), dbClusterName: clusterIdentifier, }); @@ -494,10 +464,8 @@ describe('DatabaseCluster', () => { masterUser: { username: 'admin', }, - instanceProps: { - vpc, - instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), - }, + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), backup: { retention: cdk.Duration.days(20), }, @@ -519,10 +487,8 @@ describe('DatabaseCluster', () => { masterUser: { username: 'admin', }, - instanceProps: { - vpc, - instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), - }, + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), backup: { retention: cdk.Duration.days(20), preferredWindow: '07:34-08:04', @@ -546,10 +512,8 @@ describe('DatabaseCluster', () => { masterUser: { username: 'admin', }, - instanceProps: { - vpc, - instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), - }, + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), preferredMaintenanceWindow: '07:34-08:04', }); @@ -567,10 +531,8 @@ describe('DatabaseCluster', () => { masterUser: { username: 'admin', }, - instanceProps: { - vpc, - instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), - }, + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), }); // WHEN @@ -630,10 +592,8 @@ describe('DatabaseCluster', () => { username: 'admin', password: cdk.SecretValue.plainText('secret'), }, - instanceProps: { - vpc, - instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), - }, + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), }); // WHEN @@ -653,10 +613,8 @@ describe('DatabaseCluster', () => { masterUser: { username: 'admin', }, - instanceProps: { - vpc, - instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), - }, + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), }); // WHEN @@ -677,10 +635,8 @@ describe('DatabaseCluster', () => { masterUser: { username: 'admin', }, - instanceProps: { - vpc, - instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), - }, + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), }); const userSecret = new DatabaseSecret(stack, 'UserSecret', { username: 'seconduser', @@ -749,10 +705,8 @@ describe('DatabaseCluster', () => { username: 'admin', password: cdk.SecretValue.plainText('secret'), }, - instanceProps: { - vpc, - instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), - }, + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), }); const userSecret = new DatabaseSecret(stack, 'UserSecret', { username: 'seconduser', @@ -771,6 +725,29 @@ describe('DatabaseCluster', () => { expect(addMultiUserRotation).toThrow(); }); + test('adds security groups', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new DatabaseCluster(stack, 'Database', { + vpc, + masterUser: { + username: 'admin', + }, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), + }); + const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup', { + vpc, + }); + + // WHEN + cluster.addSecurityGroups(securityGroup); + + // THEN + expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + VpcSecurityGroupIds: arrayWith(stack.resolve(securityGroup.securityGroupId)), + })); + }); }); function testStack() { diff --git a/packages/@aws-cdk/aws-docdb/test/instance.test.ts b/packages/@aws-cdk/aws-docdb/test/instance.test.ts index b3785e700ca01..f1382746db07d 100644 --- a/packages/@aws-cdk/aws-docdb/test/instance.test.ts +++ b/packages/@aws-cdk/aws-docdb/test/instance.test.ts @@ -1,4 +1,4 @@ -import { expect as expectCDK, haveOutput, haveResource, ResourcePart } from '@aws-cdk/assert'; +import { expect as expectCDK, haveOutput, haveResource, ResourcePart } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import * as constructs from 'constructs'; @@ -17,7 +17,7 @@ describe('DatabaseInstance', () => { // WHEN new DatabaseInstance(stack, 'Instance', { cluster: stack.cluster, - instanceClass: SINGLE_INSTANCE_TYPE, + instanceType: SINGLE_INSTANCE_TYPE, }); // THEN @@ -43,7 +43,7 @@ describe('DatabaseInstance', () => { // WHEN new DatabaseInstance(stack, 'Instance', { cluster: stack.cluster, - instanceClass: SINGLE_INSTANCE_TYPE, + instanceType: SINGLE_INSTANCE_TYPE, autoMinorVersionUpgrade: given, }); @@ -64,7 +64,7 @@ describe('DatabaseInstance', () => { const stack = testStack(); const instance = new DatabaseInstance(stack, 'Instance', { cluster: stack.cluster, - instanceClass: SINGLE_INSTANCE_TYPE, + instanceType: SINGLE_INSTANCE_TYPE, }); const exportName = 'DbInstanceEndpoint'; @@ -95,7 +95,7 @@ describe('DatabaseInstance', () => { const stack = testStack(); const instance = new DatabaseInstance(stack, 'Instance', { cluster: stack.cluster, - instanceClass: SINGLE_INSTANCE_TYPE, + instanceType: SINGLE_INSTANCE_TYPE, }); const exportName = 'DbInstanceArn'; @@ -182,10 +182,8 @@ class TestStack extends cdk.Stack { username: 'admin', password: cdk.SecretValue.plainText('tooshort'), }, - instanceProps: { - instanceType: CLUSTER_INSTANCE_TYPE, - vpc: this.vpc, - }, + instanceType: CLUSTER_INSTANCE_TYPE, + vpc: this.vpc, }); } } diff --git a/packages/@aws-cdk/aws-docdb/test/integ.cluster-rotation.lit.ts b/packages/@aws-cdk/aws-docdb/test/integ.cluster-rotation.lit.ts index e8c6ed141e1f9..ae655dd213a4d 100644 --- a/packages/@aws-cdk/aws-docdb/test/integ.cluster-rotation.lit.ts +++ b/packages/@aws-cdk/aws-docdb/test/integ.cluster-rotation.lit.ts @@ -20,10 +20,8 @@ const cluster = new docdb.DatabaseCluster(stack, 'Database', { masterUser: { username: 'docdb', }, - instanceProps: { - instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.LARGE), - vpc, - }, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.LARGE), + vpc, removalPolicy: cdk.RemovalPolicy.DESTROY, }); diff --git a/packages/@aws-cdk/aws-docdb/test/integ.cluster.ts b/packages/@aws-cdk/aws-docdb/test/integ.cluster.ts index 5e7b2049507aa..084502d0dae65 100644 --- a/packages/@aws-cdk/aws-docdb/test/integ.cluster.ts +++ b/packages/@aws-cdk/aws-docdb/test/integ.cluster.ts @@ -35,11 +35,9 @@ class TestStack extends cdk.Stack { username: 'docdb', password: cdk.SecretValue.plainText('7959866cacc02c2d243ecfe177464fe6'), }, - instanceProps: { - instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.LARGE), - vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC }, - vpc, - }, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.LARGE), + vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC }, + vpc, parameterGroup: params, kmsKey, removalPolicy: cdk.RemovalPolicy.DESTROY, diff --git a/packages/@aws-cdk/aws-docdb/test/parameter-group.test.ts b/packages/@aws-cdk/aws-docdb/test/parameter-group.test.ts index 34f88c5b33f4d..66cf65e5ece60 100644 --- a/packages/@aws-cdk/aws-docdb/test/parameter-group.test.ts +++ b/packages/@aws-cdk/aws-docdb/test/parameter-group.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import { Stack } from '@aws-cdk/core'; import { ClusterParameterGroup } from '../lib'; 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 2753afe5af09f..3225b16fa7879 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package.json +++ b/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package.json @@ -29,7 +29,7 @@ "devDependencies": { "aws-sdk": "^2.596.0", "aws-sdk-mock": "^5.1.0", - "eslint": "^7.22.0", + "eslint": "^7.25.0", "eslint-config-standard": "^14.1.1", "eslint-plugin-import": "^2.22.1", "eslint-plugin-node": "^11.1.0", diff --git a/packages/@aws-cdk/aws-dynamodb-global/package.json b/packages/@aws-cdk/aws-dynamodb-global/package.json index 2a3a41bc29fbb..0484fb895af5a 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/package.json +++ b/packages/@aws-cdk/aws-dynamodb-global/package.json @@ -53,22 +53,22 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "devDependencies": { - "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "nodeunit": "^0.11.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "peerDependencies": { "@aws-cdk/aws-dynamodb": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "scripts": { "build": "cdk-build", diff --git a/packages/@aws-cdk/aws-dynamodb-global/test/test.dynamodb.global.ts b/packages/@aws-cdk/aws-dynamodb-global/test/test.dynamodb.global.ts index bd534f7032f74..4a4c7596b4dfa 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/test/test.dynamodb.global.ts +++ b/packages/@aws-cdk/aws-dynamodb-global/test/test.dynamodb.global.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import { Attribute, AttributeType, StreamViewType, Table } from '@aws-cdk/aws-dynamodb'; import { App, CfnOutput, Stack } from '@aws-cdk/core'; import { Test } from 'nodeunit'; @@ -62,7 +62,7 @@ export = { }, 'GlobalTable generated stacks inherit their account from the parent stack'(test: Test) { - const app = new App(); + const app = new App({ context: { '@aws-cdk/core:stackRelativeExports': true } }); const stack = new Stack(app, 'GlobalTableStack', { env: { account: '123456789012', region: 'us-east-1' } }); const globalTable = new GlobalTable(stack, CONSTRUCT_NAME, { @@ -81,7 +81,7 @@ export = { 'Outputs': { 'DynamoDbOutput': { 'Value': { - 'Fn::ImportValue': 'GlobalTableStackawscdkdynamodbglobalawscdkdynamodbglobaluseast19C1C8A14:awscdkdynamodbglobalawscdkdynamodbglobaluseast1ExportsOutputFnGetAttawscdkdynamodbglobalGlobalTableuseast1FC03DD69StreamArn28E90DB8', + 'Fn::ImportValue': 'GlobalTableStackawscdkdynamodbglobalawscdkdynamodbglobaluseast19C1C8A14:ExportsOutputFnGetAttawscdkdynamodbglobalGlobalTableuseast1FC03DD69StreamArn9CE585ED', }, }, }, diff --git a/packages/@aws-cdk/aws-dynamodb/lib/table.ts b/packages/@aws-cdk/aws-dynamodb/lib/table.ts index a958bf135546e..776159b110e27 100644 --- a/packages/@aws-cdk/aws-dynamodb/lib/table.ts +++ b/packages/@aws-cdk/aws-dynamodb/lib/table.ts @@ -3,7 +3,7 @@ import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import { - Aws, CfnCondition, CfnCustomResource, CustomResource, Duration, + Aws, CfnCondition, CfnCustomResource, CfnResource, CustomResource, Duration, Fn, IResource, Lazy, Names, RemovalPolicy, Resource, Stack, Token, } from '@aws-cdk/core'; import { Construct } from 'constructs'; @@ -215,7 +215,6 @@ export interface TableOptions { * Regions where replica tables will be created * * @default - no replica tables are created - * @experimental */ readonly replicationRegions?: string[]; @@ -1477,7 +1476,8 @@ export class Table extends TableBase { this.grant(onEventHandlerPolicy, 'dynamodb:*'); this.grant(isCompleteHandlerPolicy, 'dynamodb:DescribeTable'); - let previousRegion; + let previousRegion: CustomResource | undefined; + let previousRegionCondition: CfnCondition | undefined; for (const region of new Set(regions)) { // Remove duplicates // Use multiple custom resources because multiple create/delete // updates cannot be combined in a single API call. @@ -1498,8 +1498,9 @@ export class Table extends TableBase { // Deploy time check to prevent from creating a replica in the region // where this stack is deployed. Only needed for environment agnostic // stacks. + let createReplica: CfnCondition | undefined; if (Token.isUnresolved(stack.region)) { - const createReplica = new CfnCondition(this, `StackRegionNotEquals${region}`, { + createReplica = new CfnCondition(this, `StackRegionNotEquals${region}`, { expression: Fn.conditionNot(Fn.conditionEquals(region, Aws.REGION)), }); const cfnCustomResource = currentRegion.node.defaultChild as CfnCustomResource; @@ -1518,9 +1519,22 @@ export class Table extends TableBase { // have multiple table updates at the same time. The `isCompleteHandler` // of the provider waits until the replica is in an ACTIVE state. if (previousRegion) { - currentRegion.node.addDependency(previousRegion); + if (previousRegionCondition) { + // we can't simply use a Dependency, + // because the previousRegion is protected by the "different region" Condition, + // and you can't have Fn::If in DependsOn. + // Instead, rely on Ref adding a dependency implicitly! + const previousRegionCfnResource = previousRegion.node.defaultChild as CfnResource; + const currentRegionCfnResource = currentRegion.node.defaultChild as CfnResource; + currentRegionCfnResource.addMetadata('DynamoDbReplicationDependency', + Fn.conditionIf(previousRegionCondition.logicalId, previousRegionCfnResource.ref, Aws.NO_VALUE)); + } else { + currentRegion.node.addDependency(previousRegion); + } } + previousRegion = currentRegion; + previousRegionCondition = createReplica; } // Permissions in the destination regions (outside of the loop to diff --git a/packages/@aws-cdk/aws-dynamodb/package.json b/packages/@aws-cdk/aws-dynamodb/package.json index b0e4e4484ae37..f99331bc3df35 100644 --- a/packages/@aws-cdk/aws-dynamodb/package.json +++ b/packages/@aws-cdk/aws-dynamodb/package.json @@ -71,8 +71,9 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", - "@types/jest": "^26.0.21", + "@types/aws-lambda": "^8.10.76", + "@types/jest": "^26.0.23", + "@types/sinon": "^9.0.11", "aws-sdk": "^2.848.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", @@ -81,7 +82,8 @@ "jest": "^26.6.3", "pkglint": "0.0.0", "sinon": "^9.2.4", - "ts-jest": "^26.5.4" + "ts-jest": "^26.5.5", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-applicationautoscaling": "0.0.0", @@ -91,7 +93,7 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -102,7 +104,7 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts index cddba2ff1504b..31fb1d682d674 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts @@ -1,5 +1,5 @@ -import { arrayWith, ABSENT, ResourcePart, SynthUtils } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { arrayWith, ABSENT, ResourcePart, SynthUtils } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as appscaling from '@aws-cdk/aws-applicationautoscaling'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.global-replicas-provisioned.expected.json b/packages/@aws-cdk/aws-dynamodb/test/integ.global-replicas-provisioned.expected.json index af1e8defceed6..ce43b532ea7c6 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.global-replicas-provisioned.expected.json +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.global-replicas-provisioned.expected.json @@ -199,7 +199,6 @@ "Region": "eu-west-3" }, "DependsOn": [ - "TableReplicauseast28A15C236", "TableSourceTableAttachedManagedPolicyawscdkdynamodbglobalreplicasprovisionedawscdkawsdynamodbReplicaProviderIsCompleteHandlerServiceRoleBE2B1C1A5DC546D2", "TableSourceTableAttachedManagedPolicyawscdkdynamodbglobalreplicasprovisionedawscdkawsdynamodbReplicaProviderOnEventHandlerServiceRoleD9856B771F8F2CCB", "TableWriteScalingTargetE5669214", @@ -207,6 +206,19 @@ ], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete", + "Metadata": { + "DynamoDbReplicationDependency": { + "Fn::If": [ + "TableStackRegionNotEqualsuseast2D20A1E77", + { + "Ref": "TableReplicauseast28A15C236" + }, + { + "Ref": "AWS::NoValue" + } + ] + } + }, "Condition": "TableStackRegionNotEqualseuwest302B3591C" }, "TableWriteScalingTargetE5669214": { diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.global-replicas-provisioned.ts b/packages/@aws-cdk/aws-dynamodb/test/integ.global-replicas-provisioned.ts index 8403538c2bd50..7135e5c5f10ef 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.global-replicas-provisioned.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.global-replicas-provisioned.ts @@ -1,3 +1,4 @@ +/// !cdk-integ pragma:ignore-assets import * as cdk from '@aws-cdk/core'; import * as dynamodb from '../lib'; diff --git a/packages/@aws-cdk/aws-ec2/README.md b/packages/@aws-cdk/aws-ec2/README.md index 90b5b4be9cfb8..434729361bfa9 100644 --- a/packages/@aws-cdk/aws-ec2/README.md +++ b/packages/@aws-cdk/aws-ec2/README.md @@ -520,6 +520,27 @@ listener.connections.allowDefaultPortFromAnyIpv4('Allow public'); appFleet.connections.allowDefaultPortTo(rdsDatabase, 'Fleet can access database'); ``` +### Security group rules + +By default, security group wills be added inline to the security group in the output cloud formation +template, if applicable. This includes any static rules by ip address and port range. This +optimization helps to minimize the size of the template. + +In some environments this is not desirable, for example if your security group access is controlled +via tags. You can disable inline rules per security group or globally via the context key +`@aws-cdk/aws-ec2.securityGroupDisableInlineRules`. + +```ts fixture=with-vpc +const mySecurityGroupWithoutInlineRules = new ec2.SecurityGroup(this, 'SecurityGroup', { + vpc, + description: 'Allow ssh access to ec2 instances', + allowAllOutbound: true, + disableInlineRules: true +}); +//This will add the rule as an external cloud formation construct +mySecurityGroupWithoutInlineRules.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(22), 'allow ssh access from the world'); +``` + ## Machine Images (AMIs) AMIs control the OS that gets launched when you start your EC2 instance. The EC2 @@ -651,13 +672,13 @@ Alternatively, existing security groups can be used by specifying the `securityG ### VPC endpoint services -A VPC endpoint service enables you to expose a Network Load Balancer(s) as a provider service to consumers, who connect to your service over a VPC endpoint. You can restrict access to your service via whitelisted principals (anything that extends ArnPrincipal), and require that new connections be manually accepted. +A VPC endpoint service enables you to expose a Network Load Balancer(s) as a provider service to consumers, who connect to your service over a VPC endpoint. You can restrict access to your service via allowed principals (anything that extends ArnPrincipal), and require that new connections be manually accepted. ```ts new VpcEndpointService(this, 'EndpointService', { vpcEndpointServiceLoadBalancers: [networkLoadBalancer1, networkLoadBalancer2], acceptanceRequired: true, - whitelistedPrincipals: [new ArnPrincipal('arn:aws:iam::123456789012:root')] + allowedPrincipals: [new ArnPrincipal('arn:aws:iam::123456789012:root')] }); ``` @@ -678,6 +699,71 @@ Note: The domain name must be owned (registered through Route53) by the account The VpcEndpointServiceDomainName will handle the AWS side of domain verification, the process for which can be found [here](https://docs.aws.amazon.com/vpc/latest/userguide/endpoint-services-dns-validation.html) +### Client VPN endpoint + +AWS Client VPN is a managed client-based VPN service that enables you to securely access your AWS +resources and resources in your on-premises network. With Client VPN, you can access your resources +from any location using an OpenVPN-based VPN client. + +Use the `addClientVpnEndpoint()` method to add a client VPN endpoint to a VPC: + +```ts fixture=client-vpn +vpc.addClientVpnEndpoint('Endpoint', { + cidr: '10.100.0.0/16', + serverCertificateArn: 'arn:aws:acm:us-east-1:123456789012:certificate/server-certificate-id', + // Mutual authentication + clientCertificateArn: 'arn:aws:acm:us-east-1:123456789012:certificate/client-certificate-id', + // User-based authentication + userBasedAuthentication: ec2.ClientVpnUserBasedAuthentication.federated(samlProvider), +}); +``` + +The endpoint must use at least one [authentication method](https://docs.aws.amazon.com/vpn/latest/clientvpn-admin/client-authentication.html): + +* Mutual authentication with a client certificate +* User-based authentication (directory or federated) + +If user-based authentication is used, the [self-service portal URL](https://docs.aws.amazon.com/vpn/latest/clientvpn-user/self-service-portal.html) +is made available via a CloudFormation output. + +By default, a new security group is created and logging is enabled. Moreover, a rule to +authorize all users to the VPC CIDR is created. + +To customize authorization rules, set the `authorizeAllUsersToVpcCidr` prop to `false` +and use `addaddAuthorizationRule()`: + +```ts fixture=client-vpn +const endpoint = vpc.addClientVpnEndpoint('Endpoint', { + cidr: '10.100.0.0/16', + serverCertificateArn: 'arn:aws:acm:us-east-1:123456789012:certificate/server-certificate-id', + userBasedAuthentication: ec2.ClientVpnUserBasedAuthentication.federated(samlProvider), + authorizeAllUsersToVpcCidr: false, +}); + +endpoint.addAuthorizationRule('Rule', { + cidr: '10.0.10.0/32', + groupId: 'group-id', +}); +``` + +Use `addRoute()` to configure network routes: + +```ts fixture=client-vpn +const endpoint = vpc.addClientVpnEndpoint('Endpoint', { + cidr: '10.100.0.0/16', + serverCertificateArn: 'arn:aws:acm:us-east-1:123456789012:certificate/server-certificate-id', + userBasedAuthentication: ec2.ClientVpnUserBasedAuthentication.federated(samlProvider), +}); + +// Client-to-client access +endpoint.addRoute('Route', { + cidr: '10.100.0.0/16', + target: ec2.ClientVpnRouteTarget.local(), +}); +``` + +Use the `connections` object of the endpoint to allow traffic to other security groups. + ## Instances You can use the `Instance` class to start up a single EC2 instance. For production setups, we recommend @@ -876,8 +962,12 @@ const instance = new ec2.Instance(this, 'Instance', { volume.grantAttachVolumeByResourceTag(instance.grantPrincipal, [instance]); const targetDevice = '/dev/xvdz'; instance.userData.addCommands( + // Retrieve token for accessing EC2 instance metadata (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html) + `TOKEN=$(curl -SsfX PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")`, + // Retrieve the instance Id of the current EC2 instance + `INSTANCE_ID=$(curl -SsfH "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id)`, // Attach the volume to /dev/xvdz - `aws --region ${Stack.of(this).region} ec2 attach-volume --volume-id ${volume.volumeId} --instance-id ${instance.instanceId} --device ${targetDevice}`, + `aws --region ${Stack.of(this).region} ec2 attach-volume --volume-id ${volume.volumeId} --instance-id $INSTANCE_ID --device ${targetDevice}`, // Wait until the volume has attached `while ! test -e ${targetDevice}; do sleep 1; done` // The volume will now be mounted. You may have to add additional code to format the volume if it has not been prepared. @@ -1022,7 +1112,7 @@ new ec2.LaunchTemplate(stack, '', { }); ``` -For more information see +For more information see [Specifying Multiple User Data Blocks Using a MIME Multi Part Archive](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/bootstrap_container_instance.html#multi-part_user_data) diff --git a/packages/@aws-cdk/aws-ec2/lib/bastion-host.ts b/packages/@aws-cdk/aws-ec2/lib/bastion-host.ts index 0656440ea3ff4..b0345f34b6b98 100644 --- a/packages/@aws-cdk/aws-ec2/lib/bastion-host.ts +++ b/packages/@aws-cdk/aws-ec2/lib/bastion-host.ts @@ -14,7 +14,7 @@ import { IVpc, SubnetSelection } from './vpc'; /** * Properties of the bastion host * - * @experimental + * */ export interface BastionHostLinuxProps { @@ -90,7 +90,7 @@ export interface BastionHostLinuxProps { * * You can also configure this bastion host to allow connections via SSH * - * @experimental + * * @resource AWS::EC2::Instance */ export class BastionHostLinux extends Resource implements IInstance { diff --git a/packages/@aws-cdk/aws-ec2/lib/client-vpn-authorization-rule.ts b/packages/@aws-cdk/aws-ec2/lib/client-vpn-authorization-rule.ts new file mode 100644 index 0000000000000..c63f940ab4883 --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/lib/client-vpn-authorization-rule.ts @@ -0,0 +1,57 @@ +import { Resource } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import { IClientVpnEndpoint } from './client-vpn-endpoint-types'; +import { CfnClientVpnAuthorizationRule } from './ec2.generated'; + +/** + * Options for a ClientVpnAuthorizationRule + */ +export interface ClientVpnAuthorizationRuleOptions { + /** + * The IPv4 address range, in CIDR notation, of the network for which access + * is being authorized. + */ + readonly cidr: string; + + /** + * The ID of the group to grant access to, for example, the Active Directory + * group or identity provider (IdP) group. + * + * @default - authorize all groups + */ + readonly groupId?: string; + + /** + * A brief description of the authorization rule. + * + * @default - no description + */ + readonly description?: string; +} + +/** + * Properties for a ClientVpnAuthorizationRule + */ +export interface ClientVpnAuthorizationRuleProps extends ClientVpnAuthorizationRuleOptions { + /** + * The client VPN endpoint to which to add the rule. + */ + readonly clientVpnEndoint: IClientVpnEndpoint; +} + +/** + * A client VPN authorization rule + */ +export class ClientVpnAuthorizationRule extends Resource { + constructor(scope: Construct, id: string, props: ClientVpnAuthorizationRuleProps) { + super(scope, id); + + new CfnClientVpnAuthorizationRule(this, 'Resource', { + clientVpnEndpointId: props.clientVpnEndoint.endpointId, + targetNetworkCidr: props.cidr, + accessGroupId: props.groupId, + authorizeAllGroups: !props.groupId, + description: props.description, + }); + } +} diff --git a/packages/@aws-cdk/aws-ec2/lib/client-vpn-endpoint-types.ts b/packages/@aws-cdk/aws-ec2/lib/client-vpn-endpoint-types.ts new file mode 100644 index 0000000000000..ef33493a8f225 --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/lib/client-vpn-endpoint-types.ts @@ -0,0 +1,52 @@ +import { IDependable, IResource } from '@aws-cdk/core'; +import { IConnectable } from './connections'; + +/** + * A client VPN endpoint + */ +export interface IClientVpnEndpoint extends IResource, IConnectable { + /** + * The endpoint ID + */ + readonly endpointId: string; + + /** + * Dependable that can be depended upon to force target networks associations + */ + readonly targetNetworksAssociated: IDependable; +} + +/** + * A connection handler for client VPN endpoints + */ +export interface IClientVpnConnectionHandler { + /** + * The name of the function + */ + readonly functionName: string; + + /** + * The ARN of the function. + */ + readonly functionArn: string; +} + +/** + * Transport protocol for client VPN + */ +export enum TransportProtocol { + /** Transmission Control Protocol (TCP) */ + TCP = 'tcp', + /** User Datagram Protocol (UDP) */ + UDP = 'udp', +} + +/** + * Port for client VPN + */ +export enum VpnPort { + /** HTTPS */ + HTTPS = 443, + /** OpenVPN */ + OPENVPN = 1194, +} diff --git a/packages/@aws-cdk/aws-ec2/lib/client-vpn-endpoint.ts b/packages/@aws-cdk/aws-ec2/lib/client-vpn-endpoint.ts new file mode 100644 index 0000000000000..43431bd649046 --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/lib/client-vpn-endpoint.ts @@ -0,0 +1,407 @@ +import { ISamlProvider } from '@aws-cdk/aws-iam'; +import * as logs from '@aws-cdk/aws-logs'; +import { CfnOutput, ConcreteDependable, IDependable, Resource, Token } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import { ClientVpnAuthorizationRule, ClientVpnAuthorizationRuleOptions } from './client-vpn-authorization-rule'; +import { IClientVpnConnectionHandler, IClientVpnEndpoint, TransportProtocol, VpnPort } from './client-vpn-endpoint-types'; +import { ClientVpnRoute, ClientVpnRouteOptions } from './client-vpn-route'; +import { Connections } from './connections'; +import { CfnClientVpnEndpoint, CfnClientVpnTargetNetworkAssociation } from './ec2.generated'; +import { CidrBlock } from './network-util'; +import { ISecurityGroup, SecurityGroup } from './security-group'; +import { IVpc, SubnetSelection } from './vpc'; + +/** + * Options for a client VPN endpoint + */ +export interface ClientVpnEndpointOptions { + /** + * The IPv4 address range, in CIDR notation, from which to assign client IP + * addresses. The address range cannot overlap with the local CIDR of the VPC + * in which the associated subnet is located, or the routes that you add manually. + * + * Changing the address range will replace the Client VPN endpoint. + * + * The CIDR block should be /22 or greater. + */ + readonly cidr: string; + + /** + * The ARN of the client certificate for mutual authentication. + * + * The certificate must be signed by a certificate authority (CA) and it must + * be provisioned in AWS Certificate Manager (ACM). + * + * @default - use user-based authentication + */ + readonly clientCertificateArn?: string; + + /** + * The type of user-based authentication to use. + * + * @see https://docs.aws.amazon.com/vpn/latest/clientvpn-admin/client-authentication.html + * + * @default - use mutual authentication + */ + readonly userBasedAuthentication?: ClientVpnUserBasedAuthentication; + + /** + * Whether to enable connections logging + * + * @default true + */ + readonly logging?: boolean; + + /** + * A CloudWatch Logs log group for connection logging + * + * @default - a new group is created + */ + readonly logGroup?: logs.ILogGroup; + + /** + * A CloudWatch Logs log stream for connection logging + * + * @default - a new stream is created + */ + readonly logStream?: logs.ILogStream; + + /** + * The AWS Lambda function used for connection authorization + * + * The name of the Lambda function must begin with the `AWSClientVPN-` prefix + * + * @default - no connection handler + */ + readonly clientConnectionHandler?: IClientVpnConnectionHandler; + + /** + * A brief description of the Client VPN endpoint. + * + * @default - no description + */ + readonly description?: string; + + /** + * The security groups to apply to the target network. + * + * @default - a new security group is created + */ + readonly securityGroups?: ISecurityGroup[]; + + /** + * Specify whether to enable the self-service portal for the Client VPN endpoint. + * + * @default true + */ + readonly selfServicePortal?: boolean; + + /** + * The ARN of the server certificate + */ + readonly serverCertificateArn: string; + + /** + * Indicates whether split-tunnel is enabled on the AWS Client VPN endpoint. + * + * @see https://docs.aws.amazon.com/vpn/latest/clientvpn-admin/split-tunnel-vpn.html + * + * @default false + */ + readonly splitTunnel?: boolean; + + /** + * The transport protocol to be used by the VPN session. + * + * @default TransportProtocol.UDP + */ + readonly transportProtocol?: TransportProtocol; + + /** + * The port number to assign to the Client VPN endpoint for TCP and UDP + * traffic. + * + * @default VpnPort.HTTPS + */ + readonly port?: VpnPort; + + /** + * Information about the DNS servers to be used for DNS resolution. + * + * A Client VPN endpoint can have up to two DNS servers. + * + * @default - use the DNS address configured on the device + */ + readonly dnsServers?: string[]; + + /** + * Subnets to associate to the client VPN endpoint. + * + * @default - the VPC default strategy + */ + readonly vpcSubnets?: SubnetSelection; + + /** + * Whether to authorize all users to the VPC CIDR + * + * This automatically creates an authorization rule. Set this to `false` and + * use `addAuthorizationRule()` to create your own rules instead. + * + * @default true + */ + readonly authorizeAllUsersToVpcCidr?: boolean; +} + +/** + * User-based authentication for a client VPN endpoint + */ +export abstract class ClientVpnUserBasedAuthentication { + /** + * Active Directory authentication + */ + public static activeDirectory(directoryId: string): ClientVpnUserBasedAuthentication { + return new ActiveDirectoryAuthentication(directoryId); + } + + /** Federated authentication */ + public static federated(samlProvider: ISamlProvider, selfServiceSamlProvider?: ISamlProvider): ClientVpnUserBasedAuthentication { + return new FederatedAuthentication(samlProvider, selfServiceSamlProvider); + } + + /** Renders the user based authentication */ + public abstract render(): any; +} + +/** + * Active Directory authentication + */ +class ActiveDirectoryAuthentication extends ClientVpnUserBasedAuthentication { + constructor(private readonly directoryId: string) { + super(); + } + + render(): any { + return { + type: 'directory-service-authentication', + activeDirectory: { directoryId: this.directoryId }, + }; + } +} + +/** + * Federated authentication + */ +class FederatedAuthentication extends ClientVpnUserBasedAuthentication { + constructor(private readonly samlProvider: ISamlProvider, private readonly selfServiceSamlProvider?: ISamlProvider) { + super(); + } + + render(): any { + return { + type: 'federated-authentication', + federatedAuthentication: { + samlProviderArn: this.samlProvider.samlProviderArn, + selfServiceSamlProviderArn: this.selfServiceSamlProvider?.samlProviderArn, + }, + }; + } +} + +/** + * Properties for a client VPN endpoint + */ +export interface ClientVpnEndpointProps extends ClientVpnEndpointOptions { + /** + * The VPC to connect to. + */ + readonly vpc: IVpc; +} + +/** + * Attributes when importing an existing client VPN endpoint + */ +export interface ClientVpnEndpointAttributes { + /** + * The endpoint ID + */ + readonly endpointId: string; + + /** + * The security groups associated with the endpoint + */ + readonly securityGroups: ISecurityGroup[]; +} + +/** + * A client VPN connnection + */ +export class ClientVpnEndpoint extends Resource implements IClientVpnEndpoint { + /** + * Import an existing client VPN endpoint + */ + public static fromEndpointAttributes(scope: Construct, id: string, attrs: ClientVpnEndpointAttributes): IClientVpnEndpoint { + class Import extends Resource implements IClientVpnEndpoint { + public readonly endpointId = attrs.endpointId; + public readonly connections = new Connections({ securityGroups: attrs.securityGroups }); + public readonly targetNetworksAssociated: IDependable = new ConcreteDependable(); + } + return new Import(scope, id); + } + + public readonly endpointId: string; + + /** + * Allows specify security group connections for the endpoint. + */ + public readonly connections: Connections; + + public readonly targetNetworksAssociated: IDependable; + + private readonly _targetNetworksAssociated = new ConcreteDependable(); + + constructor(scope: Construct, id: string, props: ClientVpnEndpointProps) { + super(scope, id); + + if (!Token.isUnresolved(props.vpc.vpcCidrBlock)) { + const clientCidr = new CidrBlock(props.cidr); + const vpcCidr = new CidrBlock(props.vpc.vpcCidrBlock); + if (vpcCidr.containsCidr(clientCidr)) { + throw new Error('The client CIDR cannot overlap with the local CIDR of the VPC'); + } + } + + if (props.dnsServers && props.dnsServers.length > 2) { + throw new Error('A client VPN endpoint can have up to two DNS servers'); + } + + if (props.logging == false && (props.logGroup || props.logStream)) { + throw new Error('Cannot specify `logGroup` or `logStream` when logging is disabled'); + } + + if (props.clientConnectionHandler + && !Token.isUnresolved(props.clientConnectionHandler.functionName) + && !props.clientConnectionHandler.functionName.startsWith('AWSClientVPN-')) { + throw new Error('The name of the Lambda function must begin with the `AWSClientVPN-` prefix'); + } + + const logging = props.logging ?? true; + const logGroup = logging + ? props.logGroup ?? new logs.LogGroup(this, 'LogGroup') + : undefined; + + const securityGroups = props.securityGroups ?? [new SecurityGroup(this, 'SecurityGroup', { + vpc: props.vpc, + })]; + this.connections = new Connections({ securityGroups }); + + const endpoint = new CfnClientVpnEndpoint(this, 'Resource', { + authenticationOptions: renderAuthenticationOptions(props.clientCertificateArn, props.userBasedAuthentication), + clientCidrBlock: props.cidr, + clientConnectOptions: props.clientConnectionHandler + ? { + enabled: true, + lambdaFunctionArn: props.clientConnectionHandler.functionArn, + } + : undefined, + connectionLogOptions: { + enabled: logging, + cloudwatchLogGroup: logGroup?.logGroupName, + cloudwatchLogStream: props.logStream?.logStreamName, + }, + description: props.description, + dnsServers: props.dnsServers, + securityGroupIds: securityGroups.map(s => s.securityGroupId), + selfServicePortal: booleanToEnabledDisabled(props.selfServicePortal), + serverCertificateArn: props.serverCertificateArn, + splitTunnel: props.splitTunnel, + transportProtocol: props.transportProtocol, + vpcId: props.vpc.vpcId, + vpnPort: props.port, + }); + + this.endpointId = endpoint.ref; + + if (props.userBasedAuthentication && (props.selfServicePortal ?? true)) { + // Output self-service portal URL + new CfnOutput(this, 'SelfServicePortalUrl', { + value: `https://self-service.clientvpn.amazonaws.com/endpoints/${this.endpointId}`, + }); + } + + // Associate subnets + const subnetIds = props.vpc.selectSubnets(props.vpcSubnets).subnetIds; + + if (Token.isUnresolved(subnetIds)) { + throw new Error('Cannot associate subnets when VPC are imported from parameters or exports containing lists of subnet IDs.'); + } + + for (const [idx, subnetId] of Object.entries(subnetIds)) { + this._targetNetworksAssociated.add(new CfnClientVpnTargetNetworkAssociation(this, `Association${idx}`, { + clientVpnEndpointId: this.endpointId, + subnetId, + })); + } + this.targetNetworksAssociated = this._targetNetworksAssociated; + + if (props.authorizeAllUsersToVpcCidr ?? true) { + this.addAuthorizationRule('AuthorizeAll', { + cidr: props.vpc.vpcCidrBlock, + }); + } + } + + /** + * Adds an authorization rule to this endpoint + */ + public addAuthorizationRule(id: string, props: ClientVpnAuthorizationRuleOptions): ClientVpnAuthorizationRule { + return new ClientVpnAuthorizationRule(this, id, { + ...props, + clientVpnEndoint: this, + }); + } + + /** + * Adds a route to this endpoint + */ + public addRoute(id: string, props: ClientVpnRouteOptions): ClientVpnRoute { + return new ClientVpnRoute(this, id, { + ...props, + clientVpnEndoint: this, + }); + } +} + +function renderAuthenticationOptions( + clientCertificateArn?: string, + userBasedAuthentication?: ClientVpnUserBasedAuthentication): CfnClientVpnEndpoint.ClientAuthenticationRequestProperty[] { + const authenticationOptions: CfnClientVpnEndpoint.ClientAuthenticationRequestProperty[] = []; + + if (clientCertificateArn) { + authenticationOptions.push({ + type: 'certificate-authentication', + mutualAuthentication: { + clientRootCertificateChainArn: clientCertificateArn, + }, + }); + } + + if (userBasedAuthentication) { + authenticationOptions.push(userBasedAuthentication.render()); + } + + if (authenticationOptions.length === 0) { + throw new Error('A client VPN endpoint must use at least one authentication option'); + } + return authenticationOptions; +} + +function booleanToEnabledDisabled(val?: boolean): 'enabled' | 'disabled' | undefined { + switch (val) { + case undefined: + return undefined; + case true: + return 'enabled'; + case false: + return 'disabled'; + } +} diff --git a/packages/@aws-cdk/aws-ec2/lib/client-vpn-route.ts b/packages/@aws-cdk/aws-ec2/lib/client-vpn-route.ts new file mode 100644 index 0000000000000..38734631a5d91 --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/lib/client-vpn-route.ts @@ -0,0 +1,88 @@ +import { Resource } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import { IClientVpnEndpoint } from './client-vpn-endpoint-types'; +import { CfnClientVpnRoute } from './ec2.generated'; +import { ISubnet } from './vpc'; + +/** + * Options for a ClientVpnRoute + */ +export interface ClientVpnRouteOptions { + /** + * The IPv4 address range, in CIDR notation, of the route destination. + * + * For example: + * - To add a route for Internet access, enter 0.0.0.0/0 + * - To add a route for a peered VPC, enter the peered VPC's IPv4 CIDR range + * - To add a route for an on-premises network, enter the AWS Site-to-Site VPN + * connection's IPv4 CIDR range + * - To add a route for the local network, enter the client CIDR range + */ + readonly cidr: string; + + /** + * A brief description of the authorization rule. + * + * @default - no description + */ + readonly description?: string; + + /** + * The target for the route + */ + readonly target: ClientVpnRouteTarget; +} + +/** + * Target for a client VPN route + */ +export abstract class ClientVpnRouteTarget { + /** + * Subnet + * + * The specified subnet must be an existing target network of the client VPN + * endpoint. + */ + public static subnet(subnet: ISubnet): ClientVpnRouteTarget { + return { subnetId: subnet.subnetId }; + } + + /** + * Local network + */ + public static local(): ClientVpnRouteTarget { + return { subnetId: 'local' }; + } + + /** The subnet ID */ + public abstract readonly subnetId: string; +} + +/** + * Properties for a ClientVpnRoute + */ +export interface ClientVpnRouteProps extends ClientVpnRouteOptions { + /** + * The client VPN endpoint to which to add the route. + */ + readonly clientVpnEndoint: IClientVpnEndpoint; +} + +/** + * A client VPN route + */ +export class ClientVpnRoute extends Resource { + constructor(scope: Construct, id: string, props: ClientVpnRouteProps) { + super(scope, id); + + const route = new CfnClientVpnRoute(this, 'Resource', { + clientVpnEndpointId: props.clientVpnEndoint.endpointId, + description: props.description, + destinationCidrBlock: props.cidr, + targetVpcSubnetId: props.target.subnetId, + }); + + // See https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-clientvpnroute.html + route.node.addDependency(props.clientVpnEndoint.targetNetworksAssociated); + } +} diff --git a/packages/@aws-cdk/aws-ec2/lib/index.ts b/packages/@aws-cdk/aws-ec2/lib/index.ts index 9f70a4320060d..1b10e6fa1d566 100644 --- a/packages/@aws-cdk/aws-ec2/lib/index.ts +++ b/packages/@aws-cdk/aws-ec2/lib/index.ts @@ -22,6 +22,10 @@ export * from './vpc-endpoint-service'; export * from './user-data'; export * from './windows-versions'; export * from './vpc-flow-logs'; +export * from './client-vpn-endpoint-types'; +export * from './client-vpn-endpoint'; +export * from './client-vpn-authorization-rule'; +export * from './client-vpn-route'; // AWS::EC2 CloudFormation Resources: export * from './ec2.generated'; diff --git a/packages/@aws-cdk/aws-ec2/lib/instance-types.ts b/packages/@aws-cdk/aws-ec2/lib/instance-types.ts index c9a7f8ac74509..fc3b3b411d7b3 100644 --- a/packages/@aws-cdk/aws-ec2/lib/instance-types.ts +++ b/packages/@aws-cdk/aws-ec2/lib/instance-types.ts @@ -141,12 +141,12 @@ export enum InstanceClass { /** * Memory optimized instances based on AMD EPYC with local NVME drive, 5th generation */ - MEMORY5_AMD_NVME_DRIVE = 'r5a', + MEMORY5_AMD_NVME_DRIVE = 'r5ad', /** * Memory optimized instances based on AMD EPYC with local NVME drive, 5th generation */ - R5AD = 'r5a', + R5AD = 'r5ad', /** * Memory optimized instances that are also EBS-optimized, 5th generation diff --git a/packages/@aws-cdk/aws-ec2/lib/nat.ts b/packages/@aws-cdk/aws-ec2/lib/nat.ts index bf65671b92287..e991e732f38b0 100644 --- a/packages/@aws-cdk/aws-ec2/lib/nat.ts +++ b/packages/@aws-cdk/aws-ec2/lib/nat.ts @@ -1,4 +1,5 @@ import * as iam from '@aws-cdk/aws-iam'; +import { Fn, Token } from '@aws-cdk/core'; import { Connections, IConnectable } from './connections'; import { Instance } from './instance'; import { InstanceType } from './instance-types'; @@ -49,7 +50,7 @@ export interface GatewayConfig { * Determines what type of NAT provider to create, either NAT gateways or NAT * instance. * - * @experimental + * */ export abstract class NatProvider { /** @@ -59,8 +60,8 @@ export abstract class NatProvider { * * @see https://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat-gateway.html */ - public static gateway(): NatProvider { - return new NatGatewayProvider(); + public static gateway(props: NatGatewayProps = {}): NatProvider { + return new NatGatewayProvider(props); } /** @@ -101,7 +102,7 @@ export abstract class NatProvider { /** * Options passed by the VPC when NAT needs to be configured * - * @experimental + * */ export interface ConfigureNatOptions { /** @@ -122,10 +123,23 @@ export interface ConfigureNatOptions { readonly privateSubnets: PrivateSubnet[]; } +/** + * Properties for a NAT gateway + * + */ +export interface NatGatewayProps { + /** + * EIP allocation IDs for the NAT gateways + * + * @default - No fixed EIPs allocated for the NAT gateways + */ + readonly eipAllocationIds?: string[]; +} + /** * Properties for a NAT instance * - * @experimental + * */ export interface NatInstanceProps { /** @@ -203,11 +217,20 @@ export interface NatInstanceProps { class NatGatewayProvider extends NatProvider { private gateways: PrefSet = new PrefSet(); + constructor(private readonly props: NatGatewayProps = {}) { + super(); + } + public configureNat(options: ConfigureNatOptions) { // Create the NAT gateways + let i = 0; for (const sub of options.natSubnets) { const gateway = sub.addNatGateway(); + if (this.props.eipAllocationIds) { + gateway.allocationId = pickN(i, this.props.eipAllocationIds); + } this.gateways.add(sub.availabilityZone, gateway.ref); + i++; } // Add routes to them in the private subnets @@ -359,7 +382,7 @@ class PrefSet { /** * Machine image representing the latest NAT instance image * - * @experimental + * */ export class NatInstanceImage extends LookupMachineImage { constructor() { @@ -377,4 +400,17 @@ function isOutboundAllowed(direction: NatTrafficDirection) { function isInboundAllowed(direction: NatTrafficDirection) { return direction === NatTrafficDirection.INBOUND_AND_OUTBOUND; +} + +/** + * Token-aware pick index function + */ +function pickN(i: number, xs: string[]) { + if (Token.isUnresolved(xs)) { return Fn.select(i, xs); } + + if (i >= xs.length) { + throw new Error(`Cannot get element ${i} from ${xs}`); + } + + return xs[i]; } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/lib/network-acl-types.ts b/packages/@aws-cdk/aws-ec2/lib/network-acl-types.ts index deb5c25e43fba..2a4b25d765188 100644 --- a/packages/@aws-cdk/aws-ec2/lib/network-acl-types.ts +++ b/packages/@aws-cdk/aws-ec2/lib/network-acl-types.ts @@ -1,7 +1,7 @@ /** * Either an IPv4 or an IPv6 CIDR * - * @experimental + * */ export abstract class AclCidr { /** @@ -52,7 +52,7 @@ class AclCidrImpl extends AclCidr { /** * Acl Configuration for CIDR * - * @experimental + * */ export interface AclCidrConfig { /** @@ -69,7 +69,7 @@ export interface AclCidrConfig { /** * The traffic that is configured using a Network ACL entry * - * @experimental + * */ export abstract class AclTraffic { /** @@ -171,7 +171,7 @@ class AclTrafficImpl extends AclTraffic { /** * Acl Configuration for traffic * - * @experimental + * */ export interface AclTrafficConfig { /** @@ -210,7 +210,7 @@ export interface AclTrafficConfig { /** * Properties to create Icmp * - * @experimental + * */ export interface AclIcmp { /** @@ -230,7 +230,7 @@ export interface AclIcmp { /** * Properties to create PortRange * - * @experimental + * */ export interface AclPortRange { /** diff --git a/packages/@aws-cdk/aws-ec2/lib/network-acl.ts b/packages/@aws-cdk/aws-ec2/lib/network-acl.ts index 911948e8df39c..a957c3f46e92c 100644 --- a/packages/@aws-cdk/aws-ec2/lib/network-acl.ts +++ b/packages/@aws-cdk/aws-ec2/lib/network-acl.ts @@ -7,7 +7,7 @@ import { ISubnet, IVpc, SubnetSelection } from './vpc'; /** * A NetworkAcl * - * @experimental + * */ export interface INetworkAcl extends IResource { /** @@ -25,7 +25,7 @@ export interface INetworkAcl extends IResource { /** * A NetworkAclBase that is not created in this template * - * @experimental + * */ abstract class NetworkAclBase extends Resource implements INetworkAcl { public abstract readonly networkAclId: string; @@ -45,7 +45,7 @@ abstract class NetworkAclBase extends Resource implements INetworkAcl { /** * Properties to create NetworkAcl * - * @experimental + * */ export interface NetworkAclProps { /** @@ -80,7 +80,7 @@ export interface NetworkAclProps { * By default, will deny all inbound and outbound traffic unless entries are * added explicitly allowing it. * - * @experimental + * */ export class NetworkAcl extends NetworkAclBase { /** @@ -144,7 +144,7 @@ export class NetworkAcl extends NetworkAclBase { /** * What action to apply to traffic matching the ACL * - * @experimental + * */ export enum Action { /** @@ -161,7 +161,7 @@ export enum Action { /** * A NetworkAclEntry * - * @experimental + * */ export interface INetworkAclEntry extends IResource { /** @@ -174,7 +174,7 @@ export interface INetworkAclEntry extends IResource { /** * Base class for NetworkAclEntries * - * @experimental + * */ abstract class NetworkAclEntryBase extends Resource implements INetworkAclEntry { public abstract readonly networkAcl: INetworkAcl; @@ -183,7 +183,7 @@ abstract class NetworkAclEntryBase extends Resource implements INetworkAclEntry /** * Direction of traffic the AclEntry applies to * - * @experimental + * */ export enum TrafficDirection { /** @@ -200,7 +200,7 @@ export enum TrafficDirection { /** * Basic NetworkACL entry props * - * @experimental + * */ export interface CommonNetworkAclEntryOptions { /** @@ -250,7 +250,7 @@ export interface CommonNetworkAclEntryOptions { /** * Properties to create NetworkAclEntry * - * @experimental + * */ export interface NetworkAclEntryProps extends CommonNetworkAclEntryOptions { /** @@ -262,7 +262,7 @@ export interface NetworkAclEntryProps extends CommonNetworkAclEntryOptions { /** * Define an entry in a Network ACL table * - * @experimental + * */ export class NetworkAclEntry extends NetworkAclEntryBase { public readonly networkAcl: INetworkAcl; @@ -288,7 +288,7 @@ export class NetworkAclEntry extends NetworkAclEntryBase { /** * A SubnetNetworkAclAssociation * - * @experimental + * */ export interface ISubnetNetworkAclAssociation extends IResource { /** @@ -301,7 +301,7 @@ export interface ISubnetNetworkAclAssociation extends IResource { /** * Properties to create a SubnetNetworkAclAssociation * - * @experimental + * */ export interface SubnetNetworkAclAssociationProps { /** @@ -331,7 +331,7 @@ export interface SubnetNetworkAclAssociationProps { /** * Associate a network ACL with a subnet * - * @experimental + * */ abstract class SubnetNetworkAclAssociationBase extends Resource implements ISubnetNetworkAclAssociation { public abstract readonly subnetNetworkAclAssociationAssociationId: string; diff --git a/packages/@aws-cdk/aws-ec2/lib/peer.ts b/packages/@aws-cdk/aws-ec2/lib/peer.ts index 7bd343b6f2828..333bd66bc91a9 100644 --- a/packages/@aws-cdk/aws-ec2/lib/peer.ts +++ b/packages/@aws-cdk/aws-ec2/lib/peer.ts @@ -198,4 +198,4 @@ class PrefixList implements IPeer { public toEgressRuleConfig(): any { return { destinationPrefixListId: this.prefixListId }; } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-ec2/lib/security-group.ts b/packages/@aws-cdk/aws-ec2/lib/security-group.ts index b5c3e4bf5cff2..c56a6b9dd34d1 100644 --- a/packages/@aws-cdk/aws-ec2/lib/security-group.ts +++ b/packages/@aws-cdk/aws-ec2/lib/security-group.ts @@ -4,12 +4,14 @@ import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; import { Connections } from './connections'; import { CfnSecurityGroup, CfnSecurityGroupEgress, CfnSecurityGroupIngress } from './ec2.generated'; -import { IPeer } from './peer'; +import { IPeer, Peer } from './peer'; import { Port } from './port'; import { IVpc } from './vpc'; const SECURITY_GROUP_SYMBOL = Symbol.for('@aws-cdk/iam.SecurityGroup'); +const SECURITY_GROUP_DISABLE_INLINE_RULES_CONTEXT_KEY = '@aws-cdk/aws-ec2.securityGroupDisableInlineRules'; + /** * Interface for security group-like objects */ @@ -229,6 +231,22 @@ export interface SecurityGroupProps { * @default true */ readonly allowAllOutbound?: boolean; + + /** + * Whether to disable inline ingress and egress rule optimization. + * + * If this is set to true, ingress and egress rules will not be declared under the + * SecurityGroup in cloudformation, but will be separate elements. + * + * Inlining rules is an optimization for producing smaller stack templates. Sometimes + * this is not desirable, for example when security group access is managed via tags. + * + * The default value can be overriden globally by setting the context variable + * '@aws-cdk/aws-ec2.securityGroupDisableInlineRules'. + * + * @default false + */ + readonly disableInlineRules?: boolean; } /** @@ -242,7 +260,7 @@ export interface SecurityGroupImportOptions { * group. Be aware, this would undo any potential "all outbound traffic" * default. * - * @experimental + * * @default true */ readonly allowAllOutbound?: boolean; @@ -253,7 +271,7 @@ export interface SecurityGroupImportOptions { * Beware that making a SecurityGroup immutable might lead to issue * due to missing ingress/egress rules for new resources. * - * @experimental + * * @default true */ readonly mutable?: boolean; @@ -390,6 +408,11 @@ export class SecurityGroup extends SecurityGroupBase { private readonly directIngressRules: CfnSecurityGroup.IngressProperty[] = []; private readonly directEgressRules: CfnSecurityGroup.EgressProperty[] = []; + /** + * Whether to disable optimization for inline security group rules. + */ + private readonly disableInlineRules: boolean; + constructor(scope: Construct, id: string, props: SecurityGroupProps) { super(scope, id, { physicalName: props.securityGroupName, @@ -399,6 +422,10 @@ export class SecurityGroup extends SecurityGroupBase { this.allowAllOutbound = props.allowAllOutbound !== false; + this.disableInlineRules = props.disableInlineRules !== undefined ? + !!props.disableInlineRules : + !!this.node.tryGetContext(SECURITY_GROUP_DISABLE_INLINE_RULES_CONTEXT_KEY); + this.securityGroup = new CfnSecurityGroup(this, 'Resource', { groupName: this.physicalName, groupDescription, @@ -415,7 +442,7 @@ export class SecurityGroup extends SecurityGroupBase { } public addIngressRule(peer: IPeer, connection: Port, description?: string, remoteRule?: boolean) { - if (!peer.canInlineRule || !connection.canInlineRule) { + if (!peer.canInlineRule || !connection.canInlineRule || this.disableInlineRules) { super.addIngressRule(peer, connection, description, remoteRule); return; } @@ -445,7 +472,7 @@ export class SecurityGroup extends SecurityGroupBase { this.removeNoTrafficRule(); } - if (!peer.canInlineRule || !connection.canInlineRule) { + if (!peer.canInlineRule || !connection.canInlineRule || this.disableInlineRules) { super.addEgressRule(peer, connection, description, remoteRule); return; } @@ -519,10 +546,14 @@ export class SecurityGroup extends SecurityGroupBase { * strictly necessary). */ private addDefaultEgressRule() { - if (this.allowAllOutbound) { - this.directEgressRules.push(ALLOW_ALL_RULE); + if (this.disableInlineRules) { + const peer = this.allowAllOutbound ? ALL_TRAFFIC_PEER : NO_TRAFFIC_PEER; + const port = this.allowAllOutbound ? ALL_TRAFFIC_PORT : NO_TRAFFIC_PORT; + const description = this.allowAllOutbound ? ALLOW_ALL_RULE.description : MATCH_NO_TRAFFIC.description; + super.addEgressRule(peer, port, description, false); } else { - this.directEgressRules.push(MATCH_NO_TRAFFIC); + const rule = this.allowAllOutbound? ALLOW_ALL_RULE : MATCH_NO_TRAFFIC; + this.directEgressRules.push(rule); } } @@ -530,9 +561,20 @@ export class SecurityGroup extends SecurityGroupBase { * Remove the bogus rule if it exists */ private removeNoTrafficRule() { - const i = this.directEgressRules.findIndex(r => egressRulesEqual(r, MATCH_NO_TRAFFIC)); - if (i > -1) { - this.directEgressRules.splice(i, 1); + if (this.disableInlineRules) { + const [scope, id] = determineRuleScope( + this, + NO_TRAFFIC_PEER, + NO_TRAFFIC_PORT, + 'to', + false); + + scope.node.tryRemoveChild(id); + } else { + const i = this.directEgressRules.findIndex(r => egressRulesEqual(r, MATCH_NO_TRAFFIC)); + if (i > -1) { + this.directEgressRules.splice(i, 1); + } } } } @@ -554,6 +596,9 @@ const MATCH_NO_TRAFFIC = { toPort: 86, }; +const NO_TRAFFIC_PEER = Peer.ipv4(MATCH_NO_TRAFFIC.cidrIp); +const NO_TRAFFIC_PORT = Port.icmpTypeAndCode(MATCH_NO_TRAFFIC.fromPort, MATCH_NO_TRAFFIC.toPort); + /** * Egress rule that matches all traffic */ @@ -563,6 +608,9 @@ const ALLOW_ALL_RULE = { ipProtocol: '-1', }; +const ALL_TRAFFIC_PEER = Peer.anyIpv4(); +const ALL_TRAFFIC_PORT = Port.allTraffic(); + export interface ConnectionRule { /** * The IP protocol name (tcp, udp, icmp) or number (see Protocol Numbers). diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc-endpoint-service.ts b/packages/@aws-cdk/aws-ec2/lib/vpc-endpoint-service.ts index 87f67391f8c9b..ffd90a32df56b 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc-endpoint-service.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc-endpoint-service.ts @@ -17,7 +17,7 @@ export interface IVpcEndpointServiceLoadBalancer { /** * A VPC endpoint service. - * @experimental + * */ export interface IVpcEndpointService extends IResource { /** @@ -40,7 +40,7 @@ export interface IVpcEndpointService extends IResource { /** * A VPC endpoint service * @resource AWS::EC2::VPCEndpointService - * @experimental + * */ export class VpcEndpointService extends Resource implements IVpcEndpointService { @@ -52,16 +52,22 @@ export class VpcEndpointService extends Resource implements IVpcEndpointService /** * Whether to require manual acceptance of new connections to the service. - * @experimental + * */ public readonly acceptanceRequired: boolean; /** * One or more Principal ARNs to allow inbound connections to. - * @experimental + * @deprecated use `allowedPrincipals` */ public readonly whitelistedPrincipals: ArnPrincipal[]; + /** + * One or more Principal ARNs to allow inbound connections to. + * + */ + public readonly allowedPrincipals: ArnPrincipal[]; + /** * The id of the VPC Endpoint Service, like vpce-svc-xxxxxxxxxxxxxxxx. * @attribute @@ -87,7 +93,12 @@ export class VpcEndpointService extends Resource implements IVpcEndpointService this.vpcEndpointServiceLoadBalancers = props.vpcEndpointServiceLoadBalancers; this.acceptanceRequired = props.acceptanceRequired ?? true; - this.whitelistedPrincipals = props.whitelistedPrincipals ?? []; + + if (props.allowedPrincipals && props.whitelistedPrincipals) { + throw new Error('`whitelistedPrincipals` is deprecated; please use `allowedPrincipals` instead'); + } + this.allowedPrincipals = props.allowedPrincipals ?? props.whitelistedPrincipals ?? []; + this.whitelistedPrincipals = this.allowedPrincipals; this.endpointService = new CfnVPCEndpointService(this, id, { networkLoadBalancerArns: this.vpcEndpointServiceLoadBalancers.map(lb => lb.loadBalancerArn), @@ -102,10 +113,10 @@ export class VpcEndpointService extends Resource implements IVpcEndpointService Default.VPC_ENDPOINT_SERVICE_NAME_PREFIX; this.vpcEndpointServiceName = Fn.join('.', [serviceNamePrefix, Aws.REGION, this.vpcEndpointServiceId]); - if (this.whitelistedPrincipals.length > 0) { + if (this.allowedPrincipals.length > 0) { new CfnVPCEndpointServicePermissions(this, 'Permissions', { serviceId: this.endpointService.ref, - allowedPrincipals: this.whitelistedPrincipals.map(x => x.arn), + allowedPrincipals: this.allowedPrincipals.map(x => x.arn), }); } } @@ -113,7 +124,7 @@ export class VpcEndpointService extends Resource implements IVpcEndpointService /** * Construction properties for a VpcEndpointService. - * @experimental + * */ export interface VpcEndpointServiceProps { @@ -126,7 +137,7 @@ export interface VpcEndpointServiceProps { /** * One or more load balancers to host the VPC Endpoint Service. - * @experimental + * */ readonly vpcEndpointServiceLoadBalancers: IVpcEndpointServiceLoadBalancer[]; @@ -134,7 +145,7 @@ export interface VpcEndpointServiceProps { * Whether requests from service consumers to connect to the service through * an endpoint must be accepted. * @default true - * @experimental + * */ readonly acceptanceRequired?: boolean; @@ -143,7 +154,16 @@ export interface VpcEndpointServiceProps { * These principals can connect to your service using VPC endpoints. Takes a * list of one or more ArnPrincipal. * @default - no principals - * @experimental + * @deprecated use `allowedPrincipals` */ readonly whitelistedPrincipals?: ArnPrincipal[]; + + /** + * IAM users, IAM roles, or AWS accounts to allow inbound connections from. + * These principals can connect to your service using VPC endpoints. Takes a + * list of one or more ArnPrincipal. + * @default - no principals + * + */ + readonly allowedPrincipals?: ArnPrincipal[]; } diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc-flow-logs.ts b/packages/@aws-cdk/aws-ec2/lib/vpc-flow-logs.ts index 498940fab878a..fdc4a06ad2227 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc-flow-logs.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc-flow-logs.ts @@ -13,7 +13,7 @@ import { Construct as CoreConstruct } from '@aws-cdk/core'; /** * A FlowLog * - * @experimental + * */ export interface IFlowLog extends IResource { /** @@ -27,7 +27,7 @@ export interface IFlowLog extends IResource { /** * The type of VPC traffic to log * - * @experimental + * */ export enum FlowLogTrafficType { /** @@ -48,7 +48,7 @@ export enum FlowLogTrafficType { /** * The available destination types for Flow Logs - * @experimental + * */ export enum FlowLogDestinationType { /** @@ -65,7 +65,7 @@ export enum FlowLogDestinationType { /** * The type of resource to create the flow log for * - * @experimental + * */ export abstract class FlowLogResourceType { /** @@ -112,7 +112,7 @@ export abstract class FlowLogResourceType { /** * The destination type for the flow log * - * @experimental + * */ export abstract class FlowLogDestination { /** @@ -146,7 +146,7 @@ export abstract class FlowLogDestination { /** * Flow Log Destination configuration * - * @experimental + * */ export interface FlowLogDestinationConfig { /** @@ -186,7 +186,7 @@ export interface FlowLogDestinationConfig { } /** - * @experimental + * */ class S3Destination extends FlowLogDestination { constructor(private readonly props: FlowLogDestinationConfig) { @@ -212,7 +212,7 @@ class S3Destination extends FlowLogDestination { } /** - * @experimental + * */ class CloudWatchLogsDestination extends FlowLogDestination { constructor(private readonly props: FlowLogDestinationConfig) { @@ -268,7 +268,7 @@ class CloudWatchLogsDestination extends FlowLogDestination { /** * Options to add a flow log to a VPC * - * @experimental + * */ export interface FlowLogOptions { /** @@ -290,7 +290,7 @@ export interface FlowLogOptions { /** * Properties of a VPC Flow Log * - * @experimental + * */ export interface FlowLogProps extends FlowLogOptions { /** @@ -312,7 +312,7 @@ export interface FlowLogProps extends FlowLogOptions { /** * The base class for a Flow Log * - * @experimental + * */ abstract class FlowLogBase extends Resource implements IFlowLog { /** @@ -327,7 +327,7 @@ abstract class FlowLogBase extends Resource implements IFlowLog { * A VPC flow log. * @resource AWS::EC2::FlowLog * - * @experimental + * */ export class FlowLog extends FlowLogBase { /** diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index 8d878dde26024..1fe534df6c483 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -5,6 +5,7 @@ import { } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { Construct, Node } from 'constructs'; +import { ClientVpnEndpoint, ClientVpnEndpointOptions } from './client-vpn-endpoint'; import { CfnEIP, CfnInternetGateway, CfnNatGateway, CfnRoute, CfnRouteTable, CfnSubnet, CfnSubnetRouteTableAssociation, CfnVPC, CfnVPCGatewayAttachment, CfnVPNGatewayRoutePropagation, @@ -132,6 +133,11 @@ export interface IVpc extends IResource { */ addVpnConnection(id: string, options: VpnConnectionOptions): VpnConnection; + /** + * Adds a new client VPN endpoint to this VPC + */ + addClientVpnEndpoint(id: string, options: ClientVpnEndpointOptions): ClientVpnEndpoint; + /** * Adds a new gateway endpoint to this VPC */ @@ -421,6 +427,16 @@ abstract class VpcBase extends Resource implements IVpc { }); } + /** + * Adds a new client VPN endpoint to this VPC + */ + public addClientVpnEndpoint(id: string, options: ClientVpnEndpointOptions): ClientVpnEndpoint { + return new ClientVpnEndpoint(this, id, { + ...options, + vpc: this, + }); + } + /** * Adds a new interface endpoint to this VPC */ @@ -799,7 +815,7 @@ export interface VpcProps { * may not be available in all AWS regions. * * @default NatProvider.gateway() - * @experimental + * */ readonly natGatewayProvider?: NatProvider; diff --git a/packages/@aws-cdk/aws-ec2/package.json b/packages/@aws-cdk/aws-ec2/package.json index e454bface8c4a..5b6e630634d10 100644 --- a/packages/@aws-cdk/aws-ec2/package.json +++ b/packages/@aws-cdk/aws-ec2/package.json @@ -71,14 +71,16 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/aws-lambda": "^8.10.76", + "@types/jest": "^26.0.23", "@aws-cdk/cx-api": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "nodeunit-shim": "0.0.0", "pkglint": "0.0.0", - "@aws-cdk/cloud-assembly-schema": "0.0.0" + "@aws-cdk/cloud-assembly-schema": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", @@ -92,7 +94,7 @@ "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/region-info": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -107,7 +109,7 @@ "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/region-info": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" @@ -636,7 +638,10 @@ "docs-public-apis:@aws-cdk/aws-ec2.WindowsVersion.WINDOWS_SERVER_2008_R2_SP1_PORTUGUESE_BRAZIL_64BIT_BASE", "props-default-doc:@aws-cdk/aws-ec2.InterfaceVpcEndpointAttributes.securityGroupId", "props-default-doc:@aws-cdk/aws-ec2.InterfaceVpcEndpointAttributes.securityGroups", - "props-physical-name:@aws-cdk/aws-ec2.VpnGatewayProps" + "props-physical-name:@aws-cdk/aws-ec2.VpnGatewayProps", + "props-physical-name:@aws-cdk/aws-ec2.ClientVpnEndpointProps", + "props-physical-name:@aws-cdk/aws-ec2.ClientVpnAuthorizationRuleProps", + "props-physical-name:@aws-cdk/aws-ec2.ClientVpnRouteProps" ] }, "stability": "stable", diff --git a/packages/@aws-cdk/aws-ec2/rosetta/client-vpn.ts-fixture b/packages/@aws-cdk/aws-ec2/rosetta/client-vpn.ts-fixture new file mode 100644 index 0000000000000..4886d590211df --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/rosetta/client-vpn.ts-fixture @@ -0,0 +1,17 @@ +// Fixture with packages imported and a VPC created +import { Construct, Stack } from '@aws-cdk/core'; +import iam = require('@aws-cdk/aws-iam'); +import ec2 = require('@aws-cdk/aws-ec2'); + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + const vpc = new ec2.Vpc(this, 'VPC'); + const samlProvider = new iam.SamlProvider(this, 'Provider', { + metadataDocument: SamlMetadataDocument.fromXml('xml'), + }) + + /// here + } +} diff --git a/packages/@aws-cdk/aws-ec2/test/bastion-host.test.ts b/packages/@aws-cdk/aws-ec2/test/bastion-host.test.ts index 6c547d7859c1a..f774cf9aaa3d8 100644 --- a/packages/@aws-cdk/aws-ec2/test/bastion-host.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/bastion-host.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import { Stack } from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import { BastionHostLinux, BlockDeviceVolume, InstanceClass, InstanceSize, InstanceType, SubnetType, Vpc } from '../lib'; diff --git a/packages/@aws-cdk/aws-ec2/test/cfn-init.test.ts b/packages/@aws-cdk/aws-ec2/test/cfn-init.test.ts index 3b4fbb779a36d..61ed0e53fa887 100644 --- a/packages/@aws-cdk/aws-ec2/test/cfn-init.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/cfn-init.test.ts @@ -1,8 +1,8 @@ import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; -import { arrayWith, ResourcePart, stringLike } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { arrayWith, ResourcePart, stringLike } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as iam from '@aws-cdk/aws-iam'; import * as s3 from '@aws-cdk/aws-s3'; import { Asset } from '@aws-cdk/aws-s3-assets'; diff --git a/packages/@aws-cdk/aws-ec2/test/client-vpn-endpoint.test.ts b/packages/@aws-cdk/aws-ec2/test/client-vpn-endpoint.test.ts new file mode 100644 index 0000000000000..bd52982d76fd6 --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/test/client-vpn-endpoint.test.ts @@ -0,0 +1,271 @@ +import { ResourcePart } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import { SamlMetadataDocument, SamlProvider } from '@aws-cdk/aws-iam'; +import * as logs from '@aws-cdk/aws-logs'; +import { Stack } from '@aws-cdk/core'; +import * as ec2 from '../lib'; +import { ClientVpnUserBasedAuthentication } from '../lib/client-vpn-endpoint'; + +let stack: Stack; +let vpc: ec2.IVpc; +beforeEach(() => { + stack = new Stack(); + vpc = new ec2.Vpc(stack, 'Vpc'); +}); + +test('client vpn endpoint', () => { + const samlProvider = new SamlProvider(stack, 'Provider', { + metadataDocument: SamlMetadataDocument.fromXml('xml'), + }); + + vpc.addClientVpnEndpoint('Endpoint', { + cidr: '10.100.0.0/16', + serverCertificateArn: 'server-certificate-arn', + clientCertificateArn: 'client-certificate-arn', + clientConnectionHandler: { functionArn: 'function-arn', functionName: 'AWSClientVPN-function-name' }, + dnsServers: ['8.8.8.8', '8.8.4.4'], + userBasedAuthentication: ClientVpnUserBasedAuthentication.federated(samlProvider), + }); + + expect(stack).toHaveResource('AWS::EC2::ClientVpnEndpoint', { + AuthenticationOptions: [ + { + MutualAuthentication: { + ClientRootCertificateChainArn: 'client-certificate-arn', + }, + Type: 'certificate-authentication', + }, + { + FederatedAuthentication: { + SAMLProviderArn: { + Ref: 'Provider2281708E', + }, + }, + Type: 'federated-authentication', + }, + ], + ClientCidrBlock: '10.100.0.0/16', + ConnectionLogOptions: { + CloudwatchLogGroup: { + Ref: 'VpcEndpointLogGroup96A18897', + }, + Enabled: true, + }, + ServerCertificateArn: 'server-certificate-arn', + ClientConnectOptions: { + Enabled: true, + LambdaFunctionArn: 'function-arn', + }, + DnsServers: [ + '8.8.8.8', + '8.8.4.4', + ], + SecurityGroupIds: [ + { + 'Fn::GetAtt': [ + 'VpcEndpointSecurityGroup7B25EFDC', + 'GroupId', + ], + }, + ], + VpcId: { + Ref: 'Vpc8378EB38', + }, + }); + + expect(stack).toCountResources('AWS::EC2::ClientVpnTargetNetworkAssociation', 2); + + expect(stack).toHaveResource('AWS::EC2::ClientVpnTargetNetworkAssociation', { + ClientVpnEndpointId: { + Ref: 'VpcEndpoint6FF034F6', + }, + SubnetId: { + Ref: 'VpcPrivateSubnet1Subnet536B997A', + }, + }); + + expect(stack).toHaveResource('AWS::EC2::ClientVpnTargetNetworkAssociation', { + ClientVpnEndpointId: { + Ref: 'VpcEndpoint6FF034F6', + }, + SubnetId: { + Ref: 'VpcPrivateSubnet2Subnet3788AAA1', + }, + }); + + expect(stack).toHaveOutput({ + outputName: 'VpcEndpointSelfServicePortalUrl760AFE23', + outputValue: { + 'Fn::Join': [ + '', + [ + 'https://self-service.clientvpn.amazonaws.com/endpoints/', + { + Ref: 'VpcEndpoint6FF034F6', + }, + ], + ], + }, + }); + + expect(stack).toHaveResource('AWS::EC2::ClientVpnAuthorizationRule', { + ClientVpnEndpointId: { + Ref: 'VpcEndpoint6FF034F6', + }, + TargetNetworkCidr: { + 'Fn::GetAtt': [ + 'Vpc8378EB38', + 'CidrBlock', + ], + }, + AuthorizeAllGroups: true, + }); +}); + +test('client vpn endpoint with custom security groups', () => { + vpc.addClientVpnEndpoint('Endpoint', { + cidr: '10.100.0.0/16', + serverCertificateArn: 'server-certificate-arn', + clientCertificateArn: 'client-certificate-arn', + securityGroups: [ + new ec2.SecurityGroup(stack, 'SG1', { vpc }), + new ec2.SecurityGroup(stack, 'SG2', { vpc }), + ], + }); + + expect(stack).toHaveResource('AWS::EC2::ClientVpnEndpoint', { + SecurityGroupIds: [ + { + 'Fn::GetAtt': [ + 'SG1BA065B6E', + 'GroupId', + ], + }, + { + 'Fn::GetAtt': [ + 'SG20CE3219C', + 'GroupId', + ], + }, + ], + }); +}); + +test('client vpn endpoint with custom logging', () => { + const logGroup = new logs.LogGroup(stack, 'LogGroup', { + retention: logs.RetentionDays.TWO_MONTHS, + }); + vpc.addClientVpnEndpoint('Endpoint', { + cidr: '10.100.0.0/16', + serverCertificateArn: 'server-certificate-arn', + clientCertificateArn: 'client-certificate-arn', + logGroup, + logStream: logGroup.addStream('LogStream'), + }); + + expect(stack).toHaveResource('AWS::EC2::ClientVpnEndpoint', { + ConnectionLogOptions: { + CloudwatchLogGroup: { + Ref: 'LogGroupF5B46931', + }, + CloudwatchLogStream: { + Ref: 'LogGroupLogStream245D76D6', + }, + Enabled: true, + }, + }); +}); + +test('client vpn endpoint with logging disabled', () => { + vpc.addClientVpnEndpoint('Endpoint', { + cidr: '10.100.0.0/16', + serverCertificateArn: 'server-certificate-arn', + clientCertificateArn: 'client-certificate-arn', + logging: false, + }); + + expect(stack).toHaveResource('AWS::EC2::ClientVpnEndpoint', { + ConnectionLogOptions: { + Enabled: false, + }, + }); +}); + +test('client vpn endpoint with custom authorization rules', () => { + const endpoint = vpc.addClientVpnEndpoint('Endpoint', { + cidr: '10.100.0.0/16', + serverCertificateArn: 'server-certificate-arn', + clientCertificateArn: 'client-certificate-arn', + authorizeAllUsersToVpcCidr: false, + }); + + endpoint.addAuthorizationRule('Rule', { + cidr: '10.0.10.0/32', + groupId: 'group-id', + }); + + expect(stack).toCountResources('AWS::EC2::ClientVpnAuthorizationRule', 1); + + expect(stack).toHaveResource('AWS::EC2::ClientVpnAuthorizationRule', { + ClientVpnEndpointId: { + Ref: 'VpcEndpoint6FF034F6', + }, + TargetNetworkCidr: '10.0.10.0/32', + AccessGroupId: 'group-id', + AuthorizeAllGroups: false, + }); +}); + +test('client vpn endpoint with custom route', () => { + const endpoint = vpc.addClientVpnEndpoint('Endpoint', { + cidr: '10.100.0.0/16', + serverCertificateArn: 'server-certificate-arn', + clientCertificateArn: 'client-certificate-arn', + authorizeAllUsersToVpcCidr: false, + }); + + endpoint.addRoute('Route', { + cidr: '10.100.0.0/16', + target: ec2.ClientVpnRouteTarget.local(), + }); + + expect(stack).toHaveResource('AWS::EC2::ClientVpnRoute', { + Properties: { + ClientVpnEndpointId: { + Ref: 'VpcEndpoint6FF034F6', + }, + DestinationCidrBlock: '10.100.0.0/16', + TargetVpcSubnetId: 'local', + }, + DependsOn: [ + 'VpcEndpointAssociation06B066321', + 'VpcEndpointAssociation12B51A67F', + ], + }, ResourcePart.CompleteDefinition); +}); + +test('throws with more than 2 dns servers', () => { + expect(() => vpc.addClientVpnEndpoint('Endpoint', { + cidr: '10.100.0.0/16', + serverCertificateArn: 'server-certificate-arn', + clientCertificateArn: 'client-certificate-arn', + dnsServers: ['1.1.1.1', '2.2.2.2', '3.3.3.3'], + })).toThrow(/A client VPN endpoint can have up to two DNS servers/); +}); + +test('throws when specifying logGroup with logging disabled', () => { + expect(() => vpc.addClientVpnEndpoint('Endpoint', { + cidr: '10.100.0.0/16', + serverCertificateArn: 'server-certificate-arn', + clientCertificateArn: 'client-certificate-arn', + logging: false, + logGroup: new logs.LogGroup(stack, 'LogGroup'), + })).toThrow(/Cannot specify `logGroup` or `logStream` when logging is disabled/); +}); + +test('throws without authentication options', () => { + expect(() => vpc.addClientVpnEndpoint('Endpoint', { + cidr: '10.100.0.0/16', + serverCertificateArn: 'server-certificate-arn', + })).toThrow(/A client VPN endpoint must use at least one authentication option/); +}); diff --git a/packages/@aws-cdk/aws-ec2/test/connections.test.ts b/packages/@aws-cdk/aws-ec2/test/connections.test.ts index 0c9ce25effd13..2adc0ce242db8 100644 --- a/packages/@aws-cdk/aws-ec2/test/connections.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/connections.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import { App, Stack } from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; diff --git a/packages/@aws-cdk/aws-ec2/test/import-certificates-handler/ca.crt b/packages/@aws-cdk/aws-ec2/test/import-certificates-handler/ca.crt new file mode 100644 index 0000000000000..0a6dbb2b76dc4 --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/test/import-certificates-handler/ca.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDSzCCAjOgAwIBAgIUb5Jgse1JNcl13gP/IFvfOWbm6z4wDQYJKoZIhvcNAQEL +BQAwFjEUMBIGA1UEAwwLRWFzeS1SU0EgQ0EwHhcNMjAxMjI1MjEwMTM5WhcNMzAx +MjIzMjEwMTM5WjAWMRQwEgYDVQQDDAtFYXN5LVJTQSBDQTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAOJ/zBeR69zOKbd8GJoL0W1C9gZbqUgykcDYwX03 +1rEhXZWlHQtdejsDgWweIeZjlxHWOSxOCGIjoQh5Syq3ssxNRWGyku2nGsLZHJLL +BAX4nKAmyN3q7EDtRR3t8rYu3x4+eJB0qlE7KNOJE0dyxVwDlW0c5rbccXZXSRU4 +aTWBBkHPM+zswOWQDD2oZm0hAx+8IsjQHPS1omsHaC8jXKADk+ssKO2oom8vMzkE +w7Oeo6ZOGxz8FdDsZo3BpeouW5Wrp92ZvuH1SHZ7RbYGmWEBwDKRO0b+HmRFXiVc +BR1almVY+9clMEKHTpHRKfzw3pBT5bwSA7ndOSu5og3HzdECAwEAAaOBkDCBjTAd +BgNVHQ4EFgQUXmyUf1TxXzxwRV9wnb88M/P+yLIwUQYDVR0jBEowSIAUXmyUf1Tx +XzxwRV9wnb88M/P+yLKhGqQYMBYxFDASBgNVBAMMC0Vhc3ktUlNBIENBghRvkmCx +7Uk1yXXeA/8gW985ZubrPjAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjANBgkq +hkiG9w0BAQsFAAOCAQEAvDHUc5+xIWkuNBJXeR1e18SRuddgTejvc01AMe+H4Oz9 +y8R4/Jv4fYDGRAnWGVFowuwNj6FGdlf1MXOPl0Ukv9pv1svgHW+XlXEU8uwX7J9H +bG6NEuHVfdyfaiDw3MiUWTKGRbjUiHDIkGFVKJxapFHe1XsrVocmy0s8AizbnqIx +MsWLQQ09BU117bsz2Cbr9nd89OvhOUEmVraw99SiEkYte+VF+K0j+ze5sn111LW3 +KqSKHDehEMySBS3sFc6Wp68lfE7g6XFEsqocU+0s/wHg2dfrrS7QQfnWy7tpFWMn +KlljAoS8PN+N3ptEn4JIbaYVd5mYJhR18oLRUTOnOw== +-----END CERTIFICATE----- diff --git a/packages/@aws-cdk/aws-ec2/test/import-certificates-handler/client1.domain.tld.crt b/packages/@aws-cdk/aws-ec2/test/import-certificates-handler/client1.domain.tld.crt new file mode 100644 index 0000000000000..dcbd3cf5f2248 --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/test/import-certificates-handler/client1.domain.tld.crt @@ -0,0 +1,85 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 85:d1:c0:75:1d:a4:9f:4d:d1:0c:d0:a8:25:94:db:85 + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=Easy-RSA CA + Validity + Not Before: Dec 25 21:01:55 2020 GMT + Not After : Mar 30 21:01:55 2023 GMT + Subject: CN=client1.domain.tld + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:ee:35:7c:d5:1f:da:fc:60:cd:6d:e4:d9:a2:a7: + 99:08:16:3f:9a:84:e4:43:64:f1:5b:d4:ce:ba:7a: + 2a:66:e8:e4:14:1e:62:0b:61:bf:ed:78:cd:34:96: + 22:ef:e2:67:76:18:6f:bc:50:4b:17:2b:b4:6e:c5: + 60:fc:5f:a7:a9:a6:12:ba:08:74:6f:e5:07:90:8a: + 69:25:45:e5:73:4b:be:75:c4:be:8e:4f:a6:8f:7b: + 8c:c7:e4:32:cb:e2:b4:ba:5e:24:75:17:8b:49:92: + f6:7c:51:94:d2:55:4d:0b:da:19:81:83:2f:c3:b8: + c3:8f:7f:e5:b4:31:e3:26:47:0a:ed:ef:fe:77:69: + 01:6f:fb:91:c9:30:76:a4:76:6b:c4:22:39:95:d4: + e5:c1:40:2a:a8:dd:e5:53:85:22:af:b7:70:2d:ce: + d8:be:df:7f:d4:2a:fd:ac:a4:f7:dd:4f:8e:c6:c0: + a5:dd:a1:b6:69:9f:98:0d:a6:ca:cd:7a:44:85:81: + 5f:c3:01:f5:c4:b5:81:c1:a6:7c:1e:8b:da:21:60: + b3:b0:8d:15:6c:d7:9f:7d:ac:e9:a8:cf:f0:0b:b2: + e0:30:ad:85:83:39:42:90:58:f4:ae:c4:ad:63:2d: + 3d:a4:58:59:2a:0c:f6:15:f1:00:7d:ea:7d:d0:42: + ba:31 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Subject Key Identifier: + 14:04:30:68:68:A7:F3:CA:C0:D2:35:F4:F4:BF:ED:F6:CA:18:CA:65 + X509v3 Authority Key Identifier: + keyid:5E:6C:94:7F:54:F1:5F:3C:70:45:5F:70:9D:BF:3C:33:F3:FE:C8:B2 + DirName:/CN=Easy-RSA CA + serial:6F:92:60:B1:ED:49:35:C9:75:DE:03:FF:20:5B:DF:39:66:E6:EB:3E + + X509v3 Extended Key Usage: + TLS Web Client Authentication + X509v3 Key Usage: + Digital Signature + Signature Algorithm: sha256WithRSAEncryption + ab:25:52:5a:10:0a:eb:fd:cb:d4:30:89:de:ee:4f:62:c7:c9: + e5:db:03:70:5e:2a:9f:8d:fa:9a:18:cc:92:07:ae:65:21:3d: + b6:58:75:1b:74:77:c7:b5:58:27:a4:00:e3:a0:7d:d3:0e:44: + 4b:8e:0f:4f:3e:0a:80:66:7e:68:00:a9:da:5c:0b:75:19:1a: + f9:5b:b3:3a:f6:57:0b:59:5c:11:92:55:93:df:a0:39:ef:d4: + 00:77:d3:58:fd:e2:f4:1c:0a:b1:7f:43:57:4f:8a:cc:7f:46: + f6:46:6c:b3:4f:56:78:22:72:93:7c:26:44:79:a9:85:d3:ac: + ce:24:10:b1:59:24:77:4d:79:50:a2:78:f6:73:56:87:bb:a2: + a2:91:3b:d8:42:ff:66:a6:24:ec:1a:b0:c2:9c:c2:6c:5f:ca: + 14:5c:9f:86:f0:d7:0e:af:1b:cc:48:7f:d8:80:58:0a:8a:6d: + de:35:10:2f:37:3b:af:6d:49:3a:b3:8d:b7:cb:ec:80:4a:b8: + 4b:81:fd:3e:39:a0:e6:e1:35:dc:b1:99:95:9b:8a:af:50:73: + 71:9c:e6:d5:d8:bf:53:0a:c8:ef:af:84:d5:9b:0a:68:49:de: + 55:05:57:9f:06:a1:70:e4:40:94:f0:ca:9b:39:79:33:2f:72: + 29:e0:ae:de +-----BEGIN CERTIFICATE----- +MIIDYTCCAkmgAwIBAgIRAIXRwHUdpJ9N0QzQqCWU24UwDQYJKoZIhvcNAQELBQAw +FjEUMBIGA1UEAwwLRWFzeS1SU0EgQ0EwHhcNMjAxMjI1MjEwMTU1WhcNMjMwMzMw +MjEwMTU1WjAdMRswGQYDVQQDDBJjbGllbnQxLmRvbWFpbi50bGQwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDuNXzVH9r8YM1t5Nmip5kIFj+ahORDZPFb +1M66eipm6OQUHmILYb/teM00liLv4md2GG+8UEsXK7RuxWD8X6epphK6CHRv5QeQ +imklReVzS751xL6OT6aPe4zH5DLL4rS6XiR1F4tJkvZ8UZTSVU0L2hmBgy/DuMOP +f+W0MeMmRwrt7/53aQFv+5HJMHakdmvEIjmV1OXBQCqo3eVThSKvt3Atzti+33/U +Kv2spPfdT47GwKXdobZpn5gNpsrNekSFgV/DAfXEtYHBpnwei9ohYLOwjRVs1599 +rOmoz/ALsuAwrYWDOUKQWPSuxK1jLT2kWFkqDPYV8QB96n3QQroxAgMBAAGjgaIw +gZ8wCQYDVR0TBAIwADAdBgNVHQ4EFgQUFAQwaGin88rA0jX09L/t9soYymUwUQYD +VR0jBEowSIAUXmyUf1TxXzxwRV9wnb88M/P+yLKhGqQYMBYxFDASBgNVBAMMC0Vh +c3ktUlNBIENBghRvkmCx7Uk1yXXeA/8gW985ZubrPjATBgNVHSUEDDAKBggrBgEF +BQcDAjALBgNVHQ8EBAMCB4AwDQYJKoZIhvcNAQELBQADggEBAKslUloQCuv9y9Qw +id7uT2LHyeXbA3BeKp+N+poYzJIHrmUhPbZYdRt0d8e1WCekAOOgfdMOREuOD08+ +CoBmfmgAqdpcC3UZGvlbszr2VwtZXBGSVZPfoDnv1AB301j94vQcCrF/Q1dPisx/ +RvZGbLNPVngicpN8JkR5qYXTrM4kELFZJHdNeVCiePZzVoe7oqKRO9hC/2amJOwa +sMKcwmxfyhRcn4bw1w6vG8xIf9iAWAqKbd41EC83O69tSTqzjbfL7IBKuEuB/T45 +oObhNdyxmZWbiq9Qc3Gc5tXYv1MKyO+vhNWbCmhJ3lUFV58GoXDkQJTwyps5eTMv +cingrt4= +-----END CERTIFICATE----- diff --git a/packages/@aws-cdk/aws-ec2/test/import-certificates-handler/client1.domain.tld.key b/packages/@aws-cdk/aws-ec2/test/import-certificates-handler/client1.domain.tld.key new file mode 100644 index 0000000000000..8d6a2b7f8769f --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/test/import-certificates-handler/client1.domain.tld.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDuNXzVH9r8YM1t +5Nmip5kIFj+ahORDZPFb1M66eipm6OQUHmILYb/teM00liLv4md2GG+8UEsXK7Ru +xWD8X6epphK6CHRv5QeQimklReVzS751xL6OT6aPe4zH5DLL4rS6XiR1F4tJkvZ8 +UZTSVU0L2hmBgy/DuMOPf+W0MeMmRwrt7/53aQFv+5HJMHakdmvEIjmV1OXBQCqo +3eVThSKvt3Atzti+33/UKv2spPfdT47GwKXdobZpn5gNpsrNekSFgV/DAfXEtYHB +pnwei9ohYLOwjRVs1599rOmoz/ALsuAwrYWDOUKQWPSuxK1jLT2kWFkqDPYV8QB9 +6n3QQroxAgMBAAECggEALs3pqkKpF3+5vYcC0DfYFMOyWZ0U8L0Lw3xr5i4M2M2X +yvAxWYUqXfGneFarpLC6nXStt7WbG4Fl4YH8zXnKCsZr1YvFvRqmQts/T6iNLftK +//7ZZkL2OikPf1MyO+delWPcC/nFT36F2eV5tV43VkXTTyREpVNPcYmyy5YlyKY5 +za/xqcAZaTfvsVHROb0k4kmFnLMfdjqaL/ufo+j1l4KYg4mEANVg8byckawqcLpn +buLT4qu0oP1Bu69lX6RKlPvzP0VG+3k8+gi/jNztt7Q9fXrw7H0M40oZMWZX828l +nBvgmVS+9t8l9msGzmIBxc/1aiKUzIdNhDSt29KoZQKBgQD5/OiA1unKLO7DuLon +SAhlW/2qMPjSei36TsyaTWT38+yPslOMqPgaoWFdBNTFuIkEKNidcdDruVGwn/xR +aaYeOk62ptqwAMDssQQYmsUawqSwPw7PmocFcjxe8glCE07ix3sm/v9eFn2Ot5iX +gE6U6m36/0fsbxv8q+tFEKpYcwKBgQDz8A9lay6yb0HT53BQrpaRlLn7t8k+zwgp +Lukzp2IzHR+MDDDGUsAOcCCjVW8jMhk4i3PBxrJyw4LUyB6D05Axo9WEKvQx2akR +Ss9To1ZArfVsmKtBCq0jNnYKBKgn+xKPEdAL6MY+BmOuiaGiRgRefxMoba/tD70t +a31ckBxNywKBgQDv6+xxCtIiOXGF4lq2rIlyThFsL8f+qUhLPSlcxf6rgi191BYf +n2NOm6fIEITspijKFzGeGcf7FEb0jvcoY48M38T/w6+Kz45ZG6LkwlV9U2WfyUU7 +tgD0Fykdrol4IvPI7s6hJIaOFGO4fzgx3vCMN1oKVMsAfbqMi6snA9GZRQKBgH7u +rbRCX5wt1H0lcwYosuSyFUzsR2XNaRu081gTgz/BqcbAGSk5qgJZSkJzlE8mJIWN +2wA8GmMpZQy/zVEfZ2rNK6+IgmTmM9lxqgyFc75YRtrpXkOMAKfQEQAJiE61kOSt +iiqIR4/C11/c8iR0dpWNXjStTtv2UqQtyJ+/xVqdAoGBAJdSIlgFdAmxa3lATbAy +XN7abtkNhIsi+GSKhEFdAFWsZAPjP4M1NRFr1go/z+RwtsDYJxqrG4eAxWQPShl5 +ggR/CIrM9gc8Ju8As33+i3stKOVKcrZWcvdAj1XU8V/OdmfnVFQVrjyHLqY+RU94 +T4q0NBKfcsiroJOqOSAkiAvU +-----END PRIVATE KEY----- diff --git a/packages/@aws-cdk/aws-ec2/test/import-certificates-handler/index.ts b/packages/@aws-cdk/aws-ec2/test/import-certificates-handler/index.ts new file mode 100644 index 0000000000000..846af4be6bcc3 --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/test/import-certificates-handler/index.ts @@ -0,0 +1,49 @@ +import * as fs from 'fs'; +import { ACM } from 'aws-sdk'; // eslint-disable-line import/no-extraneous-dependencies + +const acm = new ACM(); + +export async function handler(event: AWSLambda.CloudFormationCustomResourceEvent) { + switch (event.RequestType) { + case 'Create': + let serverImport; + if (!event.ResourceProperties.ServerCertificateArn) { + serverImport = await acm.importCertificate({ + Certificate: fs.readFileSync('./server.crt'), + PrivateKey: fs.readFileSync('./server.key'), + CertificateChain: fs.readFileSync('./ca.crt'), + }).promise(); + } + + let clientImport; + if (!event.ResourceProperties.ClientCertificateArn) { + clientImport = await acm.importCertificate({ + Certificate: fs.readFileSync('./client1.domain.tld.crt'), + PrivateKey: fs.readFileSync('./client1.domain.tld.key'), + CertificateChain: fs.readFileSync('./ca.crt'), + }).promise(); + } + + + return { + Data: { + ServerCertificateArn: serverImport?.CertificateArn, + ClientCertificateArn: clientImport?.CertificateArn, + }, + }; + case 'Update': + return; + case 'Delete': + if (event.ResourceProperties.ServerCertificateArn) { + await acm.deleteCertificate({ + CertificateArn: event.ResourceProperties.ServerCertificateArn, + }).promise(); + } + if (event.ResourceProperties.ClientCertificateArn) { + await acm.deleteCertificate({ + CertificateArn: event.ResourceProperties.ClientCertificateArn, + }).promise(); + } + return; + } +} diff --git a/packages/@aws-cdk/aws-ec2/test/import-certificates-handler/server.crt b/packages/@aws-cdk/aws-ec2/test/import-certificates-handler/server.crt new file mode 100644 index 0000000000000..2f0cf944f824b --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/test/import-certificates-handler/server.crt @@ -0,0 +1,87 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 3f:dd:e1:9d:b0:34:f0:d6:d7:57:1d:bf:fe:76:ee:c0 + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=Easy-RSA CA + Validity + Not Before: Dec 25 21:01:47 2020 GMT + Not After : Mar 30 21:01:47 2023 GMT + Subject: CN=server + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:da:80:19:4b:f2:f2:7e:36:ac:01:4c:aa:db:0d: + 50:7d:03:8c:b3:a7:51:1b:9b:e9:13:ec:8e:f6:b5: + 38:bb:b9:fc:16:39:1d:70:1c:62:49:48:d3:48:ae: + 3c:b9:bc:27:38:69:08:42:cd:20:10:fa:bd:4e:24: + 4b:b8:f9:1d:0a:3d:a4:06:5d:b6:8f:87:8d:fa:ac: + d4:9f:b4:97:d8:9f:80:d3:de:ff:64:29:c8:50:86: + 5f:ca:fa:c0:c3:92:ac:ba:22:8f:59:e6:5f:57:d4: + 72:cc:5d:5e:f7:06:81:a0:0c:20:4f:79:61:38:10: + e7:77:a2:4a:4c:3b:8c:3b:98:61:7a:83:85:af:5b: + de:0f:31:6c:58:f3:bf:3f:19:e6:2f:14:8a:43:ea: + 43:be:e8:25:e5:8e:16:cb:32:94:f4:58:89:a7:5c: + 18:22:9f:dd:0e:a3:68:d1:e1:92:10:de:50:b0:91: + 82:b2:0b:97:60:41:f4:32:26:76:66:67:55:e8:0b: + 3a:4d:63:be:46:ab:5a:56:2f:ee:f6:9f:d3:99:b3: + 76:79:a8:57:b3:5f:9a:93:47:0d:23:3e:73:18:72: + 71:33:37:ef:fe:c7:0f:fc:ca:c4:4f:cc:59:8a:c0: + 7b:3e:fc:70:1b:5f:15:92:e3:59:ba:fd:a8:fc:3d: + 1a:89 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Subject Key Identifier: + BF:09:F8:C9:97:0B:72:EE:D2:1A:A9:4C:04:CB:E3:81:48:FF:A8:BD + X509v3 Authority Key Identifier: + keyid:5E:6C:94:7F:54:F1:5F:3C:70:45:5F:70:9D:BF:3C:33:F3:FE:C8:B2 + DirName:/CN=Easy-RSA CA + serial:6F:92:60:B1:ED:49:35:C9:75:DE:03:FF:20:5B:DF:39:66:E6:EB:3E + + X509v3 Extended Key Usage: + TLS Web Server Authentication + X509v3 Key Usage: + Digital Signature, Key Encipherment + X509v3 Subject Alternative Name: + DNS:server + Signature Algorithm: sha256WithRSAEncryption + 9e:7e:15:5b:5d:9d:1e:9b:b8:fe:c8:2a:d8:10:44:08:c1:60: + 1f:e4:83:9a:89:ac:82:94:72:6e:b3:c0:11:c8:03:6d:52:64: + be:63:69:f7:61:ca:9a:66:f0:81:36:83:87:02:6e:b0:01:e4: + cf:34:e1:b4:be:ec:e2:bc:72:5f:02:53:29:ea:87:2d:32:96: + 34:ff:73:32:31:85:63:f7:34:cd:e3:64:5d:ac:c5:0e:b3:09: + c6:3d:0a:bb:73:11:7b:f1:ca:b9:e0:76:96:b3:b1:7b:b2:ef: + ab:b9:70:f5:e0:65:9e:b0:e2:09:8b:12:cd:3a:4d:f9:b5:e2: + c3:aa:b5:ee:a2:05:60:e0:7e:7b:4c:e9:ee:f5:94:78:7b:3b: + b7:90:d3:b0:5b:83:47:7d:1a:06:b3:90:8e:79:3e:3a:66:01: + da:a4:b6:a6:d4:2b:6c:a5:6f:b1:a4:45:11:39:0c:b4:35:64: + 75:e5:f1:07:f2:01:62:74:ab:bf:26:b7:5f:cb:11:d0:c7:71: + 05:73:bb:ee:60:99:2f:31:73:63:a6:25:ef:90:a6:8c:da:ca: + ef:80:42:68:e9:0b:34:ea:f0:fd:f8:98:5d:73:b2:6a:45:d6: + ab:78:21:24:12:1d:14:2d:2e:11:87:20:55:c7:40:df:ed:28: + f9:0e:67:84 +-----BEGIN CERTIFICATE----- +MIIDZzCCAk+gAwIBAgIQP93hnbA08NbXVx2//nbuwDANBgkqhkiG9w0BAQsFADAW +MRQwEgYDVQQDDAtFYXN5LVJTQSBDQTAeFw0yMDEyMjUyMTAxNDdaFw0yMzAzMzAy +MTAxNDdaMBExDzANBgNVBAMMBnNlcnZlcjCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBANqAGUvy8n42rAFMqtsNUH0DjLOnURub6RPsjva1OLu5/BY5HXAc +YklI00iuPLm8JzhpCELNIBD6vU4kS7j5HQo9pAZdto+Hjfqs1J+0l9ifgNPe/2Qp +yFCGX8r6wMOSrLoij1nmX1fUcsxdXvcGgaAMIE95YTgQ53eiSkw7jDuYYXqDha9b +3g8xbFjzvz8Z5i8UikPqQ77oJeWOFssylPRYiadcGCKf3Q6jaNHhkhDeULCRgrIL +l2BB9DImdmZnVegLOk1jvkarWlYv7vaf05mzdnmoV7NfmpNHDSM+cxhycTM37/7H +D/zKxE/MWYrAez78cBtfFZLjWbr9qPw9GokCAwEAAaOBtTCBsjAJBgNVHRMEAjAA +MB0GA1UdDgQWBBS/CfjJlwty7tIaqUwEy+OBSP+ovTBRBgNVHSMESjBIgBRebJR/ +VPFfPHBFX3Cdvzwz8/7IsqEapBgwFjEUMBIGA1UEAwwLRWFzeS1SU0EgQ0GCFG+S +YLHtSTXJdd4D/yBb3zlm5us+MBMGA1UdJQQMMAoGCCsGAQUFBwMBMAsGA1UdDwQE +AwIFoDARBgNVHREECjAIggZzZXJ2ZXIwDQYJKoZIhvcNAQELBQADggEBAJ5+FVtd +nR6buP7IKtgQRAjBYB/kg5qJrIKUcm6zwBHIA21SZL5jafdhyppm8IE2g4cCbrAB +5M804bS+7OK8cl8CUynqhy0yljT/czIxhWP3NM3jZF2sxQ6zCcY9CrtzEXvxyrng +dpazsXuy76u5cPXgZZ6w4gmLEs06Tfm14sOqte6iBWDgfntM6e71lHh7O7eQ07Bb +g0d9GgazkI55PjpmAdqktqbUK2ylb7GkRRE5DLQ1ZHXl8QfyAWJ0q78mt1/LEdDH +cQVzu+5gmS8xc2OmJe+Qpozayu+AQmjpCzTq8P34mF1zsmpF1qt4ISQSHRQtLhGH +IFXHQN/tKPkOZ4Q= +-----END CERTIFICATE----- diff --git a/packages/@aws-cdk/aws-ec2/test/import-certificates-handler/server.key b/packages/@aws-cdk/aws-ec2/test/import-certificates-handler/server.key new file mode 100644 index 0000000000000..d6b35dc97101b --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/test/import-certificates-handler/server.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDagBlL8vJ+NqwB +TKrbDVB9A4yzp1Ebm+kT7I72tTi7ufwWOR1wHGJJSNNIrjy5vCc4aQhCzSAQ+r1O +JEu4+R0KPaQGXbaPh436rNSftJfYn4DT3v9kKchQhl/K+sDDkqy6Io9Z5l9X1HLM +XV73BoGgDCBPeWE4EOd3okpMO4w7mGF6g4WvW94PMWxY878/GeYvFIpD6kO+6CXl +jhbLMpT0WImnXBgin90Oo2jR4ZIQ3lCwkYKyC5dgQfQyJnZmZ1XoCzpNY75Gq1pW +L+72n9OZs3Z5qFezX5qTRw0jPnMYcnEzN+/+xw/8ysRPzFmKwHs+/HAbXxWS41m6 +/aj8PRqJAgMBAAECggEAYBbXiRv1YmX+rK+fr6eiTugBt3wMYjzlenqcwIgfxAbd +gpRpisUgwCPDrwHY+MFy6g7esCnvQShTmgrCNj1vdPJ4sMgDogk1+hiJhRZxdLVo +fURjQhRR4H/Hnsc5gIh/Z3gNXLbAFSr7tT4WpkH5PX43s1uo0nQ0ptr7G51QZWAk +yz1K2Ff4PJ0hpQXFJAMoi+tbSh+dqz0jewN0bcKBpq7/bJr++bJiChTyiVSq8a5b +73XfRuSI8k8L3TJkv2DiEZ5aLsDSqbwqF03f9Dm8I7iaMRfKCS7UhLHFP1kPGyK4 +1vZbexZnelTd+pM2+X+XKSwISGecWd0+GaEtJhV/UQKBgQD1l1N+NeDR1+vHZK7C +dvU33FZBkA/61emV70XrM5Yl8H+o3oTLU72Tgt1/xcTRRcPKi51S+UJpH7FjoE45 +YwoDKlhkpGfUmIsWklOC1szDcVkg2cZ75G9pEzB3noHOxIJXLZ1oyDhOqSsIXx2J +f0DcmnwRcg81UQKr5Ql6RtdFPQKBgQDjwtZMXqhMZ2cOxNxA4pw3KjtB9yWMHaId +3/8bx5XmxBnqBFKi1AGC5UW7TOhe/rLnumbzEyX3wEj0A9kgh35jccJTyha3Wzpf +JTiwyNLxxFADjcMmptysJyVkPOJjXDV9w+qbqlT/KNNPweE047WMP8zBJUst68Hk +lox5L2+3PQKBgQDTqZdxCDh6QrDXyaOAwIu5mDHTEblkAybtbSoCexRmIG+1+AnV +P5f84WXLcISfpJQJJejykRc2iPUWmxuwA/amIcHLA5LlPI9rZbOJ6VzS+QbK9EZH +kuqeUcaM4dSYgu6e+hZXL3CwAsau0WMglMcvGgnh8z6+QdKemahgdVulNQKBgC65 +uQcf4D0UdZMVFe6FzvCOTGvjDSPqrGienJKRZpJaJsrYqi9XeRvmd2DOjVl3vTJH +DnnNsttZ6l2NMI043tf97ZUM/44MPDRqyW+TM5t/375q5d9XGiyDN2uSBgvGTf8I +I2heEGPsdzWEm/QixwsHx7TUNtEr7bI8pIL0FWItAoGAFNQRDOeogfMDPV96EQOP +cWpO0L4S0Xe/9EVfQiBoz9Ga/sciysMCsPMzBajoV2gQPCcqx9rgQ3H8b01stTlp +0cVyrrlbcDUz0ZYe24hN5XlKHDAyZmKpVCmRduQJYTfExZtdhWDl77JSAyyno45G +5c5Y5wQLBH//3hCyVTh1NTA= +-----END PRIVATE KEY----- diff --git a/packages/@aws-cdk/aws-ec2/test/instance.test.ts b/packages/@aws-cdk/aws-ec2/test/instance.test.ts index a2049fb31e86b..d5b77e01ad0ea 100644 --- a/packages/@aws-cdk/aws-ec2/test/instance.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/instance.test.ts @@ -1,6 +1,6 @@ import * as path from 'path'; -import { arrayWith, expect as cdkExpect, haveResource, ResourcePart, stringLike, SynthUtils } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { arrayWith, expect as cdkExpect, haveResource, ResourcePart, stringLike, SynthUtils } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import { Asset } from '@aws-cdk/aws-s3-assets'; import { StringParameter } from '@aws-cdk/aws-ssm'; import * as cxschema from '@aws-cdk/cloud-assembly-schema'; @@ -138,6 +138,39 @@ nodeunitShim({ test.done(); }, + 'instances with local NVME drive are correctly named'(test: Test) { + // GIVEN + const sampleInstanceClassKeys = [{ + key: 'R5D', + value: 'r5d', + }, { + key: 'MEMORY5_NVME_DRIVE', + value: 'r5d', + }, { + key: 'R5AD', + value: 'r5ad', + }, { + key: 'MEMORY5_AMD_NVME_DRIVE', + value: 'r5ad', + }, { + key: 'M5AD', + value: 'm5ad', + }, { + key: 'STANDARD5_AMD_NVME_DRIVE', + value: 'm5ad', + }]; // A sample of instances with NVME drives + + for (const instanceClass of sampleInstanceClassKeys) { + // WHEN + const key = instanceClass.key as keyof(typeof InstanceClass); + const instanceType = InstanceClass[key]; + + // THEN + expect(instanceType).toBe(instanceClass.value); + } + + test.done(); + }, 'instance architecture throws an error when instance type is invalid'(test: Test) { // GIVEN const malformedInstanceTypes = ['t4', 't4g.nano.', 't4gnano', '']; diff --git a/packages/@aws-cdk/aws-ec2/test/integ.client-vpn-endpoint.expected.json b/packages/@aws-cdk/aws-ec2/test/integ.client-vpn-endpoint.expected.json new file mode 100644 index 0000000000000..17e0059d601d1 --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/test/integ.client-vpn-endpoint.expected.json @@ -0,0 +1,612 @@ +{ + "Resources": { + "ImportCertificatesCreateCertificates71085A81": { + "Type": "Custom::ACMImportCertificates", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "CustomACMImportCertificatesCustomResourceProviderHandler2EB12457", + "Arn" + ] + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ImportCertificatesDeleteCertificates6462F0A6": { + "Type": "Custom::ACMImportCertificates", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "CustomACMImportCertificatesCustomResourceProviderHandler2EB12457", + "Arn" + ] + }, + "ServerCertificateArn": { + "Fn::GetAtt": [ + "ImportCertificatesCreateCertificates71085A81", + "ClientCertificateArn" + ] + }, + "ClientCertificateArn": { + "Fn::GetAtt": [ + "ImportCertificatesCreateCertificates71085A81", + "ServerCertificateArn" + ] + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "CustomACMImportCertificatesCustomResourceProviderRole2CE46D14": { + "Type": "AWS::IAM::Role", + "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": [ + { + "Effect": "Allow", + "Action": [ + "acm:ImportCertificate", + "acm:DeleteCertificate" + ], + "Resource": "*" + } + ] + } + } + ] + } + }, + "CustomACMImportCertificatesCustomResourceProviderHandler2EB12457": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "AssetParametersbb3ce11d35aa60dce674523850f7a4a038127a6c48af335699cff4cc55cb0957S3Bucket60FDAA05" + }, + "S3Key": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersbb3ce11d35aa60dce674523850f7a4a038127a6c48af335699cff4cc55cb0957S3VersionKeyF2886582" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersbb3ce11d35aa60dce674523850f7a4a038127a6c48af335699cff4cc55cb0957S3VersionKeyF2886582" + } + ] + } + ] + } + ] + ] + } + }, + "Timeout": 900, + "MemorySize": 128, + "Handler": "__entrypoint__.handler", + "Role": { + "Fn::GetAtt": [ + "CustomACMImportCertificatesCustomResourceProviderRole2CE46D14", + "Arn" + ] + }, + "Runtime": "nodejs12.x" + }, + "DependsOn": [ + "CustomACMImportCertificatesCustomResourceProviderRole2CE46D14" + ] + }, + "Vpc8378EB38": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "cdk-ec2-client-vpn-endpoint/Vpc" + } + ] + }, + "DependsOn": [ + "ImportCertificatesCreateCertificates71085A81", + "ImportCertificatesDeleteCertificates6462F0A6" + ] + }, + "VpcPublicSubnet1Subnet5C2D37C4": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "cdk-ec2-client-vpn-endpoint/Vpc/PublicSubnet1" + } + ] + }, + "DependsOn": [ + "ImportCertificatesCreateCertificates71085A81", + "ImportCertificatesDeleteCertificates6462F0A6" + ] + }, + "VpcPublicSubnet1RouteTable6C95E38E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "cdk-ec2-client-vpn-endpoint/Vpc/PublicSubnet1" + } + ] + }, + "DependsOn": [ + "ImportCertificatesCreateCertificates71085A81", + "ImportCertificatesDeleteCertificates6462F0A6" + ] + }, + "VpcPublicSubnet1RouteTableAssociation97140677": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + } + }, + "DependsOn": [ + "ImportCertificatesCreateCertificates71085A81", + "ImportCertificatesDeleteCertificates6462F0A6" + ] + }, + "VpcPublicSubnet1DefaultRoute3DA9E72A": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "ImportCertificatesCreateCertificates71085A81", + "ImportCertificatesDeleteCertificates6462F0A6", + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet2Subnet691E08A3": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "cdk-ec2-client-vpn-endpoint/Vpc/PublicSubnet2" + } + ] + }, + "DependsOn": [ + "ImportCertificatesCreateCertificates71085A81", + "ImportCertificatesDeleteCertificates6462F0A6" + ] + }, + "VpcPublicSubnet2RouteTable94F7E489": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "cdk-ec2-client-vpn-endpoint/Vpc/PublicSubnet2" + } + ] + }, + "DependsOn": [ + "ImportCertificatesCreateCertificates71085A81", + "ImportCertificatesDeleteCertificates6462F0A6" + ] + }, + "VpcPublicSubnet2RouteTableAssociationDD5762D8": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + } + }, + "DependsOn": [ + "ImportCertificatesCreateCertificates71085A81", + "ImportCertificatesDeleteCertificates6462F0A6" + ] + }, + "VpcPublicSubnet2DefaultRoute97F91067": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "ImportCertificatesCreateCertificates71085A81", + "ImportCertificatesDeleteCertificates6462F0A6", + "VpcVPCGWBF912B6E" + ] + }, + "VpcIsolatedSubnet1SubnetE48C5737": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Isolated" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Isolated" + }, + { + "Key": "Name", + "Value": "cdk-ec2-client-vpn-endpoint/Vpc/IsolatedSubnet1" + } + ] + }, + "DependsOn": [ + "ImportCertificatesCreateCertificates71085A81", + "ImportCertificatesDeleteCertificates6462F0A6" + ] + }, + "VpcIsolatedSubnet1RouteTable4771E3E5": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "cdk-ec2-client-vpn-endpoint/Vpc/IsolatedSubnet1" + } + ] + }, + "DependsOn": [ + "ImportCertificatesCreateCertificates71085A81", + "ImportCertificatesDeleteCertificates6462F0A6" + ] + }, + "VpcIsolatedSubnet1RouteTableAssociationD300FCBB": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcIsolatedSubnet1RouteTable4771E3E5" + }, + "SubnetId": { + "Ref": "VpcIsolatedSubnet1SubnetE48C5737" + } + }, + "DependsOn": [ + "ImportCertificatesCreateCertificates71085A81", + "ImportCertificatesDeleteCertificates6462F0A6" + ] + }, + "VpcIsolatedSubnet2Subnet16364B91": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.192.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Isolated" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Isolated" + }, + { + "Key": "Name", + "Value": "cdk-ec2-client-vpn-endpoint/Vpc/IsolatedSubnet2" + } + ] + }, + "DependsOn": [ + "ImportCertificatesCreateCertificates71085A81", + "ImportCertificatesDeleteCertificates6462F0A6" + ] + }, + "VpcIsolatedSubnet2RouteTable1D30AF7D": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "cdk-ec2-client-vpn-endpoint/Vpc/IsolatedSubnet2" + } + ] + }, + "DependsOn": [ + "ImportCertificatesCreateCertificates71085A81", + "ImportCertificatesDeleteCertificates6462F0A6" + ] + }, + "VpcIsolatedSubnet2RouteTableAssociationF7B18CCA": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcIsolatedSubnet2RouteTable1D30AF7D" + }, + "SubnetId": { + "Ref": "VpcIsolatedSubnet2Subnet16364B91" + } + }, + "DependsOn": [ + "ImportCertificatesCreateCertificates71085A81", + "ImportCertificatesDeleteCertificates6462F0A6" + ] + }, + "VpcIGWD7BA715C": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "cdk-ec2-client-vpn-endpoint/Vpc" + } + ] + }, + "DependsOn": [ + "ImportCertificatesCreateCertificates71085A81", + "ImportCertificatesDeleteCertificates6462F0A6" + ] + }, + "VpcVPCGWBF912B6E": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "InternetGatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "ImportCertificatesCreateCertificates71085A81", + "ImportCertificatesDeleteCertificates6462F0A6" + ] + }, + "VpcEndpointSecurityGroup7B25EFDC": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "cdk-ec2-client-vpn-endpoint/Vpc/Endpoint/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "Tags": [ + { + "Key": "Name", + "Value": "cdk-ec2-client-vpn-endpoint/Vpc" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + }, + "DependsOn": [ + "ImportCertificatesCreateCertificates71085A81", + "ImportCertificatesDeleteCertificates6462F0A6" + ] + }, + "VpcEndpoint6FF034F6": { + "Type": "AWS::EC2::ClientVpnEndpoint", + "Properties": { + "AuthenticationOptions": [ + { + "MutualAuthentication": { + "ClientRootCertificateChainArn": { + "Fn::GetAtt": [ + "ImportCertificatesCreateCertificates71085A81", + "ServerCertificateArn" + ] + } + }, + "Type": "certificate-authentication" + } + ], + "ClientCidrBlock": "10.100.0.0/16", + "ConnectionLogOptions": { + "CloudwatchLogGroup": { + "Ref": "LogGroupF5B46931" + }, + "Enabled": true + }, + "ServerCertificateArn": { + "Fn::GetAtt": [ + "ImportCertificatesCreateCertificates71085A81", + "ClientCertificateArn" + ] + }, + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "VpcEndpointSecurityGroup7B25EFDC", + "GroupId" + ] + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + }, + "DependsOn": [ + "ImportCertificatesCreateCertificates71085A81", + "ImportCertificatesDeleteCertificates6462F0A6" + ] + }, + "VpcEndpointAssociation06B066321": { + "Type": "AWS::EC2::ClientVpnTargetNetworkAssociation", + "Properties": { + "ClientVpnEndpointId": { + "Ref": "VpcEndpoint6FF034F6" + }, + "SubnetId": { + "Ref": "VpcIsolatedSubnet1SubnetE48C5737" + } + }, + "DependsOn": [ + "ImportCertificatesCreateCertificates71085A81", + "ImportCertificatesDeleteCertificates6462F0A6" + ] + }, + "VpcEndpointAssociation12B51A67F": { + "Type": "AWS::EC2::ClientVpnTargetNetworkAssociation", + "Properties": { + "ClientVpnEndpointId": { + "Ref": "VpcEndpoint6FF034F6" + }, + "SubnetId": { + "Ref": "VpcIsolatedSubnet2Subnet16364B91" + } + }, + "DependsOn": [ + "ImportCertificatesCreateCertificates71085A81", + "ImportCertificatesDeleteCertificates6462F0A6" + ] + }, + "VpcEndpointAuthorizeAll70F0E613": { + "Type": "AWS::EC2::ClientVpnAuthorizationRule", + "Properties": { + "ClientVpnEndpointId": { + "Ref": "VpcEndpoint6FF034F6" + }, + "TargetNetworkCidr": { + "Fn::GetAtt": [ + "Vpc8378EB38", + "CidrBlock" + ] + }, + "AuthorizeAllGroups": true + }, + "DependsOn": [ + "ImportCertificatesCreateCertificates71085A81", + "ImportCertificatesDeleteCertificates6462F0A6" + ] + }, + "LogGroupF5B46931": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "RetentionInDays": 731 + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + }, + "Parameters": { + "AssetParametersbb3ce11d35aa60dce674523850f7a4a038127a6c48af335699cff4cc55cb0957S3Bucket60FDAA05": { + "Type": "String", + "Description": "S3 bucket for asset \"bb3ce11d35aa60dce674523850f7a4a038127a6c48af335699cff4cc55cb0957\"" + }, + "AssetParametersbb3ce11d35aa60dce674523850f7a4a038127a6c48af335699cff4cc55cb0957S3VersionKeyF2886582": { + "Type": "String", + "Description": "S3 key for asset version \"bb3ce11d35aa60dce674523850f7a4a038127a6c48af335699cff4cc55cb0957\"" + }, + "AssetParametersbb3ce11d35aa60dce674523850f7a4a038127a6c48af335699cff4cc55cb0957ArtifactHashF17C10B6": { + "Type": "String", + "Description": "Artifact hash for asset \"bb3ce11d35aa60dce674523850f7a4a038127a6c48af335699cff4cc55cb0957\"" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/test/integ.client-vpn-endpoint.ts b/packages/@aws-cdk/aws-ec2/test/integ.client-vpn-endpoint.ts new file mode 100644 index 0000000000000..878f8f057bb3d --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/test/integ.client-vpn-endpoint.ts @@ -0,0 +1,73 @@ +import * as path from 'path'; +import * as logs from '@aws-cdk/aws-logs'; +import { App, CustomResource, CustomResourceProvider, CustomResourceProviderRuntime, RemovalPolicy, Stack, StackProps } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import * as ec2 from '../lib'; + +// keep this import separate from other imports to reduce chance for merge conflicts with v2-main +// eslint-disable-next-line no-duplicate-imports, import/order +import { Construct as CoreConstruct } from '@aws-cdk/core'; + +class TestStack extends Stack { + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + + // Import server and client certificates in ACM + const certificates = new ImportCertificates(this, 'ImportCertificates'); + + const vpc = new ec2.Vpc(this, 'Vpc', { maxAzs: 2, natGateways: 0 }); + vpc.node.addDependency(certificates); // ensure certificates are deleted last, when not in use anymore + + const logGroup = new logs.LogGroup(this, 'LogGroup', { + removalPolicy: RemovalPolicy.DESTROY, + }); + + vpc.addClientVpnEndpoint('Endpoint', { + cidr: '10.100.0.0/16', + serverCertificateArn: certificates.serverCertificateArn, + clientCertificateArn: certificates.clientCertificateArn, + logGroup, + }); + } +} + +const IMPORT_CERTIFICATES_RESOURCE_TYPE = 'Custom::ACMImportCertificates'; + +class ImportCertificates extends CoreConstruct { + public readonly serverCertificateArn: string; + public readonly clientCertificateArn: string; + + constructor(scope: Construct, id: string) { + super(scope, id); + + const serviceToken = CustomResourceProvider.getOrCreate(this, IMPORT_CERTIFICATES_RESOURCE_TYPE, { + codeDirectory: path.join(__dirname, 'import-certificates-handler'), + runtime: CustomResourceProviderRuntime.NODEJS_12, + policyStatements: [{ + Effect: 'Allow', + Action: ['acm:ImportCertificate', 'acm:DeleteCertificate'], + Resource: '*', + }], + }); + + const createCertificates = new CustomResource(this, 'CreateCertificates', { + resourceType: IMPORT_CERTIFICATES_RESOURCE_TYPE, + serviceToken, + }); + this.serverCertificateArn = createCertificates.getAttString('ClientCertificateArn'); + this.clientCertificateArn = createCertificates.getAttString('ServerCertificateArn'); + + new CustomResource(this, 'DeleteCertificates', { + resourceType: IMPORT_CERTIFICATES_RESOURCE_TYPE, + serviceToken, + properties: { + ServerCertificateArn: this.serverCertificateArn, + ClientCertificateArn: this.clientCertificateArn, + }, + }); + } +} + +const app = new App(); +new TestStack(app, 'cdk-ec2-client-vpn-endpoint'); +app.synth(); diff --git a/packages/@aws-cdk/aws-ec2/test/integ.vpc-endpoint-service.ts b/packages/@aws-cdk/aws-ec2/test/integ.vpc-endpoint-service.ts index f4c1d81a065fe..01d22ea92c444 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.vpc-endpoint-service.ts +++ b/packages/@aws-cdk/aws-ec2/test/integ.vpc-endpoint-service.ts @@ -27,7 +27,7 @@ class VpcEndpointServiceStack extends cdk.Stack { const service1 = new ec2.VpcEndpointService(this, 'MyVpcEndpointServiceWithNoPrincipals', { vpcEndpointServiceLoadBalancers: [nlbNoPrincipals], acceptanceRequired: false, - whitelistedPrincipals: [], + allowedPrincipals: [], }); const nlbWithPrincipals = new DummyEndpointLoadBalacer( @@ -37,7 +37,7 @@ class VpcEndpointServiceStack extends cdk.Stack { const service2 = new ec2.VpcEndpointService(this, 'MyVpcEndpointServiceWithPrincipals', { vpcEndpointServiceLoadBalancers: [nlbWithPrincipals], acceptanceRequired: false, - whitelistedPrincipals: [principalArn], + allowedPrincipals: [principalArn], }); new cdk.CfnOutput(this, 'MyVpcEndpointServiceWithNoPrincipalsServiceName', { @@ -55,4 +55,4 @@ class VpcEndpointServiceStack extends cdk.Stack { } new VpcEndpointServiceStack(app, 'aws-cdk-ec2-vpc-endpoint-service'); -app.synth(); \ No newline at end of file +app.synth(); diff --git a/packages/@aws-cdk/aws-ec2/test/launch-template.test.ts b/packages/@aws-cdk/aws-ec2/test/launch-template.test.ts index 882cd69ed282f..4d033a0cad78c 100644 --- a/packages/@aws-cdk/aws-ec2/test/launch-template.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/launch-template.test.ts @@ -4,7 +4,7 @@ import { haveResource, haveResourceLike, stringLike, -} from '@aws-cdk/assert'; +} from '@aws-cdk/assert-internal'; import { CfnInstanceProfile, Role, 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 43e6dbdcd88cf..6a6a6f3c7332f 100644 --- a/packages/@aws-cdk/aws-ec2/test/machine-image.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/machine-image.test.ts @@ -1,4 +1,4 @@ -import { expect as cdkExpect, matchTemplate, MatchStyle } from '@aws-cdk/assert'; +import { expect as cdkExpect, matchTemplate, MatchStyle } from '@aws-cdk/assert-internal'; import { App, Stack } from '@aws-cdk/core'; import * as ec2 from '../lib'; diff --git a/packages/@aws-cdk/aws-ec2/test/security-group.test.ts b/packages/@aws-cdk/aws-ec2/test/security-group.test.ts index 9851d87235c41..1a7cb23b51493 100644 --- a/packages/@aws-cdk/aws-ec2/test/security-group.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/security-group.test.ts @@ -1,7 +1,9 @@ -import { expect, haveResource, not } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike, not } from '@aws-cdk/assert-internal'; import { App, Intrinsic, Lazy, Stack, Token } from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; -import { Peer, Port, SecurityGroup, Vpc } from '../lib'; +import { Peer, Port, SecurityGroup, SecurityGroupProps, Vpc } from '../lib'; + +const SECURITY_GROUP_DISABLE_INLINE_RULES_CONTEXT_KEY = '@aws-cdk/aws-ec2.securityGroupDisableInlineRules'; nodeunitShim({ 'security group can allows all outbound traffic by default'(test: Test) { @@ -148,6 +150,23 @@ nodeunitShim({ test.done(); }, + 'Inline Rule Control': { + //Not inlined + 'When props.disableInlineRules is true': testRulesAreNotInlined(undefined, true), + 'When context.disableInlineRules is true': testRulesAreNotInlined(true, undefined), + 'When context.disableInlineRules is true and props.disableInlineRules is true': testRulesAreNotInlined(true, true), + 'When context.disableInlineRules is false and props.disableInlineRules is true': testRulesAreNotInlined(false, true), + 'When props.disableInlineRules is true and context.disableInlineRules is null': testRulesAreNotInlined(null, true), + //Inlined + 'When context.disableInlineRules is false and props.disableInlineRules is false': testRulesAreInlined(false, false), + 'When context.disableInlineRules is true and props.disableInlineRules is false': testRulesAreInlined(true, false), + 'When context.disableInlineRules is false': testRulesAreInlined(false, undefined), + 'When props.disableInlineRules is false': testRulesAreInlined(undefined, false), + 'When neither props.disableInlineRules nor context.disableInlineRules are defined': testRulesAreInlined(undefined, undefined), + 'When props.disableInlineRules is undefined and context.disableInlineRules is null': testRulesAreInlined(null, undefined), + 'When props.disableInlineRules is false and context.disableInlineRules is null': testRulesAreInlined(null, false), + }, + 'peer between all types of peers and port range types'(test: Test) { // GIVEN const stack = new Stack(undefined, 'TestStack', { env: { account: '12345678', region: 'dummy' } }); @@ -311,3 +330,432 @@ nodeunitShim({ test.done(); }, }); + +function testRulesAreInlined(contextDisableInlineRules: boolean | undefined | null, optionsDisableInlineRules: boolean | undefined) { + return { + 'When allowAllOutbound': { + 'new SecurityGroup will create an inline SecurityGroupEgress rule to allow all traffic'(test: Test) { + // GIVEN + const stack = new Stack(); + stack.node.setContext(SECURITY_GROUP_DISABLE_INLINE_RULES_CONTEXT_KEY, contextDisableInlineRules); + const vpc = new Vpc(stack, 'VPC'); + const props: SecurityGroupProps = { vpc, allowAllOutbound: true, disableInlineRules: optionsDisableInlineRules }; + + // WHEN + new SecurityGroup(stack, 'SG1', props); + + expect(stack).to(haveResource('AWS::EC2::SecurityGroup', { + GroupDescription: 'Default/SG1', + VpcId: stack.resolve(vpc.vpcId), + SecurityGroupEgress: [ + { + CidrIp: '0.0.0.0/0', + Description: 'Allow all outbound traffic by default', + IpProtocol: '-1', + }, + ], + })); + expect(stack).to(not(haveResourceLike('AWS::EC2::SecurityGroupEgress', {}))); + expect(stack).to(not(haveResourceLike('AWS::EC2::SecurityGroupIngress', {}))); + test.done(); + }, + + 'addEgressRule rule will not modify egress rules'(test: Test) { + // GIVEN + const stack = new Stack(); + stack.node.setContext(SECURITY_GROUP_DISABLE_INLINE_RULES_CONTEXT_KEY, contextDisableInlineRules); + const vpc = new Vpc(stack, 'VPC'); + const props: SecurityGroupProps = { vpc, allowAllOutbound: true, disableInlineRules: optionsDisableInlineRules }; + + // WHEN + const sg = new SecurityGroup(stack, 'SG1', props); + sg.addEgressRule(Peer.anyIpv4(), Port.tcp(86), 'An external Rule'); + + expect(stack).to(haveResource('AWS::EC2::SecurityGroup', { + GroupDescription: 'Default/SG1', + VpcId: stack.resolve(vpc.vpcId), + SecurityGroupEgress: [ + { + CidrIp: '0.0.0.0/0', + Description: 'Allow all outbound traffic by default', + IpProtocol: '-1', + }, + ], + })); + + expect(stack).to(not(haveResourceLike('AWS::EC2::SecurityGroupEgress', {}))); + expect(stack).to(not(haveResourceLike('AWS::EC2::SecurityGroupIngress', {}))); + test.done(); + }, + + 'addIngressRule will add a new ingress rule'(test: Test) { + // GIVEN + const stack = new Stack(); + stack.node.setContext(SECURITY_GROUP_DISABLE_INLINE_RULES_CONTEXT_KEY, contextDisableInlineRules); + const vpc = new Vpc(stack, 'VPC'); + const props: SecurityGroupProps = { vpc, allowAllOutbound: true, disableInlineRules: optionsDisableInlineRules }; + + // WHEN + const sg = new SecurityGroup(stack, 'SG1', props); + sg.addIngressRule(Peer.anyIpv4(), Port.tcp(86), 'An external Rule'); + + expect(stack).to(haveResource('AWS::EC2::SecurityGroup', { + GroupDescription: 'Default/SG1', + VpcId: stack.resolve(vpc.vpcId), + SecurityGroupIngress: [ + { + CidrIp: '0.0.0.0/0', + Description: 'An external Rule', + FromPort: 86, + IpProtocol: 'tcp', + ToPort: 86, + }, + ], + SecurityGroupEgress: [ + { + CidrIp: '0.0.0.0/0', + Description: 'Allow all outbound traffic by default', + IpProtocol: '-1', + }, + ], + })); + + expect(stack).to(not(haveResourceLike('AWS::EC2::SecurityGroupEgress', {}))); + expect(stack).to(not(haveResourceLike('AWS::EC2::SecurityGroupIngress', {}))); + test.done(); + }, + }, + + 'When do not allowAllOutbound': { + 'new SecurityGroup rule will create an egress rule that denies all traffic'(test: Test) { + // GIVEN + const stack = new Stack(); + stack.node.setContext(SECURITY_GROUP_DISABLE_INLINE_RULES_CONTEXT_KEY, contextDisableInlineRules); + const vpc = new Vpc(stack, 'VPC'); + const props: SecurityGroupProps = { vpc, allowAllOutbound: false, disableInlineRules: optionsDisableInlineRules }; + + // WHEN + new SecurityGroup(stack, 'SG1', props); + + expect(stack).to(haveResource('AWS::EC2::SecurityGroup', { + GroupDescription: 'Default/SG1', + VpcId: stack.resolve(vpc.vpcId), + SecurityGroupEgress: [ + { + CidrIp: '255.255.255.255/32', + Description: 'Disallow all traffic', + IpProtocol: 'icmp', + FromPort: 252, + ToPort: 86, + }, + ], + })); + expect(stack).to(not(haveResourceLike('AWS::EC2::SecurityGroupIngress', {}))); + expect(stack).to(not(haveResourceLike('AWS::EC2::SecurityGroupIngress', {}))); + + test.done(); + }, + 'addEgressRule rule will add a new inline egress rule and remove the denyAllTraffic rule'(test: Test) { + // GIVEN + const stack = new Stack(); + stack.node.setContext(SECURITY_GROUP_DISABLE_INLINE_RULES_CONTEXT_KEY, contextDisableInlineRules); + const vpc = new Vpc(stack, 'VPC'); + const props: SecurityGroupProps = { vpc, allowAllOutbound: false, disableInlineRules: optionsDisableInlineRules }; + + // WHEN + const sg = new SecurityGroup(stack, 'SG1', props); + sg.addEgressRule(Peer.anyIpv4(), Port.tcp(86), 'An inline Rule'); + + expect(stack).to(haveResource('AWS::EC2::SecurityGroup', { + GroupDescription: 'Default/SG1', + VpcId: stack.resolve(vpc.vpcId), + SecurityGroupEgress: [ + { + CidrIp: '0.0.0.0/0', + Description: 'An inline Rule', + FromPort: 86, + IpProtocol: 'tcp', + ToPort: 86, + }, + ], + })); + + expect(stack).to(not(haveResourceLike('AWS::EC2::SecurityGroupEgress', {}))); + expect(stack).to(not(haveResourceLike('AWS::EC2::SecurityGroupIngress', {}))); + test.done(); + }, + + 'addIngressRule will add a new ingress rule'(test: Test) { + // GIVEN + const stack = new Stack(); + stack.node.setContext(SECURITY_GROUP_DISABLE_INLINE_RULES_CONTEXT_KEY, contextDisableInlineRules); + const vpc = new Vpc(stack, 'VPC'); + const props: SecurityGroupProps = { vpc, allowAllOutbound: false, disableInlineRules: optionsDisableInlineRules }; + + // WHEN + const sg = new SecurityGroup(stack, 'SG1', props); + sg.addIngressRule(Peer.anyIpv4(), Port.tcp(86), 'An external Rule'); + + expect(stack).to(haveResource('AWS::EC2::SecurityGroup', { + GroupDescription: 'Default/SG1', + VpcId: stack.resolve(vpc.vpcId), + SecurityGroupIngress: [ + { + CidrIp: '0.0.0.0/0', + Description: 'An external Rule', + FromPort: 86, + IpProtocol: 'tcp', + ToPort: 86, + }, + ], + SecurityGroupEgress: [ + { + CidrIp: '255.255.255.255/32', + Description: 'Disallow all traffic', + IpProtocol: 'icmp', + FromPort: 252, + ToPort: 86, + }, + ], + })); + + expect(stack).to(not(haveResourceLike('AWS::EC2::SecurityGroupEgress', {}))); + expect(stack).to(not(haveResourceLike('AWS::EC2::SecurityGroupIngress', {}))); + test.done(); + }, + }, + }; +} + + +function testRulesAreNotInlined(contextDisableInlineRules: boolean | undefined | null, optionsDisableInlineRules: boolean | undefined) { + return { + 'When allowAllOutbound': { + 'new SecurityGroup will create an external SecurityGroupEgress rule'(test: Test) { + // GIVEN + const stack = new Stack(); + stack.node.setContext(SECURITY_GROUP_DISABLE_INLINE_RULES_CONTEXT_KEY, contextDisableInlineRules); + const vpc = new Vpc(stack, 'VPC'); + const props: SecurityGroupProps = { vpc, allowAllOutbound: true, disableInlineRules: optionsDisableInlineRules }; + + // WHEN + const sg = new SecurityGroup(stack, 'SG1', props); + + expect(stack).to(haveResource('AWS::EC2::SecurityGroup', { + GroupDescription: 'Default/SG1', + VpcId: stack.resolve(vpc.vpcId), + })); + expect(stack).to(haveResource('AWS::EC2::SecurityGroupEgress', { + GroupId: stack.resolve(sg.securityGroupId), + CidrIp: '0.0.0.0/0', + Description: 'Allow all outbound traffic by default', + IpProtocol: '-1', + })); + expect(stack).to(not(haveResourceLike('AWS::EC2::SecurityGroupIngress', {}))); + test.done(); + }, + + 'addIngressRule rule will not remove external allowAllOutbound rule'(test: Test) { + // GIVEN + const stack = new Stack(); + stack.node.setContext(SECURITY_GROUP_DISABLE_INLINE_RULES_CONTEXT_KEY, contextDisableInlineRules); + const vpc = new Vpc(stack, 'VPC'); + const props: SecurityGroupProps = { vpc, allowAllOutbound: true, disableInlineRules: optionsDisableInlineRules }; + + // WHEN + const sg = new SecurityGroup(stack, 'SG1', props); + sg.addEgressRule(Peer.anyIpv4(), Port.tcp(86), 'An external Rule'); + + expect(stack).to(haveResource('AWS::EC2::SecurityGroup', { + GroupDescription: 'Default/SG1', + VpcId: stack.resolve(vpc.vpcId), + })); + + expect(stack).to(haveResource('AWS::EC2::SecurityGroupEgress', { + GroupId: stack.resolve(sg.securityGroupId), + CidrIp: '0.0.0.0/0', + Description: 'Allow all outbound traffic by default', + IpProtocol: '-1', + })); + + expect(stack).to(not(haveResourceLike('AWS::EC2::SecurityGroupIngress', {}))); + test.done(); + }, + + 'addIngressRule rule will not add a new egress rule'(test: Test) { + // GIVEN + const stack = new Stack(); + stack.node.setContext(SECURITY_GROUP_DISABLE_INLINE_RULES_CONTEXT_KEY, contextDisableInlineRules); + const vpc = new Vpc(stack, 'VPC'); + const props: SecurityGroupProps = { vpc, allowAllOutbound: true, disableInlineRules: optionsDisableInlineRules }; + + // WHEN + const sg = new SecurityGroup(stack, 'SG1', props); + sg.addEgressRule(Peer.anyIpv4(), Port.tcp(86), 'An external Rule'); + + expect(stack).to(haveResource('AWS::EC2::SecurityGroup', { + GroupDescription: 'Default/SG1', + VpcId: stack.resolve(vpc.vpcId), + })); + + expect(stack).to(not(haveResource('AWS::EC2::SecurityGroupEgress', { + GroupId: stack.resolve(sg.securityGroupId), + Description: 'An external Rule', + }))); + + expect(stack).to(not(haveResourceLike('AWS::EC2::SecurityGroupIngress', {}))); + test.done(); + }, + + 'addIngressRule rule will add a new external ingress rule even if it could have been inlined'(test: Test) { + // GIVEN + const stack = new Stack(); + stack.node.setContext(SECURITY_GROUP_DISABLE_INLINE_RULES_CONTEXT_KEY, contextDisableInlineRules); + const vpc = new Vpc(stack, 'VPC'); + const props: SecurityGroupProps = { vpc, allowAllOutbound: true, disableInlineRules: optionsDisableInlineRules }; + + // WHEN + const sg = new SecurityGroup(stack, 'SG1', props); + sg.addIngressRule(Peer.anyIpv4(), Port.tcp(86), 'An external Rule'); + + expect(stack).to(haveResource('AWS::EC2::SecurityGroup', { + GroupDescription: 'Default/SG1', + VpcId: stack.resolve(vpc.vpcId), + })); + + expect(stack).to(haveResource('AWS::EC2::SecurityGroupIngress', { + GroupId: stack.resolve(sg.securityGroupId), + CidrIp: '0.0.0.0/0', + Description: 'An external Rule', + FromPort: 86, + IpProtocol: 'tcp', + ToPort: 86, + })); + + expect(stack).to(haveResource('AWS::EC2::SecurityGroupEgress', { + GroupId: stack.resolve(sg.securityGroupId), + CidrIp: '0.0.0.0/0', + Description: 'Allow all outbound traffic by default', + IpProtocol: '-1', + })); + test.done(); + }, + }, + + 'When do not allowAllOutbound': { + 'new SecurityGroup rule will create an external egress rule that denies all traffic'(test: Test) { + // GIVEN + const stack = new Stack(); + stack.node.setContext(SECURITY_GROUP_DISABLE_INLINE_RULES_CONTEXT_KEY, contextDisableInlineRules); + const vpc = new Vpc(stack, 'VPC'); + const props: SecurityGroupProps = { vpc, allowAllOutbound: false, disableInlineRules: optionsDisableInlineRules }; + + // WHEN + const sg = new SecurityGroup(stack, 'SG1', props); + + expect(stack).to(haveResource('AWS::EC2::SecurityGroup', { + GroupDescription: 'Default/SG1', + VpcId: stack.resolve(vpc.vpcId), + })); + expect(stack).to(not(haveResourceLike('AWS::EC2::SecurityGroupIngress', {}))); + expect(stack).to(haveResource('AWS::EC2::SecurityGroupEgress', { + GroupId: stack.resolve(sg.securityGroupId), + CidrIp: '255.255.255.255/32', + Description: 'Disallow all traffic', + IpProtocol: 'icmp', + FromPort: 252, + ToPort: 86, + })); + test.done(); + }, + + 'addEgressRule rule will remove the rule that denies all traffic if another egress rule is added'(test: Test) { + // GIVEN + const stack = new Stack(); + stack.node.setContext(SECURITY_GROUP_DISABLE_INLINE_RULES_CONTEXT_KEY, contextDisableInlineRules); + const vpc = new Vpc(stack, 'VPC'); + const props: SecurityGroupProps = { vpc, allowAllOutbound: false, disableInlineRules: optionsDisableInlineRules }; + + // WHEN + const sg = new SecurityGroup(stack, 'SG1', props); + sg.addEgressRule(Peer.anyIpv4(), Port.tcp(86), 'An external Rule'); + + expect(stack).to(haveResource('AWS::EC2::SecurityGroup', { + GroupDescription: 'Default/SG1', + VpcId: stack.resolve(vpc.vpcId), + })); + expect(stack).to(not(haveResourceLike('AWS::EC2::SecurityGroupIngress', {}))); + expect(stack).to(not(haveResourceLike('AWS::EC2::SecurityGroupEgress', { + GroupId: stack.resolve(sg.securityGroupId), + CidrIp: '255.255.255.255/32', + }))); + test.done(); + }, + + 'addEgressRule rule will add a new external egress rule even if it could have been inlined'(test: Test) { + // GIVEN + const stack = new Stack(); + stack.node.setContext(SECURITY_GROUP_DISABLE_INLINE_RULES_CONTEXT_KEY, contextDisableInlineRules); + const vpc = new Vpc(stack, 'VPC'); + const props: SecurityGroupProps = { vpc, allowAllOutbound: false, disableInlineRules: optionsDisableInlineRules }; + + // WHEN + const sg = new SecurityGroup(stack, 'SG1', props); + sg.addEgressRule(Peer.anyIpv4(), Port.tcp(86), 'An external Rule'); + + expect(stack).to(haveResource('AWS::EC2::SecurityGroup', { + GroupDescription: 'Default/SG1', + VpcId: stack.resolve(vpc.vpcId), + })); + + expect(stack).to(haveResource('AWS::EC2::SecurityGroupEgress', { + GroupId: stack.resolve(sg.securityGroupId), + CidrIp: '0.0.0.0/0', + Description: 'An external Rule', + FromPort: 86, + IpProtocol: 'tcp', + ToPort: 86, + })); + + expect(stack).to(not(haveResourceLike('AWS::EC2::SecurityGroupIngress', {}))); + test.done(); + }, + + 'addIngressRule will add a new external ingress rule even if it could have been inlined'(test: Test) { + // GIVEN + const stack = new Stack(); + stack.node.setContext(SECURITY_GROUP_DISABLE_INLINE_RULES_CONTEXT_KEY, contextDisableInlineRules); + const vpc = new Vpc(stack, 'VPC'); + const props: SecurityGroupProps = { vpc, allowAllOutbound: false, disableInlineRules: optionsDisableInlineRules }; + + // WHEN + const sg = new SecurityGroup(stack, 'SG1', props); + sg.addIngressRule(Peer.anyIpv4(), Port.tcp(86), 'An external Rule'); + + expect(stack).to(haveResource('AWS::EC2::SecurityGroup', { + GroupDescription: 'Default/SG1', + VpcId: stack.resolve(vpc.vpcId), + })); + + expect(stack).to(haveResource('AWS::EC2::SecurityGroupIngress', { + GroupId: stack.resolve(sg.securityGroupId), + CidrIp: '0.0.0.0/0', + Description: 'An external Rule', + FromPort: 86, + IpProtocol: 'tcp', + ToPort: 86, + })); + + expect(stack).to(haveResource('AWS::EC2::SecurityGroupEgress', { + GroupId: stack.resolve(sg.securityGroupId), + CidrIp: '255.255.255.255/32', + Description: 'Disallow all traffic', + IpProtocol: 'icmp', + FromPort: 252, + ToPort: 86, + })); + test.done(); + }, + }, + }; +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/test/volume.test.ts b/packages/@aws-cdk/aws-ec2/test/volume.test.ts index c390821c3a37a..308e1ad4fa1ef 100644 --- a/packages/@aws-cdk/aws-ec2/test/volume.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/volume.test.ts @@ -4,7 +4,7 @@ import { haveResource, haveResourceLike, ResourcePart, -} from '@aws-cdk/assert'; +} from '@aws-cdk/assert-internal'; import { AccountRootPrincipal, Role, diff --git a/packages/@aws-cdk/aws-ec2/test/vpc-endpoint-service.test.ts b/packages/@aws-cdk/aws-ec2/test/vpc-endpoint-service.test.ts index 0f641a3403839..744e32953cc15 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc-endpoint-service.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/vpc-endpoint-service.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import { ArnPrincipal } from '@aws-cdk/aws-iam'; import { Stack } from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; @@ -31,7 +31,7 @@ nodeunitShim({ new VpcEndpointService(stack, 'EndpointService', { vpcEndpointServiceLoadBalancers: [lb], acceptanceRequired: false, - whitelistedPrincipals: [new ArnPrincipal('arn:aws:iam::123456789012:root')], + allowedPrincipals: [new ArnPrincipal('arn:aws:iam::123456789012:root')], }); // THEN expect(stack).to(haveResource('AWS::EC2::VPCEndpointService', { @@ -57,7 +57,7 @@ nodeunitShim({ new VpcEndpointService(stack, 'EndpointService', { vpcEndpointServiceLoadBalancers: [lb], acceptanceRequired: false, - whitelistedPrincipals: [new ArnPrincipal('arn:aws:iam::123456789012:root')], + allowedPrincipals: [new ArnPrincipal('arn:aws:iam::123456789012:root')], }); // THEN @@ -85,7 +85,7 @@ nodeunitShim({ new VpcEndpointService(stack, 'EndpointService', { vpcEndpointServiceLoadBalancers: [lb], acceptanceRequired: true, - whitelistedPrincipals: [new ArnPrincipal('arn:aws:iam::123456789012:root')], + allowedPrincipals: [new ArnPrincipal('arn:aws:iam::123456789012:root')], }); // THEN diff --git a/packages/@aws-cdk/aws-ec2/test/vpc-endpoint.test.ts b/packages/@aws-cdk/aws-ec2/test/vpc-endpoint.test.ts index fa51431963fe5..036e173910454 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc-endpoint.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/vpc-endpoint.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; import { AnyPrincipal, PolicyStatement } from '@aws-cdk/aws-iam'; import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import { ContextProvider, Fn, Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-ec2/test/vpc-flow-logs.test.ts b/packages/@aws-cdk/aws-ec2/test/vpc-flow-logs.test.ts index 8d341924c3bad..243d5fef0b46c 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc-flow-logs.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/vpc-flow-logs.test.ts @@ -1,4 +1,4 @@ -import { countResources, expect, haveResource } from '@aws-cdk/assert'; +import { countResources, expect, haveResource } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import * as logs from '@aws-cdk/aws-logs'; import * as s3 from '@aws-cdk/aws-s3'; diff --git a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts index 77de63770cd6a..172bec102ccd0 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts @@ -1,4 +1,4 @@ -import { countResources, expect as cdkExpect, haveResource, haveResourceLike, isSuperObject, MatchStyle, SynthUtils } from '@aws-cdk/assert'; +import { countResources, expect as cdkExpect, haveResource, haveResourceLike, isSuperObject, MatchStyle, SynthUtils } from '@aws-cdk/assert-internal'; import { CfnOutput, CfnResource, Fn, Lazy, Stack, Tags } from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import { @@ -855,6 +855,24 @@ nodeunitShim({ test.done(); }, + + 'NAT gateway provider with EIP allocations'(test: Test) { + const stack = new Stack(); + const natGatewayProvider = NatProvider.gateway({ + eipAllocationIds: ['a', 'b', 'c', 'd'], + }); + new Vpc(stack, 'VpcNetwork', { natGatewayProvider }); + + cdkExpect(stack).to(haveResource('AWS::EC2::NatGateway', { + AllocationId: 'a', + })); + cdkExpect(stack).to(haveResource('AWS::EC2::NatGateway', { + AllocationId: 'b', + })); + + test.done(); + }, + 'Can add an IPv6 route'(test: Test) { // GIVEN const stack = getTestStack(); diff --git a/packages/@aws-cdk/aws-ec2/test/vpn.test.ts b/packages/@aws-cdk/aws-ec2/test/vpn.test.ts index 4cf8880c3b0ab..3240c59a5c9e0 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpn.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/vpn.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import { Duration, Stack, Token } from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import { PublicSubnet, Vpc, VpnConnection } from '../lib'; diff --git a/packages/@aws-cdk/aws-ecr-assets/.gitignore b/packages/@aws-cdk/aws-ecr-assets/.gitignore index c6e7daac3ab7e..21e1d17bb7d3d 100644 --- a/packages/@aws-cdk/aws-ecr-assets/.gitignore +++ b/packages/@aws-cdk/aws-ecr-assets/.gitignore @@ -20,4 +20,4 @@ junit.xml !jest.config.js -!test/whitelisted-image/node_modules +!test/allow-listed-image/node_modules diff --git a/packages/@aws-cdk/aws-ecr-assets/README.md b/packages/@aws-cdk/aws-ecr-assets/README.md index dc621f942b430..a2d7ff50d8773 100644 --- a/packages/@aws-cdk/aws-ecr-assets/README.md +++ b/packages/@aws-cdk/aws-ecr-assets/README.md @@ -3,13 +3,7 @@ --- -![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. +![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge) --- @@ -75,6 +69,38 @@ const asset = new DockerImageAsset(this, 'MyBuildImage', { }) ``` +## Publishing images to ECR repositories + +`DockerImageAsset` is designed for seamless build & consumption of image assets by CDK code deployed to multiple environments +through the CDK CLI or through CI/CD workflows. To that end, the ECR repository behind this construct is controlled by the AWS CDK. +The mechanics of where these images are published and how are intentionally kept as an implementation detail, and the construct +does not support customizations such as specifying the ECR repository name or tags. + +If you are looking for a way to _publish_ image assets to an ECR repository in your control, you should consider using +[wchaws/cdk-ecr-deployment], which is able to replicate an image asset from the CDK-controlled ECR repository to a repository of +your choice. + +Here an example from the [wchaws/cdk-ecr-deployment] project: + +```ts +import * as ecrdeploy from 'cdk-ecr-deployment'; + +const image = new DockerImageAsset(this, 'CDKDockerImage', { + directory: path.join(__dirname, 'docker'), +}); + +new ecrdeploy.ECRDeployment(this, 'DeployDockerImage', { + src: new ecrdeploy.DockerImageName(image.imageUri), + dest: new ecrdeploy.DockerImageName(`${cdk.Aws.ACCOUNT_ID}.dkr.ecr.us-west-2.amazonaws.com/test:nginx`), +}); +``` + +⚠️ Please note that this is a 3rd-party construct library and is not officially supported by AWS. +You are welcome to +1 [this GitHub issue](https://github.com/aws/aws-cdk/issues/12597) if you would like to see +native support for this use-case in the AWS CDK. + +[wchaws/cdk-ecr-deployment]: https://github.com/wchaws/cdk-ecr-deployment + ## Pull Permissions Depending on the consumer of your image asset, you will need to make sure diff --git a/packages/@aws-cdk/aws-ecr-assets/lib/image-asset.ts b/packages/@aws-cdk/aws-ecr-assets/lib/image-asset.ts index 26a3a40f35335..928fb286cb3a0 100644 --- a/packages/@aws-cdk/aws-ecr-assets/lib/image-asset.ts +++ b/packages/@aws-cdk/aws-ecr-assets/lib/image-asset.ts @@ -1,11 +1,13 @@ import * as fs from 'fs'; import * as path from 'path'; -import * as assets from '@aws-cdk/assets'; import * as ecr from '@aws-cdk/aws-ecr'; -import { Annotations, FeatureFlags, IgnoreMode, Stack, Token } from '@aws-cdk/core'; +import { Annotations, AssetStaging, FeatureFlags, FileFingerprintOptions, IgnoreMode, Stack, SymlinkFollowMode, Token } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; +// keep this import separate from other imports to reduce chance for merge conflicts with v2-main +// eslint-disable-next-line +import { FingerprintOptions, FollowMode, IAsset } from '@aws-cdk/assets'; // keep this import separate from other imports to reduce chance for merge conflicts with v2-main // eslint-disable-next-line no-duplicate-imports, import/order import { Construct as CoreConstruct } from '@aws-cdk/core'; @@ -13,7 +15,7 @@ import { Construct as CoreConstruct } from '@aws-cdk/core'; /** * Options for DockerImageAsset */ -export interface DockerImageAssetOptions extends assets.FingerprintOptions { +export interface DockerImageAssetOptions extends FingerprintOptions, FileFingerprintOptions { /** * ECR repository name * @@ -69,7 +71,7 @@ export interface DockerImageAssetProps extends DockerImageAssetOptions { * * The image will be created in build time and uploaded to an ECR repository. */ -export class DockerImageAsset extends CoreConstruct implements assets.IAsset { +export class DockerImageAsset extends CoreConstruct implements IAsset { /** * The full URI of the image (including a tag). Use this reference to pull * the asset. @@ -81,8 +83,21 @@ export class DockerImageAsset extends CoreConstruct implements assets.IAsset { */ public repository: ecr.IRepository; + /** + * A hash of the source of this asset, which is available at construction time. As this is a plain + * string, it can be used in construct IDs in order to enforce creation of a new resource when + * the content hash has changed. + * @deprecated use assetHash + */ public readonly sourceHash: string; + /** + * A hash of this asset, which is available at construction time. As this is a plain string, it + * can be used in construct IDs in order to enforce creation of a new resource when the content + * hash has changed. + */ + public readonly assetHash: string; + constructor(scope: Construct, id: string, props: DockerImageAssetProps) { super(scope, id); @@ -116,12 +131,12 @@ export class DockerImageAsset extends CoreConstruct implements assets.IAsset { ...dockerIgnorePatterns, ...exclude, - // Ensure .dockerignore is whitelisted no matter what. + // Ensure .dockerignore is included no matter what. '!.dockerignore', ]; } - // Ensure the Dockerfile is whitelisted no matter what. + // Ensure the Dockerfile is included no matter what. exclude.push('!' + path.basename(file)); if (props.repositoryName) { @@ -141,8 +156,9 @@ export class DockerImageAsset extends CoreConstruct implements assets.IAsset { // deletion of the ECR repository the app used). extraHash.version = '1.21.0'; - const staging = new assets.Staging(this, 'Staging', { + const staging = new AssetStaging(this, 'Staging', { ...props, + follow: props.followSymlinks ?? toSymlinkFollow(props.follow), exclude, ignoreMode, sourcePath: dir, @@ -151,7 +167,8 @@ export class DockerImageAsset extends CoreConstruct implements assets.IAsset { : JSON.stringify(extraHash), }); - this.sourceHash = staging.sourceHash; + this.sourceHash = staging.assetHash; + this.assetHash = staging.assetHash; const stack = Stack.of(this); const location = stack.synthesizer.addDockerImageAsset({ @@ -159,8 +176,7 @@ export class DockerImageAsset extends CoreConstruct implements assets.IAsset { dockerBuildArgs: props.buildArgs, dockerBuildTarget: props.target, dockerFile: props.file, - repositoryName: props.repositoryName, - sourceHash: staging.sourceHash, + sourceHash: staging.assetHash, }); this.repository = ecr.Repository.fromRepositoryName(this, 'Repository', location.repositoryName); @@ -185,3 +201,13 @@ function validateBuildArgs(buildArgs?: { [key: string]: string }) { } } } + +function toSymlinkFollow(follow?: FollowMode): SymlinkFollowMode | undefined { + switch (follow) { + case undefined: return undefined; + case FollowMode.NEVER: return SymlinkFollowMode.NEVER; + case FollowMode.ALWAYS: return SymlinkFollowMode.ALWAYS; + case FollowMode.BLOCK_EXTERNAL: return SymlinkFollowMode.BLOCK_EXTERNAL; + case FollowMode.EXTERNAL: return SymlinkFollowMode.EXTERNAL; + } +} diff --git a/packages/@aws-cdk/aws-ecr-assets/package.json b/packages/@aws-cdk/aws-ecr-assets/package.json index 3d8b54ee08122..055015cc313cd 100644 --- a/packages/@aws-cdk/aws-ecr-assets/package.json +++ b/packages/@aws-cdk/aws-ecr-assets/package.json @@ -63,7 +63,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "@types/proxyquire": "^1.3.28", "aws-cdk": "0.0.0", "cdk-build-tools": "0.0.0", @@ -71,7 +71,8 @@ "nodeunit-shim": "0.0.0", "pkglint": "0.0.0", "proxyquire": "^2.1.3", - "@aws-cdk/cloud-assembly-schema": "0.0.0" + "@aws-cdk/cloud-assembly-schema": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-ecr": "0.0.0", @@ -81,7 +82,7 @@ "@aws-cdk/assets": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "minimatch": "^3.0.4", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -91,7 +92,7 @@ "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "nyc": { "statements": 70 @@ -102,8 +103,8 @@ "bundledDependencies": [ "minimatch" ], - "stability": "experimental", - "maturity": "experimental", + "stability": "stable", + "maturity": "stable", "awscdkio": { "announce": false }, diff --git a/packages/@aws-cdk/aws-ecr-assets/test/whitelisted-image/.dockerignore b/packages/@aws-cdk/aws-ecr-assets/test/allow-listed-image/.dockerignore similarity index 100% rename from packages/@aws-cdk/aws-ecr-assets/test/whitelisted-image/.dockerignore rename to packages/@aws-cdk/aws-ecr-assets/test/allow-listed-image/.dockerignore diff --git a/packages/@aws-cdk/aws-ecr-assets/test/whitelisted-image/Dockerfile b/packages/@aws-cdk/aws-ecr-assets/test/allow-listed-image/Dockerfile similarity index 100% rename from packages/@aws-cdk/aws-ecr-assets/test/whitelisted-image/Dockerfile rename to packages/@aws-cdk/aws-ecr-assets/test/allow-listed-image/Dockerfile diff --git a/packages/@aws-cdk/aws-ecr-assets/test/whitelisted-image/foobar.txt b/packages/@aws-cdk/aws-ecr-assets/test/allow-listed-image/foobar.txt similarity index 100% rename from packages/@aws-cdk/aws-ecr-assets/test/whitelisted-image/foobar.txt rename to packages/@aws-cdk/aws-ecr-assets/test/allow-listed-image/foobar.txt diff --git a/packages/@aws-cdk/aws-ecr-assets/test/whitelisted-image/index.py b/packages/@aws-cdk/aws-ecr-assets/test/allow-listed-image/index.py similarity index 100% rename from packages/@aws-cdk/aws-ecr-assets/test/whitelisted-image/index.py rename to packages/@aws-cdk/aws-ecr-assets/test/allow-listed-image/index.py diff --git a/packages/@aws-cdk/aws-ecr-assets/test/whitelisted-image/node_modules/one b/packages/@aws-cdk/aws-ecr-assets/test/allow-listed-image/node_modules/one similarity index 100% rename from packages/@aws-cdk/aws-ecr-assets/test/whitelisted-image/node_modules/one rename to packages/@aws-cdk/aws-ecr-assets/test/allow-listed-image/node_modules/one diff --git a/packages/@aws-cdk/aws-ecr-assets/test/whitelisted-image/node_modules/some_dep/file b/packages/@aws-cdk/aws-ecr-assets/test/allow-listed-image/node_modules/some_dep/file similarity index 100% rename from packages/@aws-cdk/aws-ecr-assets/test/whitelisted-image/node_modules/some_dep/file rename to packages/@aws-cdk/aws-ecr-assets/test/allow-listed-image/node_modules/some_dep/file diff --git a/packages/@aws-cdk/aws-ecr-assets/test/whitelisted-image/subdirectory/baz.txt b/packages/@aws-cdk/aws-ecr-assets/test/allow-listed-image/subdirectory/baz.txt similarity index 100% rename from packages/@aws-cdk/aws-ecr-assets/test/whitelisted-image/subdirectory/baz.txt rename to packages/@aws-cdk/aws-ecr-assets/test/allow-listed-image/subdirectory/baz.txt diff --git a/packages/@aws-cdk/aws-ecr-assets/test/image-asset.test.ts b/packages/@aws-cdk/aws-ecr-assets/test/image-asset.test.ts index 17fd37be2e234..76dac04f66852 100644 --- a/packages/@aws-cdk/aws-ecr-assets/test/image-asset.test.ts +++ b/packages/@aws-cdk/aws-ecr-assets/test/image-asset.test.ts @@ -1,6 +1,6 @@ import * as fs from 'fs'; import * as path from 'path'; -import { expect as ourExpect, haveResource } from '@aws-cdk/assert'; +import { expect as ourExpect, haveResource } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import { App, DefaultStackSynthesizer, IgnoreMode, Lazy, LegacyStackSynthesizer, Stack, Stage } from '@aws-cdk/core'; @@ -192,8 +192,8 @@ describe('image asset', () => { const session = app.synth(); - expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'Dockerfile'))).toBeDefined(); - expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'index.py'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'Dockerfile'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'index.py'))).toBeDefined(); }); @@ -205,25 +205,25 @@ describe('image asset', () => { testDockerDirectoryIsStagedWithoutFilesSpecifiedInDockerignore(app, IgnoreMode.GLOB); }); - testFutureBehavior('docker directory is staged with whitelisted files specified in .dockerignore', flags, App, (app) => { + testFutureBehavior('docker directory is staged with allow-listed files specified in .dockerignore', flags, App, (app) => { const stack = new Stack(app); const image = new DockerImageAsset(stack, 'MyAsset', { - directory: path.join(__dirname, 'whitelisted-image'), + directory: path.join(__dirname, 'allow-listed-image'), }); const session = app.synth(); // Only the files exempted above should be included. - expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, '.dockerignore'))).toBeDefined(); - expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'Dockerfile'))).toBeDefined(); - expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'index.py'))).toBeDefined(); - expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'foobar.txt'))).toBeDefined(); - expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'subdirectory'))).toBeDefined(); - expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'subdirectory', 'baz.txt'))).toBeDefined(); - expect(!fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'node_modules'))).toBeDefined(); - expect(!fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'node_modules', 'one'))).toBeDefined(); - expect(!fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'node_modules', 'some_dep'))).toBeDefined(); - expect(!fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'node_modules', 'some_dep', 'file'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, '.dockerignore'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'Dockerfile'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'index.py'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'foobar.txt'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'subdirectory'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'subdirectory', 'baz.txt'))).toBeDefined(); + expect(!fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'node_modules'))).toBeDefined(); + expect(!fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'node_modules', 'one'))).toBeDefined(); + expect(!fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'node_modules', 'some_dep'))).toBeDefined(); + expect(!fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'node_modules', 'some_dep', 'file'))).toBeDefined(); }); @@ -283,13 +283,13 @@ describe('image asset', () => { const asset6 = new DockerImageAsset(stack, 'Asset6', { directory, extraHash: 'random-extra' }); const asset7 = new DockerImageAsset(stack, 'Asset7', { directory, repositoryName: 'foo' }); - expect(asset1.sourceHash).toEqual('ab01ecd4419f59e1ec0ac9e57a60dbb653be68a29af0223fa8cb24b4b747bc73'); - expect(asset2.sourceHash).toEqual('7fb12f6148098e3f5c56c788a865d2af689125ead403b795fe6a262ec34384b3'); - expect(asset3.sourceHash).toEqual('fc3b6d802ba198ba2ee55079dbef27682bcd1288d5849eb5bbd5cd69038359b3'); - expect(asset4.sourceHash).toEqual('30439ea6dfeb4ddfd9175097286895c78393ef52a78c68f92db08abc4513cad6'); - expect(asset5.sourceHash).toEqual('5775170880e26ba31799745241b90d4340c674bb3b1c01d758e416ee3f1c386f'); - expect(asset6.sourceHash).toEqual('ba82fd351a4d3e3f5c5d948b9948e7e829badc3da90f97e00bb7724afbeacfd4'); - expect(asset7.sourceHash).toEqual('26ec194928431cab6ec5af24ea9f01af2cf7b20e361128b07b2a7405d2951f95'); + expect(asset1.assetHash).toEqual('ab01ecd4419f59e1ec0ac9e57a60dbb653be68a29af0223fa8cb24b4b747bc73'); + expect(asset2.assetHash).toEqual('7fb12f6148098e3f5c56c788a865d2af689125ead403b795fe6a262ec34384b3'); + expect(asset3.assetHash).toEqual('fc3b6d802ba198ba2ee55079dbef27682bcd1288d5849eb5bbd5cd69038359b3'); + expect(asset4.assetHash).toEqual('30439ea6dfeb4ddfd9175097286895c78393ef52a78c68f92db08abc4513cad6'); + expect(asset5.assetHash).toEqual('5775170880e26ba31799745241b90d4340c674bb3b1c01d758e416ee3f1c386f'); + expect(asset6.assetHash).toEqual('ba82fd351a4d3e3f5c5d948b9948e7e829badc3da90f97e00bb7724afbeacfd4'); + expect(asset7.assetHash).toEqual('26ec194928431cab6ec5af24ea9f01af2cf7b20e361128b07b2a7405d2951f95'); }); }); @@ -304,12 +304,12 @@ function testDockerDirectoryIsStagedWithoutFilesSpecifiedInDockerignore(app: App const session = app.synth(); // .dockerignore itself should be included in output to be processed during docker build - expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, '.dockerignore'))).toBeDefined(); - expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'Dockerfile'))).toBeDefined(); - expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'index.py'))).toBeDefined(); - expect(!fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'foobar.txt'))).toBeDefined(); - expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'subdirectory'))).toBeDefined(); - expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'subdirectory', 'baz.txt'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, '.dockerignore'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'Dockerfile'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'index.py'))).toBeDefined(); + expect(!fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'foobar.txt'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'subdirectory'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'subdirectory', 'baz.txt'))).toBeDefined(); } @@ -324,12 +324,12 @@ function testDockerDirectoryIsStagedWithoutFilesSpecifiedInExcludeOption(app: Ap const session = app.synth(); - expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, '.dockerignore'))).toBeDefined(); - expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'Dockerfile'))).toBeDefined(); - expect(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'index.py'))).toBeDefined(); - expect(!fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'foobar.txt'))).toBeDefined(); - expect(!fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'subdirectory'))).toBeDefined(); - expect(!fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, 'subdirectory', 'baz.txt'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, '.dockerignore'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'Dockerfile'))).toBeDefined(); + expect(fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'index.py'))).toBeDefined(); + expect(!fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'foobar.txt'))).toBeDefined(); + expect(!fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'subdirectory'))).toBeDefined(); + expect(!fs.existsSync(path.join(session.directory, `asset.${image.assetHash}`, 'subdirectory', 'baz.txt'))).toBeDefined(); } diff --git a/packages/@aws-cdk/aws-ecr/.gitignore b/packages/@aws-cdk/aws-ecr/.gitignore index 018c65919d67c..266c0684c6844 100644 --- a/packages/@aws-cdk/aws-ecr/.gitignore +++ b/packages/@aws-cdk/aws-ecr/.gitignore @@ -14,5 +14,6 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js -junit.xml \ No newline at end of file +junit.xml diff --git a/packages/@aws-cdk/aws-ecr/.npmignore b/packages/@aws-cdk/aws-ecr/.npmignore index a94c531529866..94b89531c7268 100644 --- a/packages/@aws-cdk/aws-ecr/.npmignore +++ b/packages/@aws-cdk/aws-ecr/.npmignore @@ -19,8 +19,9 @@ dist tsconfig.json .eslintrc.js +jest.config.js # exclude cdk artifacts **/cdk.out junit.xml -test/ \ No newline at end of file +test/ diff --git a/packages/@aws-cdk/aws-ecr/jest.config.js b/packages/@aws-cdk/aws-ecr/jest.config.js new file mode 100644 index 0000000000000..07a010c639ba8 --- /dev/null +++ b/packages/@aws-cdk/aws-ecr/jest.config.js @@ -0,0 +1,10 @@ +const baseConfig = require('cdk-build-tools/config/jest.config'); +module.exports = { + ...baseConfig, + coverageThreshold: { + global: { + ...baseConfig.coverageThreshold.global, + branches: 70, + }, + }, +}; diff --git a/packages/@aws-cdk/aws-ecr/package.json b/packages/@aws-cdk/aws-ecr/package.json index bc3671a7c5585..6fcba59ace523 100644 --- a/packages/@aws-cdk/aws-ecr/package.json +++ b/packages/@aws-cdk/aws-ecr/package.json @@ -55,7 +55,8 @@ "cloudformation": "AWS::ECR", "env": { "AWSLINT_BASE_CONSTRUCT": true - } + }, + "jest": true }, "nyc": { "lines": 78, @@ -74,26 +75,25 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.31", + "@aws-cdk/assert-internal": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "nodeunit": "^0.11.3", "pkglint": "0.0.0" }, "dependencies": { "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-ecr/test/test.auth-token.ts b/packages/@aws-cdk/aws-ecr/test/auth-token.test.ts similarity index 71% rename from packages/@aws-cdk/aws-ecr/test/test.auth-token.ts rename to packages/@aws-cdk/aws-ecr/test/auth-token.test.ts index bb1e13c5566b4..f9be93b1e15d0 100644 --- a/packages/@aws-cdk/aws-ecr/test/test.auth-token.ts +++ b/packages/@aws-cdk/aws-ecr/test/auth-token.test.ts @@ -1,11 +1,10 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect as expectCDK, haveResourceLike } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import { Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; import { AuthorizationToken, PublicGalleryAuthorizationToken } from '../lib'; -export = { - 'AuthorizationToken.grantRead()'(test: Test) { +describe('auth-token', () => { + test('AuthorizationToken.grantRead()', () => { // GIVEN const stack = new Stack(); const user = new iam.User(stack, 'User'); @@ -14,7 +13,7 @@ export = { AuthorizationToken.grantRead(user); // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + expectCDK(stack).to(haveResourceLike('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -25,11 +24,9 @@ export = { ], }, })); + }); - test.done(); - }, - - 'PublicGalleryAuthorizationToken.grantRead()'(test: Test) { + test('PublicGalleryAuthorizationToken.grantRead()', () => { // GIVEN const stack = new Stack(); const user = new iam.User(stack, 'User'); @@ -38,7 +35,7 @@ export = { PublicGalleryAuthorizationToken.grantRead(user); // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + expectCDK(stack).to(haveResourceLike('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -52,8 +49,5 @@ export = { ], }, })); - - test.done(); - }, - -}; \ No newline at end of file + }); +}); diff --git a/packages/@aws-cdk/aws-ecr/test/test.repository.ts b/packages/@aws-cdk/aws-ecr/test/repository.test.ts similarity index 71% rename from packages/@aws-cdk/aws-ecr/test/test.repository.ts rename to packages/@aws-cdk/aws-ecr/test/repository.test.ts index fe020462f7716..5c7efecca1380 100644 --- a/packages/@aws-cdk/aws-ecr/test/test.repository.ts +++ b/packages/@aws-cdk/aws-ecr/test/repository.test.ts @@ -1,13 +1,12 @@ -import { expect, haveResource, haveResourceLike, ResourcePart } from '@aws-cdk/assert'; +import { expect as expectCDK, haveResource, haveResourceLike, ResourcePart } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; import * as ecr from '../lib'; /* eslint-disable quote-props */ -export = { - 'construct repository'(test: Test) { +describe('repository', () => { + test('construct repository', () => { // GIVEN const stack = new cdk.Stack(); @@ -15,7 +14,7 @@ export = { new ecr.Repository(stack, 'Repo'); // THEN - expect(stack).toMatch({ + expectCDK(stack).toMatch({ Resources: { Repo02AC86CF: { Type: 'AWS::ECR::Repository', @@ -24,11 +23,9 @@ export = { }, }, }); + }); - test.done(); - }, - - 'repository creation with imageScanOnPush'(test: Test) { + test('repository creation with imageScanOnPush', () => { // GIVEN const stack = new cdk.Stack(); @@ -36,15 +33,14 @@ export = { new ecr.Repository(stack, 'Repo', { imageScanOnPush: true }); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', { + expectCDK(stack).to(haveResource('AWS::ECR::Repository', { ImageScanningConfiguration: { ScanOnPush: true, }, })); - test.done(); - }, + }); - 'tag-based lifecycle policy'(test: Test) { + test('tag-based lifecycle policy', () => { // GIVEN const stack = new cdk.Stack(); const repo = new ecr.Repository(stack, 'Repo'); @@ -53,31 +49,26 @@ export = { repo.addLifecycleRule({ tagPrefixList: ['abc'], maxImageCount: 1 }); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', { + expectCDK(stack).to(haveResource('AWS::ECR::Repository', { LifecyclePolicy: { // eslint-disable-next-line max-len LifecyclePolicyText: '{"rules":[{"rulePriority":1,"selection":{"tagStatus":"tagged","tagPrefixList":["abc"],"countType":"imageCountMoreThan","countNumber":1},"action":{"type":"expire"}}]}', }, })); + }); - test.done(); - }, - - - 'image tag mutability can be set'(test: Test) { + test('image tag mutability can be set', () => { // GIVEN const stack = new cdk.Stack(); new ecr.Repository(stack, 'Repo', { imageTagMutability: ecr.TagMutability.IMMUTABLE }); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', { + expectCDK(stack).to(haveResource('AWS::ECR::Repository', { ImageTagMutability: 'IMMUTABLE', })); + }); - test.done(); - }, - - 'add day-based lifecycle policy'(test: Test) { + test('add day-based lifecycle policy', () => { // GIVEN const stack = new cdk.Stack(); @@ -88,17 +79,15 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', { + expectCDK(stack).to(haveResource('AWS::ECR::Repository', { LifecyclePolicy: { // eslint-disable-next-line max-len LifecyclePolicyText: '{"rules":[{"rulePriority":1,"selection":{"tagStatus":"any","countType":"sinceImagePushed","countNumber":5,"countUnit":"days"},"action":{"type":"expire"}}]}', }, })); + }); - test.done(); - }, - - 'add count-based lifecycle policy'(test: Test) { + test('add count-based lifecycle policy', () => { // GIVEN const stack = new cdk.Stack(); const repo = new ecr.Repository(stack, 'Repo'); @@ -109,17 +98,15 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', { + expectCDK(stack).to(haveResource('AWS::ECR::Repository', { LifecyclePolicy: { // eslint-disable-next-line max-len LifecyclePolicyText: '{"rules":[{"rulePriority":1,"selection":{"tagStatus":"any","countType":"imageCountMoreThan","countNumber":5},"action":{"type":"expire"}}]}', }, })); + }); - test.done(); - }, - - 'mixing numbered and unnumbered rules'(test: Test) { + test('mixing numbered and unnumbered rules', () => { // GIVEN const stack = new cdk.Stack(); const repo = new ecr.Repository(stack, 'Repo'); @@ -129,17 +116,15 @@ export = { repo.addLifecycleRule({ rulePriority: 10, tagStatus: ecr.TagStatus.TAGGED, tagPrefixList: ['b'], maxImageCount: 5 }); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', { + expectCDK(stack).to(haveResource('AWS::ECR::Repository', { LifecyclePolicy: { // eslint-disable-next-line max-len LifecyclePolicyText: '{"rules":[{"rulePriority":10,"selection":{"tagStatus":"tagged","tagPrefixList":["b"],"countType":"imageCountMoreThan","countNumber":5},"action":{"type":"expire"}},{"rulePriority":11,"selection":{"tagStatus":"tagged","tagPrefixList":["a"],"countType":"imageCountMoreThan","countNumber":5},"action":{"type":"expire"}}]}', }, })); + }); - test.done(); - }, - - 'tagstatus Any is automatically sorted to the back'(test: Test) { + test('tagstatus Any is automatically sorted to the back', () => { // GIVEN const stack = new cdk.Stack(); const repo = new ecr.Repository(stack, 'Repo'); @@ -149,17 +134,15 @@ export = { repo.addLifecycleRule({ tagStatus: ecr.TagStatus.TAGGED, tagPrefixList: ['important'], maxImageCount: 999 }); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', { + expectCDK(stack).to(haveResource('AWS::ECR::Repository', { LifecyclePolicy: { // eslint-disable-next-line max-len LifecyclePolicyText: '{"rules":[{"rulePriority":1,"selection":{"tagStatus":"tagged","tagPrefixList":["important"],"countType":"imageCountMoreThan","countNumber":999},"action":{"type":"expire"}},{"rulePriority":2,"selection":{"tagStatus":"any","countType":"imageCountMoreThan","countNumber":5},"action":{"type":"expire"}}]}', }, })); + }); - test.done(); - }, - - 'lifecycle rules can be added upon initialization'(test: Test) { + test('lifecycle rules can be added upon initialization', () => { // GIVEN const stack = new cdk.Stack(); @@ -171,16 +154,15 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', { + expectCDK(stack).to(haveResource('AWS::ECR::Repository', { 'LifecyclePolicy': { // eslint-disable-next-line max-len 'LifecyclePolicyText': '{"rules":[{"rulePriority":1,"selection":{"tagStatus":"any","countType":"imageCountMoreThan","countNumber":3},"action":{"type":"expire"}}]}', }, })); - test.done(); - }, + }); - 'calculate repository URI'(test: Test) { + test('calculate repository URI', () => { // GIVEN const stack = new cdk.Stack(); const repo = new ecr.Repository(stack, 'Repo'); @@ -190,7 +172,7 @@ export = { // THEN const arnSplit = { 'Fn::Split': [':', { 'Fn::GetAtt': ['Repo02AC86CF', 'Arn'] }] }; - test.deepEqual(stack.resolve(uri), { + expectCDK(stack.resolve(uri)).toMatch({ 'Fn::Join': ['', [ { 'Fn::Select': [4, arnSplit] }, '.dkr.ecr.', @@ -201,11 +183,9 @@ export = { { Ref: 'Repo02AC86CF' }, ]], }); + }); - test.done(); - }, - - 'import with concrete arn'(test: Test) { + test('import with concrete arn', () => { // GIVEN const stack = new cdk.Stack(); @@ -213,24 +193,21 @@ export = { const repo2 = ecr.Repository.fromRepositoryArn(stack, 'repo', 'arn:aws:ecr:us-east-1:585695036304:repository/foo/bar/foo/fooo'); // THEN - test.deepEqual(stack.resolve(repo2.repositoryArn), 'arn:aws:ecr:us-east-1:585695036304:repository/foo/bar/foo/fooo'); - test.deepEqual(stack.resolve(repo2.repositoryName), 'foo/bar/foo/fooo'); + expect(stack.resolve(repo2.repositoryArn)).toBe('arn:aws:ecr:us-east-1:585695036304:repository/foo/bar/foo/fooo'); + expect(stack.resolve(repo2.repositoryName)).toBe('foo/bar/foo/fooo'); + }); - test.done(); - }, - - 'fails if importing with token arn and no name'(test: Test) { + test('fails if importing with token arn and no name', () => { // GIVEN const stack = new cdk.Stack(); // WHEN/THEN - test.throws(() => ecr.Repository.fromRepositoryArn(stack, 'arn', cdk.Fn.getAtt('Boom', 'Boom').toString()), - /\"repositoryArn\" is a late-bound value, and therefore \"repositoryName\" is required\. Use \`fromRepositoryAttributes\` instead/); - - test.done(); - }, + expect(() => { + ecr.Repository.fromRepositoryArn(stack, 'arn', cdk.Fn.getAtt('Boom', 'Boom').toString()); + }).toThrow(/\"repositoryArn\" is a late-bound value, and therefore \"repositoryName\" is required\. Use \`fromRepositoryAttributes\` instead/); + }); - 'import with token arn and repository name (see awslabs/aws-cdk#1232)'(test: Test) { + test('import with token arn and repository name (see awslabs/aws-cdk#1232)', () => { // GIVEN const stack = new cdk.Stack(); @@ -241,12 +218,11 @@ export = { }); // THEN - test.deepEqual(stack.resolve(repo.repositoryArn), { 'Fn::GetAtt': ['Boom', 'Arn'] }); - test.deepEqual(stack.resolve(repo.repositoryName), { 'Fn::GetAtt': ['Boom', 'Name'] }); - test.done(); - }, + expectCDK(stack.resolve(repo.repositoryArn)).toMatch({ 'Fn::GetAtt': ['Boom', 'Arn'] }); + expectCDK(stack.resolve(repo.repositoryName)).toMatch({ 'Fn::GetAtt': ['Boom', 'Name'] }); + }); - 'import only with a repository name (arn is deduced)'(test: Test) { + test('import only with a repository name (arn is deduced)', () => { // GIVEN const stack = new cdk.Stack(); @@ -254,7 +230,7 @@ export = { const repo = ecr.Repository.fromRepositoryName(stack, 'just-name', 'my-repo'); // THEN - test.deepEqual(stack.resolve(repo.repositoryArn), { + expectCDK(stack.resolve(repo.repositoryArn)).toMatch({ 'Fn::Join': ['', [ 'arn:', { Ref: 'AWS::Partition' }, @@ -265,11 +241,10 @@ export = { ':repository/my-repo', ]], }); - test.deepEqual(stack.resolve(repo.repositoryName), 'my-repo'); - test.done(); - }, + expect(stack.resolve(repo.repositoryName)).toBe('my-repo'); + }); - 'arnForLocalRepository can be used to render an ARN for a local repository'(test: Test) { + test('arnForLocalRepository can be used to render an ARN for a local repository', () => { // GIVEN const stack = new cdk.Stack(); const repoName = cdk.Fn.getAtt('Boom', 'Name').toString(); @@ -281,8 +256,8 @@ export = { }); // THEN - test.deepEqual(stack.resolve(repo.repositoryName), { 'Fn::GetAtt': ['Boom', 'Name'] }); - test.deepEqual(stack.resolve(repo.repositoryArn), { + expectCDK(stack.resolve(repo.repositoryName)).toMatch({ 'Fn::GetAtt': ['Boom', 'Name'] }); + expectCDK(stack.resolve(repo.repositoryArn)).toMatch({ 'Fn::Join': ['', [ 'arn:', { Ref: 'AWS::Partition' }, @@ -294,10 +269,9 @@ export = { { 'Fn::GetAtt': ['Boom', 'Name'] }, ]], }); - test.done(); - }, + }); - 'resource policy'(test: Test) { + test('resource policy', () => { // GIVEN const stack = new cdk.Stack(); const repo = new ecr.Repository(stack, 'Repo'); @@ -309,7 +283,7 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', { + expectCDK(stack).to(haveResource('AWS::ECR::Repository', { RepositoryPolicyText: { Statement: [ { @@ -321,11 +295,9 @@ export = { Version: '2012-10-17', }, })); + }); - test.done(); - }, - - 'fails if repository policy has no actions'(test: Test) { + test('fails if repository policy has no actions', () => { // GIVEN const app = new cdk.App(); const stack = new cdk.Stack(app, 'my-stack'); @@ -338,11 +310,10 @@ export = { })); // THEN - test.throws(() => app.synth(), /A PolicyStatement must specify at least one \'action\' or \'notAction\'/); - test.done(); - }, + expect(() => app.synth()).toThrow(/A PolicyStatement must specify at least one \'action\' or \'notAction\'/); + }); - 'fails if repository policy has no IAM principals'(test: Test) { + test('fails if repository policy has no IAM principals', () => { // GIVEN const app = new cdk.App(); const stack = new cdk.Stack(app, 'my-stack'); @@ -355,12 +326,11 @@ export = { })); // THEN - test.throws(() => app.synth(), /A PolicyStatement used in a resource-based policy must specify at least one IAM principal/); - test.done(); - }, + expect(() => app.synth()).toThrow(/A PolicyStatement used in a resource-based policy must specify at least one IAM principal/); + }); - 'events': { - 'onImagePushed without imageTag creates the correct event'(test: Test) { + describe('events', () => { + test('onImagePushed without imageTag creates the correct event', () => { const stack = new cdk.Stack(); const repo = new ecr.Repository(stack, 'Repo'); @@ -370,7 +340,7 @@ export = { }, }); - expect(stack).to(haveResourceLike('AWS::Events::Rule', { + expectCDK(stack).to(haveResourceLike('AWS::Events::Rule', { 'EventPattern': { 'source': [ 'aws.ecr', @@ -390,10 +360,9 @@ export = { }, 'State': 'ENABLED', })); + }); - test.done(); - }, - 'onImageScanCompleted without imageTags creates the correct event'(test: Test) { + test('onImageScanCompleted without imageTags creates the correct event', () => { const stack = new cdk.Stack(); const repo = new ecr.Repository(stack, 'Repo'); @@ -403,7 +372,7 @@ export = { }, }); - expect(stack).to(haveResourceLike('AWS::Events::Rule', { + expectCDK(stack).to(haveResourceLike('AWS::Events::Rule', { 'EventPattern': { 'source': [ 'aws.ecr', @@ -421,11 +390,9 @@ export = { }, 'State': 'ENABLED', })); + }); - test.done(); - - }, - 'onImageScanCompleted with one imageTag creates the correct event'(test: Test) { + test('onImageScanCompleted with one imageTag creates the correct event', () => { const stack = new cdk.Stack(); const repo = new ecr.Repository(stack, 'Repo'); @@ -436,7 +403,7 @@ export = { }, }); - expect(stack).to(haveResourceLike('AWS::Events::Rule', { + expectCDK(stack).to(haveResourceLike('AWS::Events::Rule', { 'EventPattern': { 'source': [ 'aws.ecr', @@ -457,11 +424,9 @@ export = { }, 'State': 'ENABLED', })); + }); - test.done(); - - }, - 'onImageScanCompleted with multiple imageTags creates the correct event'(test: Test) { + test('onImageScanCompleted with multiple imageTags creates the correct event', () => { const stack = new cdk.Stack(); const repo = new ecr.Repository(stack, 'Repo'); @@ -472,7 +437,7 @@ export = { }, }); - expect(stack).to(haveResourceLike('AWS::Events::Rule', { + expectCDK(stack).to(haveResourceLike('AWS::Events::Rule', { 'EventPattern': { 'source': [ 'aws.ecr', @@ -495,12 +460,9 @@ export = { }, 'State': 'ENABLED', })); + }); - test.done(); - - }, - - 'removal policy is "Retain" by default'(test: Test) { + test('removal policy is "Retain" by default', () => { // GIVEN const stack = new cdk.Stack(); @@ -508,14 +470,13 @@ export = { new ecr.Repository(stack, 'Repo'); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', { + expectCDK(stack).to(haveResource('AWS::ECR::Repository', { 'Type': 'AWS::ECR::Repository', 'DeletionPolicy': 'Retain', }, ResourcePart.CompleteDefinition)); - test.done(); - }, + }); - '"Delete" removal policy can be set explicitly'(test: Test) { + test('"Delete" removal policy can be set explicitly', () => { // GIVEN const stack = new cdk.Stack(); @@ -525,14 +486,13 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', { + expectCDK(stack).to(haveResource('AWS::ECR::Repository', { 'Type': 'AWS::ECR::Repository', 'DeletionPolicy': 'Delete', }, ResourcePart.CompleteDefinition)); - test.done(); - }, + }); - 'grant adds appropriate resource-*'(test: Test) { + test('grant adds appropriate resource-*', () => { // GIVEN const stack = new cdk.Stack(); const repo = new ecr.Repository(stack, 'TestHarnessRepo'); @@ -541,7 +501,7 @@ export = { repo.grantPull(new iam.AnyPrincipal()); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', { + expectCDK(stack).to(haveResource('AWS::ECR::Repository', { 'RepositoryPolicyText': { 'Statement': [ { @@ -557,8 +517,6 @@ export = { 'Version': '2012-10-17', }, })); - - test.done(); - }, - }, -}; + }); + }); +}); diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/application-load-balanced-service-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/application-load-balanced-service-base.ts index 2593853cd0350..cc0bbfc3427de 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/application-load-balanced-service-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/application-load-balanced-service-base.ts @@ -5,7 +5,7 @@ import { ICluster, LogDriver, PropagatedTagSource, Secret, } from '@aws-cdk/aws-ecs'; import { - ApplicationListener, ApplicationLoadBalancer, ApplicationProtocol, ApplicationTargetGroup, + ApplicationListener, ApplicationLoadBalancer, ApplicationProtocol, ApplicationProtocolVersion, ApplicationTargetGroup, IApplicationLoadBalancer, ListenerCertificate, ListenerAction, AddApplicationTargetsProps, } from '@aws-cdk/aws-elasticloadbalancingv2'; import { IRole } from '@aws-cdk/aws-iam'; @@ -117,6 +117,13 @@ export interface ApplicationLoadBalancedServiceBaseProps { */ readonly protocol?: ApplicationProtocol; + /** + * The protocol version to use + * + * @default ApplicationProtocolVersion.HTTP1 + */ + readonly protocolVersion?: ApplicationProtocolVersion; + /** * The domain name for the service, e.g. "api.example.com." * @@ -412,6 +419,7 @@ export abstract class ApplicationLoadBalancedServiceBase extends CoreConstruct { const targetProps: AddApplicationTargetsProps = { protocol: props.targetProtocol ?? ApplicationProtocol.HTTP, + protocolVersion: props.protocolVersion, }; this.listener = loadBalancer.addListener('PublicListener', { @@ -422,13 +430,14 @@ export abstract class ApplicationLoadBalancedServiceBase extends CoreConstruct { this.targetGroup = this.listener.addTargets('ECS', targetProps); if (protocol === ApplicationProtocol.HTTPS) { - if (typeof props.domainName === 'undefined' || typeof props.domainZone === 'undefined') { - throw new Error('A domain name and zone is required when using the HTTPS protocol'); - } if (props.certificate !== undefined) { this.certificate = props.certificate; } else { + if (typeof props.domainName === 'undefined' || typeof props.domainZone === 'undefined') { + throw new Error('A domain name and zone is required when using the HTTPS protocol'); + } + this.certificate = new Certificate(this, 'Certificate', { domainName: props.domainName, validation: CertificateValidation.fromDns(props.domainZone), diff --git a/packages/@aws-cdk/aws-ecs-patterns/package.json b/packages/@aws-cdk/aws-ecs-patterns/package.json index dcb4d8b436bda..b3af376e719f9 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/package.json +++ b/packages/@aws-cdk/aws-ecs-patterns/package.json @@ -63,14 +63,14 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "jest": "^26.6.3", "nodeunit": "^0.11.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-applicationautoscaling": "0.0.0", @@ -87,7 +87,7 @@ "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -105,7 +105,7 @@ "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.multiple-application-load-balanced-ecs-service.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.multiple-application-load-balanced-ecs-service.expected.json index ec9686e054019..0412778adb2e8 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.multiple-application-load-balanced-ecs-service.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.multiple-application-load-balanced-ecs-service.expected.json @@ -717,7 +717,7 @@ "Type": "AWS::Lambda::Function", "Properties": { "Code": { - "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" + "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n task_arns = container_instance_task_arns(cluster, instance_arn)\n \n if task_arns:\n print('Instance ARN %s has task ARNs %s' % (instance_arn, ', '.join(task_arns)))\n\n while has_tasks(cluster, instance_arn, task_arns):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\ndef container_instance_task_arns(cluster, instance_arn):\n \"\"\"Fetch tasks for a container instance ARN.\"\"\"\n arns = ecs.list_tasks(cluster=cluster, containerInstance=instance_arn)['taskArns']\n return arns\n\ndef has_tasks(cluster, instance_arn, task_arns):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n task_count = None\n\n if task_arns:\n # Fetch details for tasks running on the container instance\n tasks = ecs.describe_tasks(cluster=cluster, tasks=task_arns)['tasks']\n if tasks:\n # Consider any non-stopped tasks as running\n task_count = sum(task['lastStatus'] != 'STOPPED' for task in tasks) + instance['pendingTasksCount']\n \n if not task_count:\n # Fallback to instance task counts if detailed task information is unavailable\n task_count = instance['runningTasksCount'] + instance['pendingTasksCount']\n \n print('Instance %s has %s tasks' % (instance_arn, task_count))\n\n return task_count > 0\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, "Role": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.lit.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.lit.expected.json index 53c05f9aeba8e..e3afaddbeb7c6 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.lit.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.lit.expected.json @@ -534,7 +534,7 @@ "Type": "AWS::Lambda::Function", "Properties": { "Code": { - "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" + "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n task_arns = container_instance_task_arns(cluster, instance_arn)\n \n if task_arns:\n print('Instance ARN %s has task ARNs %s' % (instance_arn, ', '.join(task_arns)))\n\n while has_tasks(cluster, instance_arn, task_arns):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\ndef container_instance_task_arns(cluster, instance_arn):\n \"\"\"Fetch tasks for a container instance ARN.\"\"\"\n arns = ecs.list_tasks(cluster=cluster, containerInstance=instance_arn)['taskArns']\n return arns\n\ndef has_tasks(cluster, instance_arn, task_arns):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n task_count = None\n\n if task_arns:\n # Fetch details for tasks running on the container instance\n tasks = ecs.describe_tasks(cluster=cluster, tasks=task_arns)['tasks']\n if tasks:\n # Consider any non-stopped tasks as running\n task_count = sum(task['lastStatus'] != 'STOPPED' for task in tasks) + instance['pendingTasksCount']\n \n if not task_count:\n # Fallback to instance task counts if detailed task information is unavailable\n task_count = instance['runningTasksCount'] + instance['pendingTasksCount']\n \n print('Instance %s has %s tasks' % (instance_arn, task_count))\n\n return task_count > 0\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, "Role": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s-v2.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s-v2.ts index 745bad2c660fc..77f171425c88a 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s-v2.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s-v2.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike, SynthUtils } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike, SynthUtils } from '@aws-cdk/assert-internal'; import { Certificate } from '@aws-cdk/aws-certificatemanager'; import { InstanceType, Vpc } from '@aws-cdk/aws-ec2'; import { AwsLogDriver, Cluster, ContainerImage, Ec2TaskDefinition, PropagatedTagSource, Protocol } from '@aws-cdk/aws-ecs'; diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s.ts index d41a7684fd677..a028d34c22157 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s.ts @@ -1,8 +1,8 @@ -import { ABSENT, arrayWith, expect, haveResource, haveResourceLike, objectLike } from '@aws-cdk/assert'; +import { ABSENT, arrayWith, expect, haveResource, haveResourceLike, objectLike } from '@aws-cdk/assert-internal'; import { Certificate } from '@aws-cdk/aws-certificatemanager'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; -import { ApplicationLoadBalancer, ApplicationProtocol, NetworkLoadBalancer } from '@aws-cdk/aws-elasticloadbalancingv2'; +import { ApplicationLoadBalancer, ApplicationProtocol, ApplicationProtocolVersion, NetworkLoadBalancer } from '@aws-cdk/aws-elasticloadbalancingv2'; import { PublicHostedZone } from '@aws-cdk/aws-route53'; import * as cloudmap from '@aws-cdk/aws-servicediscovery'; import * as cdk from '@aws-cdk/core'; @@ -1010,6 +1010,36 @@ export = { test.done(); }, + 'ALB - includes provided protocol version properties'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }, + desiredCount: 1, + domainName: 'api.example.com', + domainZone: zone, + protocol: ApplicationProtocol.HTTPS, + protocolVersion: ApplicationProtocolVersion.GRPC, + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup', { + ProtocolVersion: 'GRPC', + })); + + test.done(); + }, + 'NLB - having *HealthyPercent properties'(test: Test) { // GIVEN const stack = new cdk.Stack(); @@ -1198,7 +1228,7 @@ export = { 'NetworkLoadBalancedEC2Service accepts imported load balancer'(test: Test) { // GIVEN const stack = new cdk.Stack(); - const nlbArn = 'arn:aws:elasticloadbalancing::000000000000::dummyloadbalancer'; + const nlbArn = 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188'; const vpc = new ec2.Vpc(stack, 'Vpc'); const cluster = new ecs.Cluster(stack, 'Cluster', { vpc, clusterName: 'MyCluster' }); cluster.addCapacity('Capacity', { instanceType: new ec2.InstanceType('t2.micro') }); @@ -1274,7 +1304,7 @@ export = { 'ApplicationLoadBalancedEC2Service accepts imported load balancer'(test: Test) { // GIVEN const stack = new cdk.Stack(); - const albArn = 'arn:aws:elasticloadbalancing::000000000000::dummyloadbalancer'; + const albArn = 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188'; const vpc = new ec2.Vpc(stack, 'Vpc'); const cluster = new ecs.Cluster(stack, 'Cluster', { vpc, clusterName: 'MyCluster' }); cluster.addCapacity('Capacity', { instanceType: new ec2.InstanceType('t2.micro') }); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.queue-processing-ecs-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.queue-processing-ecs-service.ts index 77d822d443048..2eb19e03540e6 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.queue-processing-ecs-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.queue-processing-ecs-service.ts @@ -1,4 +1,4 @@ -import { ABSENT, expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; +import { ABSENT, expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; import * as sqs from '@aws-cdk/aws-sqs'; diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.scheduled-ecs-task.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.scheduled-ecs-task.ts index af262cd5de5ef..2a6d94784bc5d 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.scheduled-ecs-task.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.scheduled-ecs-task.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; import * as events from '@aws-cdk/aws-events'; diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service-v2.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service-v2.ts index becc38e6a9fd1..81f1711c961c0 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service-v2.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service-v2.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; import { Vpc } from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; import { CompositePrincipal, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service.ts index 3a17962c8b230..a8c588d1187ef 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service.ts @@ -1,4 +1,5 @@ -import { expect, haveResource, haveResourceLike, SynthUtils } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike, SynthUtils } from '@aws-cdk/assert-internal'; +import { DnsValidatedCertificate } from '@aws-cdk/aws-certificatemanager'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; import { ApplicationLoadBalancer, ApplicationProtocol, NetworkLoadBalancer } from '@aws-cdk/aws-elasticloadbalancingv2'; @@ -810,7 +811,7 @@ export = { const stack1 = new cdk.Stack(app, 'MyStack'); const vpc1 = new ec2.Vpc(stack1, 'VPC'); const cluster1 = new ecs.Cluster(stack1, 'Cluster', { vpc: vpc1 }); - const nlbArn = 'arn:aws:elasticloadbalancing::000000000000::dummyloadbalancer'; + const nlbArn = 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188'; const stack2 = new cdk.Stack(stack1, 'Stack2'); const cluster2 = ecs.Cluster.fromClusterAttributes(stack2, 'ImportedCluster', { vpc: vpc1, @@ -887,7 +888,7 @@ export = { 'passing in imported application load balancer and resources to ALB Fargate Service'(test: Test) { // GIVEN const stack1 = new cdk.Stack(); - const albArn = 'arn:aws:elasticloadbalancing::000000000000::dummyloadbalancer'; + const albArn = 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188'; const vpc = new ec2.Vpc(stack1, 'Vpc'); const cluster = new ecs.Cluster(stack1, 'Cluster', { vpc, clusterName: 'MyClusterName' }); const sg = new ec2.SecurityGroup(stack1, 'SecurityGroup', { vpc }); @@ -977,4 +978,38 @@ export = { test.done(); }, + 'domainName and domainZone not required for HTTPS listener with provided cert'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + const exampleDotComZone = new route53.PublicHostedZone(stack, 'ExampleDotCom', { + zoneName: 'example.com', + }); + const certificate = new DnsValidatedCertificate(stack, 'Certificate', { + domainName: 'test.example.com', + hostedZone: exampleDotComZone, + }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { + cluster, + protocol: ApplicationProtocol.HTTPS, + + taskImageOptions: { + containerPort: 2015, + image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), + }, + certificate: certificate, + }); + + // THEN + expect(stack).notTo(haveResourceLike('AWS::Route53::RecordSet', { + Name: 'test.domain.com.', + })); + + test.done(); + + }, + }; diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts index 5207f92629c10..58ca7508efb9c 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts @@ -1,4 +1,4 @@ -import { ABSENT, expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; +import { ABSENT, expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; import * as sqs from '@aws-cdk/aws-sqs'; diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.scheduled-fargate-task.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.scheduled-fargate-task.ts index 9496288f3b235..67370131045f3 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.scheduled-fargate-task.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.scheduled-fargate-task.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; import * as events from '@aws-cdk/aws-events'; diff --git a/packages/@aws-cdk/aws-ecs/README.md b/packages/@aws-cdk/aws-ecs/README.md index 5ad2855c8f642..7f0338ed3ff18 100644 --- a/packages/@aws-cdk/aws-ecs/README.md +++ b/packages/@aws-cdk/aws-ecs/README.md @@ -153,6 +153,22 @@ cluster.addCapacity('bottlerocket-asg', { }); ``` +### ARM64 (Graviton) Instances + +To launch instances with ARM64 hardware, you can use the Amazon ECS-optimized +Amazon Linux 2 (arm64) AMI. Based on Amazon Linux 2, this AMI is recommended +for use when launching your EC2 instances that are powered by Arm-based AWS +Graviton Processors. + +```ts +cluster.addCapacity('graviton-cluster', { + minCapacity: 2, + instanceType: new ec2.InstanceType('c6g.large'), + machineImage: ecs.EcsOptimizedImage.amazonLinux2(ecs.AmiHardwareType.ARM), +}); + +``` + ### Spot Instances To add spot instances into the cluster, you must specify the `spotPrice` in the `ecs.AddCapacityOptions` and optionally enable the `spotInstanceDraining` property. @@ -525,7 +541,7 @@ const taskDefinition = new ecs.Ec2TaskDefinition(this, 'TaskDef'); taskDefinition.addContainer('TheContainer', { image: ecs.ContainerImage.fromAsset(path.resolve(__dirname, '..', 'eventhandler-image')), memoryLimitMiB: 256, - logging: new ecs.AwsLogDriver({ streamPrefix: 'EventDemo' }) + logging: new ecs.AwsLogDriver({ streamPrefix: 'EventDemo', mode: AwsLogDriverMode.NON_BLOCKING }) }); // An Rule that describes the event trigger (in this case a scheduled run) @@ -788,3 +804,36 @@ new ecs.FargateService(stack, 'FargateService', { app.synth(); ``` + +## Elastic Inference Accelerators + +Currently, this feature is only supported for services with EC2 launch types. + +To add elastic inference accelerators to your EC2 instance, first add +`inferenceAccelerators` field to the EC2TaskDefinition and set the `deviceName` +and `deviceType` properties. + +```ts +const inferenceAccelerators = [{ + deviceName: 'device1', + deviceType: 'eia2.medium', +}]; + +const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { + inferenceAccelerators, +}); +``` + +To enable using the inference accelerators in the containers, add `inferenceAcceleratorResources` +field and set it to a list of device names used for the inference accelerators. Each value in the +list should match a `DeviceName` for an `InferenceAccelerator` specified in the task definition. + +```ts +const inferenceAcceleratorResources = ['device1']; + +taskDefinition.addContainer('cont', { + image: ecs.ContainerImage.fromRegistry('test'), + memoryLimitMiB: 1024, + inferenceAcceleratorResources, +}); +``` diff --git a/packages/@aws-cdk/aws-ecs/jest.config.js b/packages/@aws-cdk/aws-ecs/jest.config.js index f5d5c4c8ad18f..54e28beb9798b 100644 --- a/packages/@aws-cdk/aws-ecs/jest.config.js +++ b/packages/@aws-cdk/aws-ecs/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); -module.exports = baseConfig; \ No newline at end of file +const baseConfig = require('cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ecs/lib/base/_imported-task-definition.ts b/packages/@aws-cdk/aws-ecs/lib/base/_imported-task-definition.ts index 3c9c583b96de0..accffb9dac20b 100644 --- a/packages/@aws-cdk/aws-ecs/lib/base/_imported-task-definition.ts +++ b/packages/@aws-cdk/aws-ecs/lib/base/_imported-task-definition.ts @@ -1,9 +1,9 @@ import { IRole } from '@aws-cdk/aws-iam'; +import { Resource } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { IEc2TaskDefinition } from '../ec2/ec2-task-definition'; import { IFargateTaskDefinition } from '../fargate/fargate-task-definition'; import { Compatibility, NetworkMode, isEc2Compatible, isFargateCompatible } from './task-definition'; -import { Resource } from '@aws-cdk/core'; /** * The properties of ImportedTaskDefinition diff --git a/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts b/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts index 306b2bced3477..e51756cf7fa91 100644 --- a/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts +++ b/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts @@ -8,8 +8,8 @@ import * as cloudmap from '@aws-cdk/aws-servicediscovery'; import { Annotations, Duration, IResolvable, IResource, Lazy, Resource, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { LoadBalancerTargetOptions, NetworkMode, TaskDefinition } from '../base/task-definition'; -import { ContainerDefinition, Protocol } from '../container-definition'; import { ICluster, CapacityProviderStrategy } from '../cluster'; +import { ContainerDefinition, Protocol } from '../container-definition'; import { CfnService } from '../ecs.generated'; import { ScalableTaskCount } from './scalable-task-count'; @@ -637,7 +637,7 @@ export abstract class BaseService extends Resource } /** - * This method returns the CloudWatch metric for this clusters memory utilization. + * This method returns the CloudWatch metric for this service's memory utilization. * * @default average over 5 minutes */ @@ -646,7 +646,7 @@ export abstract class BaseService extends Resource } /** - * This method returns the CloudWatch metric for this clusters CPU utilization. + * This method returns the CloudWatch metric for this service's CPU utilization. * * @default average over 5 minutes */ 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 7c3bb618142a5..3e7f82160d3fa 100644 --- a/packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts +++ b/packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts @@ -184,6 +184,15 @@ export interface TaskDefinitionProps extends CommonTaskDefinitionProps { * @default - PidMode used by the task is not specified */ readonly pidMode?: PidMode; + + /** + * The inference accelerators to use for the containers in the task. + * + * Not supported in Fargate. + * + * @default - No inference accelerators. + */ + readonly inferenceAccelerators?: InferenceAccelerator[]; } /** @@ -322,6 +331,11 @@ export class TaskDefinition extends TaskDefinitionBase { */ private readonly placementConstraints = new Array(); + /** + * Inference accelerators for task instances + */ + private readonly _inferenceAccelerators: InferenceAccelerator[] = []; + private _executionRole?: iam.IRole; private _referencesSecretJsonField?: boolean; @@ -354,12 +368,20 @@ export class TaskDefinition extends TaskDefinitionBase { throw new Error(`Fargate-compatible tasks require both CPU (${props.cpu}) and memory (${props.memoryMiB}) specifications`); } + if (props.inferenceAccelerators && props.inferenceAccelerators.length > 0 && this.isFargateCompatible) { + throw new Error('Cannot use inference accelerators on tasks that run on Fargate'); + } + this._executionRole = props.executionRole; this.taskRole = props.taskRole || new iam.Role(this, 'TaskRole', { assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), }); + if (props.inferenceAccelerators) { + props.inferenceAccelerators.forEach(ia => this.addInferenceAccelerator(ia)); + } + const taskDef = new CfnTaskDefinition(this, 'Resource', { containerDefinitions: Lazy.any({ produce: () => this.renderContainers() }, { omitEmptyArray: true }), volumes: Lazy.any({ produce: () => this.renderVolumes() }, { omitEmptyArray: true }), @@ -380,6 +402,10 @@ export class TaskDefinition extends TaskDefinitionBase { memory: props.memoryMiB, ipcMode: props.ipcMode, pidMode: props.pidMode, + inferenceAccelerators: Lazy.any({ + produce: () => + !isFargateCompatible(this.compatibility) ? this.renderInferenceAccelerators() : undefined, + }, { omitEmptyArray: true }), }); if (props.placementConstraints) { @@ -393,6 +419,13 @@ export class TaskDefinition extends TaskDefinitionBase { return this._executionRole; } + /** + * Public getter method to access list of inference accelerators attached to the instance. + */ + public get inferenceAccelerators(): InferenceAccelerator[] { + return this._inferenceAccelerators; + } + private renderVolumes(): CfnTaskDefinition.VolumeProperty[] { return this.volumes.map(renderVolume); @@ -419,6 +452,17 @@ export class TaskDefinition extends TaskDefinitionBase { } } + private renderInferenceAccelerators(): CfnTaskDefinition.InferenceAcceleratorProperty[] { + return this._inferenceAccelerators.map(renderInferenceAccelerator); + + function renderInferenceAccelerator(inferenceAccelerator: InferenceAccelerator) : CfnTaskDefinition.InferenceAcceleratorProperty { + return { + deviceName: inferenceAccelerator.deviceName, + deviceType: inferenceAccelerator.deviceType, + }; + } + } + /** * Validate the existence of the input target and set default values. * @@ -531,6 +575,16 @@ export class TaskDefinition extends TaskDefinitionBase { extension.extend(this); } + /** + * Adds an inference accelerator to the task definition. + */ + public addInferenceAccelerator(inferenceAccelerator: InferenceAccelerator) { + if (isFargateCompatible(this.compatibility)) { + throw new Error('Cannot use inference accelerators on tasks that run on Fargate'); + } + this._inferenceAccelerators.push(inferenceAccelerator); + } + /** * Creates the task execution IAM role if it doesn't already exist. */ @@ -683,6 +737,24 @@ export enum PidMode { TASK = 'task', } +/** + * Elastic Inference Accelerator. + * For more information, see [Elastic Inference Basics](https://docs.aws.amazon.com/elastic-inference/latest/developerguide/basics.html) + */ +export interface InferenceAccelerator { + /** + * The Elastic Inference accelerator device name. + * @default - empty + */ + readonly deviceName?: string; + + /** + * The Elastic Inference accelerator type to use. The allowed values are: eia2.medium, eia2.large and eia2.xlarge. + * @default - empty + */ + readonly deviceType?: string; +} + /** * A data volume used in a task definition. * diff --git a/packages/@aws-cdk/aws-ecs/lib/cluster.ts b/packages/@aws-cdk/aws-ecs/lib/cluster.ts index c60fc9f4b1dee..a65efaa83e17e 100644 --- a/packages/@aws-cdk/aws-ecs/lib/cluster.ts +++ b/packages/@aws-cdk/aws-ecs/lib/cluster.ts @@ -466,7 +466,7 @@ export enum WindowsOptimizedVersion { /* * TODO:v2.0.0 * * remove `export` keyword - * * remove @depracted + * * remove @deprecated */ /** * The properties that define which ECS-optimized AMI is used. diff --git a/packages/@aws-cdk/aws-ecs/lib/container-definition.ts b/packages/@aws-cdk/aws-ecs/lib/container-definition.ts index 9911a49a039cf..f817a5280315e 100644 --- a/packages/@aws-cdk/aws-ecs/lib/container-definition.ts +++ b/packages/@aws-cdk/aws-ecs/lib/container-definition.ts @@ -77,6 +77,13 @@ export interface ContainerDefinitionOptions { */ readonly image: ContainerImage; + /** + * The name of the container. + * + * @default - id of node associated with ContainerDefinition. + */ + readonly containerName?: string; + /** * The command that is passed to the container. * @@ -294,6 +301,12 @@ export interface ContainerDefinitionOptions { * @default - No ports are mapped. */ readonly portMappings?: PortMapping[]; + + /** + * The inference accelerators referenced by the container. + * @default - No inference accelerators assigned. + */ + readonly inferenceAcceleratorResources?: string[]; } /** @@ -351,7 +364,7 @@ export class ContainerDefinition extends CoreConstruct { * stopped. If the essential parameter of a container is marked as false, then its * failure does not affect the rest of the containers in a task. * - * If this parameter isomitted, a container is assumed to be essential. + * If this parameter is omitted, a container is assumed to be essential. */ public readonly essential: boolean; @@ -386,6 +399,11 @@ export class ContainerDefinition extends CoreConstruct { */ public readonly referencesSecretJsonField?: boolean; + /** + * The inference accelerators referenced by this container. + */ + private readonly inferenceAcceleratorResources: string[] = []; + /** * The configured container links */ @@ -409,7 +427,7 @@ export class ContainerDefinition extends CoreConstruct { this.taskDefinition = props.taskDefinition; this.memoryLimitSpecified = props.memoryLimitMiB !== undefined || props.memoryReservationMiB !== undefined; this.linuxParameters = props.linuxParameters; - this.containerName = this.node.id; + this.containerName = props.containerName ?? this.node.id; this.imageConfig = props.image.bind(this, this); if (props.logging) { @@ -443,6 +461,10 @@ export class ContainerDefinition extends CoreConstruct { if (props.portMappings) { this.addPortMappings(...props.portMappings); } + + if (props.inferenceAcceleratorResources) { + this.addInferenceAcceleratorResource(...props.inferenceAcceleratorResources); + } } /** @@ -516,6 +538,20 @@ export class ContainerDefinition extends CoreConstruct { })); } + /** + * This method adds one or more resources to the container. + */ + public addInferenceAcceleratorResource(...inferenceAcceleratorResources: string[]) { + this.inferenceAcceleratorResources.push(...inferenceAcceleratorResources.map(resource => { + for (const inferenceAccelerator of this.taskDefinition.inferenceAccelerators) { + if (resource === inferenceAccelerator.deviceName) { + return resource; + } + } + throw new Error(`Resource value ${resource} in container definition doesn't match any inference accelerator device name in the task definition.`); + })); + } + /** * This method adds one or more ulimits to the container. */ @@ -631,7 +667,8 @@ export class ContainerDefinition extends CoreConstruct { healthCheck: this.props.healthCheck && renderHealthCheck(this.props.healthCheck), links: cdk.Lazy.list({ produce: () => this.links }, { omitEmpty: true }), linuxParameters: this.linuxParameters && this.linuxParameters.renderLinuxParameters(), - resourceRequirements: (this.props.gpuCount !== undefined) ? renderResourceRequirements(this.props.gpuCount) : undefined, + resourceRequirements: (!this.props.gpuCount && this.inferenceAcceleratorResources.length == 0 ) ? undefined : + renderResourceRequirements(this.props.gpuCount, this.inferenceAcceleratorResources), }; } } @@ -742,12 +779,22 @@ function getHealthCheckCommand(hc: HealthCheck): string[] { return hcCommand.concat(cmd); } -function renderResourceRequirements(gpuCount: number): CfnTaskDefinition.ResourceRequirementProperty[] | undefined { - if (gpuCount === 0) { return undefined; } - return [{ - type: 'GPU', - value: gpuCount.toString(), - }]; +function renderResourceRequirements(gpuCount: number = 0, inferenceAcceleratorResources: string[] = []): +CfnTaskDefinition.ResourceRequirementProperty[] | undefined { + const ret = []; + for (const resource of inferenceAcceleratorResources) { + ret.push({ + type: 'InferenceAccelerator', + value: resource, + }); + } + if (gpuCount > 0) { + ret.push({ + type: 'GPU', + value: gpuCount.toString(), + }); + } + return ret; } /** diff --git a/packages/@aws-cdk/aws-ecs/lib/drain-hook/lambda-source/index.py b/packages/@aws-cdk/aws-ecs/lib/drain-hook/lambda-source/index.py index e17ac68681300..0b4590f9e4768 100644 --- a/packages/@aws-cdk/aws-ecs/lib/drain-hook/lambda-source/index.py +++ b/packages/@aws-cdk/aws-ecs/lib/drain-hook/lambda-source/index.py @@ -20,7 +20,12 @@ def lambda_handler(event, context): if not instance_arn: return - while has_tasks(cluster, instance_arn): + task_arns = container_instance_task_arns(cluster, instance_arn) + + if task_arns: + print('Instance ARN %s has task ARNs %s' % (instance_arn, ', '.join(task_arns))) + + while has_tasks(cluster, instance_arn, task_arns): time.sleep(10) try: @@ -40,8 +45,12 @@ def container_instance_arn(cluster, instance_id): return None return arns[0] +def container_instance_task_arns(cluster, instance_arn): + """Fetch tasks for a container instance ARN.""" + arns = ecs.list_tasks(cluster=cluster, containerInstance=instance_arn)['taskArns'] + return arns -def has_tasks(cluster, instance_arn): +def has_tasks(cluster, instance_arn, task_arns): """Return True if the instance is running tasks for the given cluster.""" instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances'] if not instances: @@ -53,11 +62,22 @@ def has_tasks(cluster, instance_arn): set_container_instance_to_draining(cluster, instance_arn) return True - tasks = instance['runningTasksCount'] + instance['pendingTasksCount'] - print('Instance %s has %s tasks' % (instance_arn, tasks)) - - return tasks > 0 - + task_count = None + + if task_arns: + # Fetch details for tasks running on the container instance + tasks = ecs.describe_tasks(cluster=cluster, tasks=task_arns)['tasks'] + if tasks: + # Consider any non-stopped tasks as running + task_count = sum(task['lastStatus'] != 'STOPPED' for task in tasks) + instance['pendingTasksCount'] + + if not task_count: + # Fallback to instance task counts if detailed task information is unavailable + task_count = instance['runningTasksCount'] + instance['pendingTasksCount'] + + print('Instance %s has %s tasks' % (instance_arn, task_count)) + + return task_count > 0 def set_container_instance_to_draining(cluster, instance_arn): ecs.update_container_instances_state( diff --git a/packages/@aws-cdk/aws-ecs/lib/ec2/ec2-task-definition.ts b/packages/@aws-cdk/aws-ecs/lib/ec2/ec2-task-definition.ts index ff571c884b73e..3b65516ba7dfa 100644 --- a/packages/@aws-cdk/aws-ecs/lib/ec2/ec2-task-definition.ts +++ b/packages/@aws-cdk/aws-ecs/lib/ec2/ec2-task-definition.ts @@ -1,4 +1,5 @@ import { Construct } from 'constructs'; +import { ImportedTaskDefinition } from '../base/_imported-task-definition'; import { CommonTaskDefinitionAttributes, CommonTaskDefinitionProps, @@ -8,9 +9,9 @@ import { NetworkMode, PidMode, TaskDefinition, + InferenceAccelerator, } from '../base/task-definition'; import { PlacementConstraint } from '../placement'; -import { ImportedTaskDefinition } from '../base/_imported-task-definition'; /** * The properties for a task definition run on an EC2 cluster. @@ -51,6 +52,15 @@ export interface Ec2TaskDefinitionProps extends CommonTaskDefinitionProps { * @default - PidMode used by the task is not specified */ readonly pidMode?: PidMode; + + /** + * The inference accelerators to use for the containers in the task. + * + * Not supported in Fargate. + * + * @default - No inference accelerators. + */ + readonly inferenceAccelerators?: InferenceAccelerator[]; } /** @@ -109,6 +119,7 @@ export class Ec2TaskDefinition extends TaskDefinition implements IEc2TaskDefinit placementConstraints: props.placementConstraints, ipcMode: props.ipcMode, pidMode: props.pidMode, + inferenceAccelerators: props.inferenceAccelerators, }); } } diff --git a/packages/@aws-cdk/aws-ecs/lib/fargate/fargate-task-definition.ts b/packages/@aws-cdk/aws-ecs/lib/fargate/fargate-task-definition.ts index 3d8d113886709..ccf3291859708 100644 --- a/packages/@aws-cdk/aws-ecs/lib/fargate/fargate-task-definition.ts +++ b/packages/@aws-cdk/aws-ecs/lib/fargate/fargate-task-definition.ts @@ -1,5 +1,6 @@ import { Tokenization } from '@aws-cdk/core'; import { Construct } from 'constructs'; +import { ImportedTaskDefinition } from '../base/_imported-task-definition'; import { CommonTaskDefinitionAttributes, CommonTaskDefinitionProps, @@ -8,7 +9,6 @@ import { NetworkMode, TaskDefinition, } from '../base/task-definition'; -import { ImportedTaskDefinition } from '../base/_imported-task-definition'; /** * The properties for a task definition. diff --git a/packages/@aws-cdk/aws-ecs/lib/images/repository.ts b/packages/@aws-cdk/aws-ecs/lib/images/repository.ts index bf014fb18cb68..4ef78bc3854c1 100644 --- a/packages/@aws-cdk/aws-ecs/lib/images/repository.ts +++ b/packages/@aws-cdk/aws-ecs/lib/images/repository.ts @@ -10,7 +10,6 @@ import { Construct as CoreConstruct } from '@aws-cdk/core'; /** * Regex pattern to check if it is an ECR image URL. * - * @experimental */ const ECR_IMAGE_REGEX = /(^[a-zA-Z0-9][a-zA-Z0-9-_]*).dkr.ecr.([a-zA-Z0-9][a-zA-Z0-9-_]*).amazonaws.com(.cn)?\/.*/; diff --git a/packages/@aws-cdk/aws-ecs/lib/log-drivers/aws-log-driver.ts b/packages/@aws-cdk/aws-ecs/lib/log-drivers/aws-log-driver.ts index 705c4ed7fcb72..e6da02b29797e 100644 --- a/packages/@aws-cdk/aws-ecs/lib/log-drivers/aws-log-driver.ts +++ b/packages/@aws-cdk/aws-ecs/lib/log-drivers/aws-log-driver.ts @@ -8,6 +8,23 @@ import { removeEmpty } from './utils'; // eslint-disable-next-line import { Construct as CoreConstruct } from '@aws-cdk/core'; +/** + * awslogs provides two modes for delivering messages from the container to the log driver + */ +export enum AwsLogDriverMode { + + /** + * (default) direct, blocking delivery from container to driver. + */ + BLOCKING = 'blocking', + + /** + * The non-blocking message delivery mode prevents applications from blocking due to logging back pressure. + * Applications are likely to fail in unexpected ways when STDERR or STDOUT streams block. + */ + NON_BLOCKING = 'non-blocking' +} + /** * Specifies the awslogs log driver configuration options. */ @@ -62,6 +79,13 @@ export interface AwsLogDriverProps { * @default - No multiline matching. */ readonly multilinePattern?: string; + + /** + * The delivery mode of log messages from the container to awslogs. + * + * @default - AwsLogDriverMode.BLOCKING + */ + readonly mode?: AwsLogDriverMode; } /** @@ -106,6 +130,7 @@ export class AwsLogDriver extends LogDriver { 'awslogs-region': Stack.of(containerDefinition).region, 'awslogs-datetime-format': this.props.datetimeFormat, 'awslogs-multiline-pattern': this.props.multilinePattern, + 'mode': this.props.mode, }), }; } diff --git a/packages/@aws-cdk/aws-ecs/package.json b/packages/@aws-cdk/aws-ecs/package.json index ec829127f9e84..c427a0fd4870c 100644 --- a/packages/@aws-cdk/aws-ecs/package.json +++ b/packages/@aws-cdk/aws-ecs/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "@aws-cdk/aws-s3-deployment": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@types/nodeunit": "^0.0.31", @@ -81,7 +81,8 @@ "cfn2ts": "0.0.0", "nodeunit-shim": "0.0.0", "pkglint": "0.0.0", - "proxyquire": "^2.1.3" + "proxyquire": "^2.1.3", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-applicationautoscaling": "0.0.0", @@ -109,7 +110,7 @@ "@aws-cdk/aws-ssm": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -138,7 +139,7 @@ "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-ecs/test/app-mesh-proxy-configuration.test.ts b/packages/@aws-cdk/aws-ecs/test/app-mesh-proxy-configuration.test.ts index 69f3d30e9b865..7865809011a32 100644 --- a/packages/@aws-cdk/aws-ecs/test/app-mesh-proxy-configuration.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/app-mesh-proxy-configuration.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; diff --git a/packages/@aws-cdk/aws-ecs/test/aws-log-driver.test.ts b/packages/@aws-cdk/aws-ecs/test/aws-log-driver.test.ts index d36fb943e8b2d..8a802ac72014b 100644 --- a/packages/@aws-cdk/aws-ecs/test/aws-log-driver.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/aws-log-driver.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; import * as logs from '@aws-cdk/aws-logs'; import * as cdk from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; @@ -25,6 +25,7 @@ nodeunitShim({ logRetention: logs.RetentionDays.ONE_MONTH, multilinePattern: 'pattern', streamPrefix: 'hello', + mode: ecs.AwsLogDriverMode.NON_BLOCKING, }), }); @@ -44,6 +45,7 @@ nodeunitShim({ 'awslogs-region': { Ref: 'AWS::Region' }, 'awslogs-datetime-format': 'format', 'awslogs-multiline-pattern': 'pattern', + 'mode': 'non-blocking', }, }, }, diff --git a/packages/@aws-cdk/aws-ecs/test/ecs-cluster.test.ts b/packages/@aws-cdk/aws-ecs/test/cluster.test.ts similarity index 99% rename from packages/@aws-cdk/aws-ecs/test/ecs-cluster.test.ts rename to packages/@aws-cdk/aws-ecs/test/cluster.test.ts index 119e6d11a93ce..713338284e57b 100644 --- a/packages/@aws-cdk/aws-ecs/test/ecs-cluster.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/cluster.test.ts @@ -4,7 +4,7 @@ import { haveResource, haveResourceLike, ResourcePart, -} from '@aws-cdk/assert'; +} from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as kms from '@aws-cdk/aws-kms'; import * as cloudmap from '@aws-cdk/aws-servicediscovery'; @@ -990,6 +990,17 @@ nodeunitShim({ test.done(); }, + 'allows returning the correct image for linux 2 for EcsOptimizedImage with ARM hardware'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + test.equal(ecs.EcsOptimizedImage.amazonLinux2(ecs.AmiHardwareType.ARM).getImage(stack).osType, + ec2.OperatingSystemType.LINUX); + + test.done(); + }, + + 'allows returning the correct image for windows for EcsOptimizedImage'(test: Test) { // GIVEN const stack = new cdk.Stack(); diff --git a/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts b/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts index 88fa5545c830e..3a8671cdf22f7 100644 --- a/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts @@ -1,6 +1,6 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as path from 'path'; -import { InspectionFailure } from '@aws-cdk/assert'; +import { InspectionFailure } from '@aws-cdk/assert-internal'; import * as ecr_assets from '@aws-cdk/aws-ecr-assets'; import * as s3 from '@aws-cdk/aws-s3'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; @@ -48,6 +48,7 @@ describe('container definition', () => { taskDefinition, memoryLimitMiB: 1024, memoryReservationMiB: 512, + containerName: 'Example Container', command: ['CMD-SHELL'], cpu: 128, disableNetworking: true, @@ -198,7 +199,7 @@ describe('container definition', () => { }, Memory: 1024, MemoryReservation: 512, - Name: 'Container', + Name: 'Example Container', Privileged: true, ReadonlyRootFilesystem: true, ResourceRequirements: [ @@ -997,6 +998,176 @@ describe('container definition', () => { }); }); + describe('Given InferenceAccelerator resource parameter', () => { + test('correctly adds resource requirements to container definition using inference accelerator resource property', () => { + // GIVEN + const stack = new cdk.Stack(); + + const inferenceAccelerators = [{ + deviceName: 'device1', + deviceType: 'eia2.medium', + }]; + + const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { + inferenceAccelerators, + }); + + const inferenceAcceleratorResources = ['device1']; + + // WHEN + taskDefinition.addContainer('cont', { + image: ecs.ContainerImage.fromRegistry('test'), + memoryLimitMiB: 1024, + inferenceAcceleratorResources, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Family: 'Ec2TaskDef', + InferenceAccelerators: [{ + DeviceName: 'device1', + DeviceType: 'eia2.medium', + }], + ContainerDefinitions: [ + { + Image: 'test', + ResourceRequirements: [ + { + Type: 'InferenceAccelerator', + Value: 'device1', + }, + ], + }, + ], + }); + + + }); + test('correctly adds resource requirements to container definition using both props and addInferenceAcceleratorResource method', () => { + // GIVEN + const stack = new cdk.Stack(); + + const inferenceAccelerators = [{ + deviceName: 'device1', + deviceType: 'eia2.medium', + }, { + deviceName: 'device2', + deviceType: 'eia2.large', + }]; + + const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { + inferenceAccelerators, + }); + + const inferenceAcceleratorResources = ['device1']; + + const container = taskDefinition.addContainer('cont', { + image: ecs.ContainerImage.fromRegistry('test'), + memoryLimitMiB: 1024, + inferenceAcceleratorResources, + }); + + // WHEN + container.addInferenceAcceleratorResource('device2'); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Family: 'Ec2TaskDef', + InferenceAccelerators: [{ + DeviceName: 'device1', + DeviceType: 'eia2.medium', + }, { + DeviceName: 'device2', + DeviceType: 'eia2.large', + }], + ContainerDefinitions: [ + { + Image: 'test', + ResourceRequirements: [ + { + Type: 'InferenceAccelerator', + Value: 'device1', + }, + { + Type: 'InferenceAccelerator', + Value: 'device2', + }, + ], + }, + ], + }); + + }); + test('throws when the value of inference accelerator resource does not match any inference accelerators defined in the Task Definition', () => { + // GIVEN + const stack = new cdk.Stack(); + + const inferenceAccelerators = [{ + deviceName: 'device1', + deviceType: 'eia2.medium', + }]; + + const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { + inferenceAccelerators, + }); + + const inferenceAcceleratorResources = ['device2']; + + // THEN + expect(() => { + taskDefinition.addContainer('cont', { + image: ecs.ContainerImage.fromRegistry('test'), + memoryLimitMiB: 1024, + inferenceAcceleratorResources, + }); + }).toThrow(/Resource value device2 in container definition doesn't match any inference accelerator device name in the task definition./); + }); + }); + + test('adds resource requirements when both inference accelerator and gpu count are defined in the container definition', () => { + // GIVEN + const stack = new cdk.Stack(); + + const inferenceAccelerators = [{ + deviceName: 'device1', + deviceType: 'eia2.medium', + }]; + + const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { + inferenceAccelerators, + }); + + const inferenceAcceleratorResources = ['device1']; + + taskDefinition.addContainer('cont', { + image: ecs.ContainerImage.fromRegistry('test'), + memoryLimitMiB: 1024, + gpuCount: 2, + inferenceAcceleratorResources, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Family: 'Ec2TaskDef', + InferenceAccelerators: [{ + DeviceName: 'device1', + DeviceType: 'eia2.medium', + }], + ContainerDefinitions: [ + { + Image: 'test', + ResourceRequirements: [{ + Type: 'InferenceAccelerator', + Value: 'device1', + }, { + Type: 'GPU', + Value: '2', + }], + }, + ], + }); + }); + test('can add secret environment variables to the container definition', () => { // GIVEN const stack = new cdk.Stack(); diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/cross-stack.test.ts b/packages/@aws-cdk/aws-ecs/test/ec2/cross-stack.test.ts index 12d908957fc88..7e6fce7a4f301 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/cross-stack.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/cross-stack.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import { App, Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/ec2-service.test.ts b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-service.test.ts index 945832a09b869..f6d6a47efc6c3 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/ec2-service.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-service.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elb from '@aws-cdk/aws-elasticloadbalancing'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts index 4f713b06d2d71..06f891868feb8 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as path from 'path'; import { Protocol } from '@aws-cdk/aws-ec2'; import { Repository } from '@aws-cdk/aws-ecr'; @@ -1199,6 +1199,72 @@ describe('ec2 task definition', () => { }); }); + describe('setting inferenceAccelerators', () => { + test('correctly sets inferenceAccelerators using props', () => { + // GIVEN + const stack = new cdk.Stack(); + const inferenceAccelerators = [{ + deviceName: 'device1', + deviceType: 'eia2.medium', + }]; + + // WHEN + const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { + inferenceAccelerators, + }); + + taskDefinition.addContainer('web', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 512, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Family: 'Ec2TaskDef', + InferenceAccelerators: [{ + DeviceName: 'device1', + DeviceType: 'eia2.medium', + }], + }); + + }); + test('correctly sets inferenceAccelerators using props and addInferenceAccelerator method', () => { + // GIVEN + const stack = new cdk.Stack(); + const inferenceAccelerators = [{ + deviceName: 'device1', + deviceType: 'eia2.medium', + }]; + + const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { + inferenceAccelerators, + }); + + // WHEN + taskDefinition.addInferenceAccelerator({ + deviceName: 'device2', + deviceType: 'eia2.large', + }); + + taskDefinition.addContainer('web', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 512, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + Family: 'Ec2TaskDef', + InferenceAccelerators: [{ + DeviceName: 'device1', + DeviceType: 'eia2.medium', + }, { + DeviceName: 'device2', + DeviceType: 'eia2.large', + }], + }); + }); + }); + describe('When importing from an existing Ec2 TaskDefinition', () => { test('can succeed using TaskDefinition Arn', () => { // GIVEN diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.expected.json index 7a40a11d952ca..2e5eed7f911c6 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.expected.json @@ -696,7 +696,7 @@ "Type": "AWS::Lambda::Function", "Properties": { "Code": { - "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" + "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n task_arns = container_instance_task_arns(cluster, instance_arn)\n \n if task_arns:\n print('Instance ARN %s has task ARNs %s' % (instance_arn, ', '.join(task_arns)))\n\n while has_tasks(cluster, instance_arn, task_arns):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\ndef container_instance_task_arns(cluster, instance_arn):\n \"\"\"Fetch tasks for a container instance ARN.\"\"\"\n arns = ecs.list_tasks(cluster=cluster, containerInstance=instance_arn)['taskArns']\n return arns\n\ndef has_tasks(cluster, instance_arn, task_arns):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n task_count = None\n\n if task_arns:\n # Fetch details for tasks running on the container instance\n tasks = ecs.describe_tasks(cluster=cluster, tasks=task_arns)['tasks']\n if tasks:\n # Consider any non-stopped tasks as running\n task_count = sum(task['lastStatus'] != 'STOPPED' for task in tasks) + instance['pendingTasksCount']\n \n if not task_count:\n # Fallback to instance task counts if detailed task information is unavailable\n task_count = instance['runningTasksCount'] + instance['pendingTasksCount']\n \n print('Instance %s has %s tasks' % (instance_arn, task_count))\n\n return task_count > 0\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, "Role": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.bottlerocket.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.bottlerocket.expected.json index 23ba70a23584d..616a80172092e 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.bottlerocket.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.bottlerocket.expected.json @@ -690,7 +690,7 @@ "Type": "AWS::Lambda::Function", "Properties": { "Code": { - "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" + "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n task_arns = container_instance_task_arns(cluster, instance_arn)\n \n if task_arns:\n print('Instance ARN %s has task ARNs %s' % (instance_arn, ', '.join(task_arns)))\n\n while has_tasks(cluster, instance_arn, task_arns):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\ndef container_instance_task_arns(cluster, instance_arn):\n \"\"\"Fetch tasks for a container instance ARN.\"\"\"\n arns = ecs.list_tasks(cluster=cluster, containerInstance=instance_arn)['taskArns']\n return arns\n\ndef has_tasks(cluster, instance_arn, task_arns):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n task_count = None\n\n if task_arns:\n # Fetch details for tasks running on the container instance\n tasks = ecs.describe_tasks(cluster=cluster, tasks=task_arns)['tasks']\n if tasks:\n # Consider any non-stopped tasks as running\n task_count = sum(task['lastStatus'] != 'STOPPED' for task in tasks) + instance['pendingTasksCount']\n \n if not task_count:\n # Fallback to instance task counts if detailed task information is unavailable\n task_count = instance['runningTasksCount'] + instance['pendingTasksCount']\n \n print('Instance %s has %s tasks' % (instance_arn, task_count))\n\n return task_count > 0\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, "Role": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.expected.json index 3a323b0d36eff..77ccc9c6c36c6 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.expected.json @@ -717,7 +717,7 @@ "Type": "AWS::Lambda::Function", "Properties": { "Code": { - "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" + "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n task_arns = container_instance_task_arns(cluster, instance_arn)\n \n if task_arns:\n print('Instance ARN %s has task ARNs %s' % (instance_arn, ', '.join(task_arns)))\n\n while has_tasks(cluster, instance_arn, task_arns):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\ndef container_instance_task_arns(cluster, instance_arn):\n \"\"\"Fetch tasks for a container instance ARN.\"\"\"\n arns = ecs.list_tasks(cluster=cluster, containerInstance=instance_arn)['taskArns']\n return arns\n\ndef has_tasks(cluster, instance_arn, task_arns):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n task_count = None\n\n if task_arns:\n # Fetch details for tasks running on the container instance\n tasks = ecs.describe_tasks(cluster=cluster, tasks=task_arns)['tasks']\n if tasks:\n # Consider any non-stopped tasks as running\n task_count = sum(task['lastStatus'] != 'STOPPED' for task in tasks) + instance['pendingTasksCount']\n \n if not task_count:\n # Fallback to instance task counts if detailed task information is unavailable\n task_count = instance['runningTasksCount'] + instance['pendingTasksCount']\n \n print('Instance %s has %s tasks' % (instance_arn, task_count))\n\n return task_count > 0\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, "Role": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.cloudmap-container-port.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.cloudmap-container-port.expected.json index e067e7d75a67d..da866432d8539 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.cloudmap-container-port.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.cloudmap-container-port.expected.json @@ -518,7 +518,7 @@ "Type": "AWS::Lambda::Function", "Properties": { "Code": { - "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" + "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n task_arns = container_instance_task_arns(cluster, instance_arn)\n \n if task_arns:\n print('Instance ARN %s has task ARNs %s' % (instance_arn, ', '.join(task_arns)))\n\n while has_tasks(cluster, instance_arn, task_arns):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\ndef container_instance_task_arns(cluster, instance_arn):\n \"\"\"Fetch tasks for a container instance ARN.\"\"\"\n arns = ecs.list_tasks(cluster=cluster, containerInstance=instance_arn)['taskArns']\n return arns\n\ndef has_tasks(cluster, instance_arn, task_arns):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n task_count = None\n\n if task_arns:\n # Fetch details for tasks running on the container instance\n tasks = ecs.describe_tasks(cluster=cluster, tasks=task_arns)['tasks']\n if tasks:\n # Consider any non-stopped tasks as running\n task_count = sum(task['lastStatus'] != 'STOPPED' for task in tasks) + instance['pendingTasksCount']\n \n if not task_count:\n # Fallback to instance task counts if detailed task information is unavailable\n task_count = instance['runningTasksCount'] + instance['pendingTasksCount']\n \n print('Instance %s has %s tasks' % (instance_arn, task_count))\n\n return task_count > 0\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, "Role": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json index b287e6ffc33fa..c309c8a70f249 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json @@ -709,7 +709,7 @@ "Type": "AWS::Lambda::Function", "Properties": { "Code": { - "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" + "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n task_arns = container_instance_task_arns(cluster, instance_arn)\n \n if task_arns:\n print('Instance ARN %s has task ARNs %s' % (instance_arn, ', '.join(task_arns)))\n\n while has_tasks(cluster, instance_arn, task_arns):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\ndef container_instance_task_arns(cluster, instance_arn):\n \"\"\"Fetch tasks for a container instance ARN.\"\"\"\n arns = ecs.list_tasks(cluster=cluster, containerInstance=instance_arn)['taskArns']\n return arns\n\ndef has_tasks(cluster, instance_arn, task_arns):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n task_count = None\n\n if task_arns:\n # Fetch details for tasks running on the container instance\n tasks = ecs.describe_tasks(cluster=cluster, tasks=task_arns)['tasks']\n if tasks:\n # Consider any non-stopped tasks as running\n task_count = sum(task['lastStatus'] != 'STOPPED' for task in tasks) + instance['pendingTasksCount']\n \n if not task_count:\n # Fallback to instance task counts if detailed task information is unavailable\n task_count = instance['runningTasksCount'] + instance['pendingTasksCount']\n \n print('Instance %s has %s tasks' % (instance_arn, task_count))\n\n return task_count > 0\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, "Role": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.firelens-s3-config.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.firelens-s3-config.expected.json index 967d38891c487..e863d75fa16fb 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.firelens-s3-config.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.firelens-s3-config.expected.json @@ -696,7 +696,7 @@ "Type": "AWS::Lambda::Function", "Properties": { "Code": { - "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" + "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n task_arns = container_instance_task_arns(cluster, instance_arn)\n \n if task_arns:\n print('Instance ARN %s has task ARNs %s' % (instance_arn, ', '.join(task_arns)))\n\n while has_tasks(cluster, instance_arn, task_arns):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\ndef container_instance_task_arns(cluster, instance_arn):\n \"\"\"Fetch tasks for a container instance ARN.\"\"\"\n arns = ecs.list_tasks(cluster=cluster, containerInstance=instance_arn)['taskArns']\n return arns\n\ndef has_tasks(cluster, instance_arn, task_arns):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n task_count = None\n\n if task_arns:\n # Fetch details for tasks running on the container instance\n tasks = ecs.describe_tasks(cluster=cluster, tasks=task_arns)['tasks']\n if tasks:\n # Consider any non-stopped tasks as running\n task_count = sum(task['lastStatus'] != 'STOPPED' for task in tasks) + instance['pendingTasksCount']\n \n if not task_count:\n # Fallback to instance task counts if detailed task information is unavailable\n task_count = instance['runningTasksCount'] + instance['pendingTasksCount']\n \n print('Instance %s has %s tasks' % (instance_arn, task_count))\n\n return task_count > 0\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, "Role": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.graviton.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.graviton.expected.json new file mode 100644 index 0000000000000..8529dea9b1171 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.graviton.expected.json @@ -0,0 +1,848 @@ +{ + "Resources": { + "Vpc8378EB38": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc" + } + ] + } + }, + "VpcPublicSubnet1Subnet5C2D37C4": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1RouteTable6C95E38E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1RouteTableAssociation97140677": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + } + } + }, + "VpcPublicSubnet1DefaultRoute3DA9E72A": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet1EIPD7E02669": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1NATGateway4D7517AA": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet1EIPD7E02669", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet2Subnet691E08A3": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2RouteTable94F7E489": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2RouteTableAssociationDD5762D8": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + } + } + }, + "VpcPublicSubnet2DefaultRoute97F91067": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet2EIP3C605A87": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2NATGateway9182C01D": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet2EIP3C605A87", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPrivateSubnet1Subnet536B997A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" + } + ] + } + }, + "VpcPrivateSubnet1RouteTableB2C5B500": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" + } + ] + } + }, + "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + } + } + }, + "VpcPrivateSubnet1DefaultRouteBE02A9ED": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + } + } + }, + "VpcPrivateSubnet2Subnet3788AAA1": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.192.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" + } + ] + } + }, + "VpcPrivateSubnet2RouteTableA678073B": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" + } + ] + } + }, + "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + } + }, + "VpcPrivateSubnet2DefaultRoute060D2087": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet2NATGateway9182C01D" + } + } + }, + "VpcIGWD7BA715C": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc" + } + ] + } + }, + "VpcVPCGWBF912B6E": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "InternetGatewayId": { + "Ref": "VpcIGWD7BA715C" + } + } + }, + "EcsCluster97242B84": { + "Type": "AWS::ECS::Cluster" + }, + "EcsClustergravitonclusterInstanceSecurityGroup0187E9BB": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-integ/EcsCluster/graviton-cluster/InstanceSecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsCluster/graviton-cluster" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "EcsClustergravitonclusterInstanceRole0D0E0F94": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ec2.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } + } + ], + "Version": "2012-10-17" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsCluster/graviton-cluster" + } + ] + } + }, + "EcsClustergravitonclusterInstanceRoleDefaultPolicyB89DB33F": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ecs:DeregisterContainerInstance", + "ecs:RegisterContainerInstance", + "ecs:Submit*" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "EcsCluster97242B84", + "Arn" + ] + } + }, + { + "Action": [ + "ecs:Poll", + "ecs:StartTelemetrySession" + ], + "Condition": { + "ArnEquals": { + "ecs:cluster": { + "Fn::GetAtt": [ + "EcsCluster97242B84", + "Arn" + ] + } + } + }, + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ecs:DiscoverPollEndpoint", + "ecr:GetAuthorizationToken", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "EcsClustergravitonclusterInstanceRoleDefaultPolicyB89DB33F", + "Roles": [ + { + "Ref": "EcsClustergravitonclusterInstanceRole0D0E0F94" + } + ] + } + }, + "EcsClustergravitonclusterInstanceProfileD1BBFAAE": { + "Type": "AWS::IAM::InstanceProfile", + "Properties": { + "Roles": [ + { + "Ref": "EcsClustergravitonclusterInstanceRole0D0E0F94" + } + ] + } + }, + "EcsClustergravitonclusterLaunchConfig64183B57": { + "Type": "AWS::AutoScaling::LaunchConfiguration", + "Properties": { + "ImageId": { + "Ref": "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2arm64recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, + "InstanceType": "c6g.large", + "IamInstanceProfile": { + "Ref": "EcsClustergravitonclusterInstanceProfileD1BBFAAE" + }, + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "EcsClustergravitonclusterInstanceSecurityGroup0187E9BB", + "GroupId" + ] + } + ], + "UserData": { + "Fn::Base64": { + "Fn::Join": [ + "", + [ + "#!/bin/bash\necho ECS_CLUSTER=", + { + "Ref": "EcsCluster97242B84" + }, + " >> /etc/ecs/ecs.config\nsudo iptables --insert FORWARD 1 --in-interface docker+ --destination 169.254.169.254/32 --jump DROP\nsudo service iptables save\necho ECS_AWSVPC_BLOCK_IMDS=true >> /etc/ecs/ecs.config" + ] + ] + } + } + }, + "DependsOn": [ + "EcsClustergravitonclusterInstanceRoleDefaultPolicyB89DB33F", + "EcsClustergravitonclusterInstanceRole0D0E0F94" + ] + }, + "EcsClustergravitonclusterASG869F3168": { + "Type": "AWS::AutoScaling::AutoScalingGroup", + "Properties": { + "MaxSize": "2", + "MinSize": "2", + "LaunchConfigurationName": { + "Ref": "EcsClustergravitonclusterLaunchConfig64183B57" + }, + "Tags": [ + { + "Key": "Name", + "PropagateAtLaunch": true, + "Value": "aws-ecs-integ/EcsCluster/graviton-cluster" + } + ], + "VPCZoneIdentifier": [ + { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + }, + { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + ] + }, + "UpdatePolicy": { + "AutoScalingReplacingUpdate": { + "WillReplace": true + }, + "AutoScalingScheduledAction": { + "IgnoreUnmodifiedGroupSizeProperties": true + } + } + }, + "EcsClustergravitonclusterDrainECSHookFunctionServiceRole26D97764": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ], + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsCluster/graviton-cluster" + } + ] + } + }, + "EcsClustergravitonclusterDrainECSHookFunctionServiceRoleDefaultPolicy1563DC6B": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ec2:DescribeInstances", + "ec2:DescribeInstanceAttribute", + "ec2:DescribeInstanceStatus", + "ec2:DescribeHosts" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "autoscaling:CompleteLifecycleAction", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":autoscaling:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":autoScalingGroup:*:autoScalingGroupName/", + { + "Ref": "EcsClustergravitonclusterASG869F3168" + } + ] + ] + } + }, + { + "Action": [ + "ecs:DescribeContainerInstances", + "ecs:DescribeTasks" + ], + "Condition": { + "ArnEquals": { + "ecs:cluster": { + "Fn::GetAtt": [ + "EcsCluster97242B84", + "Arn" + ] + } + } + }, + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ecs:ListContainerInstances", + "ecs:SubmitContainerStateChange", + "ecs:SubmitTaskStateChange" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "EcsCluster97242B84", + "Arn" + ] + } + }, + { + "Action": [ + "ecs:UpdateContainerInstancesState", + "ecs:ListTasks" + ], + "Condition": { + "ArnEquals": { + "ecs:cluster": { + "Fn::GetAtt": [ + "EcsCluster97242B84", + "Arn" + ] + } + } + }, + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "EcsClustergravitonclusterDrainECSHookFunctionServiceRoleDefaultPolicy1563DC6B", + "Roles": [ + { + "Ref": "EcsClustergravitonclusterDrainECSHookFunctionServiceRole26D97764" + } + ] + } + }, + "EcsClustergravitonclusterDrainECSHookFunctionB606E681": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n task_arns = container_instance_task_arns(cluster, instance_arn)\n \n if task_arns:\n print('Instance ARN %s has task ARNs %s' % (instance_arn, ', '.join(task_arns)))\n\n while has_tasks(cluster, instance_arn, task_arns):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\ndef container_instance_task_arns(cluster, instance_arn):\n \"\"\"Fetch tasks for a container instance ARN.\"\"\"\n arns = ecs.list_tasks(cluster=cluster, containerInstance=instance_arn)['taskArns']\n return arns\n\ndef has_tasks(cluster, instance_arn, task_arns):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n task_count = None\n\n if task_arns:\n # Fetch details for tasks running on the container instance\n tasks = ecs.describe_tasks(cluster=cluster, tasks=task_arns)['tasks']\n if tasks:\n # Consider any non-stopped tasks as running\n task_count = sum(task['lastStatus'] != 'STOPPED' for task in tasks) + instance['pendingTasksCount']\n \n if not task_count:\n # Fallback to instance task counts if detailed task information is unavailable\n task_count = instance['runningTasksCount'] + instance['pendingTasksCount']\n \n print('Instance %s has %s tasks' % (instance_arn, task_count))\n\n return task_count > 0\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" + }, + "Role": { + "Fn::GetAtt": [ + "EcsClustergravitonclusterDrainECSHookFunctionServiceRole26D97764", + "Arn" + ] + }, + "Environment": { + "Variables": { + "CLUSTER": { + "Ref": "EcsCluster97242B84" + } + } + }, + "Handler": "index.lambda_handler", + "Runtime": "python3.6", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsCluster/graviton-cluster" + } + ], + "Timeout": 310 + }, + "DependsOn": [ + "EcsClustergravitonclusterDrainECSHookFunctionServiceRoleDefaultPolicy1563DC6B", + "EcsClustergravitonclusterDrainECSHookFunctionServiceRole26D97764" + ] + }, + "EcsClustergravitonclusterDrainECSHookFunctionAllowInvokeawsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicF44E68AA50D91BA3": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "EcsClustergravitonclusterDrainECSHookFunctionB606E681", + "Arn" + ] + }, + "Principal": "sns.amazonaws.com", + "SourceArn": { + "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC" + } + } + }, + "EcsClustergravitonclusterDrainECSHookFunctionTopic65B3FD43": { + "Type": "AWS::SNS::Subscription", + "Properties": { + "Protocol": "lambda", + "TopicArn": { + "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC" + }, + "Endpoint": { + "Fn::GetAtt": [ + "EcsClustergravitonclusterDrainECSHookFunctionB606E681", + "Arn" + ] + } + } + }, + "EcsClustergravitonclusterLifecycleHookDrainHookRoleA16C85AD": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "autoscaling.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsCluster/graviton-cluster" + } + ] + } + }, + "EcsClustergravitonclusterLifecycleHookDrainHookRoleDefaultPolicy516A6DA7": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "sns:Publish", + "Effect": "Allow", + "Resource": { + "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC" + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "EcsClustergravitonclusterLifecycleHookDrainHookRoleDefaultPolicy516A6DA7", + "Roles": [ + { + "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookRoleA16C85AD" + } + ] + } + }, + "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC": { + "Type": "AWS::SNS::Topic", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsCluster/graviton-cluster" + } + ] + } + }, + "EcsClustergravitonclusterLifecycleHookDrainHookA1F91B1B": { + "Type": "AWS::AutoScaling::LifecycleHook", + "Properties": { + "AutoScalingGroupName": { + "Ref": "EcsClustergravitonclusterASG869F3168" + }, + "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", + "DefaultResult": "CONTINUE", + "HeartbeatTimeout": 300, + "NotificationTargetARN": { + "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC" + }, + "RoleARN": { + "Fn::GetAtt": [ + "EcsClustergravitonclusterLifecycleHookDrainHookRoleA16C85AD", + "Arn" + ] + } + }, + "DependsOn": [ + "EcsClustergravitonclusterLifecycleHookDrainHookRoleDefaultPolicy516A6DA7", + "EcsClustergravitonclusterLifecycleHookDrainHookRoleA16C85AD" + ] + } + }, + "Parameters": { + "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2arm64recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ecs/optimized-ami/amazon-linux-2/arm64/recommended/image_id" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.graviton.ts b/packages/@aws-cdk/aws-ecs/test/ec2/integ.graviton.ts new file mode 100644 index 0000000000000..4ca63a18a2262 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.graviton.ts @@ -0,0 +1,16 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as cdk from '@aws-cdk/core'; +import * as ecs from '../../lib'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-ecs-integ'); + +const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 2 }); +const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + +cluster.addCapacity('graviton-cluster', { + minCapacity: 2, + instanceType: new ec2.InstanceType('c6g.large'), + machineImage: ecs.EcsOptimizedImage.amazonLinux2(ecs.AmiHardwareType.ARM), +}); +app.synth(); diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-awsvpc-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-awsvpc-nw.expected.json index 90fd28f84cef2..1fef2d83e2784 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-awsvpc-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-awsvpc-nw.expected.json @@ -696,7 +696,7 @@ "Type": "AWS::Lambda::Function", "Properties": { "Code": { - "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" + "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n task_arns = container_instance_task_arns(cluster, instance_arn)\n \n if task_arns:\n print('Instance ARN %s has task ARNs %s' % (instance_arn, ', '.join(task_arns)))\n\n while has_tasks(cluster, instance_arn, task_arns):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\ndef container_instance_task_arns(cluster, instance_arn):\n \"\"\"Fetch tasks for a container instance ARN.\"\"\"\n arns = ecs.list_tasks(cluster=cluster, containerInstance=instance_arn)['taskArns']\n return arns\n\ndef has_tasks(cluster, instance_arn, task_arns):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n task_count = None\n\n if task_arns:\n # Fetch details for tasks running on the container instance\n tasks = ecs.describe_tasks(cluster=cluster, tasks=task_arns)['tasks']\n if tasks:\n # Consider any non-stopped tasks as running\n task_count = sum(task['lastStatus'] != 'STOPPED' for task in tasks) + instance['pendingTasksCount']\n \n if not task_count:\n # Fallback to instance task counts if detailed task information is unavailable\n task_count = instance['runningTasksCount'] + instance['pendingTasksCount']\n \n print('Instance %s has %s tasks' % (instance_arn, task_count))\n\n return task_count > 0\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, "Role": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-bridge-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-bridge-nw.expected.json index 0737785f5fea4..1bcb9d34f8dbd 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-bridge-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-bridge-nw.expected.json @@ -717,7 +717,7 @@ "Type": "AWS::Lambda::Function", "Properties": { "Code": { - "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" + "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n task_arns = container_instance_task_arns(cluster, instance_arn)\n \n if task_arns:\n print('Instance ARN %s has task ARNs %s' % (instance_arn, ', '.join(task_arns)))\n\n while has_tasks(cluster, instance_arn, task_arns):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\ndef container_instance_task_arns(cluster, instance_arn):\n \"\"\"Fetch tasks for a container instance ARN.\"\"\"\n arns = ecs.list_tasks(cluster=cluster, containerInstance=instance_arn)['taskArns']\n return arns\n\ndef has_tasks(cluster, instance_arn, task_arns):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n task_count = None\n\n if task_arns:\n # Fetch details for tasks running on the container instance\n tasks = ecs.describe_tasks(cluster=cluster, tasks=task_arns)['tasks']\n if tasks:\n # Consider any non-stopped tasks as running\n task_count = sum(task['lastStatus'] != 'STOPPED' for task in tasks) + instance['pendingTasksCount']\n \n if not task_count:\n # Fallback to instance task counts if detailed task information is unavailable\n task_count = instance['runningTasksCount'] + instance['pendingTasksCount']\n \n print('Instance %s has %s tasks' % (instance_arn, task_count))\n\n return task_count > 0\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, "Role": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-awsvpc-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-awsvpc-nw.expected.json index b4e2c72807b0e..353debc6de544 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-awsvpc-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-awsvpc-nw.expected.json @@ -696,7 +696,7 @@ "Type": "AWS::Lambda::Function", "Properties": { "Code": { - "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" + "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n task_arns = container_instance_task_arns(cluster, instance_arn)\n \n if task_arns:\n print('Instance ARN %s has task ARNs %s' % (instance_arn, ', '.join(task_arns)))\n\n while has_tasks(cluster, instance_arn, task_arns):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\ndef container_instance_task_arns(cluster, instance_arn):\n \"\"\"Fetch tasks for a container instance ARN.\"\"\"\n arns = ecs.list_tasks(cluster=cluster, containerInstance=instance_arn)['taskArns']\n return arns\n\ndef has_tasks(cluster, instance_arn, task_arns):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n task_count = None\n\n if task_arns:\n # Fetch details for tasks running on the container instance\n tasks = ecs.describe_tasks(cluster=cluster, tasks=task_arns)['tasks']\n if tasks:\n # Consider any non-stopped tasks as running\n task_count = sum(task['lastStatus'] != 'STOPPED' for task in tasks) + instance['pendingTasksCount']\n \n if not task_count:\n # Fallback to instance task counts if detailed task information is unavailable\n task_count = instance['runningTasksCount'] + instance['pendingTasksCount']\n \n print('Instance %s has %s tasks' % (instance_arn, task_count))\n\n return task_count > 0\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, "Role": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-bridge-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-bridge-nw.expected.json index ef42895037361..4722ee003bef2 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-bridge-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-bridge-nw.expected.json @@ -696,7 +696,7 @@ "Type": "AWS::Lambda::Function", "Properties": { "Code": { - "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" + "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n task_arns = container_instance_task_arns(cluster, instance_arn)\n \n if task_arns:\n print('Instance ARN %s has task ARNs %s' % (instance_arn, ', '.join(task_arns)))\n\n while has_tasks(cluster, instance_arn, task_arns):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\ndef container_instance_task_arns(cluster, instance_arn):\n \"\"\"Fetch tasks for a container instance ARN.\"\"\"\n arns = ecs.list_tasks(cluster=cluster, containerInstance=instance_arn)['taskArns']\n return arns\n\ndef has_tasks(cluster, instance_arn, task_arns):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n task_count = None\n\n if task_arns:\n # Fetch details for tasks running on the container instance\n tasks = ecs.describe_tasks(cluster=cluster, tasks=task_arns)['tasks']\n if tasks:\n # Consider any non-stopped tasks as running\n task_count = sum(task['lastStatus'] != 'STOPPED' for task in tasks) + instance['pendingTasksCount']\n \n if not task_count:\n # Fallback to instance task counts if detailed task information is unavailable\n task_count = instance['runningTasksCount'] + instance['pendingTasksCount']\n \n print('Instance %s has %s tasks' % (instance_arn, task_count))\n\n return task_count > 0\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, "Role": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.spot-drain.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.spot-drain.expected.json index 77acf122d0168..20ba3cf89516e 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.spot-drain.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.spot-drain.expected.json @@ -698,7 +698,7 @@ "Type": "AWS::Lambda::Function", "Properties": { "Code": { - "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" + "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n task_arns = container_instance_task_arns(cluster, instance_arn)\n \n if task_arns:\n print('Instance ARN %s has task ARNs %s' % (instance_arn, ', '.join(task_arns)))\n\n while has_tasks(cluster, instance_arn, task_arns):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\ndef container_instance_task_arns(cluster, instance_arn):\n \"\"\"Fetch tasks for a container instance ARN.\"\"\"\n arns = ecs.list_tasks(cluster=cluster, containerInstance=instance_arn)['taskArns']\n return arns\n\ndef has_tasks(cluster, instance_arn, task_arns):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n task_count = None\n\n if task_arns:\n # Fetch details for tasks running on the container instance\n tasks = ecs.describe_tasks(cluster=cluster, tasks=task_arns)['tasks']\n if tasks:\n # Consider any non-stopped tasks as running\n task_count = sum(task['lastStatus'] != 'STOPPED' for task in tasks) + instance['pendingTasksCount']\n \n if not task_count:\n # Fallback to instance task counts if detailed task information is unavailable\n task_count = instance['runningTasksCount'] + instance['pendingTasksCount']\n \n print('Instance %s has %s tasks' % (instance_arn, task_count))\n\n return task_count > 0\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, "Role": { "Fn::GetAtt": [ @@ -1179,7 +1179,7 @@ "Type": "AWS::Lambda::Function", "Properties": { "Code": { - "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" + "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n task_arns = container_instance_task_arns(cluster, instance_arn)\n \n if task_arns:\n print('Instance ARN %s has task ARNs %s' % (instance_arn, ', '.join(task_arns)))\n\n while has_tasks(cluster, instance_arn, task_arns):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\ndef container_instance_task_arns(cluster, instance_arn):\n \"\"\"Fetch tasks for a container instance ARN.\"\"\"\n arns = ecs.list_tasks(cluster=cluster, containerInstance=instance_arn)['taskArns']\n return arns\n\ndef has_tasks(cluster, instance_arn, task_arns):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n task_count = None\n\n if task_arns:\n # Fetch details for tasks running on the container instance\n tasks = ecs.describe_tasks(cluster=cluster, tasks=task_arns)['tasks']\n if tasks:\n # Consider any non-stopped tasks as running\n task_count = sum(task['lastStatus'] != 'STOPPED' for task in tasks) + instance['pendingTasksCount']\n \n if not task_count:\n # Fallback to instance task counts if detailed task information is unavailable\n task_count = instance['runningTasksCount'] + instance['pendingTasksCount']\n \n print('Instance %s has %s tasks' % (instance_arn, task_count))\n\n return task_count > 0\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, "Role": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts b/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts index cbd43a8d44f67..0bdbeac0c04d5 100644 --- a/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; import * as appscaling from '@aws-cdk/aws-applicationautoscaling'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as ec2 from '@aws-cdk/aws-ec2'; diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/fargate-task-definition.test.ts b/packages/@aws-cdk/aws-ecs/test/fargate/fargate-task-definition.test.ts index b8fad1bc9316f..9cd5d994c9555 100644 --- a/packages/@aws-cdk/aws-ecs/test/fargate/fargate-task-definition.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/fargate/fargate-task-definition.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; @@ -113,6 +113,24 @@ nodeunitShim({ test.done(); }, + + 'throws when adding inference accelerators'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); + + const inferenceAccelerator = { + deviceName: 'device1', + deviceType: 'eia2.medium', + }; + + // THEN + test.throws(() => { + taskDefinition.addInferenceAccelerator(inferenceAccelerator); + }, /Cannot use inference accelerators on tasks that run on Fargate/); + + test.done(); + }, }, 'When importing from an existing Fargate TaskDefinition': { diff --git a/packages/@aws-cdk/aws-ecs/test/firelens-log-driver.test.ts b/packages/@aws-cdk/aws-ecs/test/firelens-log-driver.test.ts index 99a1c6b935b64..658f316e3fa30 100644 --- a/packages/@aws-cdk/aws-ecs/test/firelens-log-driver.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/firelens-log-driver.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; diff --git a/packages/@aws-cdk/aws-ecs/test/fluentd-log-driver.test.ts b/packages/@aws-cdk/aws-ecs/test/fluentd-log-driver.test.ts index a317699d1075d..54ac824fb6c47 100644 --- a/packages/@aws-cdk/aws-ecs/test/fluentd-log-driver.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/fluentd-log-driver.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; diff --git a/packages/@aws-cdk/aws-ecs/test/gelf-log-driver.test.ts b/packages/@aws-cdk/aws-ecs/test/gelf-log-driver.test.ts index 7907b0532b0ac..9f6663304d353 100644 --- a/packages/@aws-cdk/aws-ecs/test/gelf-log-driver.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/gelf-log-driver.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; diff --git a/packages/@aws-cdk/aws-ecs/test/images/tag-parameter-container-image.test.ts b/packages/@aws-cdk/aws-ecs/test/images/tag-parameter-container-image.test.ts index d74ecb5335ac3..beaa9a23308c8 100644 --- a/packages/@aws-cdk/aws-ecs/test/images/tag-parameter-container-image.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/images/tag-parameter-container-image.test.ts @@ -1,4 +1,4 @@ -import { SynthUtils } from '@aws-cdk/assert'; +import { SynthUtils } from '@aws-cdk/assert-internal'; import * as ecr from '@aws-cdk/aws-ecr'; import * as cdk from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; diff --git a/packages/@aws-cdk/aws-ecs/test/journald-log-driver.test.ts b/packages/@aws-cdk/aws-ecs/test/journald-log-driver.test.ts index 31bec4a42e47f..aeffbc2073629 100644 --- a/packages/@aws-cdk/aws-ecs/test/journald-log-driver.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/journald-log-driver.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; diff --git a/packages/@aws-cdk/aws-ecs/test/json-file-log-driver.test.ts b/packages/@aws-cdk/aws-ecs/test/json-file-log-driver.test.ts index e75ff398eeb03..b282a61c29f88 100644 --- a/packages/@aws-cdk/aws-ecs/test/json-file-log-driver.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/json-file-log-driver.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; diff --git a/packages/@aws-cdk/aws-ecs/test/splunk-log-driver.test.ts b/packages/@aws-cdk/aws-ecs/test/splunk-log-driver.test.ts index c8afd01daade1..2ee8e9e433ce8 100644 --- a/packages/@aws-cdk/aws-ecs/test/splunk-log-driver.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/splunk-log-driver.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; diff --git a/packages/@aws-cdk/aws-ecs/test/syslog-log-driver.test.ts b/packages/@aws-cdk/aws-ecs/test/syslog-log-driver.test.ts index b14c05a5b3234..db328772d7548 100644 --- a/packages/@aws-cdk/aws-ecs/test/syslog-log-driver.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/syslog-log-driver.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; diff --git a/packages/@aws-cdk/aws-ecs/test/task-definition.test.ts b/packages/@aws-cdk/aws-ecs/test/task-definition.test.ts index 709d3abd86026..6e578952a5765 100644 --- a/packages/@aws-cdk/aws-ecs/test/task-definition.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/task-definition.test.ts @@ -1,8 +1,8 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; +import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import * as ecs from '../lib'; -import * as iam from '@aws-cdk/aws-iam'; nodeunitShim({ 'When creating a new TaskDefinition': { diff --git a/packages/@aws-cdk/aws-efs/README.md b/packages/@aws-cdk/aws-efs/README.md index 444a3a69d7480..bccae05b20547 100644 --- a/packages/@aws-cdk/aws-efs/README.md +++ b/packages/@aws-cdk/aws-efs/README.md @@ -5,17 +5,7 @@ ![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]) are always stable and safe to use. -> -> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib - -![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. +![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge) --- @@ -44,10 +34,10 @@ Access (IA) storage class. ```ts const fileSystem = new efs.FileSystem(this, 'MyEfsFileSystem', { vpc: new ec2.Vpc(this, 'VPC'), - encrypted: true, // file system is not encrypted by default lifecyclePolicy: efs.LifecyclePolicy.AFTER_14_DAYS, // files are not transitioned to infrequent access (IA) storage by default performanceMode: efs.PerformanceMode.GENERAL_PURPOSE, // default }); + ``` ⚠️ An Amazon EFS file system's performance mode can't be changed after the file system has been created. diff --git a/packages/@aws-cdk/aws-efs/lib/efs-file-system.ts b/packages/@aws-cdk/aws-efs/lib/efs-file-system.ts index 60af6fde51752..99e390a89257d 100644 --- a/packages/@aws-cdk/aws-efs/lib/efs-file-system.ts +++ b/packages/@aws-cdk/aws-efs/lib/efs-file-system.ts @@ -1,6 +1,10 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as kms from '@aws-cdk/aws-kms'; import { ConcreteDependable, IDependable, IResource, RemovalPolicy, Resource, Size, Tags } from '@aws-cdk/core'; +// keep this import separate from other imports to reduce chance for merge conflicts with v2-main +// eslint-disable-next-line no-duplicate-imports +import { FeatureFlags } from '@aws-cdk/core'; +import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; import { AccessPoint, AccessPointOptions } from './access-point'; import { CfnFileSystem, CfnMountTarget } from './efs.generated'; @@ -122,7 +126,8 @@ export interface FileSystemProps { /** * Defines if the data at rest in the file system is encrypted or not. * - * @default false + * @default - If your application has the '@aws-cdk/aws-efs:defaultEncryptionAtRest' feature flag set, the default is true, otherwise, the default is false. + * @link https://docs.aws.amazon.com/cdk/latest/guide/featureflags.html */ readonly encrypted?: boolean; @@ -249,8 +254,13 @@ export class FileSystem extends Resource implements IFileSystem { throw new Error('Property provisionedThroughputPerSecond is required when throughputMode is PROVISIONED'); } + // we explictly use 'undefined' to represent 'false' to maintain backwards compatibility since + // its considered an actual change in CloudFormations eyes, even though they have the same meaning. + const encrypted = props.encrypted ?? (FeatureFlags.of(this).isEnabled( + cxapi.EFS_DEFAULT_ENCRYPTION_AT_REST) ? true : undefined); + const filesystem = new CfnFileSystem(this, 'Resource', { - encrypted: props.encrypted, + encrypted: encrypted, kmsKeyId: props.kmsKey?.keyArn, lifecyclePolicies: (props.lifecyclePolicy ? [{ transitionToIa: props.lifecyclePolicy }] : undefined), performanceMode: props.performanceMode, diff --git a/packages/@aws-cdk/aws-efs/package.json b/packages/@aws-cdk/aws-efs/package.json index 6a7cef054b6a2..2d31b8dcf986a 100644 --- a/packages/@aws-cdk/aws-efs/package.json +++ b/packages/@aws-cdk/aws-efs/package.json @@ -71,11 +71,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", @@ -83,7 +84,7 @@ "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -92,7 +93,7 @@ "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" @@ -103,8 +104,8 @@ "resource-attribute:@aws-cdk/aws-efs.FileSystem.fileSystemArn" ] }, - "stability": "experimental", - "maturity": "experimental", + "stability": "stable", + "maturity": "stable", "awscdkio": { "announce": false }, diff --git a/packages/@aws-cdk/aws-efs/test/access-point.test.ts b/packages/@aws-cdk/aws-efs/test/access-point.test.ts index 24115574eb704..0bc90d71ad3ab 100644 --- a/packages/@aws-cdk/aws-efs/test/access-point.test.ts +++ b/packages/@aws-cdk/aws-efs/test/access-point.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import { Stack } from '@aws-cdk/core'; import { AccessPoint, FileSystem } from '../lib'; diff --git a/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts b/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts index d3868a841e0a5..d98d0f4066c61 100644 --- a/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts +++ b/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts @@ -1,7 +1,9 @@ -import { expect as expectCDK, haveResource, ResourcePart, countResources } from '@aws-cdk/assert'; +import { ABSENT, expect as expectCDK, haveResource, ResourcePart, countResources } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as kms from '@aws-cdk/aws-kms'; -import { RemovalPolicy, Size, Stack, Tags } from '@aws-cdk/core'; +import { App, RemovalPolicy, Size, Stack, Tags } from '@aws-cdk/core'; +import * as cxapi from '@aws-cdk/cx-api'; +import { testFutureBehavior, testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; import { FileSystem, LifecyclePolicy, PerformanceMode, ThroughputMode } from '../lib'; let stack = new Stack(); @@ -12,6 +14,38 @@ beforeEach(() => { vpc = new ec2.Vpc(stack, 'VPC'); }); +testFutureBehavior( + 'when @aws-cdk/aws-efs:defaultEncryptionAtRest is enabled, encryption is enabled by default', + { [cxapi.EFS_DEFAULT_ENCRYPTION_AT_REST]: true }, + App, + (app) => { + const customStack = new Stack(app); + + const customVpc = new ec2.Vpc(customStack, 'VPC'); + new FileSystem(customVpc, 'EfsFileSystem', { + vpc: customVpc, + }); + + expectCDK(customStack).to(haveResource('AWS::EFS::FileSystem', { + Encrypted: true, + })); + + }); + +testLegacyBehavior('when @aws-cdk/aws-efs:defaultEncryptionAtRest is missing, encryption is disabled by default', App, (app) => { + const customStack = new Stack(app); + + const customVpc = new ec2.Vpc(customStack, 'VPC'); + new FileSystem(customVpc, 'EfsFileSystem', { + vpc: customVpc, + }); + + expectCDK(customStack).to(haveResource('AWS::EFS::FileSystem', { + Encrypted: ABSENT, + })); + +}); + test('default file system is created correctly', () => { // WHEN new FileSystem(stack, 'EfsFileSystem', { diff --git a/packages/@aws-cdk/aws-efs/test/integ.efs.expected.json b/packages/@aws-cdk/aws-efs/test/integ.efs.expected.json index 8c1fa47948791..3ceefb75f5c10 100644 --- a/packages/@aws-cdk/aws-efs/test/integ.efs.expected.json +++ b/packages/@aws-cdk/aws-efs/test/integ.efs.expected.json @@ -453,6 +453,7 @@ "FileSystem8A8E25C0": { "Type": "AWS::EFS::FileSystem", "Properties": { + "Encrypted": true, "FileSystemTags": [ { "Key": "Name", diff --git a/packages/@aws-cdk/aws-eks-legacy/package.json b/packages/@aws-cdk/aws-eks-legacy/package.json index 67078e5830dcf..a056b364b640b 100644 --- a/packages/@aws-cdk/aws-eks-legacy/package.json +++ b/packages/@aws-cdk/aws-eks-legacy/package.json @@ -68,13 +68,13 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "nodeunit": "^0.11.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-autoscaling": "0.0.0", @@ -84,7 +84,7 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -95,7 +95,7 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" @@ -106,6 +106,7 @@ "props-no-arn-refs:@aws-cdk/aws-eks.ClusterProps.outputMastersRoleArn", "props-default-doc:@aws-cdk/aws-eks.AutoScalingGroupOptions.bootstrapOptions", "resource-attribute:@aws-cdk/aws-eks.Cluster.clusterSecurityGroupId", + "resource-attribute:@aws-cdk/aws-eks-legacy.Cluster.clusterOpenIdConnectIssuerUrl", "docs-public-apis:@aws-cdk/aws-eks.AwsAuthProps", "docs-public-apis:@aws-cdk/aws-eks.BootstrapOptions", "docs-public-apis:@aws-cdk/aws-eks.ClusterAttributes", diff --git a/packages/@aws-cdk/aws-eks-legacy/test/test.awsauth.ts b/packages/@aws-cdk/aws-eks-legacy/test/test.awsauth.ts index c9bba19a0e35e..2ebdcde32dbcf 100644 --- a/packages/@aws-cdk/aws-eks-legacy/test/test.awsauth.ts +++ b/packages/@aws-cdk/aws-eks-legacy/test/test.awsauth.ts @@ -1,4 +1,4 @@ -import { countResources, expect, haveResource } from '@aws-cdk/assert'; +import { countResources, expect, haveResource } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import { Test } from 'nodeunit'; import { Cluster, KubernetesResource } from '../lib'; diff --git a/packages/@aws-cdk/aws-eks-legacy/test/test.cluster.ts b/packages/@aws-cdk/aws-eks-legacy/test/test.cluster.ts index 28d63b780c891..cfcc21a8ce50e 100644 --- a/packages/@aws-cdk/aws-eks-legacy/test/test.cluster.ts +++ b/packages/@aws-cdk/aws-eks-legacy/test/test.cluster.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike, not } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike, not } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-eks-legacy/test/test.helm-chart.ts b/packages/@aws-cdk/aws-eks-legacy/test/test.helm-chart.ts index 5bdec9c9e62a3..e595e3d00a5ac 100644 --- a/packages/@aws-cdk/aws-eks-legacy/test/test.helm-chart.ts +++ b/packages/@aws-cdk/aws-eks-legacy/test/test.helm-chart.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import { Test } from 'nodeunit'; import * as eks from '../lib'; import { testFixtureCluster } from './util'; diff --git a/packages/@aws-cdk/aws-eks-legacy/test/test.manifest.ts b/packages/@aws-cdk/aws-eks-legacy/test/test.manifest.ts index 30afa40e3069e..32e418352f808 100644 --- a/packages/@aws-cdk/aws-eks-legacy/test/test.manifest.ts +++ b/packages/@aws-cdk/aws-eks-legacy/test/test.manifest.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import { Test } from 'nodeunit'; import { Cluster, KubernetesResource } from '../lib'; import { testFixtureNoVpc } from './util'; diff --git a/packages/@aws-cdk/aws-eks/README.md b/packages/@aws-cdk/aws-eks/README.md index 59909c9ea9a0b..bb64c62070a0e 100644 --- a/packages/@aws-cdk/aws-eks/README.md +++ b/packages/@aws-cdk/aws-eks/README.md @@ -34,7 +34,7 @@ In addition, the library also supports defining Kubernetes resource manifests wi * [Kubernetes Manifests](#kubernetes-manifests) * [Helm Charts](#helm-charts) * [CDK8s Charts](#cdk8s-charts) -* [Patching Kuberentes Resources](#patching-kubernetes-resources) +* [Patching Kubernetes Resources](#patching-kubernetes-resources) * [Querying Kubernetes Resources](#querying-kubernetes-resources) * [Using existing clusters](#using-existing-clusters) * [Known Issues and Limitations](#known-issues-and-limitations) @@ -202,7 +202,7 @@ cluster.addNodegroupCapacity('custom-node-group', { #### Spot Instances Support Use `capacityType` to create managed node groups comprised of spot instances. To maximize the availability of your applications while using -Spot Instances, we recommend that you configure a Spot managed node group to use multiple instance types with the `instanceTypes` property. +Spot Instances, we recommend that you configure a Spot managed node group to use multiple instance types with the `instanceTypes` property. > For more details visit [Managed node group capacity types](https://docs.aws.amazon.com/eks/latest/userguide/managed-node-groups.html#managed-node-group-capacity-types). @@ -356,7 +356,7 @@ const asg = new ec2.AutoScalingGroup(...); cluster.connectAutoScalingGroupCapacity(asg); ``` -In both cases, the [cluster security group](https://docs.aws.amazon.com/eks/latest/userguide/sec-group-reqs.html#cluster-sg) will be autoamtically attached to +In both cases, the [cluster security group](https://docs.aws.amazon.com/eks/latest/userguide/sec-group-reqs.html#cluster-sg) will be automatically attached to the auto-scaling group, allowing for traffic to flow freely between managed and self-managed nodes. > **Note:** The default `updateType` for auto-scaling groups does not replace existing nodes. Since security groups are determined at launch time, self-managed nodes that were provisioned with version `1.78.0` or lower, will not be updated. @@ -395,7 +395,7 @@ const asg = new ec2.AutoScalingGroup(...) cluster.connectAutoScalingGroupCapacity(asg); ``` -This will add the necessary user-data and configure all connections, roles, and tags needed for the instances in the auto-scaling group to properly join the cluster. +This will add the necessary user-data to access the apiserver and configure all connections, roles, and tags needed for the instances in the auto-scaling group to properly join the cluster. #### Spot Instances @@ -654,6 +654,15 @@ const cluster = new eks.Cluster(this, 'MyCluster', { }); ``` +You can also use a similiar configuration for running a cluster built using the FargateCluster construct. + +```ts +const secretsKey = new kms.Key(this, 'SecretsKey'); +const cluster = new eks.FargateCluster(this, 'MyFargateCluster', { + secretsEncryptionKey: secretsKey +}); +``` + The Amazon Resource Name (ARN) for that CMK can be retrieved. ```ts diff --git a/packages/@aws-cdk/aws-eks/lib/cluster.ts b/packages/@aws-cdk/aws-eks/lib/cluster.ts index c578b90fa388b..9e9a22d916e56 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster.ts @@ -467,6 +467,15 @@ export interface ClusterOptions extends CommonClusterOptions { * @default false */ readonly placeClusterHandlerInVpc?: boolean; + + /** + * KMS secret for envelope encryption for Kubernetes secrets. + * + * @default - By default, Kubernetes stores all secret object data within etcd and + * all etcd volumes used by Amazon EKS are encrypted at the disk-level + * using AWS-Managed encryption keys. + */ + readonly secretsEncryptionKey?: kms.IKey; } /** @@ -594,15 +603,6 @@ export interface ClusterProps extends ClusterOptions { * @default NODEGROUP */ readonly defaultCapacityType?: DefaultCapacityType; - - /** - * KMS secret for envelope encryption for Kubernetes secrets. - * - * @default - By default, Kubernetes stores all secret object data within etcd and - * all etcd volumes used by Amazon EKS are encrypted at the disk-level - * using AWS-Managed encryption keys. - */ - readonly secretsEncryptionKey?: kms.IKey; } /** @@ -983,8 +983,8 @@ export class Cluster extends ClusterBase { const privateSubents = this.selectPrivateSubnets().slice(0, 16); const publicAccessDisabled = !this.endpointAccess._config.publicAccess; const publicAccessRestricted = !publicAccessDisabled - && this.endpointAccess._config.publicCidrs - && this.endpointAccess._config.publicCidrs.length !== 0; + && this.endpointAccess._config.publicCidrs + && this.endpointAccess._config.publicCidrs.length !== 0; // validate endpoint access configuration @@ -1020,7 +1020,7 @@ export class Cluster extends ClusterBase { }, resources: ['secrets'], }], - } : {} ), + } : {}), endpointPrivateAccess: this.endpointAccess._config.privateAccess, endpointPublicAccess: this.endpointAccess._config.publicAccess, publicAccessCidrs: this.endpointAccess._config.publicCidrs, @@ -1167,7 +1167,7 @@ export class Cluster extends ClusterBase { * [EC2 Spot Instance Termination Notices](https://aws.amazon.com/blogs/aws/new-ec2-spot-instance-termination-notices/). */ public addAutoScalingGroupCapacity(id: string, options: AutoScalingGroupCapacityOptions): autoscaling.AutoScalingGroup { - if (options.machineImageType === MachineImageType.BOTTLEROCKET && options.bootstrapOptions !== undefined ) { + if (options.machineImageType === MachineImageType.BOTTLEROCKET && options.bootstrapOptions !== undefined) { throw new Error('bootstrapOptions is not supported for Bottlerocket'); } const asg = new autoscaling.AutoScalingGroup(this, id, { @@ -1264,7 +1264,7 @@ export class Cluster extends ClusterBase { if (bootstrapEnabled) { const userData = options.machineImageType === MachineImageType.BOTTLEROCKET ? renderBottlerocketUserData(this) : - renderAmazonLinuxUserData(this.clusterName, autoScalingGroup, options.bootstrapOptions); + renderAmazonLinuxUserData(this, autoScalingGroup, options.bootstrapOptions); autoScalingGroup.addUserData(...userData); } @@ -1637,6 +1637,16 @@ export interface BootstrapOptions { */ readonly dockerConfigJson?: string; + /** + + * Overrides the IP address to use for DNS queries within the + * cluster. + * + * @default - 10.100.0.10 or 172.20.0.10 based on the IP + * address of the primary interface. + */ + readonly dnsClusterIp?: string; + /** * Extra arguments to add to the kubelet. Useful for adding labels or taints. * @@ -1842,9 +1852,9 @@ export class EksOptimizedImage implements ec2.IMachineImage { // set the SSM parameter name this.amiParameterName = `/aws/service/eks/optimized-ami/${this.kubernetesVersion}/` - + ( this.nodeType === NodeType.STANDARD ? this.cpuArch === CpuArch.X86_64 ? - 'amazon-linux-2/' : 'amazon-linux-2-arm64/' :'' ) - + ( this.nodeType === NodeType.GPU ? 'amazon-linux-2-gpu/' : '' ) + + (this.nodeType === NodeType.STANDARD ? this.cpuArch === CpuArch.X86_64 ? + 'amazon-linux-2/' : 'amazon-linux-2-arm64/' : '') + + (this.nodeType === NodeType.GPU ? 'amazon-linux-2-gpu/' : '') + (this.nodeType === NodeType.INFERENTIA ? 'amazon-linux-2-gpu/' : '') + 'recommended/image_id'; } diff --git a/packages/@aws-cdk/aws-eks/lib/managed-nodegroup.ts b/packages/@aws-cdk/aws-eks/lib/managed-nodegroup.ts index 7d46fb00c6e92..859a94d9aee67 100644 --- a/packages/@aws-cdk/aws-eks/lib/managed-nodegroup.ts +++ b/packages/@aws-cdk/aws-eks/lib/managed-nodegroup.ts @@ -280,6 +280,12 @@ export class Nodegroup extends Resource implements INodegroup { throw new Error(`Minimum capacity ${this.minSize} can't be greater than desired size ${this.desiredSize}`); } + if (props.launchTemplateSpec && props.diskSize) { + // see - https://docs.aws.amazon.com/eks/latest/userguide/launch-templates.html + // and https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-nodegroup.html#cfn-eks-nodegroup-disksize + throw new Error('diskSize must be specified within the launch template'); + } + if (props.instanceType && props.instanceTypes) { throw new Error('"instanceType is deprecated, please use "instanceTypes" only.'); } @@ -331,6 +337,7 @@ export class Nodegroup extends Resource implements INodegroup { // because this doesn't have a default value, meaning the user had to explicitly configure this. instanceTypes: instanceTypes?.map(t => t.toString()), labels: props.labels, + launchTemplate: props.launchTemplateSpec, releaseVersion: props.releaseVersion, remoteAccess: props.remoteAccess ? { ec2SshKey: props.remoteAccess.sshKeyName, @@ -345,25 +352,6 @@ export class Nodegroup extends Resource implements INodegroup { tags: props.tags, }); - if (props.launchTemplateSpec) { - if (props.diskSize) { - // see - https://docs.aws.amazon.com/eks/latest/userguide/launch-templates.html - // and https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-nodegroup.html#cfn-eks-nodegroup-disksize - throw new Error('diskSize must be specified within the launch template'); - } - /** - * Instance types can be specified either in `instanceType` or launch template but not both. AS we can not check the content of - * the provided launch template and the `instanceType` property is preferrable. We allow users to define `instanceType` property here. - * see - https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-nodegroup.html#cfn-eks-nodegroup-instancetypes - */ - // TODO: update this when the L1 resource spec is updated. - resource.addPropertyOverride('LaunchTemplate', { - Id: props.launchTemplateSpec.id, - Version: props.launchTemplateSpec.version, - }); - } - - // managed nodegroups update the `aws-auth` on creation, but we still need to track // its state for consistency. if (this.cluster instanceof Cluster) { diff --git a/packages/@aws-cdk/aws-eks/lib/user-data.ts b/packages/@aws-cdk/aws-eks/lib/user-data.ts index 3b8d997535771..8add0f7cb5bbc 100644 --- a/packages/@aws-cdk/aws-eks/lib/user-data.ts +++ b/packages/@aws-cdk/aws-eks/lib/user-data.ts @@ -1,9 +1,9 @@ import * as autoscaling from '@aws-cdk/aws-autoscaling'; import { Stack } from '@aws-cdk/core'; -import { BootstrapOptions, ICluster } from './cluster'; +import { BootstrapOptions, ICluster, Cluster } from './cluster'; // eslint-disable-next-line max-len -export function renderAmazonLinuxUserData(clusterName: string, autoScalingGroup: autoscaling.AutoScalingGroup, options: BootstrapOptions = {}): string[] { +export function renderAmazonLinuxUserData(cluster: Cluster, autoScalingGroup: autoscaling.AutoScalingGroup, options: BootstrapOptions = {}): string[] { const stack = Stack.of(autoScalingGroup); @@ -13,6 +13,9 @@ export function renderAmazonLinuxUserData(clusterName: string, autoScalingGroup: const extraArgs = new Array(); + extraArgs.push(`--apiserver-endpoint '${cluster.clusterEndpoint}'`); + extraArgs.push(`--b64-cluster-ca '${cluster.clusterCertificateAuthorityData}'`); + extraArgs.push(`--use-max-pods ${options.useMaxPods ?? true}`); if (options.awsApiRetryAttempts) { @@ -27,6 +30,10 @@ export function renderAmazonLinuxUserData(clusterName: string, autoScalingGroup: extraArgs.push(`--docker-config-json '${options.dockerConfigJson}'`); } + if (options.dnsClusterIp) { + extraArgs.push(`--dns-cluster-ip ${options.dnsClusterIp}`); + } + if (options.additionalArgs) { extraArgs.push(options.additionalArgs); } @@ -41,7 +48,7 @@ export function renderAmazonLinuxUserData(clusterName: string, autoScalingGroup: return [ 'set -o xtrace', - `/etc/eks/bootstrap.sh ${clusterName} --kubelet-extra-args "${kubeletExtraArgs}" ${commandLineSuffix}`.trim(), + `/etc/eks/bootstrap.sh ${cluster.clusterName} --kubelet-extra-args "${kubeletExtraArgs}" ${commandLineSuffix}`.trim(), `/opt/aws/bin/cfn-signal --exit-code $? --stack ${stack.stackName} --resource ${asgLogicalId} --region ${stack.region}`, ]; } diff --git a/packages/@aws-cdk/aws-eks/package.json b/packages/@aws-cdk/aws-eks/package.json index 7e4f0e2ddf090..c91c1630858c4 100644 --- a/packages/@aws-cdk/aws-eks/package.json +++ b/packages/@aws-cdk/aws-eks/package.json @@ -70,7 +70,8 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/aws-lambda": "^8.10.76", + "@types/sinon": "^9.0.11", "@types/nodeunit": "^0.0.31", "@types/yaml": "1.9.6", "aws-sdk": "^2.848.0", @@ -81,7 +82,8 @@ "pkglint": "0.0.0", "sinon": "^9.2.4", "cdk8s-plus": "^0.33.0", - "cdk8s": "^0.33.0" + "cdk8s": "^0.33.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-autoscaling": "0.0.0", @@ -94,7 +96,7 @@ "@aws-cdk/custom-resources": "0.0.0", "@aws-cdk/lambda-layer-awscli": "0.0.0", "@aws-cdk/lambda-layer-kubectl": "0.0.0", - "constructs": "^3.2.0", + "constructs": "^3.3.69", "yaml": "1.10.2" }, "bundledDependencies": [ @@ -110,7 +112,7 @@ "@aws-cdk/aws-ssm": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", - "constructs": "^3.2.0", + "constructs": "^3.3.69", "@aws-cdk/lambda-layer-awscli": "0.0.0", "@aws-cdk/lambda-layer-kubectl": "0.0.0" }, 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 1ea62568197d4..de8e6fe0bf8ae 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 @@ -1682,7 +1682,21 @@ { "Ref": "Cluster9EE0221C" }, - " --kubelet-extra-args \"--node-labels lifecycle=OnDemand\" --use-max-pods true\n/opt/aws/bin/cfn-signal --exit-code $? --stack aws-cdk-eks-cluster-test --resource ClusterNodesASGF172BD19 --region test-region" + " --kubelet-extra-args \"--node-labels lifecycle=OnDemand\" --apiserver-endpoint '", + { + "Fn::GetAtt": [ + "Cluster9EE0221C", + "Endpoint" + ] + }, + "' --b64-cluster-ca '", + { + "Fn::GetAtt": [ + "Cluster9EE0221C", + "CertificateAuthorityData" + ] + }, + "' --use-max-pods true\n/opt/aws/bin/cfn-signal --exit-code $? --stack aws-cdk-eks-cluster-test --resource ClusterNodesASGF172BD19 --region test-region" ] ] } @@ -1993,7 +2007,21 @@ { "Ref": "Cluster9EE0221C" }, - " --kubelet-extra-args \"--node-labels lifecycle=OnDemand\" --use-max-pods true\n/opt/aws/bin/cfn-signal --exit-code $? --stack aws-cdk-eks-cluster-test --resource ClusterNodesArmASG40A593D0 --region test-region" + " --kubelet-extra-args \"--node-labels lifecycle=OnDemand\" --apiserver-endpoint '", + { + "Fn::GetAtt": [ + "Cluster9EE0221C", + "Endpoint" + ] + }, + "' --b64-cluster-ca '", + { + "Fn::GetAtt": [ + "Cluster9EE0221C", + "CertificateAuthorityData" + ] + }, + "' --use-max-pods true\n/opt/aws/bin/cfn-signal --exit-code $? --stack aws-cdk-eks-cluster-test --resource ClusterNodesArmASG40A593D0 --region test-region" ] ] } @@ -2630,7 +2658,21 @@ { "Ref": "Cluster9EE0221C" }, - " --kubelet-extra-args \"--node-labels lifecycle=Ec2Spot --register-with-taints=spotInstance=true:PreferNoSchedule --node-labels foo=bar,goo=far\" --use-max-pods true --aws-api-retry-attempts 5\n/opt/aws/bin/cfn-signal --exit-code $? --stack aws-cdk-eks-cluster-test --resource ClusterspotASG857494B6 --region test-region" + " --kubelet-extra-args \"--node-labels lifecycle=Ec2Spot --register-with-taints=spotInstance=true:PreferNoSchedule --node-labels foo=bar,goo=far\" --apiserver-endpoint '", + { + "Fn::GetAtt": [ + "Cluster9EE0221C", + "Endpoint" + ] + }, + "' --b64-cluster-ca '", + { + "Fn::GetAtt": [ + "Cluster9EE0221C", + "CertificateAuthorityData" + ] + }, + "' --use-max-pods true --aws-api-retry-attempts 5\n/opt/aws/bin/cfn-signal --exit-code $? --stack aws-cdk-eks-cluster-test --resource ClusterspotASG857494B6 --region test-region" ] ] } @@ -2973,7 +3015,21 @@ { "Ref": "Cluster9EE0221C" }, - " --kubelet-extra-args \"--node-labels lifecycle=OnDemand\" --use-max-pods true\n/opt/aws/bin/cfn-signal --exit-code $? --stack aws-cdk-eks-cluster-test --resource ClusterInferenceInstancesASGE90717C7 --region test-region" + " --kubelet-extra-args \"--node-labels lifecycle=OnDemand\" --apiserver-endpoint '", + { + "Fn::GetAtt": [ + "Cluster9EE0221C", + "Endpoint" + ] + }, + "' --b64-cluster-ca '", + { + "Fn::GetAtt": [ + "Cluster9EE0221C", + "CertificateAuthorityData" + ] + }, + "' --use-max-pods true\n/opt/aws/bin/cfn-signal --exit-code $? --stack aws-cdk-eks-cluster-test --resource ClusterInferenceInstancesASGE90717C7 --region test-region" ] ] } @@ -4146,7 +4202,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters952bd1c03e8201c4c1c67d6de0f3fdaaf88fda05f89a1232c3f6364343cd5344S3Bucket055DC235" + "Ref": "AssetParameters6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3S3BucketB7E1A9C0" }, "S3Key": { "Fn::Join": [ @@ -4159,7 +4215,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters952bd1c03e8201c4c1c67d6de0f3fdaaf88fda05f89a1232c3f6364343cd5344S3VersionKey2FFFA299" + "Ref": "AssetParameters6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3S3VersionKey542FDEBD" } ] } @@ -4172,7 +4228,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters952bd1c03e8201c4c1c67d6de0f3fdaaf88fda05f89a1232c3f6364343cd5344S3VersionKey2FFFA299" + "Ref": "AssetParameters6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3S3VersionKey542FDEBD" } ] } @@ -4674,17 +4730,17 @@ "Type": "String", "Description": "Artifact hash for asset \"b7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4\"" }, - "AssetParameters952bd1c03e8201c4c1c67d6de0f3fdaaf88fda05f89a1232c3f6364343cd5344S3Bucket055DC235": { + "AssetParameters6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3S3BucketB7E1A9C0": { "Type": "String", - "Description": "S3 bucket for asset \"952bd1c03e8201c4c1c67d6de0f3fdaaf88fda05f89a1232c3f6364343cd5344\"" + "Description": "S3 bucket for asset \"6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3\"" }, - "AssetParameters952bd1c03e8201c4c1c67d6de0f3fdaaf88fda05f89a1232c3f6364343cd5344S3VersionKey2FFFA299": { + "AssetParameters6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3S3VersionKey542FDEBD": { "Type": "String", - "Description": "S3 key for asset version \"952bd1c03e8201c4c1c67d6de0f3fdaaf88fda05f89a1232c3f6364343cd5344\"" + "Description": "S3 key for asset version \"6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3\"" }, - "AssetParameters952bd1c03e8201c4c1c67d6de0f3fdaaf88fda05f89a1232c3f6364343cd5344ArtifactHash1AB042BC": { + "AssetParameters6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3ArtifactHash5E61FCA5": { "Type": "String", - "Description": "Artifact hash for asset \"952bd1c03e8201c4c1c67d6de0f3fdaaf88fda05f89a1232c3f6364343cd5344\"" + "Description": "Artifact hash for asset \"6afd8be511f58dbedd46c8a09c07db8b7340d99fd3527b6d3dfb729208060fc3\"" }, "AssetParameters5f49893093e1ad14831626016699156d48da5f0890f19eb930bc3c46cf5f636dS3BucketA6642550": { "Type": "String", diff --git a/packages/@aws-cdk/aws-eks/test/test.awsauth.ts b/packages/@aws-cdk/aws-eks/test/test.awsauth.ts index 64c83bce12f2e..2b9aad6bf4c5c 100644 --- a/packages/@aws-cdk/aws-eks/test/test.awsauth.ts +++ b/packages/@aws-cdk/aws-eks/test/test.awsauth.ts @@ -1,4 +1,4 @@ -import { countResources, expect, haveResource } from '@aws-cdk/assert'; +import { countResources, expect, haveResource } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk/aws-eks/test/test.cluster.ts b/packages/@aws-cdk/aws-eks/test/test.cluster.ts index 46554d34dceb0..3a1866d6f460b 100644 --- a/packages/@aws-cdk/aws-eks/test/test.cluster.ts +++ b/packages/@aws-cdk/aws-eks/test/test.cluster.ts @@ -1,6 +1,6 @@ import * as fs from 'fs'; import * as path from 'path'; -import { countResources, expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; +import { countResources, expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; import * as asg from '@aws-cdk/aws-autoscaling'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; @@ -1294,7 +1294,7 @@ export = { // THEN const template = app.synth().getStackByName(stack.stackName).template; const userData = template.Resources.ClusterMyCapcityLaunchConfig58583345.Properties.UserData; - test.deepEqual(userData, { 'Fn::Base64': { 'Fn::Join': ['', ['#!/bin/bash\nset -o xtrace\n/etc/eks/bootstrap.sh ', { Ref: 'Cluster9EE0221C' }, ' --kubelet-extra-args "--node-labels lifecycle=OnDemand" --use-max-pods true\n/opt/aws/bin/cfn-signal --exit-code $? --stack Stack --resource ClusterMyCapcityASGD4CD8B97 --region us-east-1']] } }); + test.deepEqual(userData, { 'Fn::Base64': { 'Fn::Join': ['', ['#!/bin/bash\nset -o xtrace\n/etc/eks/bootstrap.sh ', { Ref: 'Cluster9EE0221C' }, ' --kubelet-extra-args "--node-labels lifecycle=OnDemand" --apiserver-endpoint \'', { 'Fn::GetAtt': ['Cluster9EE0221C', 'Endpoint'] }, '\' --b64-cluster-ca \'', { 'Fn::GetAtt': ['Cluster9EE0221C', 'CertificateAuthorityData'] }, '\' --use-max-pods true\n/opt/aws/bin/cfn-signal --exit-code $? --stack Stack --resource ClusterMyCapcityASGD4CD8B97 --region us-east-1']] } }); test.done(); }, @@ -1333,7 +1333,7 @@ export = { // THEN const template = app.synth().getStackByName(stack.stackName).template; const userData = template.Resources.ClusterMyCapcityLaunchConfig58583345.Properties.UserData; - test.deepEqual(userData, { 'Fn::Base64': { 'Fn::Join': ['', ['#!/bin/bash\nset -o xtrace\n/etc/eks/bootstrap.sh ', { Ref: 'Cluster9EE0221C' }, ' --kubelet-extra-args "--node-labels lifecycle=OnDemand --node-labels FOO=42" --use-max-pods true\n/opt/aws/bin/cfn-signal --exit-code $? --stack Stack --resource ClusterMyCapcityASGD4CD8B97 --region us-east-1']] } }); + test.deepEqual(userData, { 'Fn::Base64': { 'Fn::Join': ['', ['#!/bin/bash\nset -o xtrace\n/etc/eks/bootstrap.sh ', { Ref: 'Cluster9EE0221C' }, ' --kubelet-extra-args "--node-labels lifecycle=OnDemand --node-labels FOO=42" --apiserver-endpoint \'', { 'Fn::GetAtt': ['Cluster9EE0221C', 'Endpoint'] }, '\' --b64-cluster-ca \'', { 'Fn::GetAtt': ['Cluster9EE0221C', 'CertificateAuthorityData'] }, '\' --use-max-pods true\n/opt/aws/bin/cfn-signal --exit-code $? --stack Stack --resource ClusterMyCapcityASGD4CD8B97 --region us-east-1']] } }); test.done(); }, @@ -1353,7 +1353,7 @@ export = { // THEN const template = app.synth().getStackByName(stack.stackName).template; const userData = template.Resources.ClusterMyCapcityLaunchConfig58583345.Properties.UserData; - test.deepEqual(userData, { 'Fn::Base64': { 'Fn::Join': ['', ['#!/bin/bash\nset -o xtrace\n/etc/eks/bootstrap.sh ', { Ref: 'Cluster9EE0221C' }, ' --kubelet-extra-args "--node-labels lifecycle=Ec2Spot --register-with-taints=spotInstance=true:PreferNoSchedule" --use-max-pods true\n/opt/aws/bin/cfn-signal --exit-code $? --stack Stack --resource ClusterMyCapcityASGD4CD8B97 --region us-east-1']] } }); + test.deepEqual(userData, { 'Fn::Base64': { 'Fn::Join': ['', ['#!/bin/bash\nset -o xtrace\n/etc/eks/bootstrap.sh ', { Ref: 'Cluster9EE0221C' }, ' --kubelet-extra-args "--node-labels lifecycle=Ec2Spot --register-with-taints=spotInstance=true:PreferNoSchedule" --apiserver-endpoint \'', { 'Fn::GetAtt': ['Cluster9EE0221C', 'Endpoint'] }, '\' --b64-cluster-ca \'', { 'Fn::GetAtt': ['Cluster9EE0221C', 'CertificateAuthorityData'] }, '\' --use-max-pods true\n/opt/aws/bin/cfn-signal --exit-code $? --stack Stack --resource ClusterMyCapcityASGD4CD8B97 --region us-east-1']] } }); test.done(); }, diff --git a/packages/@aws-cdk/aws-eks/test/test.fargate.ts b/packages/@aws-cdk/aws-eks/test/test.fargate.ts index ee17950915e9d..5dabba46d0157 100644 --- a/packages/@aws-cdk/aws-eks/test/test.fargate.ts +++ b/packages/@aws-cdk/aws-eks/test/test.fargate.ts @@ -1,10 +1,12 @@ -import { expect, haveResource, haveResourceLike, ResourcePart } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike, ResourcePart } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; +import * as kms from '@aws-cdk/aws-kms'; import { Stack, Tags } from '@aws-cdk/core'; import { Test } from 'nodeunit'; import * as eks from '../lib'; + const CLUSTER_VERSION = eks.KubernetesVersion.V1_19; export = { @@ -427,4 +429,34 @@ export = { })); test.done(); }, + + 'supports passing secretsEncryptionKey with FargateCluster'(test: Test) { + // GIVEN + const stack = new Stack(); + + // WHEN + + new eks.FargateCluster(stack, 'FargateCluster', { + version: CLUSTER_VERSION, + secretsEncryptionKey: new kms.Key(stack, 'Key'), + }); + + // THEN + expect(stack).to(haveResourceLike('Custom::AWSCDK-EKS-Cluster', { + Config: { + encryptionConfig: [{ + provider: { + keyArn: { + 'Fn::GetAtt': [ + 'Key961B73FD', + 'Arn', + ], + }, + }, + resources: ['secrets'], + }], + }, + })); + test.done(); + }, }; diff --git a/packages/@aws-cdk/aws-eks/test/test.helm-chart.ts b/packages/@aws-cdk/aws-eks/test/test.helm-chart.ts index 5dcb9611282e7..cd64e8dd5f1bc 100644 --- a/packages/@aws-cdk/aws-eks/test/test.helm-chart.ts +++ b/packages/@aws-cdk/aws-eks/test/test.helm-chart.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import { Duration } from '@aws-cdk/core'; import { Test } from 'nodeunit'; import * as eks from '../lib'; diff --git a/packages/@aws-cdk/aws-eks/test/test.k8s-manifest.ts b/packages/@aws-cdk/aws-eks/test/test.k8s-manifest.ts index 8cad065c454f6..401afba503548 100644 --- a/packages/@aws-cdk/aws-eks/test/test.k8s-manifest.ts +++ b/packages/@aws-cdk/aws-eks/test/test.k8s-manifest.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, SynthUtils } from '@aws-cdk/assert'; +import { expect, haveResource, SynthUtils } from '@aws-cdk/assert-internal'; import { Stack } from '@aws-cdk/core'; import { Test } from 'nodeunit'; import { Cluster, KubernetesManifest, KubernetesVersion, HelmChart } from '../lib'; diff --git a/packages/@aws-cdk/aws-eks/test/test.k8s-object-value.ts b/packages/@aws-cdk/aws-eks/test/test.k8s-object-value.ts index 62add406b682c..19743f07ff478 100644 --- a/packages/@aws-cdk/aws-eks/test/test.k8s-object-value.ts +++ b/packages/@aws-cdk/aws-eks/test/test.k8s-object-value.ts @@ -1,4 +1,4 @@ -import { expect } from '@aws-cdk/assert'; +import { expect } from '@aws-cdk/assert-internal'; import { Stack, Duration } from '@aws-cdk/core'; import { Test } from 'nodeunit'; import * as eks from '../lib'; diff --git a/packages/@aws-cdk/aws-eks/test/test.k8s-patch.ts b/packages/@aws-cdk/aws-eks/test/test.k8s-patch.ts index 24dabbbf0c1a2..9fa9ae5a2f9a8 100644 --- a/packages/@aws-cdk/aws-eks/test/test.k8s-patch.ts +++ b/packages/@aws-cdk/aws-eks/test/test.k8s-patch.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import { Names, Stack } from '@aws-cdk/core'; import { Test } from 'nodeunit'; import * as eks from '../lib'; diff --git a/packages/@aws-cdk/aws-eks/test/test.nodegroup.ts b/packages/@aws-cdk/aws-eks/test/test.nodegroup.ts index 0599c349f6190..e82586d1cc79a 100644 --- a/packages/@aws-cdk/aws-eks/test/test.nodegroup.ts +++ b/packages/@aws-cdk/aws-eks/test/test.nodegroup.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk/aws-eks/test/test.service-account.ts b/packages/@aws-cdk/aws-eks/test/test.service-account.ts index cf83a8527cdf2..c3accc6a58d20 100644 --- a/packages/@aws-cdk/aws-eks/test/test.service-account.ts +++ b/packages/@aws-cdk/aws-eks/test/test.service-account.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import { Test } from 'nodeunit'; import * as eks from '../lib'; diff --git a/packages/@aws-cdk/aws-eks/test/test.user-data.ts b/packages/@aws-cdk/aws-eks/test/test.user-data.ts index 044d1ff55f7ca..ce582a374a3fc 100644 --- a/packages/@aws-cdk/aws-eks/test/test.user-data.ts +++ b/packages/@aws-cdk/aws-eks/test/test.user-data.ts @@ -2,6 +2,7 @@ import * as autoscaling from '@aws-cdk/aws-autoscaling'; import * as ec2 from '@aws-cdk/aws-ec2'; import { App, Stack } from '@aws-cdk/core'; import { Test } from 'nodeunit'; +import { Cluster, KubernetesVersion } from '../lib/cluster'; import { renderAmazonLinuxUserData } from '../lib/user-data'; /* eslint-disable max-len */ @@ -9,15 +10,30 @@ import { renderAmazonLinuxUserData } from '../lib/user-data'; export = { 'default user data'(test: Test) { // GIVEN - const { asg, stack } = newFixtures(); + const { asg, stack, cluster } = newFixtures(); // WHEN - const userData = stack.resolve(renderAmazonLinuxUserData('my-cluster-name', asg)); + const userData = stack.resolve(renderAmazonLinuxUserData(cluster, asg)); // THEN test.deepEqual(userData, [ 'set -o xtrace', - '/etc/eks/bootstrap.sh my-cluster-name --kubelet-extra-args "--node-labels lifecycle=OnDemand" --use-max-pods true', + { + 'Fn::Join': [ + '', + [ + '/etc/eks/bootstrap.sh ', + { Ref: 'clusterC5B25D0D' }, + ' --kubelet-extra-args "--node-labels lifecycle=OnDemand" --apiserver-endpoint \'', + { 'Fn::GetAtt': ['clusterC5B25D0D', 'Endpoint'] }, + "' --b64-cluster-ca '", + { + 'Fn::GetAtt': ['clusterC5B25D0D', 'CertificateAuthorityData'], + }, + "' --use-max-pods true", + ], + ], + }, '/opt/aws/bin/cfn-signal --exit-code $? --stack my-stack --resource ASG46ED3070 --region us-west-33', ]); @@ -26,127 +42,322 @@ export = { '--use-max-pods=true'(test: Test) { // GIVEN - const { asg, stack } = newFixtures(); + const { asg, stack, cluster } = newFixtures(); // WHEN - const userData = stack.resolve(renderAmazonLinuxUserData('my-cluster-name', asg, { + const userData = stack.resolve(renderAmazonLinuxUserData(cluster, asg, { useMaxPods: true, })); // THEN - test.deepEqual(userData[1], '/etc/eks/bootstrap.sh my-cluster-name --kubelet-extra-args "--node-labels lifecycle=OnDemand" --use-max-pods true'); + test.deepEqual( + userData[1], + { + 'Fn::Join': [ + '', + [ + '/etc/eks/bootstrap.sh ', + { Ref: 'clusterC5B25D0D' }, + ' --kubelet-extra-args "--node-labels lifecycle=OnDemand" --apiserver-endpoint \'', + { 'Fn::GetAtt': ['clusterC5B25D0D', 'Endpoint'] }, + "' --b64-cluster-ca '", + { + 'Fn::GetAtt': ['clusterC5B25D0D', 'CertificateAuthorityData'], + }, + "' --use-max-pods true", + ], + ], + }, + ); test.done(); }, '--use-max-pods=false'(test: Test) { // GIVEN - const { asg, stack } = newFixtures(); + const { asg, stack, cluster } = newFixtures(); // WHEN - const userData = stack.resolve(renderAmazonLinuxUserData('my-cluster-name', asg, { + const userData = stack.resolve(renderAmazonLinuxUserData(cluster, asg, { useMaxPods: false, })); // THEN - test.deepEqual(userData[1], '/etc/eks/bootstrap.sh my-cluster-name --kubelet-extra-args "--node-labels lifecycle=OnDemand" --use-max-pods false'); + test.deepEqual( + userData[1], + { + 'Fn::Join': [ + '', + [ + '/etc/eks/bootstrap.sh ', + { Ref: 'clusterC5B25D0D' }, + ' --kubelet-extra-args "--node-labels lifecycle=OnDemand" --apiserver-endpoint \'', + { 'Fn::GetAtt': ['clusterC5B25D0D', 'Endpoint'] }, + "' --b64-cluster-ca '", + { + 'Fn::GetAtt': ['clusterC5B25D0D', 'CertificateAuthorityData'], + }, + "' --use-max-pods false", + ], + ], + }, + ); test.done(); }, '--aws-api-retry-attempts'(test: Test) { // GIVEN - const { asg, stack } = newFixtures(); + const { asg, stack, cluster } = newFixtures(); // WHEN - const userData = stack.resolve(renderAmazonLinuxUserData('my-cluster-name', asg, { + const userData = stack.resolve(renderAmazonLinuxUserData(cluster, asg, { awsApiRetryAttempts: 123, })); // THEN - test.deepEqual(userData[1], '/etc/eks/bootstrap.sh my-cluster-name --kubelet-extra-args "--node-labels lifecycle=OnDemand" --use-max-pods true --aws-api-retry-attempts 123'); + test.deepEqual( + userData[1], + { + 'Fn::Join': [ + '', + [ + '/etc/eks/bootstrap.sh ', + { Ref: 'clusterC5B25D0D' }, + ' --kubelet-extra-args "--node-labels lifecycle=OnDemand" --apiserver-endpoint \'', + { 'Fn::GetAtt': ['clusterC5B25D0D', 'Endpoint'] }, + "' --b64-cluster-ca '", + { + 'Fn::GetAtt': ['clusterC5B25D0D', 'CertificateAuthorityData'], + }, + "' --use-max-pods true --aws-api-retry-attempts 123", + ], + ], + }, + ); + test.done(); + }, + + '--dns-cluster-ip'(test: Test) { + // GIVEN + const { asg, stack, cluster } = newFixtures(); + + // WHEN + const userData = stack.resolve(renderAmazonLinuxUserData(cluster, asg, { + dnsClusterIp: '192.0.2.53', + })); + + // THEN + test.deepEqual( + userData[1], + { + 'Fn::Join': [ + '', + [ + '/etc/eks/bootstrap.sh ', + { Ref: 'clusterC5B25D0D' }, + ' --kubelet-extra-args "--node-labels lifecycle=OnDemand" --apiserver-endpoint \'', + { 'Fn::GetAtt': ['clusterC5B25D0D', 'Endpoint'] }, + "' --b64-cluster-ca '", + { + 'Fn::GetAtt': ['clusterC5B25D0D', 'CertificateAuthorityData'], + }, + "' --use-max-pods true --dns-cluster-ip 192.0.2.53", + ], + ], + }, + ); test.done(); }, '--docker-config-json'(test: Test) { // GIVEN - const { asg } = newFixtures(); + const { asg, stack, cluster } = newFixtures(); // WHEN - const userData = renderAmazonLinuxUserData('my-cluster-name', asg, { + const userData = stack.resolve(renderAmazonLinuxUserData(cluster, asg, { dockerConfigJson: '{"docker":123}', - }); + })); // THEN - test.deepEqual(userData[1], '/etc/eks/bootstrap.sh my-cluster-name --kubelet-extra-args "--node-labels lifecycle=OnDemand" --use-max-pods true --docker-config-json \'{"docker":123}\''); + test.deepEqual( + userData[1], + { + 'Fn::Join': [ + '', + [ + '/etc/eks/bootstrap.sh ', + { Ref: 'clusterC5B25D0D' }, + ' --kubelet-extra-args "--node-labels lifecycle=OnDemand" --apiserver-endpoint \'', + { 'Fn::GetAtt': ['clusterC5B25D0D', 'Endpoint'] }, + "' --b64-cluster-ca '", + { + 'Fn::GetAtt': ['clusterC5B25D0D', 'CertificateAuthorityData'], + }, + '\' --use-max-pods true --docker-config-json \'{"docker":123}\'', + ], + ], + }, + ); test.done(); }, '--enable-docker-bridge=true'(test: Test) { // GIVEN - const { asg, stack } = newFixtures(); + const { asg, stack, cluster } = newFixtures(); // WHEN - const userData = stack.resolve(renderAmazonLinuxUserData('my-cluster-name', asg, { + const userData = stack.resolve(renderAmazonLinuxUserData(cluster, asg, { enableDockerBridge: true, })); // THEN - test.deepEqual(userData[1], '/etc/eks/bootstrap.sh my-cluster-name --kubelet-extra-args "--node-labels lifecycle=OnDemand" --use-max-pods true --enable-docker-bridge true'); + test.deepEqual( + userData[1], + { + 'Fn::Join': [ + '', + [ + '/etc/eks/bootstrap.sh ', + { Ref: 'clusterC5B25D0D' }, + ' --kubelet-extra-args "--node-labels lifecycle=OnDemand" --apiserver-endpoint \'', + { 'Fn::GetAtt': ['clusterC5B25D0D', 'Endpoint'] }, + "' --b64-cluster-ca '", + { + 'Fn::GetAtt': ['clusterC5B25D0D', 'CertificateAuthorityData'], + }, + "' --use-max-pods true --enable-docker-bridge true", + ], + ], + }, + ); test.done(); }, '--enable-docker-bridge=false'(test: Test) { // GIVEN - const { asg, stack } = newFixtures(); + const { asg, stack, cluster } = newFixtures(); // WHEN - const userData = stack.resolve(renderAmazonLinuxUserData('my-cluster-name', asg, { + const userData = stack.resolve(renderAmazonLinuxUserData(cluster, asg, { enableDockerBridge: false, })); // THEN - test.deepEqual(userData[1], '/etc/eks/bootstrap.sh my-cluster-name --kubelet-extra-args "--node-labels lifecycle=OnDemand" --use-max-pods true'); + test.deepEqual( + userData[1], + { + 'Fn::Join': [ + '', + [ + '/etc/eks/bootstrap.sh ', + { Ref: 'clusterC5B25D0D' }, + ' --kubelet-extra-args "--node-labels lifecycle=OnDemand" --apiserver-endpoint \'', + { 'Fn::GetAtt': ['clusterC5B25D0D', 'Endpoint'] }, + "' --b64-cluster-ca '", + { + 'Fn::GetAtt': ['clusterC5B25D0D', 'CertificateAuthorityData'], + }, + "' --use-max-pods true", + ], + ], + }, + ); test.done(); }, '--kubelet-extra-args'(test: Test) { // GIVEN - const { asg, stack } = newFixtures(); + const { asg, stack, cluster } = newFixtures(); // WHEN - const userData = stack.resolve(renderAmazonLinuxUserData('my-cluster-name', asg, { + const userData = stack.resolve(renderAmazonLinuxUserData(cluster, asg, { kubeletExtraArgs: '--extra-args-for --kubelet', })); // THEN - test.deepEqual(userData[1], '/etc/eks/bootstrap.sh my-cluster-name --kubelet-extra-args "--node-labels lifecycle=OnDemand --extra-args-for --kubelet" --use-max-pods true'); + test.deepEqual( + userData[1], + { + 'Fn::Join': [ + '', + [ + '/etc/eks/bootstrap.sh ', + { Ref: 'clusterC5B25D0D' }, + ' --kubelet-extra-args "--node-labels lifecycle=OnDemand --extra-args-for --kubelet" --apiserver-endpoint \'', + { 'Fn::GetAtt': ['clusterC5B25D0D', 'Endpoint'] }, + "' --b64-cluster-ca '", + { + 'Fn::GetAtt': ['clusterC5B25D0D', 'CertificateAuthorityData'], + }, + "' --use-max-pods true", + ], + ], + }, + ); test.done(); }, 'arbitrary additional bootstrap arguments can be passed through "additionalArgs"'(test: Test) { // GIVEN - const { asg, stack } = newFixtures(); + const { asg, stack, cluster } = newFixtures(); // WHEN - const userData = stack.resolve(renderAmazonLinuxUserData('my-cluster-name', asg, { + const userData = stack.resolve(renderAmazonLinuxUserData(cluster, asg, { additionalArgs: '--apiserver-endpoint 1111 --foo-bar', })); // THEN - test.deepEqual(userData[1], '/etc/eks/bootstrap.sh my-cluster-name --kubelet-extra-args "--node-labels lifecycle=OnDemand" --use-max-pods true --apiserver-endpoint 1111 --foo-bar'); + // NB: duplicated --apiserver-endpoint is fine. Last wins. + test.deepEqual( + userData[1], + { + 'Fn::Join': [ + '', + [ + '/etc/eks/bootstrap.sh ', + { Ref: 'clusterC5B25D0D' }, + ' --kubelet-extra-args "--node-labels lifecycle=OnDemand" --apiserver-endpoint \'', + { 'Fn::GetAtt': ['clusterC5B25D0D', 'Endpoint'] }, + "' --b64-cluster-ca '", + { + 'Fn::GetAtt': ['clusterC5B25D0D', 'CertificateAuthorityData'], + }, + "' --use-max-pods true --apiserver-endpoint 1111 --foo-bar", + ], + ], + }, + ); test.done(); }, 'if asg has spot instances, the correct label and taint is used'(test: Test) { // GIVEN - const { asg, stack } = newFixtures(true); + const { asg, stack, cluster } = newFixtures(true); // WHEN - const userData = stack.resolve(renderAmazonLinuxUserData('my-cluster-name', asg, { + const userData = stack.resolve(renderAmazonLinuxUserData(cluster, asg, { kubeletExtraArgs: '--node-labels X=y', })); // THEN - test.deepEqual(userData[1], '/etc/eks/bootstrap.sh my-cluster-name --kubelet-extra-args "--node-labels lifecycle=Ec2Spot --register-with-taints=spotInstance=true:PreferNoSchedule --node-labels X=y" --use-max-pods true'); + test.deepEqual( + userData[1], + { + 'Fn::Join': [ + '', + [ + '/etc/eks/bootstrap.sh ', + { Ref: 'clusterC5B25D0D' }, + ' --kubelet-extra-args "--node-labels lifecycle=Ec2Spot --register-with-taints=spotInstance=true:PreferNoSchedule --node-labels X=y" --apiserver-endpoint \'', + { 'Fn::GetAtt': ['clusterC5B25D0D', 'Endpoint'] }, + "' --b64-cluster-ca '", + { + 'Fn::GetAtt': ['clusterC5B25D0D', 'CertificateAuthorityData'], + }, + "' --use-max-pods true", + ], + ], + }, + ); test.done(); }, }; @@ -155,6 +366,11 @@ function newFixtures(spot = false) { const app = new App(); const stack = new Stack(app, 'my-stack', { env: { region: 'us-west-33' } }); const vpc = new ec2.Vpc(stack, 'vpc'); + const cluster = new Cluster(stack, 'cluster', { + version: KubernetesVersion.V1_19, + clusterName: 'my-cluster-name', + vpc, + }); const asg = new autoscaling.AutoScalingGroup(stack, 'ASG', { instanceType: new ec2.InstanceType('m4.xlarge'), machineImage: new ec2.AmazonLinuxImage(), @@ -162,5 +378,5 @@ function newFixtures(spot = false) { vpc, }); - return { stack, vpc, asg }; + return { stack, vpc, cluster, asg }; } diff --git a/packages/@aws-cdk/aws-elasticache/package.json b/packages/@aws-cdk/aws-elasticache/package.json index f0b728276adda..a21ff8758d2a3 100644 --- a/packages/@aws-cdk/aws-elasticache/package.json +++ b/packages/@aws-cdk/aws-elasticache/package.json @@ -71,19 +71,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-elasticache/test/elasticache.test.ts b/packages/@aws-cdk/aws-elasticache/test/elasticache.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-elasticache/test/elasticache.test.ts +++ b/packages/@aws-cdk/aws-elasticache/test/elasticache.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-elasticbeanstalk/package.json b/packages/@aws-cdk/aws-elasticbeanstalk/package.json index 31472f9e21d51..186248ef4f9a2 100644 --- a/packages/@aws-cdk/aws-elasticbeanstalk/package.json +++ b/packages/@aws-cdk/aws-elasticbeanstalk/package.json @@ -71,19 +71,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-elasticbeanstalk/test/elasticbeanstalk.test.ts b/packages/@aws-cdk/aws-elasticbeanstalk/test/elasticbeanstalk.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-elasticbeanstalk/test/elasticbeanstalk.test.ts +++ b/packages/@aws-cdk/aws-elasticbeanstalk/test/elasticbeanstalk.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/lib/load-balancer.ts b/packages/@aws-cdk/aws-elasticloadbalancing/lib/load-balancer.ts index eaed2daee58d2..d60d91e0a9a51 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/lib/load-balancer.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancing/lib/load-balancer.ts @@ -187,10 +187,18 @@ export interface LoadBalancerListener { readonly policyNames?: string[]; /** - * ID of SSL certificate + * the ARN of the SSL certificate + * @deprecated - use sslCertificateArn instead */ readonly sslCertificateId?: string; + /** + * the ARN of the SSL certificate + * + * @default - none + */ + readonly sslCertificateArn?: string; + /** * Allow connections to the load balancer from the given set of connection peers * @@ -264,8 +272,12 @@ export class LoadBalancer extends Resource implements IConnectable { * @returns A ListenerPort object that controls connections to the listener port */ public addListener(listener: LoadBalancerListener): ListenerPort { + if (listener.sslCertificateArn && listener.sslCertificateId) { + throw new Error('"sslCertificateId" is deprecated, please use "sslCertificateArn" only.'); + } const protocol = ifUndefinedLazy(listener.externalProtocol, () => wellKnownProtocol(listener.externalPort)); const instancePort = listener.internalPort || listener.externalPort; + const sslCertificateArn = listener.sslCertificateArn || listener.sslCertificateId; const instanceProtocol = ifUndefined(listener.internalProtocol, ifUndefined(tryWellKnownProtocol(instancePort), isHttpProtocol(protocol) ? LoadBalancingProtocol.HTTP : LoadBalancingProtocol.TCP)); @@ -275,7 +287,7 @@ export class LoadBalancer extends Resource implements IConnectable { protocol, instancePort: instancePort.toString(), instanceProtocol, - sslCertificateId: listener.sslCertificateId, + sslCertificateId: sslCertificateArn, policyNames: listener.policyNames, }); diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/package.json b/packages/@aws-cdk/aws-elasticloadbalancing/package.json index 24f25fb2470f8..355f293831e16 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancing/package.json @@ -71,22 +71,23 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/test/loadbalancer.test.ts b/packages/@aws-cdk/aws-elasticloadbalancing/test/loadbalancer.test.ts index bdddbbc512df9..9cac87e057e87 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/test/loadbalancer.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancing/test/loadbalancer.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; import { Connections, Peer, SubnetType, Vpc } from '@aws-cdk/aws-ec2'; import { Duration, Stack } from '@aws-cdk/core'; import { ILoadBalancerTarget, LoadBalancer, LoadBalancingProtocol } from '../lib'; @@ -18,14 +18,14 @@ describe('tests', () => { internalPort: 8080, }); - expect(stack).to(haveResource('AWS::ElasticLoadBalancing::LoadBalancer', { + expect(stack).toHaveResource('AWS::ElasticLoadBalancing::LoadBalancer', { Listeners: [{ InstancePort: '8080', InstanceProtocol: 'http', LoadBalancerPort: '8080', Protocol: 'http', }], - })); + }); }); test('add a health check', () => { @@ -45,7 +45,7 @@ describe('tests', () => { }); // THEN - expect(stack).to(haveResource('AWS::ElasticLoadBalancing::LoadBalancer', { + expect(stack).toHaveResource('AWS::ElasticLoadBalancing::LoadBalancer', { HealthCheck: { HealthyThreshold: '2', Interval: '60', @@ -53,7 +53,7 @@ describe('tests', () => { Timeout: '5', UnhealthyThreshold: '5', }, - })); + }); }); test('add a listener and load balancing target', () => { @@ -75,7 +75,7 @@ describe('tests', () => { elb.addTarget(new FakeTarget()); // THEN: at the very least it added a security group rule for the backend - expect(stack).to(haveResource('AWS::EC2::SecurityGroup', { + expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { SecurityGroupEgress: [ { Description: 'Port 8080 LB to fleet', @@ -85,7 +85,7 @@ describe('tests', () => { ToPort: 8080, }, ], - })); + }); }); test('enable cross zone load balancing', () => { @@ -100,9 +100,9 @@ describe('tests', () => { }); // THEN - expect(stack).to(haveResource('AWS::ElasticLoadBalancing::LoadBalancer', { + expect(stack).toHaveResource('AWS::ElasticLoadBalancing::LoadBalancer', { CrossZone: true, - })); + }); }); test('disable cross zone load balancing', () => { @@ -117,9 +117,9 @@ describe('tests', () => { }); // THEN - expect(stack).to(haveResource('AWS::ElasticLoadBalancing::LoadBalancer', { + expect(stack).toHaveResource('AWS::ElasticLoadBalancing::LoadBalancer', { CrossZone: false, - })); + }); }); test('cross zone load balancing enabled by default', () => { @@ -133,9 +133,9 @@ describe('tests', () => { }); // THEN - expect(stack).to(haveResource('AWS::ElasticLoadBalancing::LoadBalancer', { + expect(stack).toHaveResource('AWS::ElasticLoadBalancing::LoadBalancer', { CrossZone: true, - })); + }); }); test('use specified subnet', () => { @@ -170,11 +170,84 @@ describe('tests', () => { }); // THEN - expect(stack).to(haveResource('AWS::ElasticLoadBalancing::LoadBalancer', { + expect(stack).toHaveResource('AWS::ElasticLoadBalancing::LoadBalancer', { Subnets: vpc.selectSubnets({ subnetGroupName: 'private1', }).subnetIds.map((subnetId: string) => stack.resolve(subnetId)), - })); + }); + }); + + test('does not fail when deprecated property sslCertificateId is used', () => { + // GIVEN + const sslCertificateArn = 'arn:aws:acm:us-east-1:12345:test/12345'; + const stack = new Stack(); + const vpc = new Vpc(stack, 'VCP'); + + // WHEN + const lb = new LoadBalancer(stack, 'LB', { vpc }); + + lb.addListener({ + externalPort: 80, + internalPort: 8080, + sslCertificateId: sslCertificateArn, + }); + + // THEN + expect(stack).toHaveResource('AWS::ElasticLoadBalancing::LoadBalancer', { + Listeners: [{ + InstancePort: '8080', + InstanceProtocol: 'http', + LoadBalancerPort: '80', + Protocol: 'http', + SSLCertificateId: sslCertificateArn, + }], + }); + }); + + test('does not fail when sslCertificateArn is used', () => { + // GIVEN + const sslCertificateArn = 'arn:aws:acm:us-east-1:12345:test/12345'; + const stack = new Stack(); + const vpc = new Vpc(stack, 'VCP'); + + // WHEN + const lb = new LoadBalancer(stack, 'LB', { vpc }); + + lb.addListener({ + externalPort: 80, + internalPort: 8080, + sslCertificateArn: sslCertificateArn, + }); + + // THEN + expect(stack).toHaveResource('AWS::ElasticLoadBalancing::LoadBalancer', { + Listeners: [{ + InstancePort: '8080', + InstanceProtocol: 'http', + LoadBalancerPort: '80', + Protocol: 'http', + SSLCertificateId: sslCertificateArn, + }], + }); + }); + + test('throws error when both sslCertificateId and sslCertificateArn are used', () => { + // GIVEN + const sslCertificateArn = 'arn:aws:acm:us-east-1:12345:test/12345'; + const stack = new Stack(); + const vpc = new Vpc(stack, 'VCP'); + + // WHEN + const lb = new LoadBalancer(stack, 'LB', { vpc }); + + // THEN + expect(() => + lb.addListener({ + externalPort: 80, + internalPort: 8080, + sslCertificateArn: sslCertificateArn, + sslCertificateId: sslCertificateArn, + })).toThrow(/"sslCertificateId" is deprecated, please use "sslCertificateArn" only./); }); }); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json index dc606985d7c17..0ff664c1fa5ae 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json @@ -63,11 +63,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", @@ -75,7 +76,7 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-cognito": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -84,7 +85,7 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-cognito": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/cognito.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/cognito.test.ts index 2f793d28c0baa..dad0adda17691 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/cognito.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/cognito.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as cognito from '@aws-cdk/aws-cognito'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/README.md b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/README.md index 9b3a3745cb679..b94a08b0c478a 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/README.md +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/README.md @@ -3,13 +3,7 @@ --- -![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. +![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge) --- diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json index 51ae07a4caaa7..e9320a50a95c1 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json @@ -63,11 +63,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", @@ -75,7 +76,7 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -84,13 +85,13 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, - "stability": "experimental", - "maturity": "experimental", + "stability": "stable", + "maturity": "stable", "awslint": { "exclude": [ "docs-public-apis:@aws-cdk/aws-elasticloadbalancingv2-targets.InstanceTarget", diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/instance-target.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/instance-target.test.ts index 9742f8d4045fa..874adeffe2c36 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/instance-target.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/instance-target.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import { Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/ip-target.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/ip-target.test.ts index 5f6a21548d5ee..a1ab3b9f2896e 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/ip-target.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/ip-target.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import { Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/lambda-target.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/lambda-target.test.ts index 6011c39dda242..b22584404fd09 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/lambda-target.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/lambda-target.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, ResourcePart } from '@aws-cdk/assert'; +import { expect, haveResource, ResourcePart } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import * as lambda from '@aws-cdk/aws-lambda'; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md b/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md index b04d39e1862d7..76a6b7e1ddd5c 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md @@ -283,6 +283,10 @@ const tg = new elbv2.ApplicationTargetGroup(stack, 'TG', { port: 50051, protocol: elbv2.ApplicationProtocol.HTTP, protocolVersion: elbv2.ApplicationProtocolVersion.GRPC, + healthCheck: { + enabled: true, + healthyGrpcCodes: '0-99', + }, vpc, }); ``` diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts index f0876cd2cc082..8d52d3bc60eb4 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts @@ -5,7 +5,7 @@ import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; import { BaseListener, BaseListenerLookupOptions } from '../shared/base-listener'; import { HealthCheck } from '../shared/base-target-group'; -import { ApplicationProtocol, IpAddressType, SslPolicy } from '../shared/enums'; +import { ApplicationProtocol, ApplicationProtocolVersion, IpAddressType, SslPolicy } from '../shared/enums'; import { IListenerCertificate, ListenerCertificate } from '../shared/listener-certificate'; import { determineProtocolAndPort } from '../shared/util'; import { ListenerAction } from './application-listener-action'; @@ -363,6 +363,7 @@ export class ApplicationListener extends BaseListener implements IApplicationLis healthCheck: props.healthCheck, port: props.port, protocol: props.protocol, + protocolVersion: props.protocolVersion, slowStart: props.slowStart, stickinessCookieDuration: props.stickinessCookieDuration, stickinessCookieName: props.stickinessCookieName, @@ -802,6 +803,13 @@ export interface AddApplicationTargetsProps extends AddRuleProps { */ readonly protocol?: ApplicationProtocol; + /** + * The protocol version to use + * + * @default ApplicationProtocolVersion.HTTP1 + */ + readonly protocolVersion?: ApplicationProtocolVersion; + /** * The port on which the listener listens for requests. * diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts index 4ad4dcb5fa081..d686396d5e9e0 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts @@ -562,7 +562,10 @@ class ImportedApplicationLoadBalancer extends Resource implements IApplicationLo public readonly vpc?: ec2.IVpc; constructor(scope: Construct, id: string, private readonly props: ApplicationLoadBalancerAttributes) { - super(scope, id); + super(scope, id, { + environmentFromArn: props.loadBalancerArn, + }); + this.vpc = props.vpc; this.loadBalancerArn = props.loadBalancerArn; this.connections = new ec2.Connections({ @@ -601,7 +604,9 @@ class LookedUpApplicationLoadBalancer extends Resource implements IApplicationLo public readonly vpc?: ec2.IVpc; constructor(scope: Construct, id: string, props: cxapi.LoadBalancerContextResponse) { - super(scope, id); + super(scope, id, { + environmentFromArn: props.loadBalancerArn, + }); this.loadBalancerArn = props.loadBalancerArn; this.loadBalancerCanonicalHostedZoneId = props.loadBalancerCanonicalHostedZoneId; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-load-balancer.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-load-balancer.ts index d6f7858114102..5261a3ce8a63d 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-load-balancer.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-load-balancer.ts @@ -102,7 +102,7 @@ export class NetworkLoadBalancer extends BaseLoadBalancer implements INetworkLoa } } - return new Import(scope, id); + return new Import(scope, id, { environmentFromArn: attrs.loadBalancerArn }); } constructor(scope: Construct, id: string, props: NetworkLoadBalancerProps) { @@ -306,7 +306,7 @@ class LookedUpNetworkLoadBalancer extends Resource implements INetworkLoadBalanc public readonly vpc?: ec2.IVpc; constructor(scope: Construct, id: string, props: cxapi.LoadBalancerContextResponse) { - super(scope, id); + super(scope, id, { environmentFromArn: props.loadBalancerArn }); this.loadBalancerArn = props.loadBalancerArn; this.loadBalancerCanonicalHostedZoneId = props.loadBalancerCanonicalHostedZoneId; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts index 5e569fd8213ca..175f63ddc4d3d 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts @@ -136,6 +136,16 @@ export interface HealthCheck { */ readonly unhealthyThresholdCount?: number; + /** + * GRPC code to use when checking for a successful response from a target. + * + * You can specify values between 0 and 99. You can specify multiple values + * (for example, "0,1") or a range of values (for example, "0-5"). + * + * @default - 12 + */ + readonly healthyGrpcCodes?: string; + /** * HTTP code to use when checking for a successful response from a target. * @@ -259,7 +269,8 @@ export abstract class TargetGroupBase extends CoreConstruct implements ITargetGr healthyThresholdCount: cdk.Lazy.number({ produce: () => this.healthCheck?.healthyThresholdCount }), unhealthyThresholdCount: cdk.Lazy.number({ produce: () => this.healthCheck?.unhealthyThresholdCount }), matcher: cdk.Lazy.any({ - produce: () => this.healthCheck?.healthyHttpCodes !== undefined ? { + produce: () => this.healthCheck?.healthyHttpCodes !== undefined || this.healthCheck?.healthyGrpcCodes !== undefined ? { + grpcCode: this.healthCheck.healthyGrpcCodes, httpCode: this.healthCheck.healthyHttpCodes, } : undefined, }), diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json index 745b87fb4453f..fcf13262f8068 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json @@ -71,11 +71,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", @@ -88,7 +89,7 @@ "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/region-info": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -101,7 +102,7 @@ "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.2.0", + "constructs": "^3.3.69", "@aws-cdk/region-info": "0.0.0" }, "engines": { diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/actions.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/actions.test.ts index 719abb84dc44e..e69f4d241bc04 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/actions.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/actions.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import * as elbv2 from '../../lib'; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/conditions.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/conditions.test.ts index f900f04c19158..6864ecaa80c2b 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/conditions.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/conditions.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as elbv2 from '../../lib'; describe('tests', () => { diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/listener.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/listener.test.ts index e29e5a7837895..6de716df113e2 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/listener.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/listener.test.ts @@ -1,5 +1,5 @@ -import { MatchStyle } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { MatchStyle } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import { Metric } from '@aws-cdk/aws-cloudwatch'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; @@ -477,6 +477,26 @@ describe('tests', () => { expect(validationErrors).toEqual(["Health check protocol 'TCP' is not supported. Must be one of [HTTP, HTTPS]"]); }); + test('adding targets passes in provided protocol version', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Stack'); + const lb = new elbv2.ApplicationLoadBalancer(stack, 'LB', { vpc }); + const listener = lb.addListener('Listener', { port: 443, certificateArns: ['arn:someCert'] }); + + // WHEN + listener.addTargets('Group', { + port: 443, + protocolVersion: elbv2.ApplicationProtocolVersion.GRPC, + targets: [new FakeSelfRegisteringTarget(stack, 'Target', vpc)], + }); + + // THEN + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + ProtocolVersion: 'GRPC', + }); + }); + test('Can call addTargetGroups on imported listener', () => { // GIVEN const stack = new cdk.Stack(); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/load-balancer.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/load-balancer.test.ts index f017a4a67f3fa..8c09e3e5f25db 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/load-balancer.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/load-balancer.test.ts @@ -1,5 +1,5 @@ -import { ResourcePart, arrayWith } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { ResourcePart, arrayWith } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import { Metric } from '@aws-cdk/aws-cloudwatch'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as s3 from '@aws-cdk/aws-s3'; @@ -284,7 +284,7 @@ describe('tests', () => { // GIVEN const stack = new cdk.Stack(); const vpc = new ec2.Vpc(stack, 'Vpc'); - const albArn = 'myArn'; + const albArn = 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188'; const sg = new ec2.SecurityGroup(stack, 'sg', { vpc, securityGroupName: 'mySg', @@ -303,7 +303,7 @@ describe('tests', () => { // GIVEN const stack = new cdk.Stack(); const vpc = new ec2.Vpc(stack, 'Vpc'); - const albArn = 'MyArn'; + const albArn = 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188'; const sg = new ec2.SecurityGroup(stack, 'sg', { vpc, securityGroupName: 'mySg', @@ -319,6 +319,20 @@ describe('tests', () => { expect(() => listener.addTargets('Targets', { port: 8080 })).not.toThrow(); }); + test('imported load balancer knows its region', () => { + const stack = new cdk.Stack(); + + // WHEN + const albArn = 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188'; + const alb = elbv2.ApplicationLoadBalancer.fromApplicationLoadBalancerAttributes(stack, 'ALB', { + loadBalancerArn: albArn, + securityGroupId: 'sg-1234', + }); + + // THEN + expect(alb.env.region).toEqual('us-west-2'); + }); + test('can add secondary security groups', () => { const stack = new cdk.Stack(); const vpc = new ec2.Vpc(stack, 'Stack'); @@ -364,6 +378,7 @@ describe('tests', () => { expect(loadBalancer.loadBalancerDnsName).toEqual('my-load-balancer-1234567890.us-west-2.elb.amazonaws.com'); expect(loadBalancer.ipAddressType).toEqual(elbv2.IpAddressType.DUAL_STACK); expect(loadBalancer.connections.securityGroups[0].securityGroupId).toEqual('sg-12345'); + expect(loadBalancer.env.region).toEqual('us-west-2'); }); test('Can add listeners to a looked-up ApplicationLoadBalancer', () => { diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/security-group.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/security-group.test.ts index 67d14cd4f721e..93dd1c2d4ba33 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/security-group.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/security-group.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import * as elbv2 from '../../lib'; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts index ea028b543096f..965844affb709 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import * as elbv2 from '../../lib'; @@ -166,11 +166,29 @@ describe('tests', () => { new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { vpc, protocolVersion: elbv2.ApplicationProtocolVersion.GRPC, + healthCheck: { + enabled: true, + healthyGrpcCodes: '0-99', + interval: cdk.Duration.seconds(255), + timeout: cdk.Duration.seconds(192), + healthyThresholdCount: 29, + unhealthyThresholdCount: 27, + path: '/arbitrary', + }, }); // THEN expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { ProtocolVersion: 'GRPC', + HealthCheckEnabled: true, + HealthCheckIntervalSeconds: 255, + HealthCheckPath: '/arbitrary', + HealthCheckTimeoutSeconds: 192, + HealthyThresholdCount: 29, + Matcher: { + GrpcCode: '0-99', + }, + UnhealthyThresholdCount: 27, }); }); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/actions.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/actions.test.ts index cfb9b67e717ec..b6f53fa53d584 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/actions.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/actions.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import * as elbv2 from '../../lib'; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/listener.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/listener.test.ts index d40197d00a280..c2f863fd4f078 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/listener.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/listener.test.ts @@ -1,5 +1,5 @@ -import { MatchStyle } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { MatchStyle } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as acm from '@aws-cdk/aws-certificatemanager'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/load-balancer.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/load-balancer.test.ts index 546b88ab7d541..ed678caf2ce83 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/load-balancer.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/load-balancer.test.ts @@ -1,5 +1,5 @@ -import { ResourcePart, arrayWith } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { ResourcePart, arrayWith } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; @@ -227,7 +227,7 @@ describe('tests', () => { test('imported network load balancer with no vpc specified throws error when calling addTargets', () => { // GIVEN const stack = new cdk.Stack(); - const nlbArn = 'arn:aws:elasticloadbalancing::000000000000::dummyloadbalancer'; + const nlbArn = 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188'; const nlb = elbv2.NetworkLoadBalancer.fromNetworkLoadBalancerAttributes(stack, 'NLB', { loadBalancerArn: nlbArn, }); @@ -240,7 +240,7 @@ describe('tests', () => { // GIVEN const stack = new cdk.Stack(); const vpc = new ec2.Vpc(stack, 'Vpc'); - const nlbArn = 'arn:aws:elasticloadbalancing::000000000000::dummyloadbalancer'; + const nlbArn = 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188'; const nlb = elbv2.NetworkLoadBalancer.fromNetworkLoadBalancerAttributes(stack, 'NLB', { loadBalancerArn: nlbArn, vpc, @@ -250,6 +250,19 @@ describe('tests', () => { expect(() => listener.addTargets('targetgroup', { port: 8080 })).not.toThrow(); }); + test('imported load balancer knows its region', () => { + const stack = new cdk.Stack(); + + // WHEN + const albArn = 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188'; + const alb = elbv2.NetworkLoadBalancer.fromNetworkLoadBalancerAttributes(stack, 'ALB', { + loadBalancerArn: albArn, + }); + + // THEN + expect(alb.env.region).toEqual('us-west-2'); + }); + test('Trivial construction: internal with Isolated subnets only', () => { // GIVEN const stack = new cdk.Stack(); @@ -429,6 +442,7 @@ describe('tests', () => { expect(loadBalancer.loadBalancerArn).toEqual('arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/network/my-load-balancer/50dc6c495c0c9188'); expect(loadBalancer.loadBalancerCanonicalHostedZoneId).toEqual('Z3DZXE0EXAMPLE'); expect(loadBalancer.loadBalancerDnsName).toEqual('my-load-balancer-1234567890.us-west-2.elb.amazonaws.com'); + expect(loadBalancer.env.region).toEqual('us-west-2'); }); test('Can add listeners to a looked-up NetworkLoadBalancer', () => { diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/target-group.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/target-group.test.ts index d267d2cdafa90..bdddc74b2fd53 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/target-group.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/target-group.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-elasticsearch/README.md b/packages/@aws-cdk/aws-elasticsearch/README.md index 37d117c393616..8585ffdd8bc55 100644 --- a/packages/@aws-cdk/aws-elasticsearch/README.md +++ b/packages/@aws-cdk/aws-elasticsearch/README.md @@ -6,7 +6,7 @@ Features | Stability -----------------------------------|---------------------------------------------------------------- CFN Resources | ![Stable](https://img.shields.io/badge/stable-success.svg?style=for-the-badge) -Higher level constructs for Domain | ![Experimental](https://img.shields.io/badge/experimental-important.svg?style=for-the-badge) +Higher level constructs for Domain | ![Stable](https://img.shields.io/badge/stable-success.svg?style=for-the-badge) > **CFN Resources:** All classes with the `Cfn` prefix in this module ([CFN Resources]) are always > stable and safe to use. @@ -15,11 +15,8 @@ Higher level constructs for Domain | ![Experimental](https://img.shields.io/badg -> **Experimental:** Higher level constructs in this module that are marked as experimental are -> 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. +> **Stable:** Higher level constructs in this module that are marked stable will not undergo any +> breaking changes. They will strictly follow the [Semantic Versioning](https://semver.org/) model. --- @@ -43,7 +40,7 @@ To perform version upgrades without replacing the entire domain, specify the `en import * as es from '@aws-cdk/aws-elasticsearch'; const devDomain = new es.Domain(this, 'Domain', { - version: es.ElasticsearchVersion.V7_9, + version: es.ElasticsearchVersion.V7_10, enableVersionUpgrade: true // defaults to false }); ``` @@ -74,6 +71,30 @@ const prodDomain = new es.Domain(this, 'Domain', { This creates an Elasticsearch cluster and automatically sets up log groups for logging the domain logs and slow search logs. +## A note about SLR + +Some cluster configurations (e.g VPC access) require the existence of the [`AWSServiceRoleForAmazonElasticsearchService`](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/slr-es.html) Service-Linked Role. + +When performing such operations via the AWS Console, this SLR is created automatically when needed. However, this is not the behavior when using CloudFormation. If an SLR is needed, but doesn't exist, you will encounter a failure message simlar to: + +```console +Before you can proceed, you must enable a service-linked role to give Amazon ES... +``` + +To resolve this, you need to [create](https://docs.aws.amazon.com/IAM/latest/UserGuide/using-service-linked-roles.html#create-service-linked-role) the SLR. We recommend using the AWS CLI: + +```console +aws iam create-service-linked-role --aws-service-name es.amazonaws.com +``` + +You can also create it using the CDK, **but note that only the first application deploying this will succeed**: + +```ts +const slr = new iam.CfnServiceLinkedRole(this, 'ElasticSLR', { + awsServiceName: 'es.amazonaws.com' +}); +``` + ## Importing existing domains To import an existing domain into your CDK application, use the `Domain.fromDomainEndpoint` factory method. @@ -122,6 +143,33 @@ This sets up the domain with node to node encryption and encryption at rest. You can also choose to supply your own KMS key to use for encryption at rest. +## VPC Support + +Elasticsearch domains can be placed inside a VPC, providing a secure communication between Amazon ES and other services within the VPC without the need for an internet gateway, NAT device, or VPN connection. + +> Visit [VPC Support for Amazon Elasticsearch Service Domains](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-vpc.html) for more details. + +```ts +const vpc = new ec2.Vpc(this, 'Vpc'); +const domainProps: es.DomainProps = { + version: es.ElasticsearchVersion.V7_1, + removalPolicy: RemovalPolicy.DESTROY, + vpc, + // must be enabled since our VPC contains multiple private subnets. + zoneAwareness: { + enabled: true, + }, + capacity: { + // must be an even number since the default az count is 2. + dataNodes: 2, + }, +}; +new es.Domain(this, 'Domain', domainProps); +``` + +In addition, you can use the `vpcSubnets` property to control which specific subnets will be used, and the `securityGroups` property to control +which security groups will be attached to the domain. By default, CDK will select all *private* subnets in the VPC, and create one dedicated security group. + ## Metrics Helper methods exist to access common domain metrics for example: @@ -217,7 +265,7 @@ UltraWarm nodes can be enabled to provide a cost-effective way to store large am ```ts const domain = new es.Domain(this, 'Domain', { - version: es.ElasticsearchVersion.V7_9, + version: es.ElasticsearchVersion.V7_10, capacity: { masterNodes: 2, warmNodes: 2, diff --git a/packages/@aws-cdk/aws-elasticsearch/lib/domain.ts b/packages/@aws-cdk/aws-elasticsearch/lib/domain.ts index 74a4dff64f757..3f83da9ad3328 100644 --- a/packages/@aws-cdk/aws-elasticsearch/lib/domain.ts +++ b/packages/@aws-cdk/aws-elasticsearch/lib/domain.ts @@ -74,6 +74,9 @@ export class ElasticsearchVersion { /** AWS Elasticsearch 7.9 */ public static readonly V7_9 = ElasticsearchVersion.of('7.9'); + /** AWS Elasticsearch 7.10 */ + public static readonly V7_10 = ElasticsearchVersion.of('7.10'); + /** * Custom Elasticsearch version * @param version custom version number @@ -331,32 +334,6 @@ export interface CognitoOptions { readonly userPoolId: string; } -/** - * The virtual private cloud (VPC) configuration for the Amazon ES domain. For - * more information, see [VPC Support for Amazon Elasticsearch Service - * Domains](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-vpc.html) - * in the Amazon Elasticsearch Service Developer Guide. - */ -export interface VpcOptions { - /** - * The list of security groups that are associated with the VPC endpoints - * for the domain. If you don't provide a security group ID, Amazon ES uses - * the default security group for the VPC. To learn more, see [Security Groups for your VPC] - * (https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html) in the Amazon VPC - * User Guide. - */ - readonly securityGroups: ec2.ISecurityGroup[]; - - /** - * Provide one subnet for each Availability Zone that your domain uses. For - * example, you must specify three subnet IDs for a three Availability Zone - * domain. To learn more, see [VPCs and Subnets] - * (https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Subnets.html) in the - * Amazon VPC User Guide. - */ - readonly subnets: ec2.ISubnet[]; -} - /** * The minimum TLS version required for traffic to the domain. */ @@ -513,14 +490,35 @@ export interface DomainProps { readonly automatedSnapshotStartHour?: number; /** - * The virtual private cloud (VPC) configuration for the Amazon ES domain. For - * more information, see [VPC Support for Amazon Elasticsearch Service - * Domains](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-vpc.html) - * in the Amazon Elasticsearch Service Developer Guide. + * Place the domain inside this VPC. + * + * @see https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-vpc.html + * @default - Domain is not placed in a VPC. + */ + readonly vpc?: ec2.IVpc; + + /** + * The list of security groups that are associated with the VPC endpoints + * for the domain. + * + * Only used if `vpc` is specified. + * + * @see https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html + * @default - One new security group is created. + */ + readonly securityGroups?: ec2.ISecurityGroup[]; + + /** + * The specific vpc subnets the domain will be placed in. You must provide one subnet for each Availability Zone + * that your domain uses. For example, you must specify three subnet IDs for a three Availability Zone + * domain. * - * @default - VPC not used + * Only used if `vpc` is specified. + * + * @see https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Subnets.html + * @default - All private subnets. */ - readonly vpcOptions?: VpcOptions; + readonly vpcSubnets?: ec2.SubnetSelection[]; /** * True to require that all traffic to the domain arrive over HTTPS. @@ -719,7 +717,7 @@ export interface IDomain extends cdk.IResource { * * @default maximum over 1 minute */ - metricClusterIndexWriteBlocked(props?: MetricOptions): Metric; + metricClusterIndexWritesBlocked(props?: MetricOptions): Metric; /** * Metric for the number of nodes. @@ -1002,8 +1000,8 @@ abstract class DomainBase extends cdk.Resource implements IDomain { * * @default maximum over 1 minute */ - public metricClusterIndexWriteBlocked(props?: MetricOptions): Metric { - return this.metric('ClusterIndexWriteBlocked', { + public metricClusterIndexWritesBlocked(props?: MetricOptions): Metric { + return this.metric('ClusterIndexWritesBlocked', { statistic: Statistic.MAXIMUM, period: cdk.Duration.minutes(1), ...props, @@ -1177,7 +1175,7 @@ export interface DomainAttributes { /** * Provides an Elasticsearch domain. */ -export class Domain extends DomainBase implements IDomain { +export class Domain extends DomainBase implements IDomain, ec2.IConnectable { /** * Creates a Domain construct that represents an external domain via domain endpoint. * @@ -1264,6 +1262,8 @@ export class Domain extends DomainBase implements IDomain { private readonly domain: CfnDomain; + private readonly _connections: ec2.Connections | undefined; + constructor(scope: Construct, id: string, props: DomainProps) { super(scope, id, { physicalName: props.domainName, @@ -1300,11 +1300,23 @@ export class Domain extends DomainBase implements IDomain { props.zoneAwareness?.enabled ?? props.zoneAwareness?.availabilityZoneCount != null; + + let securityGroups: ec2.ISecurityGroup[] | undefined; + let subnets: ec2.ISubnet[] | undefined; + + if (props.vpc) { + subnets = selectSubnets(props.vpc, props.vpcSubnets ?? [{ subnetType: ec2.SubnetType.PRIVATE }]); + securityGroups = props.securityGroups ?? [new ec2.SecurityGroup(this, 'SecurityGroup', { + vpc: props.vpc, + description: `Security group for domain ${this.node.id}`, + })]; + this._connections = new ec2.Connections({ securityGroups }); + } + // If VPC options are supplied ensure that the number of subnets matches the number AZ - if (props.vpcOptions != null && zoneAwarenessEnabled && - new Set(props.vpcOptions?.subnets.map((subnet) => subnet.availabilityZone)).size < availabilityZoneCount) { + if (subnets && zoneAwarenessEnabled && new Set(subnets.map((subnet) => subnet.availabilityZone)).size < availabilityZoneCount) { throw new Error('When providing vpc options you need to provide a subnet for each AZ you are using'); - }; + } if ([dedicatedMasterType, instanceType, warmType].some(t => !t.endsWith('.elasticsearch'))) { throw new Error('Master, data and UltraWarm node instance types must end with ".elasticsearch".'); @@ -1491,10 +1503,11 @@ export class Domain extends DomainBase implements IDomain { } let cfnVpcOptions: CfnDomain.VPCOptionsProperty | undefined; - if (props.vpcOptions) { + + if (securityGroups && subnets) { cfnVpcOptions = { - securityGroupIds: props.vpcOptions.securityGroups.map((sg) => sg.securityGroupId), - subnetIds: props.vpcOptions.subnets.map((subnet) => subnet.subnetId), + securityGroupIds: securityGroups.map((sg) => sg.securityGroupId), + subnetIds: subnets.map((subnet) => subnet.subnetId), }; } @@ -1730,6 +1743,17 @@ export class Domain extends DomainBase implements IDomain { accessPolicy.node.addDependency(this.domain); } } + + /** + * Manages network connections to the domain. This will throw an error in case the domain + * is not placed inside a VPC. + */ + public get connections(): ec2.Connections { + if (!this._connections) { + throw new Error("Connections are only available on VPC enabled domains. Use the 'vpc' property to place a domain inside a VPC"); + } + return this._connections; + } } /** @@ -1778,3 +1802,11 @@ function parseVersion(version: ElasticsearchVersion): number { throw new Error(`Invalid Elasticsearch version: ${versionStr}. Version string needs to start with major and minor version (x.y).`); } } + +function selectSubnets(vpc: ec2.IVpc, vpcSubnets: ec2.SubnetSelection[]): ec2.ISubnet[] { + const selected = []; + for (const selection of vpcSubnets) { + selected.push(...vpc.selectSubnets(selection).subnets); + } + return selected; +} diff --git a/packages/@aws-cdk/aws-elasticsearch/package.json b/packages/@aws-cdk/aws-elasticsearch/package.json index df7d8934559ea..e7bfd0e784754 100644 --- a/packages/@aws-cdk/aws-elasticsearch/package.json +++ b/packages/@aws-cdk/aws-elasticsearch/package.json @@ -71,11 +71,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", @@ -88,7 +89,7 @@ "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -102,17 +103,17 @@ "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, - "stability": "experimental", - "maturity": "experimental", + "stability": "stable", + "maturity": "stable", "features": [ { "name": "Higher level constructs for Domain", - "stability": "Experimental" + "stability": "Stable" } ], "awscdkio": { diff --git a/packages/@aws-cdk/aws-elasticsearch/test/domain.test.ts b/packages/@aws-cdk/aws-elasticsearch/test/domain.test.ts index 12810832c0da8..63cc2a7cdd853 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/domain.test.ts +++ b/packages/@aws-cdk/aws-elasticsearch/test/domain.test.ts @@ -1,9 +1,9 @@ /* eslint-disable jest/expect-expect */ -import '@aws-cdk/assert/jest'; -import * as assert from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +import * as assert from '@aws-cdk/assert-internal'; import * as acm from '@aws-cdk/aws-certificatemanager'; import { Metric, Statistic } from '@aws-cdk/aws-cloudwatch'; -import { Subnet, Vpc, EbsDeviceVolumeType } from '@aws-cdk/aws-ec2'; +import { Vpc, EbsDeviceVolumeType, SecurityGroup } from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as logs from '@aws-cdk/aws-logs'; @@ -30,6 +30,84 @@ const readWriteActions = [ ...writeActions, ]; +test('connections throws if domain is placed inside a vpc', () => { + + expect(() => { + new Domain(stack, 'Domain', { + version: ElasticsearchVersion.V7_1, + }).connections; + }).toThrowError("Connections are only available on VPC enabled domains. Use the 'vpc' property to place a domain inside a VPC"); +}); + +test('subnets and security groups can be provided when vpc is used', () => { + + const vpc = new Vpc(stack, 'Vpc'); + const securityGroup = new SecurityGroup(stack, 'CustomSecurityGroup', { + vpc, + }); + const domain = new Domain(stack, 'Domain', { + version: ElasticsearchVersion.V7_10, + vpc, + vpcSubnets: [{ subnets: [vpc.privateSubnets[0]] }], + securityGroups: [securityGroup], + }); + + expect(domain.connections.securityGroups[0].securityGroupId).toEqual(securityGroup.securityGroupId); + expect(stack).toHaveResource('AWS::Elasticsearch::Domain', { + VPCOptions: { + SecurityGroupIds: [ + { + 'Fn::GetAtt': [ + 'CustomSecurityGroupE5E500E5', + 'GroupId', + ], + }, + ], + SubnetIds: [ + { + Ref: 'VpcPrivateSubnet1Subnet536B997A', + }, + ], + }, + }); + +}); + +test('default subnets and security group when vpc is used', () => { + + const vpc = new Vpc(stack, 'Vpc'); + const domain = new Domain(stack, 'Domain', { + version: ElasticsearchVersion.V7_10, + vpc, + }); + + expect(stack.resolve(domain.connections.securityGroups[0].securityGroupId)).toEqual({ 'Fn::GetAtt': ['DomainSecurityGroup48AA5FD6', 'GroupId'] }); + expect(stack).toHaveResource('AWS::Elasticsearch::Domain', { + VPCOptions: { + SecurityGroupIds: [ + { + 'Fn::GetAtt': [ + 'DomainSecurityGroup48AA5FD6', + 'GroupId', + ], + }, + ], + SubnetIds: [ + { + Ref: 'VpcPrivateSubnet1Subnet536B997A', + }, + { + Ref: 'VpcPrivateSubnet2Subnet3788AAA1', + }, + { + Ref: 'VpcPrivateSubnet3SubnetF258B56E', + }, + ], + }, + }); + +}); + test('default removalpolicy is retain', () => { new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_1, @@ -709,8 +787,8 @@ describe('metrics', () => { test('Can use metricClusterIndexWriteBlocked on an Elasticsearch Domain', () => { testMetric( - (domain) => domain.metricClusterIndexWriteBlocked(), - 'ClusterIndexWriteBlocked', + (domain) => domain.metricClusterIndexWritesBlocked(), + 'ClusterIndexWritesBlocked', Statistic.MAXIMUM, Duration.minutes(1), ); @@ -1150,7 +1228,9 @@ describe('custom endpoints', () => { describe('custom error responses', () => { test('error when availabilityZoneCount does not match vpcOptions.subnets length', () => { - const vpc = new Vpc(stack, 'Vpc'); + const vpc = new Vpc(stack, 'Vpc', { + maxAzs: 1, + }); expect(() => new Domain(stack, 'Domain', { version: ElasticsearchVersion.V7_4, @@ -1158,16 +1238,7 @@ describe('custom error responses', () => { enabled: true, availabilityZoneCount: 2, }, - vpcOptions: { - subnets: [ - new Subnet(stack, 'Subnet', { - availabilityZone: 'testaz', - cidrBlock: vpc.vpcCidrBlock, - vpcId: vpc.vpcId, - }), - ], - securityGroups: [], - }, + vpc, })).toThrow(/you need to provide a subnet for each AZ you are using/); }); @@ -1357,31 +1428,7 @@ describe('custom error responses', () => { expect(() => new Domain(stack, 'Domain1', { version: ElasticsearchVersion.V7_4, - vpcOptions: { - subnets: [ - new Subnet(stack, 'Subnet1', { - availabilityZone: 'testaz1', - cidrBlock: vpc.vpcCidrBlock, - vpcId: vpc.vpcId, - }), - new Subnet(stack, 'Subnet2', { - availabilityZone: 'testaz2', - cidrBlock: vpc.vpcCidrBlock, - vpcId: vpc.vpcId, - }), - new Subnet(stack, 'Subnet3', { - availabilityZone: 'testaz3', - cidrBlock: vpc.vpcCidrBlock, - vpcId: vpc.vpcId, - }), - new Subnet(stack, 'Subnet4', { - availabilityZone: 'testaz4', - cidrBlock: vpc.vpcCidrBlock, - vpcId: vpc.vpcId, - }), - ], - securityGroups: [], - }, + vpc, zoneAwareness: { availabilityZoneCount: 4, }, diff --git a/packages/@aws-cdk/aws-elasticsearch/test/elasticsearch-access-policy.test.ts b/packages/@aws-cdk/aws-elasticsearch/test/elasticsearch-access-policy.test.ts index c848e9d58bc82..6d2d484cabd9f 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/elasticsearch-access-policy.test.ts +++ b/packages/@aws-cdk/aws-elasticsearch/test/elasticsearch-access-policy.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as iam from '@aws-cdk/aws-iam'; import { App, Stack } from '@aws-cdk/core'; import { ElasticsearchAccessPolicy } from '../lib/elasticsearch-access-policy'; diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch-vpc.expected.json b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch-vpc.expected.json new file mode 100644 index 0000000000000..fc046ff8065b2 --- /dev/null +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch-vpc.expected.json @@ -0,0 +1,591 @@ +{ + "Resources": { + "Vpc8378EB38": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "cdk-integ-elasticsearch-vpc/Vpc" + } + ] + } + }, + "VpcPublicSubnet1Subnet5C2D37C4": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/19", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "cdk-integ-elasticsearch-vpc/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1RouteTable6C95E38E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "cdk-integ-elasticsearch-vpc/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1RouteTableAssociation97140677": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + } + } + }, + "VpcPublicSubnet1DefaultRoute3DA9E72A": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet1EIPD7E02669": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "cdk-integ-elasticsearch-vpc/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1NATGateway4D7517AA": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet1EIPD7E02669", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "cdk-integ-elasticsearch-vpc/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet2Subnet691E08A3": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.32.0/19", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "cdk-integ-elasticsearch-vpc/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2RouteTable94F7E489": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "cdk-integ-elasticsearch-vpc/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2RouteTableAssociationDD5762D8": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + } + } + }, + "VpcPublicSubnet2DefaultRoute97F91067": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet2EIP3C605A87": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "cdk-integ-elasticsearch-vpc/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2NATGateway9182C01D": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet2EIP3C605A87", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, + "Tags": [ + { + "Key": "Name", + "Value": "cdk-integ-elasticsearch-vpc/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet3SubnetBE12F0B6": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/19", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1c", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "cdk-integ-elasticsearch-vpc/Vpc/PublicSubnet3" + } + ] + } + }, + "VpcPublicSubnet3RouteTable93458DBB": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "cdk-integ-elasticsearch-vpc/Vpc/PublicSubnet3" + } + ] + } + }, + "VpcPublicSubnet3RouteTableAssociation1F1EDF02": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet3RouteTable93458DBB" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet3SubnetBE12F0B6" + } + } + }, + "VpcPublicSubnet3DefaultRoute4697774F": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet3RouteTable93458DBB" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet3EIP3A666A23": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "cdk-integ-elasticsearch-vpc/Vpc/PublicSubnet3" + } + ] + } + }, + "VpcPublicSubnet3NATGateway7640CD1D": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet3EIP3A666A23", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VpcPublicSubnet3SubnetBE12F0B6" + }, + "Tags": [ + { + "Key": "Name", + "Value": "cdk-integ-elasticsearch-vpc/Vpc/PublicSubnet3" + } + ] + } + }, + "VpcPrivateSubnet1Subnet536B997A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.96.0/19", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "cdk-integ-elasticsearch-vpc/Vpc/PrivateSubnet1" + } + ] + } + }, + "VpcPrivateSubnet1RouteTableB2C5B500": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "cdk-integ-elasticsearch-vpc/Vpc/PrivateSubnet1" + } + ] + } + }, + "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + } + } + }, + "VpcPrivateSubnet1DefaultRouteBE02A9ED": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + } + } + }, + "VpcPrivateSubnet2Subnet3788AAA1": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/19", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "cdk-integ-elasticsearch-vpc/Vpc/PrivateSubnet2" + } + ] + } + }, + "VpcPrivateSubnet2RouteTableA678073B": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "cdk-integ-elasticsearch-vpc/Vpc/PrivateSubnet2" + } + ] + } + }, + "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + } + }, + "VpcPrivateSubnet2DefaultRoute060D2087": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet2NATGateway9182C01D" + } + } + }, + "VpcPrivateSubnet3SubnetF258B56E": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.160.0/19", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1c", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "cdk-integ-elasticsearch-vpc/Vpc/PrivateSubnet3" + } + ] + } + }, + "VpcPrivateSubnet3RouteTableD98824C7": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "cdk-integ-elasticsearch-vpc/Vpc/PrivateSubnet3" + } + ] + } + }, + "VpcPrivateSubnet3RouteTableAssociation16BDDC43": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet3RouteTableD98824C7" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet3SubnetF258B56E" + } + } + }, + "VpcPrivateSubnet3DefaultRoute94B74F0D": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet3RouteTableD98824C7" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet3NATGateway7640CD1D" + } + } + }, + "VpcIGWD7BA715C": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "cdk-integ-elasticsearch-vpc/Vpc" + } + ] + } + }, + "VpcVPCGWBF912B6E": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "InternetGatewayId": { + "Ref": "VpcIGWD7BA715C" + } + } + }, + "DomainSecurityGroup48AA5FD6": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "Security group for domain Domain", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "Domain66AC69E0": { + "Type": "AWS::Elasticsearch::Domain", + "Properties": { + "CognitoOptions": { + "Enabled": false + }, + "DomainEndpointOptions": { + "EnforceHTTPS": false, + "TLSSecurityPolicy": "Policy-Min-TLS-1-0-2019-07" + }, + "EBSOptions": { + "EBSEnabled": true, + "VolumeSize": 10, + "VolumeType": "gp2" + }, + "ElasticsearchClusterConfig": { + "DedicatedMasterEnabled": false, + "InstanceCount": 2, + "InstanceType": "r5.large.elasticsearch", + "ZoneAwarenessConfig": { + "AvailabilityZoneCount": 2 + }, + "ZoneAwarenessEnabled": true + }, + "ElasticsearchVersion": "7.1", + "EncryptionAtRestOptions": { + "Enabled": false + }, + "LogPublishingOptions": {}, + "NodeToNodeEncryptionOptions": { + "Enabled": false + }, + "VPCOptions": { + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "DomainSecurityGroup48AA5FD6", + "GroupId" + ] + } + ], + "SubnetIds": [ + { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + }, + { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + }, + { + "Ref": "VpcPrivateSubnet3SubnetF258B56E" + } + ] + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch-vpc.ts b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch-vpc.ts new file mode 100644 index 0000000000000..b1049270c6250 --- /dev/null +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch-vpc.ts @@ -0,0 +1,28 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; +import { App, Stack, StackProps, RemovalPolicy } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import * as es from '../lib'; + +class TestStack extends Stack { + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + + const vpc = new ec2.Vpc(this, 'Vpc'); + const domainProps: es.DomainProps = { + version: es.ElasticsearchVersion.V7_1, + removalPolicy: RemovalPolicy.DESTROY, + vpc, + zoneAwareness: { + enabled: true, + }, + capacity: { + dataNodes: 2, + }, + }; + new es.Domain(this, 'Domain', domainProps); + } +} + +const app = new App(); +new TestStack(app, 'cdk-integ-elasticsearch-vpc'); +app.synth(); diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.expected.json b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.expected.json index 5424865cc3bd7..eb826dda1f40a 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.expected.json +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.expected.json @@ -343,7 +343,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3Bucket65227904" + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3Bucket4DD075F7" }, "S3Key": { "Fn::Join": [ @@ -356,7 +356,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF" + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7" } ] } @@ -369,7 +369,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF" + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7" } ] } @@ -396,17 +396,17 @@ } }, "Parameters": { - "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3Bucket65227904": { + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3Bucket4DD075F7": { "Type": "String", - "Description": "S3 bucket for asset \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\"" + "Description": "S3 bucket for asset \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" }, - "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF": { + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7": { "Type": "String", - "Description": "S3 key for asset version \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\"" + "Description": "S3 key for asset version \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" }, - "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343ArtifactHash0C561FF5": { + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98ArtifactHash35A756EB": { "Type": "String", - "Description": "Artifact hash for asset \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\"" + "Description": "Artifact hash for asset \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.ts b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.ts index 24bb07e4660ff..b18ff225d3cd9 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.ts +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.custom-kms-key.ts @@ -1,3 +1,4 @@ +/// !cdk-integ pragma:ignore-assets import { EbsDeviceVolumeType } from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.expected.json b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.expected.json index 6d54b0cfbc27e..8788b810235ec 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.expected.json +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.expected.json @@ -275,7 +275,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3Bucket65227904" + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3Bucket4DD075F7" }, "S3Key": { "Fn::Join": [ @@ -288,7 +288,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF" + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7" } ] } @@ -301,7 +301,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF" + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7" } ] } @@ -566,17 +566,17 @@ } }, "Parameters": { - "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3Bucket65227904": { + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3Bucket4DD075F7": { "Type": "String", - "Description": "S3 bucket for asset \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\"" + "Description": "S3 bucket for asset \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" }, - "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF": { + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7": { "Type": "String", - "Description": "S3 key for asset version \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\"" + "Description": "S3 key for asset version \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" }, - "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343ArtifactHash0C561FF5": { + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98ArtifactHash35A756EB": { "Type": "String", - "Description": "Artifact hash for asset \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\"" + "Description": "Artifact hash for asset \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ts b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ts index 448896e321957..d2851bd3d47b9 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ts +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.ts @@ -1,3 +1,4 @@ +/// !cdk-integ pragma:ignore-assets import { EbsDeviceVolumeType } from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import { App, RemovalPolicy, Stack, StackProps } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.expected.json b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.expected.json index 89a79c79f8316..3a59982581776 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.expected.json +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.expected.json @@ -191,7 +191,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3Bucket65227904" + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3Bucket4DD075F7" }, "S3Key": { "Fn::Join": [ @@ -204,7 +204,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF" + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7" } ] } @@ -217,7 +217,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF" + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7" } ] } @@ -243,17 +243,17 @@ } }, "Parameters": { - "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3Bucket65227904": { + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3Bucket4DD075F7": { "Type": "String", - "Description": "S3 bucket for asset \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\"" + "Description": "S3 bucket for asset \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" }, - "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF": { + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7": { "Type": "String", - "Description": "S3 key for asset version \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\"" + "Description": "S3 key for asset version \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" }, - "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343ArtifactHash0C561FF5": { + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98ArtifactHash35A756EB": { "Type": "String", - "Description": "Artifact hash for asset \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\"" + "Description": "Artifact hash for asset \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.ts b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.ts index 5e7fb2787972d..a294d793f0862 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.ts +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.unsignedbasicauth.ts @@ -1,3 +1,4 @@ +/// !cdk-integ pragma:ignore-assets import { App, RemovalPolicy, Stack, StackProps } from '@aws-cdk/core'; import { Construct } from 'constructs'; import * as es from '../lib'; diff --git a/packages/@aws-cdk/aws-elasticsearch/test/log-group-resource-policy.test.ts b/packages/@aws-cdk/aws-elasticsearch/test/log-group-resource-policy.test.ts index f007f31f38c6d..68518297588c9 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/log-group-resource-policy.test.ts +++ b/packages/@aws-cdk/aws-elasticsearch/test/log-group-resource-policy.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as iam from '@aws-cdk/aws-iam'; import { App, Stack } from '@aws-cdk/core'; import { LogGroupResourcePolicy } from '../lib/log-group-resource-policy'; diff --git a/packages/@aws-cdk/aws-emr/package.json b/packages/@aws-cdk/aws-emr/package.json index 0865f9a31783d..f666c85ab19ef 100644 --- a/packages/@aws-cdk/aws-emr/package.json +++ b/packages/@aws-cdk/aws-emr/package.json @@ -71,19 +71,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-emr/test/emr.test.ts b/packages/@aws-cdk/aws-emr/test/emr.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-emr/test/emr.test.ts +++ b/packages/@aws-cdk/aws-emr/test/emr.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-emrcontainers/package.json b/packages/@aws-cdk/aws-emrcontainers/package.json index c1e102c6a81e6..217671443029d 100644 --- a/packages/@aws-cdk/aws-emrcontainers/package.json +++ b/packages/@aws-cdk/aws-emrcontainers/package.json @@ -75,10 +75,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-emrcontainers/test/emrcontainers.test.ts b/packages/@aws-cdk/aws-emrcontainers/test/emrcontainers.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-emrcontainers/test/emrcontainers.test.ts +++ b/packages/@aws-cdk/aws-emrcontainers/test/emrcontainers.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-events-targets/.gitignore b/packages/@aws-cdk/aws-events-targets/.gitignore index 2ed02868c78fb..7ab9446974101 100644 --- a/packages/@aws-cdk/aws-events-targets/.gitignore +++ b/packages/@aws-cdk/aws-events-targets/.gitignore @@ -18,5 +18,6 @@ nyc.config.js lib/sdk-api-metadata.json !.eslintrc.js !jest.config.js +!build-tools/*.js junit.xml \ No newline at end of file diff --git a/packages/@aws-cdk/aws-events-targets/README.md b/packages/@aws-cdk/aws-events-targets/README.md index d49621b0199cd..6dcc3598a26e7 100644 --- a/packages/@aws-cdk/aws-events-targets/README.md +++ b/packages/@aws-cdk/aws-events-targets/README.md @@ -15,23 +15,29 @@ to the `rule.addTarget()` method. Currently supported are: -* Start a CodeBuild build -* Start a CodePipeline pipeline +* [Start a CodeBuild build](#start-a-codebuild-build) +* [Start a CodePipeline pipeline](#start-a-codepipeline-pipeline) * Run an ECS task -* Invoke a Lambda function +* [Invoke a Lambda function](#invoke-a-lambda-function) +* [Invoke a API Gateway REST API](#invoke-a-api-gateway-rest-api) * Publish a message to an SNS topic * Send a message to an SQS queue -* Start a StepFunctions state machine +* [Start a StepFunctions state machine](#start-a-stepfunctions-state-machine) * Queue a Batch job * Make an AWS API call * Put a record to a Kinesis stream -* Log an event into a LogGroup +* [Log an event into a LogGroup](#log-an-event-into-a-loggroup) * Put a record to a Kinesis Data Firehose stream * Put an event on an EventBridge bus See the README of the `@aws-cdk/aws-events` library for more information on EventBridge. +## Event retry policy and using dead-letter queues + +The Codebuild, CodePipeline, Lambda, StepFunctions and LogGroup targets support attaching a [dead letter queue and setting retry policies](https://docs.aws.amazon.com/eventbridge/latest/userguide/rule-dlq.html). See the [lambda example](#invoke-a-lambda-function). +Use [escape hatches](https://docs.aws.amazon.com/cdk/latest/guide/cfn_layer.html) for the other target types. + ## Invoke a Lambda function Use the `LambdaFunction` target to invoke a lambda function. @@ -45,6 +51,7 @@ import * as lambda from "@aws-cdk/aws-lambda"; import * as events from "@aws-cdk/aws-events"; import * as sqs from "@aws-cdk/aws-sqs"; import * as targets from "@aws-cdk/aws-events-targets"; +import * as cdk from '@aws-cdk/core'; const fn = new lambda.Function(this, 'MyFunc', { runtime: lambda.Runtime.NODEJS_12_X, @@ -62,6 +69,8 @@ const queue = new sqs.Queue(this, 'Queue'); rule.addTarget(new targets.LambdaFunction(fn, { deadLetterQueue: queue, // Optional: add a dead letter queue + maxEventAge: cdk.Duration.hours(2), // Otional: set the maxEventAge retry policy + retryAttempts: 2, // Optional: set the max number of retry attempts })); ``` @@ -90,7 +99,7 @@ const rule = new events.Rule(this, 'rule', { rule.addTarget(new targets.CloudWatchLogGroup(logGroup)); ``` -## Trigger a CodeBuild project +## Start a CodeBuild build Use the `CodeBuildProject` target to trigger a CodeBuild project. @@ -123,7 +132,26 @@ const onCommitRule = repo.onCommit('OnCommit', { }); ``` -## Trigger a State Machine +## Start a CodePipeline pipeline + +Use the `CodePipeline` target to trigger a CodePipeline pipeline. + +The code snippet below creates a CodePipeline pipeline that is triggered every hour + +```ts +import * as codepipeline from '@aws-sdk/aws-codepipeline'; +import * as sqs from '@aws-sdk/aws-sqs'; + +const pipeline = new codepipeline.Pipeline(this, 'Pipeline'); + +const rule = new events.Rule(stack, 'Rule', { + schedule: events.Schedule.expression('rate(1 hour)'), +}); + +rule.addTarget(new targets.CodePipeline(pipeline)); +``` + +## Start a StepFunctions state machine Use the `SfnStateMachine` target to trigger a State Machine. @@ -158,3 +186,46 @@ rule.addTarget(new targets.SfnStateMachine(stateMachine, { deadLetterQueue: dlq, })); ``` + +## Invoke a API Gateway REST API + +Use the `ApiGateway` target to trigger a REST API. + +The code snippet below creates a Api Gateway REST API that is invoked every hour. + +```typescript +import * as iam from '@aws-sdk/aws-iam'; +import * as sqs from '@aws-sdk/aws-sqs'; +import * as api from '@aws-cdk/aws-apigateway'; +import * as targets from "@aws-cdk/aws-events-targets"; + +const rule = new events.Rule(stack, 'Rule', { + schedule: events.Schedule.rate(cdk.Duration.minutes(1)), +}); + +const fn = new lambda.Function( this, 'MyFunc', { + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_12_X, + code: lambda.Code.fromInline( 'exports.handler = e => {}' ), +} ); + +const restApi = new api.LambdaRestApi( this, 'MyRestAPI', { handler: fn } ); + +const dlq = new sqs.Queue(stack, 'DeadLetterQueue'); + +rule.addTarget( + new targets.ApiGateway( restApi, { + path: '/*/test', + mehod: 'GET', + stage: 'prod', + pathParameterValues: ['path-value'], + headerParameters: { + Header1: 'header1', + }, + queryStringParameters: { + QueryParam1: 'query-param-1', + }, + deadLetterQueue: queue + } ), +) +``` diff --git a/packages/@aws-cdk/aws-events-targets/lib/api-gateway.ts b/packages/@aws-cdk/aws-events-targets/lib/api-gateway.ts new file mode 100644 index 0000000000000..168c5a65a386d --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/lib/api-gateway.ts @@ -0,0 +1,123 @@ +import * as api from '@aws-cdk/aws-apigateway'; +import * as events from '@aws-cdk/aws-events'; +import * as iam from '@aws-cdk/aws-iam'; +import { addToDeadLetterQueueResourcePolicy, bindBaseTargetConfig, singletonEventRole, TargetBaseProps } from './util'; + +/** + * Customize the API Gateway Event Target + */ +export interface ApiGatewayProps extends TargetBaseProps { + + /** + * The method for api resource invoked by the rule. + * + * @default '*' that treated as ANY + */ + readonly method?: string; + + /** + * The api resource invoked by the rule. + * We can use wildcards('*') to specify the path. In that case, + * an equal number of real values must be specified for pathParameterValues. + * + * @default '/' + */ + readonly path?: string; + + /** + * The deploy stage of api gateway invoked by the rule. + * + * @default the value of deploymentStage.stageName of target api gateway. + */ + readonly stage?: string; + + /** + * The headers to be set when requesting API + * + * @default no header parameters + */ + readonly headerParameters?: { [key: string]: (string) }; + + /** + * The path parameter values to be used to + * populate to wildcards("*") of requesting api path + * + * @default no path parameters + */ + readonly pathParameterValues?: string[]; + + /** + * The query parameters to be set when requesting API. + * + * @default no querystring parameters + */ + readonly queryStringParameters?: { [key: string]: (string) }; + + /** + * This will be the post request body send to the API. + * + * @default the entire EventBridge event + */ + readonly postBody?: events.RuleTargetInput; + + /** + * The role to assume before invoking the target + * (i.e., the pipeline) when the given rule is triggered. + * + * @default - a new role will be created + */ + readonly eventRole?: iam.IRole; +} + +/** + * Use an API Gateway REST APIs as a target for Amazon EventBridge rules. + */ +export class ApiGateway implements events.IRuleTarget { + + constructor(public readonly restApi: api.RestApi, private readonly props?: ApiGatewayProps) { + } + + /** + * Returns a RuleTarget that can be used to trigger this API Gateway REST APIs + * as a result from an EventBridge event. + * + * @see https://docs.aws.amazon.com/eventbridge/latest/userguide/resource-based-policies-eventbridge.html#sqs-permissions + */ + public bind(rule: events.IRule, _id?: string): events.RuleTargetConfig { + if (this.props?.deadLetterQueue) { + addToDeadLetterQueueResourcePolicy(rule, this.props.deadLetterQueue); + } + + const wildcardCountsInPath = this.props?.path?.match( /\*/g )?.length ?? 0; + if (wildcardCountsInPath !== (this.props?.pathParameterValues || []).length) { + throw new Error('The number of wildcards in the path does not match the number of path pathParameterValues.'); + } + + const restApiArn = this.restApi.arnForExecuteApi( + this.props?.method, + this.props?.path || '/', + this.props?.stage || this.restApi.deploymentStage.stageName, + ); + return { + ...(this.props ? bindBaseTargetConfig(this.props) : {}), + arn: restApiArn, + role: this.props?.eventRole || singletonEventRole(this.restApi, [new iam.PolicyStatement({ + resources: [restApiArn], + actions: [ + 'execute-api:Invoke', + 'execute-api:ManageConnections', + ], + })]), + deadLetterConfig: this.props?.deadLetterQueue && { arn: this.props.deadLetterQueue?.queueArn }, + input: this.props?.postBody, + targetResource: this.restApi, + httpParameters: { + headerParameters: this.props?.headerParameters, + queryStringParameters: this.props?.queryStringParameters, + pathParameterValues: this.props?.pathParameterValues, + }, + }; + } + +} + diff --git a/packages/@aws-cdk/aws-events-targets/lib/batch.ts b/packages/@aws-cdk/aws-events-targets/lib/batch.ts index 0d3e3c5b8409f..15a823549055c 100644 --- a/packages/@aws-cdk/aws-events-targets/lib/batch.ts +++ b/packages/@aws-cdk/aws-events-targets/lib/batch.ts @@ -1,12 +1,10 @@ -import * as batch from '@aws-cdk/aws-batch'; import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; -import { Names } from '@aws-cdk/core'; +import { Names, IConstruct } from '@aws-cdk/core'; import { singletonEventRole } from './util'; /** * Customize the Batch Job Event Target - * @experimental */ export interface BatchJobProps { /** @@ -44,12 +42,32 @@ export interface BatchJobProps { /** * Use an AWS Batch Job / Queue as an event rule target. - * @experimental + * Most likely the code will look something like this: + * `new BatchJob(jobQueue.jobQueueArn, jobQueue, jobDefinition.jobDefinitionArn, jobDefinition)` + * + * In the future this API will be improved to be fully typed */ export class BatchJob implements events.IRuleTarget { constructor( - private readonly jobQueue: batch.IJobQueue, - private readonly jobDefinition: batch.IJobDefinition, + /** + * The JobQueue arn + */ + private readonly jobQueueArn: string, + + /** + * The JobQueue Resource + */ + private readonly jobQueueScope: IConstruct, + + /** + * The jobDefinition arn + */ + private readonly jobDefinitionArn: string, + + /** + * The JobQueue Resource + */ + private readonly jobDefinitionScope: IConstruct, private readonly props: BatchJobProps = {}, ) { } @@ -59,27 +77,27 @@ export class BatchJob implements events.IRuleTarget { */ public bind(rule: events.IRule, _id?: string): events.RuleTargetConfig { const batchParameters: events.CfnRule.BatchParametersProperty = { - jobDefinition: this.jobDefinition.jobDefinitionArn, + jobDefinition: this.jobDefinitionArn, jobName: this.props.jobName ?? Names.nodeUniqueId(rule.node), arrayProperties: this.props.size ? { size: this.props.size } : undefined, retryStrategy: this.props.attempts ? { attempts: this.props.attempts } : undefined, }; return { - arn: this.jobQueue.jobQueueArn, + arn: this.jobQueueArn, // When scoping resource-level access for job submission, you must provide both job queue and job definition resource types. // https://docs.aws.amazon.com/batch/latest/userguide/ExamplePolicies_BATCH.html#iam-example-restrict-job-def - role: singletonEventRole(this.jobDefinition, [ + role: singletonEventRole(this.jobDefinitionScope, [ new iam.PolicyStatement({ actions: ['batch:SubmitJob'], resources: [ - this.jobDefinition.jobDefinitionArn, - this.jobQueue.jobQueueArn, + this.jobDefinitionArn, + this.jobQueueArn, ], }), ]), input: this.props.event, - targetResource: this.jobQueue, + targetResource: this.jobQueueScope, batchParameters, }; } diff --git a/packages/@aws-cdk/aws-events-targets/lib/codebuild.ts b/packages/@aws-cdk/aws-events-targets/lib/codebuild.ts index a5264b2abe378..a9da8719cfef7 100644 --- a/packages/@aws-cdk/aws-events-targets/lib/codebuild.ts +++ b/packages/@aws-cdk/aws-events-targets/lib/codebuild.ts @@ -1,13 +1,12 @@ import * as codebuild from '@aws-cdk/aws-codebuild'; import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; -import * as sqs from '@aws-cdk/aws-sqs'; -import { addToDeadLetterQueueResourcePolicy, singletonEventRole } from './util'; +import { addToDeadLetterQueueResourcePolicy, bindBaseTargetConfig, singletonEventRole, TargetBaseProps } from './util'; /** * Customize the CodeBuild Event Target */ -export interface CodeBuildProjectProps { +export interface CodeBuildProjectProps extends TargetBaseProps { /** * The role to assume before invoking the target @@ -25,18 +24,6 @@ export interface CodeBuildProjectProps { * @default - the entire EventBridge event */ readonly event?: events.RuleTargetInput; - - /** - * The SQS queue to be used as deadLetterQueue. - * Check out the [considerations for using a dead-letter queue](https://docs.aws.amazon.com/eventbridge/latest/userguide/rule-dlq.html#dlq-considerations). - * - * The events not successfully delivered are automatically retried for a specified period of time, - * depending on the retry policy of the target. - * If an event is not delivered before all retry attempts are exhausted, it will be sent to the dead letter queue. - * - * @default - no dead-letter queue - */ - readonly deadLetterQueue?: sqs.IQueue; } /** @@ -58,8 +45,8 @@ export class CodeBuildProject implements events.IRuleTarget { } return { + ...bindBaseTargetConfig(this.props), arn: this.project.projectArn, - deadLetterConfig: this.props.deadLetterQueue ? { arn: this.props.deadLetterQueue?.queueArn } : undefined, role: this.props.eventRole || singletonEventRole(this.project, [ new iam.PolicyStatement({ actions: ['codebuild:StartBuild'], diff --git a/packages/@aws-cdk/aws-events-targets/lib/codepipeline.ts b/packages/@aws-cdk/aws-events-targets/lib/codepipeline.ts index fc0eb095cfecd..8d2006378f121 100644 --- a/packages/@aws-cdk/aws-events-targets/lib/codepipeline.ts +++ b/packages/@aws-cdk/aws-events-targets/lib/codepipeline.ts @@ -1,12 +1,12 @@ import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; -import { singletonEventRole } from './util'; +import { bindBaseTargetConfig, singletonEventRole, TargetBaseProps } from './util'; /** * Customization options when creating a {@link CodePipeline} event target. */ -export interface CodePipelineTargetOptions { +export interface CodePipelineTargetOptions extends TargetBaseProps { /** * The role to assume before invoking the target * (i.e., the pipeline) when the given rule is triggered. @@ -27,6 +27,8 @@ export class CodePipeline implements events.IRuleTarget { public bind(_rule: events.IRule, _id?: string): events.RuleTargetConfig { return { + ...bindBaseTargetConfig(this.options), + id: '', arn: this.pipeline.pipelineArn, role: this.options.eventRole || singletonEventRole(this.pipeline, [new iam.PolicyStatement({ resources: [this.pipeline.pipelineArn], diff --git a/packages/@aws-cdk/aws-events-targets/lib/event-bus.ts b/packages/@aws-cdk/aws-events-targets/lib/event-bus.ts index 1d07261a8eace..8237b8cdd7993 100644 --- a/packages/@aws-cdk/aws-events-targets/lib/event-bus.ts +++ b/packages/@aws-cdk/aws-events-targets/lib/event-bus.ts @@ -24,13 +24,12 @@ export class EventBus implements events.IRuleTarget { this.role = props.role; } - bind(rule: events.IRule, id?: string): events.RuleTargetConfig { + bind(rule: events.IRule, _id?: string): events.RuleTargetConfig { if (this.role) { this.role.addToPrincipalPolicy(this.putEventStatement()); } const role = this.role ?? singletonEventRole(rule, [this.putEventStatement()]); return { - id: id ?? '', arn: this.eventBus.eventBusArn, role, }; diff --git a/packages/@aws-cdk/aws-events-targets/lib/index.ts b/packages/@aws-cdk/aws-events-targets/lib/index.ts index 155791c195d1e..bafb83751f468 100644 --- a/packages/@aws-cdk/aws-events-targets/lib/index.ts +++ b/packages/@aws-cdk/aws-events-targets/lib/index.ts @@ -12,3 +12,5 @@ export * from './state-machine'; export * from './kinesis-stream'; export * from './log-group'; export * from './kinesis-firehose-stream'; +export * from './api-gateway'; +export * from './util'; diff --git a/packages/@aws-cdk/aws-events-targets/lib/lambda.ts b/packages/@aws-cdk/aws-events-targets/lib/lambda.ts index 903b3a2f33683..8dd455ce51056 100644 --- a/packages/@aws-cdk/aws-events-targets/lib/lambda.ts +++ b/packages/@aws-cdk/aws-events-targets/lib/lambda.ts @@ -1,12 +1,11 @@ import * as events from '@aws-cdk/aws-events'; import * as lambda from '@aws-cdk/aws-lambda'; -import * as sqs from '@aws-cdk/aws-sqs'; -import { addLambdaPermission, addToDeadLetterQueueResourcePolicy } from './util'; +import { addLambdaPermission, addToDeadLetterQueueResourcePolicy, TargetBaseProps, bindBaseTargetConfig } from './util'; /** * Customize the Lambda Event Target */ -export interface LambdaFunctionProps { +export interface LambdaFunctionProps extends TargetBaseProps { /** * The event to send to the Lambda * @@ -15,18 +14,6 @@ export interface LambdaFunctionProps { * @default the entire EventBridge event */ readonly event?: events.RuleTargetInput; - - /** - * The SQS queue to be used as deadLetterQueue. - * Check out the [considerations for using a dead-letter queue](https://docs.aws.amazon.com/eventbridge/latest/userguide/rule-dlq.html#dlq-considerations). - * - * The events not successfully delivered are automatically retried for a specified period of time, - * depending on the retry policy of the target. - * If an event is not delivered before all retry attempts are exhausted, it will be sent to the dead letter queue. - * - * @default - no dead-letter queue - */ - readonly deadLetterQueue?: sqs.IQueue; } /** @@ -50,8 +37,8 @@ export class LambdaFunction implements events.IRuleTarget { } return { + ...bindBaseTargetConfig(this.props), arn: this.handler.functionArn, - deadLetterConfig: this.props.deadLetterQueue ? { arn: this.props.deadLetterQueue?.queueArn } : undefined, input: this.props.event, targetResource: this.handler, }; diff --git a/packages/@aws-cdk/aws-events-targets/lib/log-group.ts b/packages/@aws-cdk/aws-events-targets/lib/log-group.ts index d437adaf2375c..688cfc3773c13 100644 --- a/packages/@aws-cdk/aws-events-targets/lib/log-group.ts +++ b/packages/@aws-cdk/aws-events-targets/lib/log-group.ts @@ -3,11 +3,12 @@ import * as iam from '@aws-cdk/aws-iam'; import * as logs from '@aws-cdk/aws-logs'; import * as cdk from '@aws-cdk/core'; import { LogGroupResourcePolicy } from './log-group-resource-policy'; +import { TargetBaseProps, bindBaseTargetConfig } from './util'; /** * Customize the CloudWatch LogGroup Event Target */ -export interface LogGroupProps { +export interface LogGroupProps extends TargetBaseProps { /** * The event to send to the CloudWatch LogGroup * @@ -45,6 +46,7 @@ export class CloudWatchLogGroup implements events.IRuleTarget { } return { + ...bindBaseTargetConfig(this.props), arn: logGroupStack.formatArn({ service: 'logs', resource: 'log-group', diff --git a/packages/@aws-cdk/aws-events-targets/lib/state-machine.ts b/packages/@aws-cdk/aws-events-targets/lib/state-machine.ts index 2407a2023c96b..ce780bf99d2d2 100644 --- a/packages/@aws-cdk/aws-events-targets/lib/state-machine.ts +++ b/packages/@aws-cdk/aws-events-targets/lib/state-machine.ts @@ -1,13 +1,12 @@ import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; -import * as sqs from '@aws-cdk/aws-sqs'; import * as sfn from '@aws-cdk/aws-stepfunctions'; -import { addToDeadLetterQueueResourcePolicy, singletonEventRole } from './util'; +import { addToDeadLetterQueueResourcePolicy, bindBaseTargetConfig, singletonEventRole, TargetBaseProps } from './util'; /** * Customize the Step Functions State Machine target */ -export interface SfnStateMachineProps { +export interface SfnStateMachineProps extends TargetBaseProps { /** * The input to the state machine execution * @@ -21,18 +20,6 @@ export interface SfnStateMachineProps { * @default - a new role will be created */ readonly role?: iam.IRole; - - /** - * The SQS queue to be used as deadLetterQueue. - * Check out the [considerations for using a dead-letter queue](https://docs.aws.amazon.com/eventbridge/latest/userguide/rule-dlq.html#dlq-considerations). - * - * The events not successfully delivered are automatically retried for a specified period of time, - * depending on the retry policy of the target. - * If an event is not delivered before all retry attempts are exhausted, it will be sent to the dead letter queue. - * - * @default - no dead-letter queue - */ - readonly deadLetterQueue?: sqs.IQueue; } /** @@ -61,8 +48,8 @@ export class SfnStateMachine implements events.IRuleTarget { } return { + ...bindBaseTargetConfig(this.props), arn: this.machine.stateMachineArn, - deadLetterConfig: this.props.deadLetterQueue ? { arn: this.props.deadLetterQueue?.queueArn } : undefined, role: this.role, input: this.props.input, targetResource: this.machine, diff --git a/packages/@aws-cdk/aws-events-targets/lib/util.ts b/packages/@aws-cdk/aws-events-targets/lib/util.ts index 069b04a8c5131..6805b7245000f 100644 --- a/packages/@aws-cdk/aws-events-targets/lib/util.ts +++ b/packages/@aws-cdk/aws-events-targets/lib/util.ts @@ -2,17 +2,74 @@ import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; import * as lambda from '@aws-cdk/aws-lambda'; import * as sqs from '@aws-cdk/aws-sqs'; -import { Annotations, ConstructNode, IConstruct, Names, Token, TokenComparison } from '@aws-cdk/core'; +import { Annotations, ConstructNode, IConstruct, Names, Token, TokenComparison, Duration } from '@aws-cdk/core'; // keep this import separate from other imports to reduce chance for merge conflicts with v2-main // eslint-disable-next-line no-duplicate-imports, import/order import { Construct } from '@aws-cdk/core'; +/** + * The generic properties for an RuleTarget + */ +export interface TargetBaseProps { + /** + * The SQS queue to be used as deadLetterQueue. + * Check out the [considerations for using a dead-letter queue](https://docs.aws.amazon.com/eventbridge/latest/userguide/rule-dlq.html#dlq-considerations). + * + * The events not successfully delivered are automatically retried for a specified period of time, + * depending on the retry policy of the target. + * If an event is not delivered before all retry attempts are exhausted, it will be sent to the dead letter queue. + * + * @default - no dead-letter queue + */ + readonly deadLetterQueue?: sqs.IQueue; + /** + * The maximum age of a request that Lambda sends to a function for + * processing. + * + * Minimum value of 60. + * Maximum value of 86400. + * + * @default Duration.hours(24) + */ + readonly maxEventAge?: Duration; + + /** + * The maximum number of times to retry when the function returns an error. + * + * Minimum value of 0. + * Maximum value of 185. + * + * @default 185 + */ + readonly retryAttempts?: number; +} + +/** + * Bind props to base rule target config. + * @internal + */ +export function bindBaseTargetConfig(props: TargetBaseProps) { + let { deadLetterQueue, retryAttempts, maxEventAge } = props; + + return { + deadLetterConfig: deadLetterQueue ? { arn: deadLetterQueue?.queueArn } : undefined, + retryPolicy: retryAttempts || maxEventAge + ? { + maximumRetryAttempts: retryAttempts, + maximumEventAgeInSeconds: maxEventAge?.toSeconds({ integral: true }), + } + : undefined, + }; +} + + /** * Obtain the Role for the EventBridge event * * If a role already exists, it will be returned. This ensures that if multiple * events have the same target, they will share a role. + * @internal */ export function singletonEventRole(scope: IConstruct, policyStatements: iam.PolicyStatement[]): iam.IRole { const id = 'EventsRole'; @@ -30,6 +87,7 @@ export function singletonEventRole(scope: IConstruct, policyStatements: iam.Poli /** * Allows a Lambda function to be called from a rule + * @internal */ export function addLambdaPermission(rule: events.IRule, handler: lambda.IFunction): void { let scope: Construct | undefined; @@ -54,6 +112,7 @@ export function addLambdaPermission(rule: events.IRule, handler: lambda.IFunctio /** * Allow a rule to send events with failed invocation to an Amazon SQS queue. + * @internal */ export function addToDeadLetterQueueResourcePolicy(rule: events.IRule, queue: sqs.IQueue) { if (!sameEnvDimension(rule.env.region, queue.env.region)) { @@ -89,6 +148,7 @@ export function addToDeadLetterQueueResourcePolicy(rule: events.IRule, queue: sq * * Used to compare either accounts or regions, and also returns true if both * are unresolved (in which case both are expted to be "current region" or "current account"). + * @internal */ function sameEnvDimension(dim1: string, dim2: string) { return [TokenComparison.SAME, TokenComparison.BOTH_UNRESOLVED].includes(Token.compareStrings(dim1, dim2)); diff --git a/packages/@aws-cdk/aws-events-targets/package.json b/packages/@aws-cdk/aws-events-targets/package.json index a4eee23c9a028..e36df0baf5c71 100644 --- a/packages/@aws-cdk/aws-events-targets/package.json +++ b/packages/@aws-cdk/aws-events-targets/package.json @@ -71,18 +71,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", + "@aws-cdk/aws-batch": "0.0.0", "aws-sdk": "^2.848.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { - "@aws-cdk/aws-batch": "0.0.0", + "@aws-cdk/aws-apigateway": "0.0.0", "@aws-cdk/aws-codebuild": "0.0.0", "@aws-cdk/aws-codepipeline": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", @@ -99,11 +101,11 @@ "@aws-cdk/aws-stepfunctions": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { - "@aws-cdk/aws-batch": "0.0.0", + "@aws-cdk/aws-apigateway": "0.0.0", "@aws-cdk/aws-codebuild": "0.0.0", "@aws-cdk/aws-codepipeline": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", @@ -120,7 +122,7 @@ "@aws-cdk/aws-stepfunctions": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" @@ -132,6 +134,7 @@ "docs-public-apis:@aws-cdk/aws-events-targets.SfnStateMachine.machine", "docs-public-apis:@aws-cdk/aws-events-targets.SnsTopic.topic", "docs-public-apis:@aws-cdk/aws-events-targets.SqsQueue.queue", + "docs-public-apis:@aws-cdk/aws-events-targets.ApiGateway.restApi", "docs-public-apis:@aws-cdk/aws-events-targets.ContainerOverride", "props-default-doc:@aws-cdk/aws-events-targets.ContainerOverride.environment", "props-default-doc:@aws-cdk/aws-events-targets.EcsTaskProps.containerOverrides" diff --git a/packages/@aws-cdk/aws-events-targets/test/api-gateway/api-gateway.test.ts b/packages/@aws-cdk/aws-events-targets/test/api-gateway/api-gateway.test.ts new file mode 100644 index 0000000000000..7c1033537dd41 --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/test/api-gateway/api-gateway.test.ts @@ -0,0 +1,263 @@ +import '@aws-cdk/assert-internal/jest'; +import * as api from '@aws-cdk/aws-apigateway'; +import * as events from '@aws-cdk/aws-events'; +import * as iam from '@aws-cdk/aws-iam'; +import * as lambda from '@aws-cdk/aws-lambda'; +import * as sqs from '@aws-cdk/aws-sqs'; +import * as cdk from '@aws-cdk/core'; +import * as constructs from 'constructs'; +import * as targets from '../../lib'; + +test('use api gateway rest api as an event rule target', () => { + // GIVEN + const stack = new cdk.Stack(); + const restApi = newTestRestApi(stack); + const rule = new events.Rule(stack, 'Rule', { + schedule: events.Schedule.rate(cdk.Duration.minutes(1)), + }); + + // WHEN + rule.addTarget(new targets.ApiGateway(restApi)); + + // THEN + expect(stack).toHaveResource('AWS::Events::Rule', { + Targets: [ + { + Arn: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':execute-api:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':', + { + Ref: 'MyLambdaRestApiECB8AFAF', + }, + '/', + { + Ref: 'MyLambdaRestApiDeploymentStageprodA127C527', + }, + '/*/', + ], + ], + }, + HttpParameters: {}, + Id: 'Target0', + RoleArn: { + 'Fn::GetAtt': [ + 'MyLambdaRestApiEventsRole3C0505CC', + 'Arn', + ], + }, + }, + ], + }); +}); + +test('with stage, path, method setting', () => { + // GIVEN + const stack = new cdk.Stack(); + const restApi = newTestRestApi(stack); + const rule = new events.Rule(stack, 'Rule', { + schedule: events.Schedule.rate(cdk.Duration.minutes(1)), + }); + + // WHEN + const stage = 'test-stage'; + const path = '/test-path'; + const method = 'GET'; + rule.addTarget(new targets.ApiGateway(restApi, { + stage, path, method, + })); + + // THEN + expect(stack).toHaveResource('AWS::Events::Rule', { + Targets: [ + { + Arn: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':execute-api:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':', + { + Ref: 'MyLambdaRestApiECB8AFAF', + }, + '/test-stage/GET/test-path', + ], + ], + }, + HttpParameters: {}, + Id: 'Target0', + RoleArn: { + 'Fn::GetAtt': [ + 'MyLambdaRestApiEventsRole3C0505CC', + 'Arn', + ], + }, + }, + ], + }); +}); + +test('with http parameters', () => { + // GIVEN + const stack = new cdk.Stack(); + const restApi = newTestRestApi(stack); + const rule = new events.Rule(stack, 'Rule', { + schedule: events.Schedule.rate(cdk.Duration.minutes(1)), + }); + + // WHEN + const pathParameterValues = ['path1', 'path2']; + const headerParameters = { + TestHeader1: 'test-header-value-1', + TestHeader2: 'test-header-value-2', + }; + const queryStringParameters = { + TestQueryParameter1: 'test-query-parameter-value-1', + TestQueryParameter2: 'test-query-parameter-value-2', + }; + rule.addTarget(new targets.ApiGateway(restApi, { + path: '/*/*', + pathParameterValues, + headerParameters, + queryStringParameters, + })); + + // THEN + expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Targets: [ + { + HttpParameters: { + HeaderParameters: headerParameters, + QueryStringParameters: queryStringParameters, + PathParameterValues: pathParameterValues, + }, + Id: 'Target0', + }, + ], + }); +}); + +test('Throw when the number of wild cards in the path not equal to the number of pathParameterValues', () => { + // GIVEN + const stack = new cdk.Stack(); + const restApi = newTestRestApi(stack); + const rule = new events.Rule(stack, 'Rule', { + schedule: events.Schedule.rate(cdk.Duration.minutes(1)), + }); + + // WHEN, THEN + expect(() => rule.addTarget(new targets.ApiGateway(restApi, { + pathParameterValues: ['value1'], + }))).toThrow(/The number of wildcards in the path does not match the number of path pathParameterValues/); + expect(() => rule.addTarget(new targets.ApiGateway(restApi, { + path: '/*', + }))).toThrow(/The number of wildcards in the path does not match the number of path pathParameterValues/); + expect(() => rule.addTarget(new targets.ApiGateway(restApi, { + path: '/*/*', + pathParameterValues: ['value1'], + }))).toThrow(/The number of wildcards in the path does not match the number of path pathParameterValues/); + expect(() => rule.addTarget(new targets.ApiGateway(restApi, { + path: '/*/*', + pathParameterValues: ['value1', 'value2'], + }))).not.toThrow(); + +}); + +test('with an explicit event role', () => { + // GIVEN + const stack = new cdk.Stack(); + const restApi = newTestRestApi(stack); + const rule = new events.Rule(stack, 'Rule', { + schedule: events.Schedule.rate(cdk.Duration.minutes(1)), + }); + + // WHEN + const eventRole = new iam.Role(stack, 'Trigger-test-role', { + assumedBy: new iam.ServicePrincipal('events.amazonaws.com'), + }); + rule.addTarget(new targets.ApiGateway(restApi, { + eventRole, + })); + + // THEN + expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Targets: [ + { + RoleArn: { + 'Fn::GetAtt': [ + 'TriggertestroleBCF8E6AD', + 'Arn', + ], + }, + Id: 'Target0', + }, + ], + }); +}); + +test('use a Dead Letter Queue', () => { + // GIVEN + const stack = new cdk.Stack(); + const restApi = newTestRestApi(stack); + const rule = new events.Rule(stack, 'Rule', { + schedule: events.Schedule.rate(cdk.Duration.minutes(1)), + }); + + // WHEN + const queue = new sqs.Queue(stack, 'Queue'); + rule.addTarget(new targets.ApiGateway(restApi, { + deadLetterQueue: queue, + })); + + // THEN + expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Targets: [ + { + DeadLetterConfig: { + Arn: { + 'Fn::GetAtt': [ + 'Queue4A7E3555', + 'Arn', + ], + }, + }, + Id: 'Target0', + }, + ], + }); +}); + +function newTestRestApi(scope: constructs.Construct, suffix = '') { + const lambdaFunctin = new lambda.Function(scope, `MyLambda${suffix}`, { + code: new lambda.InlineCode('foo'), + handler: 'bar', + runtime: lambda.Runtime.NODEJS_12_X, + }); + return new api.LambdaRestApi( scope, `MyLambdaRestApi${suffix}`, { + handler: lambdaFunctin, + } ); +} diff --git a/packages/@aws-cdk/aws-events-targets/test/aws-api/aws-api.test.ts b/packages/@aws-cdk/aws-events-targets/test/aws-api/aws-api.test.ts index 2a93175e9c6e6..e43c9708574fc 100644 --- a/packages/@aws-cdk/aws-events-targets/test/aws-api/aws-api.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/aws-api/aws-api.test.ts @@ -1,4 +1,4 @@ -import { countResources, expect, haveResource } from '@aws-cdk/assert'; +import { countResources, expect, haveResource } from '@aws-cdk/assert-internal'; import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; import { Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-events-targets/test/batch/batch.test.ts b/packages/@aws-cdk/aws-events-targets/test/batch/batch.test.ts index 7d4ab3b3f685e..acdf2477832f5 100644 --- a/packages/@aws-cdk/aws-events-targets/test/batch/batch.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/batch/batch.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as batch from '@aws-cdk/aws-batch'; import { ContainerImage } from '@aws-cdk/aws-ecs'; import * as events from '@aws-cdk/aws-events'; @@ -28,7 +28,7 @@ test('use aws batch job as an eventrule target', () => { }); // WHEN - rule.addTarget(new targets.BatchJob(jobQueue, jobDefinition)); + rule.addTarget(new targets.BatchJob(jobQueue.jobQueueArn, jobQueue, jobDefinition.jobDefinitionArn, jobDefinition)); // THEN expect(stack).to(haveResource('AWS::Events::Rule', { diff --git a/packages/@aws-cdk/aws-events-targets/test/batch/integ.job-definition-events.ts b/packages/@aws-cdk/aws-events-targets/test/batch/integ.job-definition-events.ts index d09960c142971..01d1058eb4064 100644 --- a/packages/@aws-cdk/aws-events-targets/test/batch/integ.job-definition-events.ts +++ b/packages/@aws-cdk/aws-events-targets/test/batch/integ.job-definition-events.ts @@ -27,11 +27,11 @@ const job = new batch.JobDefinition(stack, 'MyJob', { const timer = new events.Rule(stack, 'Timer', { schedule: events.Schedule.rate(cdk.Duration.minutes(1)), }); -timer.addTarget(new targets.BatchJob(queue, job)); +timer.addTarget(new targets.BatchJob(queue.jobQueueArn, queue, job.jobDefinitionArn, job)); const timer2 = new events.Rule(stack, 'Timer2', { schedule: events.Schedule.rate(cdk.Duration.minutes(2)), }); -timer2.addTarget(new targets.BatchJob(queue, job)); +timer2.addTarget(new targets.BatchJob(queue.jobQueueArn, queue, job.jobDefinitionArn, job)); app.synth(); diff --git a/packages/@aws-cdk/aws-events-targets/test/codebuild/codebuild.test.ts b/packages/@aws-cdk/aws-events-targets/test/codebuild/codebuild.test.ts index 1eba641d7c8ce..9ad848433a981 100644 --- a/packages/@aws-cdk/aws-events-targets/test/codebuild/codebuild.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/codebuild/codebuild.test.ts @@ -1,9 +1,9 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; import * as sqs from '@aws-cdk/aws-sqs'; -import { CfnElement, Stack } from '@aws-cdk/core'; +import { CfnElement, Duration, Stack } from '@aws-cdk/core'; import * as targets from '../../lib'; describe('CodeBuild event target', () => { @@ -122,6 +122,54 @@ describe('CodeBuild event target', () => { })); }); + test('specifying retry policy', () => { + // GIVEN + const rule = new events.Rule(stack, 'Rule', { + schedule: events.Schedule.expression('rate(1 hour)'), + }); + + // WHEN + const eventInput = { + buildspecOverride: 'buildspecs/hourly.yml', + }; + + rule.addTarget( + new targets.CodeBuildProject(project, { + event: events.RuleTargetInput.fromObject(eventInput), + retryAttempts: 2, + maxEventAge: Duration.hours(2), + }), + ); + + // THEN + expect(stack).to(haveResource('AWS::Events::Rule', { + ScheduleExpression: 'rate(1 hour)', + State: 'ENABLED', + Targets: [ + { + Arn: { + 'Fn::GetAtt': [ + 'MyProject39F7B0AE', + 'Arn', + ], + }, + Id: 'Target0', + Input: '{"buildspecOverride":"buildspecs/hourly.yml"}', + RetryPolicy: { + MaximumEventAgeInSeconds: 7200, + MaximumRetryAttempts: 2, + }, + RoleArn: { + 'Fn::GetAtt': [ + 'MyProjectEventsRole5B7D93F5', + 'Arn', + ], + }, + }, + ], + })); + }); + test('use a Dead Letter Queue for the rule target', () => { // GIVEN const rule = new events.Rule(stack, 'Rule', { diff --git a/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.expected.json b/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.expected.json index aec41898a4622..6d65b68ccb033 100644 --- a/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.expected.json @@ -51,6 +51,10 @@ ] } }, + "RetryPolicy": { + "MaximumEventAgeInSeconds": 7200, + "MaximumRetryAttempts": 2 + }, "Id": "Target0", "RoleArn": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.ts b/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.ts index 7974a4188f969..83b48805d2387 100644 --- a/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.ts +++ b/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.ts @@ -42,6 +42,8 @@ project.onPhaseChange('PhaseChange', { const onCommitRule = repo.onCommit('OnCommit', { target: new targets.CodeBuildProject(project, { deadLetterQueue: deadLetterQueue, + maxEventAge: cdk.Duration.hours(2), + retryAttempts: 2, }), branches: ['master'], }); diff --git a/packages/@aws-cdk/aws-events-targets/test/codepipeline/integ.pipeline-event-target.expected.json b/packages/@aws-cdk/aws-events-targets/test/codepipeline/integ.pipeline-event-target.expected.json index 66418749eda33..7f2c9d48da34b 100644 --- a/packages/@aws-cdk/aws-events-targets/test/codepipeline/integ.pipeline-event-target.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/codepipeline/integ.pipeline-event-target.expected.json @@ -397,6 +397,11 @@ ] } }, + "dlq09C78ACC": { + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, "ruleF2C1DCDC": { "Type": "AWS::Events::Rule", "Properties": { @@ -427,7 +432,19 @@ ] ] }, + "DeadLetterConfig": { + "Arn": { + "Fn::GetAtt": [ + "dlq09C78ACC", + "Arn" + ] + } + }, "Id": "Target0", + "RetryPolicy": { + "MaximumEventAgeInSeconds": 7200, + "MaximumRetryAttempts": 2 + }, "RoleArn": { "Fn::GetAtt": [ "pipelinePipeline22F2A91DEventsRole048D7F59", diff --git a/packages/@aws-cdk/aws-events-targets/test/codepipeline/integ.pipeline-event-target.ts b/packages/@aws-cdk/aws-events-targets/test/codepipeline/integ.pipeline-event-target.ts index b4f321230234f..dafad82627605 100644 --- a/packages/@aws-cdk/aws-events-targets/test/codepipeline/integ.pipeline-event-target.ts +++ b/packages/@aws-cdk/aws-events-targets/test/codepipeline/integ.pipeline-event-target.ts @@ -1,6 +1,7 @@ import * as codecommit from '@aws-cdk/aws-codecommit'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as events from '@aws-cdk/aws-events'; +import * as sqs from '@aws-cdk/aws-sqs'; import * as cdk from '@aws-cdk/core'; import * as constructs from 'constructs'; import * as targets from '../../lib'; @@ -64,9 +65,15 @@ pipeline.addStage({ })], }); +let queue = new sqs.Queue(stack, 'dlq'); + new events.Rule(stack, 'rule', { schedule: events.Schedule.expression('rate(1 minute)'), - targets: [new targets.CodePipeline(pipeline)], + targets: [new targets.CodePipeline(pipeline, { + deadLetterQueue: queue, + maxEventAge: cdk.Duration.hours(2), + retryAttempts: 2, + })], }); app.synth(); diff --git a/packages/@aws-cdk/aws-events-targets/test/codepipeline/pipeline.test.ts b/packages/@aws-cdk/aws-events-targets/test/codepipeline/pipeline.test.ts index 68ee1a10ae449..79dc7408cd4f7 100644 --- a/packages/@aws-cdk/aws-events-targets/test/codepipeline/pipeline.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/codepipeline/pipeline.test.ts @@ -1,8 +1,9 @@ -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; -import { CfnElement, Stack } from '@aws-cdk/core'; +import * as sqs from '@aws-cdk/aws-sqs'; +import { CfnElement, Duration, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; import * as targets from '../../lib'; @@ -93,6 +94,71 @@ describe('CodePipeline event target', () => { }); }); + describe('with retry policy and dead letter queue', () => { + test('adds retry attempts and maxEventAge to the target configuration', () => { + // WHEN + let queue = new sqs.Queue(stack, 'dlq'); + + rule.addTarget(new targets.CodePipeline(pipeline, { + retryAttempts: 2, + maxEventAge: Duration.hours(2), + deadLetterQueue: queue, + })); + + // THEN + expect(stack).to(haveResource('AWS::Events::Rule', { + ScheduleExpression: 'rate(1 minute)', + State: 'ENABLED', + Targets: [ + { + Arn: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':codepipeline:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':', + { + Ref: 'PipelineC660917D', + }, + ], + ], + }, + DeadLetterConfig: { + Arn: { + 'Fn::GetAtt': [ + 'dlq09C78ACC', + 'Arn', + ], + }, + }, + Id: 'Target0', + RetryPolicy: { + MaximumEventAgeInSeconds: 7200, + MaximumRetryAttempts: 2, + }, + RoleArn: { + 'Fn::GetAtt': [ + 'PipelineEventsRole46BEEA7C', + 'Arn', + ], + }, + }, + ], + })); + }); + }); + describe('with an explicit event role', () => { beforeEach(() => { const role = new iam.Role(stack, 'MyExampleRole', { 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 f0ab7770fadbd..1b084a0ec35b1 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 @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; import * as events from '@aws-cdk/aws-events'; diff --git a/packages/@aws-cdk/aws-events-targets/test/ecs/integ.event-ec2-task.lit.expected.json b/packages/@aws-cdk/aws-events-targets/test/ecs/integ.event-ec2-task.lit.expected.json index 6dc9c62e63102..dbdb415e57e63 100644 --- a/packages/@aws-cdk/aws-events-targets/test/ecs/integ.event-ec2-task.lit.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/ecs/integ.event-ec2-task.lit.expected.json @@ -534,7 +534,7 @@ "Type": "AWS::Lambda::Function", "Properties": { "Code": { - "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" + "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n task_arns = container_instance_task_arns(cluster, instance_arn)\n \n if task_arns:\n print('Instance ARN %s has task ARNs %s' % (instance_arn, ', '.join(task_arns)))\n\n while has_tasks(cluster, instance_arn, task_arns):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\ndef container_instance_task_arns(cluster, instance_arn):\n \"\"\"Fetch tasks for a container instance ARN.\"\"\"\n arns = ecs.list_tasks(cluster=cluster, containerInstance=instance_arn)['taskArns']\n return arns\n\ndef has_tasks(cluster, instance_arn, task_arns):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n task_count = None\n\n if task_arns:\n # Fetch details for tasks running on the container instance\n tasks = ecs.describe_tasks(cluster=cluster, tasks=task_arns)['tasks']\n if tasks:\n # Consider any non-stopped tasks as running\n task_count = sum(task['lastStatus'] != 'STOPPED' for task in tasks) + instance['pendingTasksCount']\n \n if not task_count:\n # Fallback to instance task counts if detailed task information is unavailable\n task_count = instance['runningTasksCount'] + instance['pendingTasksCount']\n \n print('Instance %s has %s tasks' % (instance_arn, task_count))\n\n return task_count > 0\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, "Role": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk/aws-events-targets/test/event-bus/event-rule-target.test.ts b/packages/@aws-cdk/aws-events-targets/test/event-bus/event-rule-target.test.ts index 4c39a907210d7..8d188f1550e8b 100644 --- a/packages/@aws-cdk/aws-events-targets/test/event-bus/event-rule-target.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/event-bus/event-rule-target.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; import { Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-events-targets/test/kinesis-firehose/kinesis-firehose-stream.test.ts b/packages/@aws-cdk/aws-events-targets/test/kinesis-firehose/kinesis-firehose-stream.test.ts index 556816853fee2..6896f2c9bf934 100644 --- a/packages/@aws-cdk/aws-events-targets/test/kinesis-firehose/kinesis-firehose-stream.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/kinesis-firehose/kinesis-firehose-stream.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; import * as events from '@aws-cdk/aws-events'; import * as firehose from '@aws-cdk/aws-kinesisfirehose'; import { Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-events-targets/test/kinesis/kinesis-stream.test.ts b/packages/@aws-cdk/aws-events-targets/test/kinesis/kinesis-stream.test.ts index 79119c5bfcf63..a36e57dfa4dc2 100644 --- a/packages/@aws-cdk/aws-events-targets/test/kinesis/kinesis-stream.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/kinesis/kinesis-stream.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; import * as events from '@aws-cdk/aws-events'; import * as kinesis from '@aws-cdk/aws-kinesis'; import { Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-events-targets/test/lambda/integ.events.expected.json b/packages/@aws-cdk/aws-events-targets/test/lambda/integ.events.expected.json index 7df2a4becf021..32474ae439abf 100644 --- a/packages/@aws-cdk/aws-events-targets/test/lambda/integ.events.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/lambda/integ.events.expected.json @@ -145,7 +145,11 @@ ] } }, - "Id": "Target0" + "Id": "Target0", + "RetryPolicy": { + "MaximumEventAgeInSeconds": 7200, + "MaximumRetryAttempts": 2 + } } ] } diff --git a/packages/@aws-cdk/aws-events-targets/test/lambda/integ.events.ts b/packages/@aws-cdk/aws-events-targets/test/lambda/integ.events.ts index c37c632d803ae..3991d56d9ef56 100644 --- a/packages/@aws-cdk/aws-events-targets/test/lambda/integ.events.ts +++ b/packages/@aws-cdk/aws-events-targets/test/lambda/integ.events.ts @@ -33,6 +33,8 @@ const queue = new sqs.Queue(stack, 'Queue'); timer3.addTarget(new targets.LambdaFunction(fn, { deadLetterQueue: queue, + maxEventAge: cdk.Duration.hours(2), + retryAttempts: 2, })); app.synth(); diff --git a/packages/@aws-cdk/aws-events-targets/test/lambda/lambda.test.ts b/packages/@aws-cdk/aws-events-targets/test/lambda/lambda.test.ts index c5fd260715293..b1222b9e178f5 100644 --- a/packages/@aws-cdk/aws-events-targets/test/lambda/lambda.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/lambda/lambda.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as events from '@aws-cdk/aws-events'; import * as lambda from '@aws-cdk/aws-lambda'; import * as sqs from '@aws-cdk/aws-sqs'; @@ -325,6 +325,52 @@ test('must display a warning when using a Dead Letter Queue from another account expect(rule?.node.metadata[0].data).toMatch(/Cannot add a resource policy to your dead letter queue associated with rule .* because the queue is in a different account\. You must add the resource policy manually to the dead letter queue in account 222222222222\./); }); + +test('specifying retry policy', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + + const fn = new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'bar', + runtime: lambda.Runtime.PYTHON_2_7, + }); + + // WHEN + new events.Rule(stack, 'Rule', { + schedule: events.Schedule.rate(cdk.Duration.minutes(1)), + targets: [new targets.LambdaFunction(fn, { + retryAttempts: 2, + maxEventAge: cdk.Duration.hours(2), + })], + }); + + // THEN + expect(() => app.synth()).not.toThrow(); + + // the Permission resource should be in the event stack + expect(stack).toHaveResource('AWS::Events::Rule', { + ScheduleExpression: 'rate(1 minute)', + State: 'ENABLED', + Targets: [ + { + Arn: { + 'Fn::GetAtt': [ + 'MyLambdaCCE802FB', + 'Arn', + ], + }, + Id: 'Target0', + RetryPolicy: { + MaximumEventAgeInSeconds: 7200, + MaximumRetryAttempts: 2, + }, + }, + ], + }); +}); + function newTestLambda(scope: constructs.Construct, suffix = '') { return new lambda.Function(scope, `MyLambda${suffix}`, { code: new lambda.InlineCode('foo'), diff --git a/packages/@aws-cdk/aws-events-targets/test/logs/integ.log-group.expected.json b/packages/@aws-cdk/aws-events-targets/test/logs/integ.log-group.expected.json index 9a150d9cafa32..9764d7387b08a 100644 --- a/packages/@aws-cdk/aws-events-targets/test/logs/integ.log-group.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/logs/integ.log-group.expected.json @@ -172,7 +172,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3Bucket65227904" + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3Bucket4DD075F7" }, "S3Key": { "Fn::Join": [ @@ -185,7 +185,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF" + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7" } ] } @@ -198,7 +198,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF" + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7" } ] } @@ -337,6 +337,11 @@ "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, + "dlq09C78ACC": { + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, "Timer30894E3BB": { "Type": "AWS::Events::Rule", "Properties": { @@ -364,7 +369,19 @@ ] ] }, - "Id": "Target0" + "DeadLetterConfig": { + "Arn": { + "Fn::GetAtt": [ + "dlq09C78ACC", + "Arn" + ] + } + }, + "Id": "Target0", + "RetryPolicy": { + "MaximumEventAgeInSeconds": 7200, + "MaximumRetryAttempts": 2 + } } ] } @@ -455,17 +472,17 @@ } }, "Parameters": { - "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3Bucket65227904": { + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3Bucket4DD075F7": { "Type": "String", - "Description": "S3 bucket for asset \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\"" + "Description": "S3 bucket for asset \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" }, - "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF": { + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7": { "Type": "String", - "Description": "S3 key for asset version \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\"" + "Description": "S3 key for asset version \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" }, - "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343ArtifactHash0C561FF5": { + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98ArtifactHash35A756EB": { "Type": "String", - "Description": "Artifact hash for asset \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\"" + "Description": "Artifact hash for asset \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-events-targets/test/logs/integ.log-group.ts b/packages/@aws-cdk/aws-events-targets/test/logs/integ.log-group.ts index 6d813dd3df3dd..1848f0d360a6b 100644 --- a/packages/@aws-cdk/aws-events-targets/test/logs/integ.log-group.ts +++ b/packages/@aws-cdk/aws-events-targets/test/logs/integ.log-group.ts @@ -1,5 +1,7 @@ +/// !cdk-integ pragma:ignore-assets import * as events from '@aws-cdk/aws-events'; import * as logs from '@aws-cdk/aws-logs'; +import * as sqs from '@aws-cdk/aws-sqs'; import * as cdk from '@aws-cdk/core'; import * as targets from '../../lib'; @@ -38,10 +40,16 @@ timer2.addTarget(new targets.CloudWatchLogGroup(logGroup2, { }), })); +const queue = new sqs.Queue(stack, 'dlq'); + const timer3 = new events.Rule(stack, 'Timer3', { schedule: events.Schedule.rate(cdk.Duration.minutes(1)), }); -timer3.addTarget(new targets.CloudWatchLogGroup(importedLogGroup)); +timer3.addTarget(new targets.CloudWatchLogGroup(importedLogGroup, { + deadLetterQueue: queue, + maxEventAge: cdk.Duration.hours(2), + retryAttempts: 2, +})); app.synth(); diff --git a/packages/@aws-cdk/aws-events-targets/test/logs/log-group-resource-policy.test.ts b/packages/@aws-cdk/aws-events-targets/test/logs/log-group-resource-policy.test.ts index e60c4b84be8bb..4193c9899e3cb 100644 --- a/packages/@aws-cdk/aws-events-targets/test/logs/log-group-resource-policy.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/logs/log-group-resource-policy.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as iam from '@aws-cdk/aws-iam'; import { App, Stack } from '@aws-cdk/core'; import { LogGroupResourcePolicy } from '../../lib/log-group-resource-policy'; diff --git a/packages/@aws-cdk/aws-events-targets/test/logs/log-group.test.ts b/packages/@aws-cdk/aws-events-targets/test/logs/log-group.test.ts index 6df5ad191770a..e9c1170fe8bb0 100644 --- a/packages/@aws-cdk/aws-events-targets/test/logs/log-group.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/logs/log-group.test.ts @@ -1,6 +1,7 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as events from '@aws-cdk/aws-events'; import * as logs from '@aws-cdk/aws-logs'; +import * as sqs from '@aws-cdk/aws-sqs'; import * as cdk from '@aws-cdk/core'; import * as targets from '../../lib'; @@ -110,3 +111,78 @@ test('use log group as an event rule target with rule target input', () => { ], }); }); + +test('specifying retry policy and dead letter queue', () => { + // GIVEN + const stack = new cdk.Stack(); + const logGroup = new logs.LogGroup(stack, 'MyLogGroup', { + logGroupName: '/aws/events/MyLogGroup', + }); + const rule1 = new events.Rule(stack, 'Rule', { + schedule: events.Schedule.rate(cdk.Duration.minutes(1)), + }); + + const queue = new sqs.Queue(stack, 'Queue'); + + // WHEN + rule1.addTarget(new targets.CloudWatchLogGroup(logGroup, { + event: events.RuleTargetInput.fromObject({ + data: events.EventField.fromPath('$'), + }), + retryAttempts: 2, + maxEventAge: cdk.Duration.hours(2), + deadLetterQueue: queue, + })); + + // THEN + expect(stack).toHaveResource('AWS::Events::Rule', { + ScheduleExpression: 'rate(1 minute)', + State: 'ENABLED', + Targets: [ + { + Arn: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':logs:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':log-group:', + { + Ref: 'MyLogGroup5C0DAD85', + }, + ], + ], + }, + DeadLetterConfig: { + Arn: { + 'Fn::GetAtt': [ + 'Queue4A7E3555', + 'Arn', + ], + }, + }, + Id: 'Target0', + InputTransformer: { + InputPathsMap: { + f1: '$', + }, + InputTemplate: '{"data":}', + }, + RetryPolicy: { + MaximumEventAgeInSeconds: 7200, + MaximumRetryAttempts: 2, + }, + }, + ], + }); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-events-targets/test/sns/sns.test.ts b/packages/@aws-cdk/aws-events-targets/test/sns/sns.test.ts index cd674d034d190..11d6a2c6806bd 100644 --- a/packages/@aws-cdk/aws-events-targets/test/sns/sns.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/sns/sns.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as events from '@aws-cdk/aws-events'; import * as sns from '@aws-cdk/aws-sns'; import { Duration, Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-events-targets/test/sqs/sqs.test.ts b/packages/@aws-cdk/aws-events-targets/test/sqs/sqs.test.ts index 6d60dc698e5a8..8893a8820f37e 100644 --- a/packages/@aws-cdk/aws-events-targets/test/sqs/sqs.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/sqs/sqs.test.ts @@ -1,4 +1,4 @@ -import { expect as cdkExpect, haveResource } from '@aws-cdk/assert'; +import { expect as cdkExpect, haveResource } from '@aws-cdk/assert-internal'; import * as events from '@aws-cdk/aws-events'; import * as sqs from '@aws-cdk/aws-sqs'; import { Duration, Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-events-targets/test/stepfunctions/statemachine.test.ts b/packages/@aws-cdk/aws-events-targets/test/stepfunctions/statemachine.test.ts index 9dc3b2d0a4e83..d50e41c1debce 100644 --- a/packages/@aws-cdk/aws-events-targets/test/stepfunctions/statemachine.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/stepfunctions/statemachine.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; import * as sqs from '@aws-cdk/aws-sqs'; @@ -112,6 +112,54 @@ test('Existing role can be used for State machine Rule target', () => { }); }); +test('specifying retry policy', () => { + // GIVEN + const stack = new cdk.Stack(); + const rule = new events.Rule(stack, 'Rule', { + schedule: events.Schedule.expression('rate(1 hour)'), + }); + + // WHEN + const role = new iam.Role(stack, 'Role', { + assumedBy: new iam.ServicePrincipal('events.amazonaws.com'), + }); + const stateMachine = new sfn.StateMachine(stack, 'SM', { + definition: new sfn.Wait(stack, 'Hello', { time: sfn.WaitTime.duration(cdk.Duration.seconds(10)) }), + role, + }); + + rule.addTarget(new targets.SfnStateMachine(stateMachine, { + input: events.RuleTargetInput.fromObject({ SomeParam: 'SomeValue' }), + maxEventAge: cdk.Duration.hours(2), + retryAttempts: 2, + })); + + // THEN + expect(stack).toHaveResource('AWS::Events::Rule', { + ScheduleExpression: 'rate(1 hour)', + State: 'ENABLED', + Targets: [ + { + Arn: { + Ref: 'SM934E715A', + }, + Id: 'Target0', + Input: '{"SomeParam":"SomeValue"}', + RetryPolicy: { + MaximumEventAgeInSeconds: 7200, + MaximumRetryAttempts: 2, + }, + RoleArn: { + 'Fn::GetAtt': [ + 'SMEventsRoleB320A902', + 'Arn', + ], + }, + }, + ], + }); +}); + test('use a Dead Letter Queue for the rule target', () => { // GIVEN const app = new cdk.App(); diff --git a/packages/@aws-cdk/aws-events/lib/rule.ts b/packages/@aws-cdk/aws-events/lib/rule.ts index 2c71054b60828..9962328f97619 100644 --- a/packages/@aws-cdk/aws-events/lib/rule.ts +++ b/packages/@aws-cdk/aws-events/lib/rule.ts @@ -296,7 +296,9 @@ export class Rule extends Resource implements IRule { runCommandParameters: targetProps.runCommandParameters, batchParameters: targetProps.batchParameters, deadLetterConfig: targetProps.deadLetterConfig, + retryPolicy: targetProps.retryPolicy, sqsParameters: targetProps.sqsParameters, + httpParameters: targetProps.httpParameters, input: inputProps && inputProps.input, inputPath: inputProps && inputProps.inputPath, inputTransformer: inputProps?.inputTemplate !== undefined ? { diff --git a/packages/@aws-cdk/aws-events/lib/schedule.ts b/packages/@aws-cdk/aws-events/lib/schedule.ts index c12afde30aa01..a3fcbaf399283 100644 --- a/packages/@aws-cdk/aws-events/lib/schedule.ts +++ b/packages/@aws-cdk/aws-events/lib/schedule.ts @@ -17,11 +17,11 @@ export abstract class Schedule { * Construct a schedule from an interval and a time unit */ public static rate(duration: Duration): Schedule { - const validDurationUnit = ['minute', 'minutes', 'hour', 'hours', 'day', 'days']; - if (validDurationUnit.indexOf(duration.unitLabel()) === -1) { - throw new Error('Allowed unit for scheduling is: \'minute\', \'minutes\', \'hour\', \'hours\', \'day\', \'days\''); - } if (duration.isUnresolved()) { + const validDurationUnit = ['minute', 'minutes', 'hour', 'hours', 'day', 'days']; + if (validDurationUnit.indexOf(duration.unitLabel()) === -1) { + throw new Error("Allowed units for scheduling are: 'minute', 'minutes', 'hour', 'hours', 'day', 'days'"); + } return new LiteralSchedule(`rate(${duration.formatTokenToNumber()})`); } if (duration.toSeconds() === 0) { diff --git a/packages/@aws-cdk/aws-events/lib/target.ts b/packages/@aws-cdk/aws-events/lib/target.ts index 1f7de7e82b36a..ba164f041c2a2 100644 --- a/packages/@aws-cdk/aws-events/lib/target.ts +++ b/packages/@aws-cdk/aws-events/lib/target.ts @@ -54,6 +54,12 @@ export interface RuleTargetConfig { */ readonly deadLetterConfig?: CfnRule.DeadLetterConfigProperty; + /** + * A RetryPolicy object that includes information about the retry policy settings. + * @default EventBridge default retry policy + */ + readonly retryPolicy?: CfnRule.RetryPolicyProperty; + /** * The Amazon ECS task definition and task count to use, if the event target * is an Amazon ECS task. @@ -79,6 +85,11 @@ export interface RuleTargetConfig { */ readonly sqsParameters?: CfnRule.SqsParametersProperty; + /** + * Parameters used when the rule invoke api gateway. + */ + readonly httpParameters?: CfnRule.HttpParametersProperty; + /** * What input to send to the event target * diff --git a/packages/@aws-cdk/aws-events/package.json b/packages/@aws-cdk/aws-events/package.json index 4c8d4fe304598..6275f43769cc2 100644 --- a/packages/@aws-cdk/aws-events/package.json +++ b/packages/@aws-cdk/aws-events/package.json @@ -72,23 +72,23 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "nodeunit": "^0.11.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" @@ -101,7 +101,8 @@ "props-default-doc:@aws-cdk/aws-events.RuleTargetConfig.kinesisParameters", "props-default-doc:@aws-cdk/aws-events.RuleTargetConfig.role", "props-default-doc:@aws-cdk/aws-events.RuleTargetConfig.runCommandParameters", - "props-default-doc:@aws-cdk/aws-events.RuleTargetConfig.sqsParameters" + "props-default-doc:@aws-cdk/aws-events.RuleTargetConfig.sqsParameters", + "props-default-doc:@aws-cdk/aws-events.RuleTargetConfig.httpParameters" ] }, "stability": "stable", diff --git a/packages/@aws-cdk/aws-events/test/test.archive.ts b/packages/@aws-cdk/aws-events/test/test.archive.ts index fc8f38a516f2b..5d04700bea20b 100644 --- a/packages/@aws-cdk/aws-events/test/test.archive.ts +++ b/packages/@aws-cdk/aws-events/test/test.archive.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import { Duration, Stack } from '@aws-cdk/core'; import { Test } from 'nodeunit'; import { EventBus } from '../lib'; diff --git a/packages/@aws-cdk/aws-events/test/test.event-bus.ts b/packages/@aws-cdk/aws-events/test/test.event-bus.ts index 2babb3f9b659e..320d8fb76f137 100644 --- a/packages/@aws-cdk/aws-events/test/test.event-bus.ts +++ b/packages/@aws-cdk/aws-events/test/test.event-bus.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import { Aws, CfnResource, Stack, Arn } from '@aws-cdk/core'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk/aws-events/test/test.input.ts b/packages/@aws-cdk/aws-events/test/test.input.ts index 49c38f63ac1e8..bbcc80d4afc66 100644 --- a/packages/@aws-cdk/aws-events/test/test.input.ts +++ b/packages/@aws-cdk/aws-events/test/test.input.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import { User } from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk/aws-events/test/test.rule.ts b/packages/@aws-cdk/aws-events/test/test.rule.ts index 72fe340242924..b4c1e15057fdf 100644 --- a/packages/@aws-cdk/aws-events/test/test.rule.ts +++ b/packages/@aws-cdk/aws-events/test/test.rule.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; @@ -70,7 +70,7 @@ export = { 'Seconds is not an allowed value for Schedule rate'(test: Test) { const lazyDuration = cdk.Duration.seconds(cdk.Lazy.number({ produce: () => 5 })); - test.throws(() => Schedule.rate(lazyDuration), /Allowed unit for scheduling is: 'minute', 'minutes', 'hour', 'hours', 'day', 'days'/); + test.throws(() => Schedule.rate(lazyDuration), /Allowed units for scheduling/i); test.done(); }, @@ -78,7 +78,7 @@ export = { const lazyDuration = cdk.Duration.millis(cdk.Lazy.number({ produce: () => 5 })); // THEN - test.throws(() => Schedule.rate(lazyDuration), /Allowed unit for scheduling is: 'minute', 'minutes', 'hour', 'hours', 'day', 'days'/); + test.throws(() => Schedule.rate(lazyDuration), /Allowed units for scheduling/i); test.done(); }, diff --git a/packages/@aws-cdk/aws-events/test/test.schedule.ts b/packages/@aws-cdk/aws-events/test/test.schedule.ts index e9c24a51c92b2..2d9728e743202 100644 --- a/packages/@aws-cdk/aws-events/test/test.schedule.ts +++ b/packages/@aws-cdk/aws-events/test/test.schedule.ts @@ -80,4 +80,18 @@ export = { .expressionString); test.done(); }, + + 'rate can be in seconds'(test: Test) { + test.equal('rate(2 minutes)', + events.Schedule.rate(Duration.seconds(120)) + .expressionString); + test.done(); + }, + + 'rate must not be in seconds when specified as a token'(test: Test) { + test.throws(() => { + events.Schedule.rate(Duration.seconds(Lazy.number({ produce: () => 5 }))); + }, /Allowed units for scheduling/); + test.done(); + }, }; diff --git a/packages/@aws-cdk/aws-eventschemas/package.json b/packages/@aws-cdk/aws-eventschemas/package.json index c141a1a389382..6fedbeab06ca7 100644 --- a/packages/@aws-cdk/aws-eventschemas/package.json +++ b/packages/@aws-cdk/aws-eventschemas/package.json @@ -73,18 +73,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-eventschemas/test/eventschemas.test.ts b/packages/@aws-cdk/aws-eventschemas/test/eventschemas.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-eventschemas/test/eventschemas.test.ts +++ b/packages/@aws-cdk/aws-eventschemas/test/eventschemas.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-fis/.eslintrc.js b/packages/@aws-cdk/aws-fis/.eslintrc.js new file mode 100644 index 0000000000000..61dd8dd001f63 --- /dev/null +++ b/packages/@aws-cdk/aws-fis/.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-fis/.gitignore b/packages/@aws-cdk/aws-fis/.gitignore new file mode 100644 index 0000000000000..62ebc95d75ce6 --- /dev/null +++ b/packages/@aws-cdk/aws-fis/.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-fis/.npmignore b/packages/@aws-cdk/aws-fis/.npmignore new file mode 100644 index 0000000000000..e4486030fcb17 --- /dev/null +++ b/packages/@aws-cdk/aws-fis/.npmignore @@ -0,0 +1,28 @@ +# 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 +test/ diff --git a/packages/@aws-cdk/aws-fis/LICENSE b/packages/@aws-cdk/aws-fis/LICENSE new file mode 100644 index 0000000000000..28e4bdcec77ec --- /dev/null +++ b/packages/@aws-cdk/aws-fis/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-2021 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-fis/NOTICE b/packages/@aws-cdk/aws-fis/NOTICE new file mode 100644 index 0000000000000..5fc3826926b5b --- /dev/null +++ b/packages/@aws-cdk/aws-fis/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/aws-fis/README.md b/packages/@aws-cdk/aws-fis/README.md new file mode 100644 index 0000000000000..6331d99791be2 --- /dev/null +++ b/packages/@aws-cdk/aws-fis/README.md @@ -0,0 +1,20 @@ +# AWS::FIS 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]) are always stable and safe to use. +> +> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib + +--- + + + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts +import fis = require('@aws-cdk/aws-fis'); +``` diff --git a/packages/@aws-cdk/aws-fis/jest.config.js b/packages/@aws-cdk/aws-fis/jest.config.js new file mode 100644 index 0000000000000..54e28beb9798b --- /dev/null +++ b/packages/@aws-cdk/aws-fis/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-fis/lib/index.ts b/packages/@aws-cdk/aws-fis/lib/index.ts new file mode 100644 index 0000000000000..09841fb313ee8 --- /dev/null +++ b/packages/@aws-cdk/aws-fis/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::FIS CloudFormation Resources: +export * from './fis.generated'; diff --git a/packages/@aws-cdk/aws-fis/package.json b/packages/@aws-cdk/aws-fis/package.json new file mode 100644 index 0000000000000..54d5b6266b4bb --- /dev/null +++ b/packages/@aws-cdk/aws-fis/package.json @@ -0,0 +1,101 @@ +{ + "name": "@aws-cdk/aws-fis", + "version": "0.0.0", + "description": "The CDK Construct Library for AWS::FIS", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "projectReferences": true, + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.FIS", + "packageId": "Amazon.CDK.AWS.FIS", + "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.fis", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "fis" + } + }, + "python": { + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 1" + ], + "distName": "aws-cdk.aws-fis", + "module": "aws_cdk.aws_fis" + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-fis" + }, + "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": "yarn build && yarn test", + "build+test+package": "yarn build+test && yarn package", + "compat": "cdk-compat", + "gen": "cfn2ts", + "rosetta:extract": "yarn --silent jsii-rosetta extract" + }, + "cdk-build": { + "cloudformation": "AWS::FIS", + "jest": true, + "env": { + "AWSLINT_BASE_CONSTRUCT": "true" + } + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::FIS", + "aws-fis" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@types/jest": "^26.0.23", + "cdk-build-tools": "0.0.0", + "cfn2ts": "0.0.0", + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "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 + }, + "publishConfig": { + "tag": "latest" + } +} diff --git a/packages/@aws-cdk/aws-fis/test/fis.test.ts b/packages/@aws-cdk/aws-fis/test/fis.test.ts new file mode 100644 index 0000000000000..c4505ad966984 --- /dev/null +++ b/packages/@aws-cdk/aws-fis/test/fis.test.ts @@ -0,0 +1,6 @@ +import '@aws-cdk/assert-internal/jest'; +import {} from '../lib'; + +test('No tests are specified for this package', () => { + expect(true).toBe(true); +}); diff --git a/packages/@aws-cdk/aws-fms/package.json b/packages/@aws-cdk/aws-fms/package.json index 352a762f1e877..15b4d8bf278f4 100644 --- a/packages/@aws-cdk/aws-fms/package.json +++ b/packages/@aws-cdk/aws-fms/package.json @@ -73,18 +73,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-fms/test/fms.test.ts b/packages/@aws-cdk/aws-fms/test/fms.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-fms/test/fms.test.ts +++ b/packages/@aws-cdk/aws-fms/test/fms.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-fsx/README.md b/packages/@aws-cdk/aws-fsx/README.md index bcb2497f145ff..ebcd311266036 100644 --- a/packages/@aws-cdk/aws-fsx/README.md +++ b/packages/@aws-cdk/aws-fsx/README.md @@ -5,17 +5,7 @@ ![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]) are always stable and safe to use. -> -> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib - -![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. +![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge) --- diff --git a/packages/@aws-cdk/aws-fsx/lib/lustre-file-system.ts b/packages/@aws-cdk/aws-fsx/lib/lustre-file-system.ts index 2206bb31dfad3..b88b3e99ac081 100644 --- a/packages/@aws-cdk/aws-fsx/lib/lustre-file-system.ts +++ b/packages/@aws-cdk/aws-fsx/lib/lustre-file-system.ts @@ -73,8 +73,8 @@ export interface LustreConfiguration { readonly perUnitStorageThroughput?: number; /** - * The preferred day and time to perform weekly maintenance. The first digit is the day of the week, starting at 0 - * for Sunday, then the following are hours and minutes in the UTC time zone, 24 hour clock. For example: '2:20:30' + * The preferred day and time to perform weekly maintenance. The first digit is the day of the week, starting at 1 + * for Monday, then the following are hours and minutes in the UTC time zone, 24 hour clock. For example: '2:20:30' * is Tuesdays at 20:30. * * @default - no preference diff --git a/packages/@aws-cdk/aws-fsx/lib/maintenance-time.ts b/packages/@aws-cdk/aws-fsx/lib/maintenance-time.ts index d9e06de3d0266..57c2da79379b4 100644 --- a/packages/@aws-cdk/aws-fsx/lib/maintenance-time.ts +++ b/packages/@aws-cdk/aws-fsx/lib/maintenance-time.ts @@ -2,10 +2,6 @@ * Enum for representing all the days of the week */ export enum Weekday { - /** - * Sunday - */ - SUNDAY = '0', /** * Monday */ @@ -29,7 +25,11 @@ export enum Weekday { /** * Saturday */ - SATURDAY = '6' + SATURDAY = '6', + /** + * Sunday + */ + SUNDAY = '7' } /** diff --git a/packages/@aws-cdk/aws-fsx/package.json b/packages/@aws-cdk/aws-fsx/package.json index f004ef50dc8b4..39f3d0f924780 100644 --- a/packages/@aws-cdk/aws-fsx/package.json +++ b/packages/@aws-cdk/aws-fsx/package.json @@ -73,25 +73,26 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" @@ -102,8 +103,8 @@ "resource-interface:@aws-cdk/aws-fsx.LustreFileSystem" ] }, - "stability": "experimental", - "maturity": "experimental", + "stability": "stable", + "maturity": "stable", "awscdkio": { "announce": false }, diff --git a/packages/@aws-cdk/aws-fsx/test/lustre-file-system.test.ts b/packages/@aws-cdk/aws-fsx/test/lustre-file-system.test.ts index fe0159a212140..ad4c4462d8c58 100644 --- a/packages/@aws-cdk/aws-fsx/test/lustre-file-system.test.ts +++ b/packages/@aws-cdk/aws-fsx/test/lustre-file-system.test.ts @@ -1,5 +1,5 @@ import { strictEqual } from 'assert'; -import { expect as expectCDK, haveResource, ResourcePart } from '@aws-cdk/assert'; +import { expect as expectCDK, haveResource, ResourcePart } from '@aws-cdk/assert-internal'; import { ISubnet, Port, SecurityGroup, Subnet, Vpc } from '@aws-cdk/aws-ec2'; import { Key } from '@aws-cdk/aws-kms'; import { Aws, Stack, Token } from '@aws-cdk/core'; @@ -121,7 +121,7 @@ describe('FSx for Lustre File System', () => { expectCDK(stack).to(haveResource('AWS::FSx::FileSystem', { LustreConfiguration: { DeploymentType: 'SCRATCH_2', - WeeklyMaintenanceStartTime: '0:12:34', + WeeklyMaintenanceStartTime: '7:12:34', }, })); expectCDK(stack).to(haveResource('AWS::EC2::SecurityGroup')); diff --git a/packages/@aws-cdk/aws-fsx/test/maintenance-time.test.ts b/packages/@aws-cdk/aws-fsx/test/maintenance-time.test.ts index 8ea63ccacd050..9a92e6041085b 100644 --- a/packages/@aws-cdk/aws-fsx/test/maintenance-time.test.ts +++ b/packages/@aws-cdk/aws-fsx/test/maintenance-time.test.ts @@ -2,10 +2,10 @@ import { strictEqual } from 'assert'; import { LustreMaintenanceTime, Weekday } from '../lib'; test.each([ - [Weekday.SUNDAY, 0, 0, '0:00:00'], + [Weekday.SUNDAY, 0, 0, '7:00:00'], [Weekday.SATURDAY, 0, 0, '6:00:00'], - [Weekday.SUNDAY, 24, 0, '0:24:00'], - [Weekday.SUNDAY, 0, 59, '0:00:59'], + [Weekday.SUNDAY, 24, 0, '7:24:00'], + [Weekday.SUNDAY, 0, 59, '7:00:59'], ])('valid maintenance time %s:%d:%d returns %s', (day: Weekday, hour: number, minute: number, expected: string) => { strictEqual( new LustreMaintenanceTime({ day, hour, minute }).toTimestamp(), diff --git a/packages/@aws-cdk/aws-gamelift/package.json b/packages/@aws-cdk/aws-gamelift/package.json index 9ce7dd38156cb..8d267810b451f 100644 --- a/packages/@aws-cdk/aws-gamelift/package.json +++ b/packages/@aws-cdk/aws-gamelift/package.json @@ -71,19 +71,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-gamelift/test/gamelift.test.ts b/packages/@aws-cdk/aws-gamelift/test/gamelift.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-gamelift/test/gamelift.test.ts +++ b/packages/@aws-cdk/aws-gamelift/test/gamelift.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-globalaccelerator-endpoints/.eslintrc.js b/packages/@aws-cdk/aws-globalaccelerator-endpoints/.eslintrc.js new file mode 100644 index 0000000000000..61dd8dd001f63 --- /dev/null +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/.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-globalaccelerator-endpoints/.gitignore b/packages/@aws-cdk/aws-globalaccelerator-endpoints/.gitignore new file mode 100644 index 0000000000000..2ed02868c78fb --- /dev/null +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/.gitignore @@ -0,0 +1,22 @@ +*.js +tsconfig.json +*.js.map +*.d.ts +*.generated.ts +dist +lib/generated/resources.ts +.jsii + +.LAST_BUILD +.nyc_output +coverage +nyc.config.js +.LAST_PACKAGE +*.snk +.cdk.staging + +lib/sdk-api-metadata.json +!.eslintrc.js +!jest.config.js + +junit.xml \ No newline at end of file diff --git a/packages/@aws-cdk/aws-globalaccelerator-endpoints/.npmignore b/packages/@aws-cdk/aws-globalaccelerator-endpoints/.npmignore new file mode 100644 index 0000000000000..63ab95621c764 --- /dev/null +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/.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 +test/ \ No newline at end of file diff --git a/packages/@aws-cdk/aws-globalaccelerator-endpoints/LICENSE b/packages/@aws-cdk/aws-globalaccelerator-endpoints/LICENSE new file mode 100644 index 0000000000000..28e4bdcec77ec --- /dev/null +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/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-2021 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-globalaccelerator-endpoints/NOTICE b/packages/@aws-cdk/aws-globalaccelerator-endpoints/NOTICE new file mode 100644 index 0000000000000..5fc3826926b5b --- /dev/null +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/aws-globalaccelerator-endpoints/README.md b/packages/@aws-cdk/aws-globalaccelerator-endpoints/README.md new file mode 100644 index 0000000000000..d4fe7f8159b5d --- /dev/null +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/README.md @@ -0,0 +1,18 @@ +# Endpoints for AWS Global Accelerator + + +--- + +![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge) + +--- + + + +This library contains integration classes to reference endpoints in AWS +Global Accelerator. Instances of these classes should be passed to the +`endpointGroup.addEndpoint()` method. + +See the README of the `@aws-cdk/aws-globalaccelerator` library for more information on +AWS Global Accelerator, and examples of all the integration classes available in +this module. diff --git a/packages/@aws-cdk/aws-globalaccelerator-endpoints/jest.config.js b/packages/@aws-cdk/aws-globalaccelerator-endpoints/jest.config.js new file mode 100644 index 0000000000000..49e81658a0875 --- /dev/null +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/jest.config.js @@ -0,0 +1,11 @@ +const baseConfig = require('cdk-build-tools/config/jest.config'); +module.exports = { + ...baseConfig, + coverageThreshold: { + global: { + ...baseConfig.coverageThreshold.global, + branches: 50, + }, + }, +}; + diff --git a/packages/@aws-cdk/aws-globalaccelerator-endpoints/lib/_util.ts b/packages/@aws-cdk/aws-globalaccelerator-endpoints/lib/_util.ts new file mode 100644 index 0000000000000..aee44257d056b --- /dev/null +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/lib/_util.ts @@ -0,0 +1,7 @@ +import { Token } from '@aws-cdk/core'; + +export function validateWeight(x?: number) { + if (x !== undefined && !Token.isUnresolved(x) && (x < 0 || x > 255)) { + throw new Error(`'weight' must be between 0 and 255, got: ${x}`); + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-globalaccelerator-endpoints/lib/alb.ts b/packages/@aws-cdk/aws-globalaccelerator-endpoints/lib/alb.ts new file mode 100644 index 0000000000000..1c4f618c16235 --- /dev/null +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/lib/alb.ts @@ -0,0 +1,50 @@ +import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; +import * as ga from '@aws-cdk/aws-globalaccelerator'; +import { validateWeight } from './_util'; + +/** + * Properties for a ApplicationLoadBalancerEndpoint + */ +export interface ApplicationLoadBalancerEndpointOptions { + /** + * Endpoint weight across all endpoints in the group + * + * Must be a value between 0 and 255. + * + * @default 128 + */ + readonly weight?: number; + + /** + * Forward the client IP address in an `X-Forwarded-For` header + * + * GlobalAccelerator will create Network Interfaces in your VPC in order + * to preserve the client IP address. + * + * Client IP address preservation is supported only in specific AWS Regions. + * See the GlobalAccelerator Developer Guide for a list. + * + * @default true if available + */ + readonly preserveClientIp?: boolean; +} + +/** + * Use an Application Load Balancer as a Global Accelerator Endpoint + */ +export class ApplicationLoadBalancerEndpoint implements ga.IEndpoint { + public readonly region?: string; + + constructor(private readonly loadBalancer: elbv2.IApplicationLoadBalancer, private readonly options: ApplicationLoadBalancerEndpointOptions = {}) { + validateWeight(options.weight); + this.region = loadBalancer.env.region; + } + + public renderEndpointConfiguration(): any { + return { + endpointId: this.loadBalancer.loadBalancerArn, + weight: this.options.weight, + clientIpPreservationEnabled: this.options.preserveClientIp, + } as ga.CfnEndpointGroup.EndpointConfigurationProperty; + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-globalaccelerator-endpoints/lib/eip.ts b/packages/@aws-cdk/aws-globalaccelerator-endpoints/lib/eip.ts new file mode 100644 index 0000000000000..924eb391efc0b --- /dev/null +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/lib/eip.ts @@ -0,0 +1,38 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ga from '@aws-cdk/aws-globalaccelerator'; +import { Stack } from '@aws-cdk/core'; +import { validateWeight } from './_util'; + +/** + * Properties for a NetworkLoadBalancerEndpoint + */ +export interface CfnEipEndpointProps { + /** + * Endpoint weight across all endpoints in the group + * + * Must be a value between 0 and 255. + * + * @default 128 + */ + readonly weight?: number; +} + +/** + * Use an EC2 Instance as a Global Accelerator Endpoint + */ +export class CfnEipEndpoint implements ga.IEndpoint { + public readonly region?: string; + + constructor(private readonly eip: ec2.CfnEIP, private readonly options: CfnEipEndpointProps = {}) { + validateWeight(options.weight); + + this.region = Stack.of(eip).region; + } + + public renderEndpointConfiguration(): any { + return { + endpointId: this.eip.attrAllocationId, + weight: this.options.weight, + } as ga.CfnEndpointGroup.EndpointConfigurationProperty; + } +} diff --git a/packages/@aws-cdk/aws-globalaccelerator-endpoints/lib/index.ts b/packages/@aws-cdk/aws-globalaccelerator-endpoints/lib/index.ts new file mode 100644 index 0000000000000..4286ae4cbd68c --- /dev/null +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/lib/index.ts @@ -0,0 +1,4 @@ +export * from './alb'; +export * from './nlb'; +export * from './instance'; +export * from './eip'; \ No newline at end of file diff --git a/packages/@aws-cdk/aws-globalaccelerator-endpoints/lib/instance.ts b/packages/@aws-cdk/aws-globalaccelerator-endpoints/lib/instance.ts new file mode 100644 index 0000000000000..a5d16298ec514 --- /dev/null +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/lib/instance.ts @@ -0,0 +1,51 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ga from '@aws-cdk/aws-globalaccelerator'; +import { validateWeight } from './_util'; + +/** + * Properties for a NetworkLoadBalancerEndpoint + */ +export interface InstanceEndpointProps { + /** + * Endpoint weight across all endpoints in the group + * + * Must be a value between 0 and 255. + * + * @default 128 + */ + readonly weight?: number; + + /** + * Forward the client IP address + * + * GlobalAccelerator will create Network Interfaces in your VPC in order + * to preserve the client IP address. + * + * Client IP address preservation is supported only in specific AWS Regions. + * See the GlobalAccelerator Developer Guide for a list. + * + * @default true if available + */ + readonly preserveClientIp?: boolean; +} + +/** + * Use an EC2 Instance as a Global Accelerator Endpoint + */ +export class InstanceEndpoint implements ga.IEndpoint { + public readonly region?: string; + + constructor(private readonly instance: ec2.IInstance, private readonly options: InstanceEndpointProps = {}) { + validateWeight(options.weight); + + this.region = instance.env.region; + } + + public renderEndpointConfiguration(): any { + return { + endpointId: this.instance.instanceId, + weight: this.options.weight, + clientIpPreservationEnabled: this.options.preserveClientIp, + } as ga.CfnEndpointGroup.EndpointConfigurationProperty; + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-globalaccelerator-endpoints/lib/nlb.ts b/packages/@aws-cdk/aws-globalaccelerator-endpoints/lib/nlb.ts new file mode 100644 index 0000000000000..f94bfff5f5357 --- /dev/null +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/lib/nlb.ts @@ -0,0 +1,36 @@ +import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; +import * as ga from '@aws-cdk/aws-globalaccelerator'; +import { validateWeight } from './_util'; + +/** + * Properties for a NetworkLoadBalancerEndpoint + */ +export interface NetworkLoadBalancerEndpointProps { + /** + * Endpoint weight across all endpoints in the group + * + * Must be a value between 0 and 255. + * + * @default 128 + */ + readonly weight?: number; +} + +/** + * Use a Network Load Balancer as a Global Accelerator Endpoint + */ +export class NetworkLoadBalancerEndpoint implements ga.IEndpoint { + public readonly region?: string; + + constructor(private readonly loadBalancer: elbv2.INetworkLoadBalancer, private readonly options: NetworkLoadBalancerEndpointProps = {}) { + validateWeight(options.weight); + this.region = loadBalancer.env.region; + } + + public renderEndpointConfiguration(): any { + return { + endpointId: this.loadBalancer.loadBalancerArn, + weight: this.options.weight, + } as ga.CfnEndpointGroup.EndpointConfigurationProperty; + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-globalaccelerator-endpoints/package.json b/packages/@aws-cdk/aws-globalaccelerator-endpoints/package.json new file mode 100644 index 0000000000000..41b96969792fc --- /dev/null +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/package.json @@ -0,0 +1,106 @@ +{ + "name": "@aws-cdk/aws-globalaccelerator-endpoints", + "version": "0.0.0", + "description": "Endpoints for AWS Global Accelerator", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.GlobalAccelerator.Endpoints", + "packageId": "Amazon.CDK.AWS.GlobalAccelerator.Endpoints", + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png" + }, + "java": { + "package": "software.amazon.awscdk.services.globalaccelerator.endpoints", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "globalaccelerator-endpoints" + } + }, + "python": { + "distName": "aws-cdk.aws-globalaccelerator-endpoints", + "module": "aws_cdk.aws_globalaccelerator_endpoints", + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 1" + ] + } + }, + "projectReferences": true + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-globalaccelerator-endpoints" + }, + "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", + "build+test+package": "yarn build+test && yarn package", + "build+test": "yarn build && yarn test", + "compat": "cdk-compat", + "rosetta:extract": "yarn --silent jsii-rosetta extract" + }, + "cdk-build": { + "jest": true, + "env": { + "AWSLINT_BASE_CONSTRUCT": true + } + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "globalaccelerator" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@types/jest": "^26.0.23", + "@aws-cdk/assert-internal": "0.0.0", + "aws-sdk": "^2.848.0", + "aws-sdk-mock": "^5.1.0", + "cdk-build-tools": "0.0.0", + "cdk-integ-tools": "0.0.0", + "jest": "^26.6.3", + "pkglint": "0.0.0" + }, + "dependencies": { + "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", + "@aws-cdk/aws-globalaccelerator": "0.0.0", + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" + }, + "homepage": "https://github.com/aws/aws-cdk", + "peerDependencies": { + "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", + "@aws-cdk/aws-globalaccelerator": "0.0.0", + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" + }, + "engines": { + "node": ">= 10.13.0 <13 || >=13.7.0" + }, + "stability": "stable", + "awscdkio": { + "announce": false + }, + "maturity": "stable", + "publishConfig": { + "tag": "latest" + } +} diff --git a/packages/@aws-cdk/aws-globalaccelerator-endpoints/test/endpoints.test.ts b/packages/@aws-cdk/aws-globalaccelerator-endpoints/test/endpoints.test.ts new file mode 100644 index 0000000000000..01b55508f11a0 --- /dev/null +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/test/endpoints.test.ts @@ -0,0 +1,183 @@ +import '@aws-cdk/assert-internal/jest'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; +import * as ga from '@aws-cdk/aws-globalaccelerator'; +import { Stack } from '@aws-cdk/core'; +import * as endpoints from '../lib'; + +let stack: Stack; +let vpc: ec2.Vpc; +let accelerator: ga.Accelerator; +let listener: ga.Listener; +beforeEach(() => { + stack = new Stack(); + vpc = new ec2.Vpc(stack, 'Vpc'); + + accelerator = new ga.Accelerator(stack, 'Accelerator'); + listener = accelerator.addListener('Listener', { + portRanges: [{ fromPort: 80 }], + }); +}); + +test('Application Load Balancer with all properties', () => { + // WHEN + const alb = new elbv2.ApplicationLoadBalancer(stack, 'ALB', { vpc, internetFacing: true }); + listener.addEndpointGroup('Group', { + endpoints: [ + new endpoints.ApplicationLoadBalancerEndpoint(alb, { + weight: 50, + preserveClientIp: true, + }), + ], + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::GlobalAccelerator::EndpointGroup', { + EndpointConfigurations: [ + { + EndpointId: { Ref: 'ALBAEE750D2' }, + Weight: 50, + ClientIPPreservationEnabled: true, + }, + ], + }); +}); + +// Doesn't work yet because 'fromApplicationLoadBalancerAttributes' doesn't set the imported resource env +test('Get region from imported ALB', () => { + // WHEN + const alb = elbv2.ApplicationLoadBalancer.fromApplicationLoadBalancerAttributes(stack, 'ALB', { + loadBalancerArn: 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188', + securityGroupId: 'sg-1234', + }); + listener.addEndpointGroup('Group', { + endpoints: [ + new endpoints.ApplicationLoadBalancerEndpoint(alb), + ], + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::GlobalAccelerator::EndpointGroup', { + EndpointGroupRegion: 'us-west-2', + EndpointConfigurations: [ + { + EndpointId: 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188', + }, + ], + }); +}); + +test('Network Load Balancer with all properties', () => { + // WHEN + const nlb = new elbv2.NetworkLoadBalancer(stack, 'NLB', { vpc, internetFacing: true }); + listener.addEndpointGroup('Group', { + endpoints: [ + new endpoints.NetworkLoadBalancerEndpoint(nlb, { + weight: 50, + }), + ], + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::GlobalAccelerator::EndpointGroup', { + EndpointConfigurations: [ + { + EndpointId: { Ref: 'NLB55158F82' }, + Weight: 50, + }, + ], + }); +}); + +// Doesn't work yet because 'fromNetworkLoadBalancerAttributes' doesn't set the imported resource env +test('Get region from imported NLB', () => { + // WHEN + const nlb = elbv2.NetworkLoadBalancer.fromNetworkLoadBalancerAttributes(stack, 'NLB', { + loadBalancerArn: 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188', + }); + listener.addEndpointGroup('Group', { + endpoints: [ + new endpoints.NetworkLoadBalancerEndpoint(nlb), + ], + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::GlobalAccelerator::EndpointGroup', { + EndpointGroupRegion: 'us-west-2', + EndpointConfigurations: [ + { + EndpointId: 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188', + }, + ], + }); +}); + +test('CFN EIP with all properties', () => { + // WHEN + const eip = new ec2.CfnEIP(stack, 'ElasticIpAddress'); + listener.addEndpointGroup('Group', { + endpoints: [ + new endpoints.CfnEipEndpoint(eip, { + weight: 50, + }), + ], + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::GlobalAccelerator::EndpointGroup', { + EndpointConfigurations: [ + { + EndpointId: { 'Fn::GetAtt': ['ElasticIpAddress', 'AllocationId'] }, + Weight: 50, + }, + ], + }); +}); + +test('EC2 Instance with all properties', () => { + // WHEN + const instance = new ec2.Instance(stack, 'Instance', { + vpc, + machineImage: new ec2.AmazonLinuxImage(), + instanceType: new ec2.InstanceType('t3.small'), + }); + listener.addEndpointGroup('Group', { + endpoints: [ + new endpoints.InstanceEndpoint(instance, { + weight: 50, + preserveClientIp: true, + }), + ], + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::GlobalAccelerator::EndpointGroup', { + EndpointConfigurations: [ + { + EndpointId: { Ref: 'InstanceC1063A87' }, + Weight: 50, + ClientIPPreservationEnabled: true, + }, + ], + }); +}); + +test('throws if weight is not in range', () => { + // WHEN + const instance = new ec2.Instance(stack, 'Instance', { + vpc, + machineImage: new ec2.AmazonLinuxImage(), + instanceType: new ec2.InstanceType('t3.small'), + }); + + expect(() => { + listener.addEndpointGroup('Group', { + endpoints: [ + new endpoints.InstanceEndpoint(instance, { + weight: 300, + preserveClientIp: true, + }), + ], + }); + }).toThrow(/'weight' must be between 0 and 255/); +}); diff --git a/packages/@aws-cdk/aws-globalaccelerator/test/integ.globalaccelerator.expected.json b/packages/@aws-cdk/aws-globalaccelerator-endpoints/test/integ.globalaccelerator.expected.json similarity index 79% rename from packages/@aws-cdk/aws-globalaccelerator/test/integ.globalaccelerator.expected.json rename to packages/@aws-cdk/aws-globalaccelerator-endpoints/test/integ.globalaccelerator.expected.json index 6e141037d0f36..72b6e81da9827 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/test/integ.globalaccelerator.expected.json +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/test/integ.globalaccelerator.expected.json @@ -453,7 +453,7 @@ "Accelerator8EB0B6B1": { "Type": "AWS::GlobalAccelerator::Accelerator", "Properties": { - "Name": "Accelerator", + "Name": "integglobalacceleratorAccelerator5D88FB42", "Enabled": true } }, @@ -476,50 +476,6 @@ "ClientAffinity": "NONE" } }, - "GroupC77FDACD": { - "Type": "AWS::GlobalAccelerator::EndpointGroup", - "Properties": { - "EndpointGroupRegion": { - "Ref": "AWS::Region" - }, - "ListenerArn": { - "Fn::GetAtt": [ - "Listener828B0E81", - "ListenerArn" - ] - }, - "EndpointConfigurations": [ - { - "EndpointId": { - "Ref": "ALBAEE750D2" - } - }, - { - "EndpointId": { - "Ref": "NLB55158F82" - } - }, - { - "EndpointId": { - "Fn::GetAtt": [ - "ElasticIpAddress", - "AllocationId" - ] - } - }, - { - "EndpointId": { - "Ref": "Instance008A4B15C" - } - }, - { - "EndpointId": { - "Ref": "Instance14BC3991D" - } - } - ] - } - }, "ALBAEE750D2": { "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", "Properties": { @@ -575,6 +531,27 @@ } } }, + "ALBSecurityGroupfromGlobalAcceleratorGroup4435D2AC398": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "Description": "from GlobalAcceleratorGroup:443", + "FromPort": 443, + "GroupId": { + "Fn::GetAtt": [ + "ALBSecurityGroup8B8624F8", + "GroupId" + ] + }, + "SourceSecurityGroupId": { + "Fn::GetAtt": [ + "GroupPeerCustomResourceB3A15D36", + "SecurityGroups.0.GroupId" + ] + }, + "ToPort": 443 + } + }, "NLB55158F82": { "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", "Properties": { @@ -808,12 +785,208 @@ "DependsOn": [ "Instance1InstanceRoleBC4D05C6" ] + }, + "GroupC77FDACD": { + "Type": "AWS::GlobalAccelerator::EndpointGroup", + "Properties": { + "EndpointGroupRegion": { + "Ref": "AWS::Region" + }, + "ListenerArn": { + "Fn::GetAtt": [ + "Listener828B0E81", + "ListenerArn" + ] + }, + "EndpointConfigurations": [ + { + "EndpointId": { + "Ref": "ALBAEE750D2" + } + }, + { + "EndpointId": { + "Ref": "NLB55158F82" + } + }, + { + "EndpointId": { + "Fn::GetAtt": [ + "ElasticIpAddress", + "AllocationId" + ] + } + }, + { + "EndpointId": { + "Ref": "Instance008A4B15C" + } + }, + { + "EndpointId": { + "Ref": "Instance14BC3991D" + } + } + ] + } + }, + "GroupPeerCustomResourceCustomResourcePolicy42EF8263": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "ec2:DescribeSecurityGroups", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "GroupPeerCustomResourceCustomResourcePolicy42EF8263", + "Roles": [ + { + "Ref": "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2" + } + ] + }, + "DependsOn": [ + "GroupC77FDACD" + ] + }, + "GroupPeerCustomResourceB3A15D36": { + "Type": "Custom::AWS", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "AWS679f53fac002430cb0da5b7982bd22872D164C4C", + "Arn" + ] + }, + "Create": { + "Fn::Join": [ + "", + [ + "{\"service\":\"EC2\",\"action\":\"describeSecurityGroups\",\"parameters\":{\"Filters\":[{\"Name\":\"group-name\",\"Values\":[\"GlobalAccelerator\"]},{\"Name\":\"vpc-id\",\"Values\":[\"", + { + "Ref": "VPCB9E5F0B4" + }, + "\"]}]},\"physicalResourceId\":{\"responsePath\":\"SecurityGroups.0.GroupId\"}}" + ] + ] + }, + "InstallLatestAwsSdk": true + }, + "DependsOn": [ + "GroupPeerCustomResourceCustomResourcePolicy42EF8263", + "GroupC77FDACD" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "AWS679f53fac002430cb0da5b7982bd22872D164C4C": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3Bucket4DD075F7" + }, + "S3Key": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7" + } + ] + } + ] + } + ] + ] + } + }, + "Role": { + "Fn::GetAtt": [ + "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs12.x", + "Timeout": 120 + }, + "DependsOn": [ + "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2" + ] } }, "Parameters": { "SsmParameterValueawsserviceamiamazonlinuxlatestamznamihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter": { "Type": "AWS::SSM::Parameter::Value", "Default": "/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2" + }, + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3Bucket4DD075F7": { + "Type": "String", + "Description": "S3 bucket for asset \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" + }, + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7": { + "Type": "String", + "Description": "S3 key for asset version \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" + }, + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98ArtifactHash35A756EB": { + "Type": "String", + "Description": "Artifact hash for asset \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-globalaccelerator/test/integ.globalaccelerator.ts b/packages/@aws-cdk/aws-globalaccelerator-endpoints/test/integ.globalaccelerator.ts similarity index 62% rename from packages/@aws-cdk/aws-globalaccelerator/test/integ.globalaccelerator.ts rename to packages/@aws-cdk/aws-globalaccelerator-endpoints/test/integ.globalaccelerator.ts index bee56b820d7ec..139d91dbd9f81 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/test/integ.globalaccelerator.ts +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/test/integ.globalaccelerator.ts @@ -1,12 +1,12 @@ - +/// !cdk-integ pragma:ignore-assets import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; -import * as cdk from '@aws-cdk/core'; +import * as ga from '@aws-cdk/aws-globalaccelerator'; +import { App, Stack } from '@aws-cdk/core'; import * as constructs from 'constructs'; -import * as ga from '../lib'; -import * as testfixture from './util'; +import * as endpoints from '../lib'; -class GaStack extends testfixture.TestStack { +class GaStack extends Stack { constructor(scope: constructs.Construct, id: string) { super(scope, id); @@ -21,7 +21,6 @@ class GaStack extends testfixture.TestStack { }, ], }); - const endpointGroup = new ga.EndpointGroup(this, 'Group', { listener }); const alb = new elbv2.ApplicationLoadBalancer(this, 'ALB', { vpc, internetFacing: true }); const nlb = new elbv2.NetworkLoadBalancer(this, 'NLB', { vpc, internetFacing: true }); const eip = new ec2.CfnEIP(this, 'ElasticIpAddress'); @@ -35,15 +34,20 @@ class GaStack extends testfixture.TestStack { })); } - endpointGroup.addLoadBalancer('AlbEndpoint', alb); - endpointGroup.addLoadBalancer('NlbEndpoint', nlb); - endpointGroup.addElasticIpAddress('EipEndpoint', eip); - endpointGroup.addEc2Instance('InstanceEndpoint', instances[0]); - endpointGroup.addEndpoint('InstanceEndpoint2', instances[1].instanceId); + const group = new ga.EndpointGroup(this, 'Group', { + listener, + endpoints: [ + new endpoints.ApplicationLoadBalancerEndpoint(alb), + new endpoints.NetworkLoadBalancerEndpoint(nlb), + new endpoints.CfnEipEndpoint(eip), + new endpoints.InstanceEndpoint(instances[0]), + new endpoints.InstanceEndpoint(instances[1]), + ], + }); + alb.connections.allowFrom(group.connectionsPeer('Peer', vpc), ec2.Port.tcp(443)); } } -const app = new cdk.App(); - +const app = new App(); new GaStack(app, 'integ-globalaccelerator'); diff --git a/packages/@aws-cdk/aws-globalaccelerator/README.md b/packages/@aws-cdk/aws-globalaccelerator/README.md index d959a2e9238ad..bdbb6780fadd2 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/README.md +++ b/packages/@aws-cdk/aws-globalaccelerator/README.md @@ -5,17 +5,7 @@ ![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]) are always stable and safe to use. -> -> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib - -![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. +![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge) --- @@ -23,115 +13,178 @@ ## Introduction -AWS Global Accelerator (AGA) is a service that improves the availability and performance of your applications with local or global users. It provides static IP addresses that act as a fixed entry point to your application endpoints in a single or multiple AWS Regions, such as your Application Load Balancers, Network Load Balancers or Amazon EC2 instances. +AWS Global Accelerator (AGA) is a service that improves the availability and +performance of your applications with local or global users. + +It intercepts your user's network connection at an edge location close to +them, and routes it to one of potentially multiple, redundant backends across +the more reliable and less congested AWS global network. -This module supports features under [AWS Global Accelerator](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_GlobalAccelerator.html) that allows users set up resources using the `@aws-cdk/aws-globalaccelerator` module. +AGA can be used to route traffic to Application Load Balancers, Network Load +Balancers, EC2 Instances and Elastic IP Addresses. -## Accelerator +For more information, see the [AWS Global +Accelerator Developer Guide](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_GlobalAccelerator.html). -The `Accelerator` resource is a Global Accelerator resource type that contains information about how you create an accelerator. An accelerator includes one or more listeners that process inbound connections and direct traffic to one or more endpoint groups, each of which includes endpoints, such as Application Load Balancers, Network Load Balancers, and Amazon EC2 instances. +## Example -To create the `Accelerator`: +Here's an example that sets up a Global Accelerator for two Application Load +Balancers in two different AWS Regions: ```ts import globalaccelerator = require('@aws-cdk/aws-globalaccelerator'); +import ga_endpoints = require('@aws-cdk/aws-globalaccelerator-endpoints'); +import elbv2 = require('@aws-cdk/aws-elasticloadbalancingv2'); -new globalaccelerator.Accelerator(stack, 'Accelerator'); +// Create an Accelerator +const accelerator = new globalaccelerator.Accelerator(stack, 'Accelerator'); + +// Create a Listener +const listener = accelerator.addListener('Listener', { + portRanges: [ + { fromPort: 80 }, + { fromPort: 443 }, + ], +}); + +// Import the Load Balancers +const nlb1 = elbv2.NetworkLoadBalancer.fromNetworkLoadBalancerAttributes(stack, 'NLB1', { + loadBalancerArn: 'arn:aws:elasticloadbalancing:us-west-2:111111111111:loadbalancer/app/my-load-balancer1/e16bef66805b', +}); +const nlb2 = elbv2.NetworkLoadBalancer.fromNetworkLoadBalancerAttributes(stack, 'NLB2', { + loadBalancerArn: 'arn:aws:elasticloadbalancing:ap-south-1:111111111111:loadbalancer/app/my-load-balancer2/5513dc2ea8a1', +}); +// Add one EndpointGroup for each Region we are targeting +listener.addEndpointGroup('Group1', { + endpoints: [new ga_endpoints.NetworkLoadBalancerEndpoint(nlb1)], +}); +listener.addEndpointGroup('Group2', { + // Imported load balancers automatically calculate their Region from the ARN. + // If you are load balancing to other resources, you must also pass a `region` + // parameter here. + endpoints: [new ga_endpoints.NetworkLoadBalancerEndpoint(nlb2)], +}); ``` -## Listener +## Concepts + +The **Accelerator** construct defines a Global Accelerator resource. + +An Accelerator includes one or more **Listeners** that accepts inbound +connections on one or more ports. + +Each Listener has one or more **Endpoint Groups**, representing multiple +geographically distributed copies of your application. There is one Endpoint +Group per Region, and user traffic is routed to the closest Region by default. + +An Endpoint Group consists of one or more **Endpoints**, which is where the +user traffic coming in on the Listener is ultimately sent. The Endpoint port +used is the same as the traffic came in on at the Listener, unless overridden. + +## Types of Endpoints + +There are 4 types of Endpoints, and they can be found in the +`@aws-cdk/aws-globalaccelerator-endpoints` package: -The `Listener` resource is a Global Accelerator resource type that contains information about how you create a listener to process inbound connections from clients to an accelerator. Connections arrive to assigned static IP addresses on a port, port range, or list of port ranges that you specify. +* Application Load Balancers +* Network Load Balancers +* EC2 Instances +* Elastic IP Addresses -To create the `Listener` listening on TCP 80: +### Application Load Balancers ```ts -new globalaccelerator.Listener(stack, 'Listener', { - accelerator, - portRanges: [ - { - fromPort: 80, - toPort: 80, - }, +const alb = new elbv2.ApplicationLoadBalancer(...); + +listener.addEndpointGroup('Group', { + endpoints: [ + new ga_endpoints.ApplicationLoadBalancerEndpoint(alb, { + weight: 128, + preserveClientIp: true, + }), ], }); ``` - -## EndpointGroup - -The `EndpointGroup` resource is a Global Accelerator resource type that contains information about how you create an endpoint group for the specified listener. An endpoint group is a collection of endpoints in one AWS Region. - -To create the `EndpointGroup`: +### Network Load Balancers ```ts -new globalaccelerator.EndpointGroup(stack, 'Group', { listener }); +const nlb = new elbv2.NetworkLoadBalancer(...); +listener.addEndpointGroup('Group', { + endpoints: [ + new ga_endpoints.NetworkLoadBalancerEndpoint(nlb, { + weight: 128, + }), + ], +}); ``` -## Add Endpoint into EndpointGroup - -You may use the following methods to add endpoints into the `EndpointGroup`: +### EC2 Instances -- `addEndpoint` to add a generic `endpoint` into the `EndpointGroup`. -- `addLoadBalancer` to add an Application Load Balancer or Network Load Balancer. -- `addEc2Instance` to add an EC2 Instance. -- `addElasticIpAddress` to add an Elastic IP Address. +```ts +const instance = new ec2.instance(...); + +listener.addEndpointGroup('Group', { + endpoints: [ + new ga_endpoints.InstanceEndpoint(instance, { + weight: 128, + preserveClientIp: true, + }), + ], +}); +``` +### Elastic IP Addresses ```ts -const endpointGroup = new globalaccelerator.EndpointGroup(stack, 'Group', { listener }); -const alb = new elbv2.ApplicationLoadBalancer(stack, 'ALB', { vpc, internetFacing: true }); -const nlb = new elbv2.NetworkLoadBalancer(stack, 'NLB', { vpc, internetFacing: true }); -const eip = new ec2.CfnEIP(stack, 'ElasticIpAddress'); -const instances = new Array(); - -for ( let i = 0; i < 2; i++) { - instances.push(new ec2.Instance(stack, `Instance${i}`, { - vpc, - machineImage: new ec2.AmazonLinuxImage(), - instanceType: new ec2.InstanceType('t3.small'), - })); -} - -endpointGroup.addLoadBalancer('AlbEndpoint', alb); -endpointGroup.addLoadBalancer('NlbEndpoint', nlb); -endpointGroup.addElasticIpAddress('EipEndpoint', eip); -endpointGroup.addEc2Instance('InstanceEndpoint', instances[0]); -endpointGroup.addEndpoint('InstanceEndpoint2', instances[1].instanceId); +const eip = new ec2.CfnEIP(...); + +listener.addEndpointGroup('Group', { + endpoints: [ + new ga_endpoints.CfnEipEndpoint(eip, { + weight: 128, + }), + ], +}); ``` -## Accelerator Security Groups +## Client IP Address Preservation and Security Groups -When using certain AGA features (client IP address preservation), AGA creates elastic network interfaces (ENI) in your AWS account which are -associated with a Security Group, and which are reused for all AGAs associated with that VPC. Per the -[best practices](https://docs.aws.amazon.com/global-accelerator/latest/dg/best-practices-aga.html) page, AGA creates a specific security group -called `GlobalAccelerator` for each VPC it has an ENI in. You can use the security group created by AGA as a source group in other security -groups, such as those for EC2 instances or Elastic Load Balancers, in order to implement least-privilege security group rules. +When using the `preserveClientIp` feature, AGA creates +**Elastic Network Interfaces** (ENIs) in your AWS account, that are +associated with a Security Group AGA creates for you. You can use the +security group created by AGA as a source group in other security groups +(such as those for EC2 instances or Elastic Load Balancers), if you want to +restrict incoming traffic to the AGA security group rules. -CloudFormation doesn't support referencing the security group created by AGA. CDK has a library that enables you to reference the AGA security group -for a VPC using an AwsCustomResource. +AGA creates a specific security group called `GlobalAccelerator` for each VPC +it has an ENI in (this behavior can not be changed). CloudFormation doesn't +support referencing the security group created by AGA, but this construct +library comes with a custom resource that enables you to reference the AGA +security group. + +Call `endpointGroup.connectionsPeer()` to obtain a reference to the Security Group +which you can use in connection rules. You must pass a reference to the VPC in whose +context the security group will be looked up. Example: ```ts -const vpc = new Vpc(stack, 'VPC', {}); -const alb = new elbv2.ApplicationLoadBalancer(stack, 'ALB', { vpc, internetFacing: false }); -const accelerator = new ga.Accelerator(stack, 'Accelerator'); -const listener = new ga.Listener(stack, 'Listener', { - accelerator, - portRanges: [ - { - fromPort: 443, - toPort: 443, - }, +// ... + +// Non-open ALB +const alb = new elbv2.ApplicationLoadBalancer(stack, 'ALB', { /* ... */ }); + +const endpointGroup = listener.addEndpointGroup('Group', { + endpoints: [ + new ga_endpoints.ApplicationLoadBalancerEndpoint(alb, { + preserveClientIps: true, + })], ], }); -const endpointGroup = new ga.EndpointGroup(stack, 'Group', { listener }); -endpointGroup.addLoadBalancer('AlbEndpoint', alb); // Remember that there is only one AGA security group per VPC. -// This code will fail at CloudFormation deployment time if you do not have an AGA -const agaSg = ga.AcceleratorSecurityGroup.fromVpc(stack, 'GlobalAcceleratorSG', vpc); +const agaSg = endpointGroup.connectionsPeer('GlobalAcceleratorSG', vpc); // Allow connections from the AGA to the ALB alb.connections.allowFrom(agaSg, Port.tcp(443)); diff --git a/packages/@aws-cdk/aws-globalaccelerator/lib/accelerator-security-group.ts b/packages/@aws-cdk/aws-globalaccelerator/lib/_accelerator-security-group.ts similarity index 72% rename from packages/@aws-cdk/aws-globalaccelerator/lib/accelerator-security-group.ts rename to packages/@aws-cdk/aws-globalaccelerator/lib/_accelerator-security-group.ts index 9197613d69b61..d59f572ecaebc 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/lib/accelerator-security-group.ts +++ b/packages/@aws-cdk/aws-globalaccelerator/lib/_accelerator-security-group.ts @@ -1,16 +1,14 @@ -import { ISecurityGroup, SecurityGroup, IVpc } from '@aws-cdk/aws-ec2'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import { CfnResource } from '@aws-cdk/core'; import { AwsCustomResource, AwsCustomResourcePolicy, PhysicalResourceId } from '@aws-cdk/custom-resources'; +import { Construct } from 'constructs'; import { EndpointGroup } from '../lib'; -// keep this import separate from other imports to reduce chance for merge conflicts with v2-main -// eslint-disable-next-line no-duplicate-imports, import/order -import { Construct } from '@aws-cdk/core'; - /** * The security group used by a Global Accelerator to send traffic to resources in a VPC. */ -export class AcceleratorSecurityGroup { +export class AcceleratorSecurityGroupPeer implements ec2.IPeer { /** * Lookup the Global Accelerator security group at CloudFormation deployment time. * @@ -21,7 +19,7 @@ export class AcceleratorSecurityGroup { * the AGA security group for a given VPC at CloudFormation deployment time, and lets you create rules for traffic from AGA * to other resources created by CDK. */ - public static fromVpc(scope: Construct, id: string, vpc: IVpc, endpointGroup: EndpointGroup): ISecurityGroup { + public static fromVpc(scope: Construct, id: string, vpc: ec2.IVpc, endpointGroup: EndpointGroup) { // The security group name is always 'GlobalAccelerator' const globalAcceleratorSGName = 'GlobalAccelerator'; @@ -59,16 +57,27 @@ export class AcceleratorSecurityGroup { }), }); - // Look up the security group ID - const sg = SecurityGroup.fromSecurityGroupId(scope, - id, - lookupAcceleratorSGCustomResource.getResponseField(ec2ResponseSGIdField)); // We add a dependency on the endpoint group, guaranteeing that CloudFormation won't // try and look up the SG before AGA creates it. The SG is created when a VPC resource // is associated with an AGA - lookupAcceleratorSGCustomResource.node.addDependency(endpointGroup); - return sg; + lookupAcceleratorSGCustomResource.node.addDependency(endpointGroup.node.defaultChild as CfnResource); + + // Look up the security group ID + return new AcceleratorSecurityGroupPeer(lookupAcceleratorSGCustomResource.getResponseField(ec2ResponseSGIdField)); + } + + public readonly canInlineRule = false; + public readonly connections: ec2.Connections = new ec2.Connections({ peer: this }); + public readonly uniqueId: string = 'GlobalAcceleratorGroup'; + + private constructor(private readonly securityGroupId: string) { } - private constructor() {} + public toIngressRuleConfig(): any { + return { sourceSecurityGroupId: this.securityGroupId }; + } + + public toEgressRuleConfig(): any { + return { destinationSecurityGroupId: this.securityGroupId }; + } } diff --git a/packages/@aws-cdk/aws-globalaccelerator/lib/accelerator.ts b/packages/@aws-cdk/aws-globalaccelerator/lib/accelerator.ts index 721f641d3c19b..939e91f0a2839 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/lib/accelerator.ts +++ b/packages/@aws-cdk/aws-globalaccelerator/lib/accelerator.ts @@ -1,6 +1,7 @@ import * as cdk from '@aws-cdk/core'; import { Construct } from 'constructs'; import * as ga from './globalaccelerator.generated'; +import { Listener, ListenerOptions } from './listener'; /** * The interface of the Accelerator @@ -63,7 +64,7 @@ export class Accelerator extends cdk.Resource implements IAccelerator { /** * import from attributes */ - public static fromAcceleratorAttributes(scope: Construct, id: string, attrs: AcceleratorAttributes ): IAccelerator { + public static fromAcceleratorAttributes(scope: Construct, id: string, attrs: AcceleratorAttributes): IAccelerator { class Import extends cdk.Resource implements IAccelerator { public readonly acceleratorArn = attrs.acceleratorArn; public readonly dnsName = attrs.dnsName; @@ -86,10 +87,20 @@ export class Accelerator extends cdk.Resource implements IAccelerator { const resource = new ga.CfnAccelerator(this, 'Resource', { enabled: props.enabled ?? true, - name: props.acceleratorName ?? id, + name: props.acceleratorName ?? cdk.Names.uniqueId(this), }); this.acceleratorArn = resource.attrAcceleratorArn; this.dnsName = resource.attrDnsName; } + + /** + * Add a listener to the accelerator + */ + public addListener(id: string, options: ListenerOptions) { + return new Listener(this, id, { + accelerator: this, + ...options, + }); + } } diff --git a/packages/@aws-cdk/aws-globalaccelerator/lib/endpoint-group.ts b/packages/@aws-cdk/aws-globalaccelerator/lib/endpoint-group.ts index b5c96bcd547ba..635ac85ff5708 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/lib/endpoint-group.ts +++ b/packages/@aws-cdk/aws-globalaccelerator/lib/endpoint-group.ts @@ -1,12 +1,11 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import { Construct } from 'constructs'; +import { AcceleratorSecurityGroupPeer } from './_accelerator-security-group'; +import { IEndpoint } from './endpoint'; import * as ga from './globalaccelerator.generated'; import { IListener } from './listener'; -// keep this import separate from other imports to reduce chance for merge conflicts with v2-main -// eslint-disable-next-line no-duplicate-imports, import/order -import { Construct as CoreConstruct } from '@aws-cdk/core'; - /** * The interface of the EndpointGroup */ @@ -19,125 +18,135 @@ export interface IEndpointGroup extends cdk.IResource { } /** - * Options for `addLoadBalancer`, `addElasticIpAddress` and `addEc2Instance` to add endpoints into the endpoint group + * Basic options for creating a new EndpointGroup */ -export interface EndpointConfigurationOptions { +export interface EndpointGroupOptions { /** - * Indicates whether client IP address preservation is enabled for an Application Load Balancer endpoint + * Name of the endpoint group * - * @default true + * @default - logical ID of the resource */ - readonly clientIpReservation?: boolean; + readonly endpointGroupName?: string; /** - * The weight associated with the endpoint. When you add weights to endpoints, you configure AWS Global Accelerator - * to route traffic based on proportions that you specify. For example, you might specify endpoint weights of 4, 5, - * 5, and 6 (sum=20). The result is that 4/20 of your traffic, on average, is routed to the first endpoint, 5/20 is - * routed both to the second and third endpoints, and 6/20 is routed to the last endpoint. - * @see https://docs.aws.amazon.com/global-accelerator/latest/dg/about-endpoints-endpoint-weights.html - * @default - not specified + * The AWS Region where the endpoint group is located. + * + * @default - region of the first endpoint in this group, or the stack region if that region can't be determined */ - readonly weight?: number; -} + readonly region?: string; -/** - * Properties to create EndpointConfiguration - * - */ -export interface EndpointConfigurationProps extends EndpointConfigurationOptions { /** - * The endopoint group reesource + * The time between health checks for each endpoint + * + * Must be either 10 or 30 seconds. * - * [disable-awslint:ref-via-interface] + * @default Duration.seconds(30) */ - readonly endpointGroup: EndpointGroup; + readonly healthCheckInterval?: cdk.Duration; /** - * An ID for the endpoint. If the endpoint is a Network Load Balancer or Application Load Balancer, - * this is the Amazon Resource Name (ARN) of the resource. If the endpoint is an Elastic IP address, - * this is the Elastic IP address allocation ID. For EC2 instances, this is the EC2 instance ID. + * The ping path for health checks (if the protocol is HTTP(S)). + * + * @default '/' */ - readonly endpointId: string; -} + readonly healthCheckPath?: string; -/** - * LoadBalancer Interface - */ -export interface LoadBalancer { /** - * The ARN of this load balancer + * The port used to perform health checks + * + * @default - The listener's port */ - readonly loadBalancerArn: string; -} + readonly healthCheckPort?: number; -/** - * EC2 Instance interface - */ -export interface Ec2Instance { /** - * The id of the instance resource + * The protocol used to perform health checks + * + * @default HealthCheckProtocol.TCP */ - readonly instanceId: string; -} + readonly healthCheckProtocol?: HealthCheckProtocol; -/** - * EIP Interface - */ -export interface ElasticIpAddress { /** - * allocation ID of the EIP resoruce + * The number of consecutive health checks required to set the state of a + * healthy endpoint to unhealthy, or to set an unhealthy endpoint to healthy. + * + * @default 3 */ - readonly attrAllocationId: string -} + readonly healthCheckThreshold?: number; -/** - * Property of the EndpointGroup - */ -export interface EndpointGroupProps { /** - * Name of the endpoint group + * The percentage of traffic to send to this AWS Region. * - * @default - logical ID of the resource + * The percentage is applied to the traffic that would otherwise have been + * routed to the Region based on optimal routing. Additional traffic is + * distributed to other endpoint groups for this listener. + * + * @default 100 */ - readonly endpointGroupName?: string; + readonly trafficDialPercentage?: number; /** - * The Amazon Resource Name (ARN) of the listener. + * Override the destination ports used to route traffic to an endpoint. + * + * Unless overridden, the port used to hit the endpoint will be the same as the port + * that traffic arrives on at the listener. + * + * @default - No overrides */ - readonly listener: IListener; + readonly portOverrides?: PortOverride[] /** - * The AWS Region where the endpoint group is located. + * Initial list of endpoints for this group * - * @default - the region of the current stack + * @default - Group is initially empty */ - readonly region?: string; + readonly endpoints?: IEndpoint[]; } /** - * The class for endpoint configuration + * Override specific listener ports used to route traffic to endpoints that are part of an endpoint group. */ -export class EndpointConfiguration extends CoreConstruct { +export interface PortOverride { /** - * The property containing all the configuration to be rendered + * The listener port that you want to map to a specific endpoint port. + * + * This is the port that user traffic arrives to the Global Accelerator on. */ - public readonly props: EndpointConfigurationProps; - constructor(scope: Construct, id: string, props: EndpointConfigurationProps) { - super(scope, id); - this.props = props; - props.endpointGroup._linkEndpoint(this); - } + readonly listenerPort: number; /** - * render the endpoint configuration for the endpoint group + * The endpoint port that you want a listener port to be mapped to. + * + * This is the port on the endpoint, such as the Application Load Balancer or Amazon EC2 instance. */ - public renderEndpointConfiguration(): ga.CfnEndpointGroup.EndpointConfigurationProperty { - return { - clientIpPreservationEnabled: this.props.clientIpReservation, - endpointId: this.props.endpointId, - weight: this.props.weight, - }; - } + readonly endpointPort: number; +} + +/** + * The protocol for the connections from clients to the accelerator. + */ +export enum HealthCheckProtocol { + /** + * TCP + */ + TCP = 'TCP', + /** + * HTTP + */ + HTTP = 'HTTP', + /** + * HTTPS + */ + HTTPS = 'HTTPS', +} + +/** + * Property of the EndpointGroup + */ +export interface EndpointGroupProps extends EndpointGroupOptions { + /** + * The Amazon Resource Name (ARN) of the listener. + */ + readonly listener: IListener; } /** @@ -165,75 +174,72 @@ export class EndpointGroup extends cdk.Resource implements IEndpointGroup { /** * The array of the endpoints in this endpoint group */ - protected readonly endpoints = new Array(); + protected readonly endpoints = new Array(); constructor(scope: Construct, id: string, props: EndpointGroupProps) { super(scope, id); const resource = new ga.CfnEndpointGroup(this, 'Resource', { listenerArn: props.listener.listenerArn, - endpointGroupRegion: props.region ?? cdk.Stack.of(this).region, + endpointGroupRegion: props.region ?? cdk.Lazy.string({ produce: () => this.firstEndpointRegion() }), endpointConfigurations: cdk.Lazy.any({ produce: () => this.renderEndpoints() }, { omitEmptyArray: true }), + healthCheckIntervalSeconds: props.healthCheckInterval?.toSeconds({ integral: true }), + healthCheckPath: props.healthCheckPath, + healthCheckPort: props.healthCheckPort, + healthCheckProtocol: props.healthCheckProtocol, + thresholdCount: props.healthCheckThreshold, + trafficDialPercentage: props.trafficDialPercentage, + portOverrides: props.portOverrides?.map(o => ({ + endpointPort: o.endpointPort, + listenerPort: o.listenerPort, + })), }); this.endpointGroupArn = resource.attrEndpointGroupArn; this.endpointGroupName = props.endpointGroupName ?? resource.logicalId; - } - /** - * Add an endpoint - */ - public addEndpoint(id: string, endpointId: string, props: EndpointConfigurationOptions = - {}) { - return new EndpointConfiguration(this, id, { - endpointGroup: this, - endpointId, - ...props, - }); + for (const endpoint of props.endpoints ?? []) { + this.addEndpoint(endpoint); + } } /** - * Add an Elastic Load Balancer as an endpoint in this endpoint group + * Add an endpoint */ - public addLoadBalancer(id: string, lb: LoadBalancer, props: EndpointConfigurationOptions = {}) { - return new EndpointConfiguration(this, id, { - endpointId: lb.loadBalancerArn, - endpointGroup: this, - ...props, - }); + public addEndpoint(endpoint: IEndpoint) { + this.endpoints.push(endpoint); } /** - * Add an EIP as an endpoint in this endpoint group + * Return an object that represents the Accelerator's Security Group + * + * Uses a Custom Resource to look up the Security Group that Accelerator + * creates at deploy time. Requires your VPC ID to perform the lookup. + * + * The Security Group will only be created if you enable **Client IP + * Preservation** on any of the endpoints. + * + * You cannot manipulate the rules inside this security group, but you can + * use this security group as a Peer in Connections rules on other + * constructs. */ - public addElasticIpAddress(id: string, eip: ElasticIpAddress, props: EndpointConfigurationOptions = {}) { - return new EndpointConfiguration(this, id, { - endpointId: eip.attrAllocationId, - endpointGroup: this, - ...props, - }); + public connectionsPeer(id: string, vpc: ec2.IVpc): ec2.IPeer { + return AcceleratorSecurityGroupPeer.fromVpc(this, id, vpc, this); } - /** - * Add an EC2 Instance as an endpoint in this endpoint group - */ - public addEc2Instance(id: string, instance: Ec2Instance, props: EndpointConfigurationOptions = {}) { - return new EndpointConfiguration(this, id, { - endpointId: instance.instanceId, - endpointGroup: this, - ...props, - }); + private renderEndpoints() { + return this.endpoints.map(e => e.renderEndpointConfiguration()); } /** - * Links a endpoint to this endpoint group - * @internal + * Return the first (readable) region of the endpoints in this group */ - public _linkEndpoint(endpoint: EndpointConfiguration) { - this.endpoints.push(endpoint); - } - - private renderEndpoints() { - return this.endpoints.map(e => e.renderEndpointConfiguration()); + private firstEndpointRegion() { + for (const endpoint of this.endpoints) { + if (endpoint.region) { + return endpoint.region; + } + } + return cdk.Stack.of(this).region; } } diff --git a/packages/@aws-cdk/aws-globalaccelerator/lib/endpoint.ts b/packages/@aws-cdk/aws-globalaccelerator/lib/endpoint.ts new file mode 100644 index 0000000000000..a99f54421fab1 --- /dev/null +++ b/packages/@aws-cdk/aws-globalaccelerator/lib/endpoint.ts @@ -0,0 +1,87 @@ +import { CfnEndpointGroup } from './globalaccelerator.generated'; + +/** + * An endpoint for the endpoint group + * + * Implementations of `IEndpoint` can be found in the `aws-globalaccelerator-endpoints` package. + */ +export interface IEndpoint { + /** + * The region where the endpoint is located + * + * If the region cannot be determined, `undefined` is returned + */ + readonly region?: string; + + /** + * Render the endpoint to an endpoint configuration + */ + renderEndpointConfiguration(): any; +} + +/** + * Properties for RawEndpoint + */ +export interface RawEndpointProps { + /** + * Identifier of the endpoint + * + * Load balancer ARN, instance ID or EIP allocation ID. + */ + readonly endpointId: string; + + /** + * Endpoint weight across all endpoints in the group + * + * Must be a value between 0 and 255. + * + * @default 128 + */ + readonly weight?: number; + + /** + * Forward the client IP address + * + * GlobalAccelerator will create Network Interfaces in your VPC in order + * to preserve the client IP address. + * + * Only applies to Application Load Balancers and EC2 instances. + * + * Client IP address preservation is supported only in specific AWS Regions. + * See the GlobalAccelerator Developer Guide for a list. + * + * @default true if possible and available + */ + readonly preserveClientIp?: boolean; + + /** + * The region where this endpoint is located + * + * @default - Unknown what region this endpoint is located + */ + readonly region?: string; +} + +/** + * Untyped endpoint implementation + * + * Prefer using the classes in the `aws-globalaccelerator-endpoints` package instead, + * as they accept typed constructs. You can use this class if you want to use an + * endpoint type that does not have an appropriate class in that package yet. + */ +export class RawEndpoint implements IEndpoint { + public readonly region?: string; + + constructor(private readonly props: RawEndpointProps) { + this.region = props.region; + } + + public renderEndpointConfiguration(): any { + return { + endpointId: this.props.endpointId, + weight: this.props.weight, + clientIpPreservationEnabled: this.props.preserveClientIp, + } as CfnEndpointGroup.EndpointConfigurationProperty; + } +} + diff --git a/packages/@aws-cdk/aws-globalaccelerator/lib/index.ts b/packages/@aws-cdk/aws-globalaccelerator/lib/index.ts index ff4675e6af2e5..de29a6d6ed08b 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/lib/index.ts +++ b/packages/@aws-cdk/aws-globalaccelerator/lib/index.ts @@ -1,6 +1,6 @@ // AWS::GlobalAccelerator CloudFormation Resources: export * from './globalaccelerator.generated'; export * from './accelerator'; -export * from './accelerator-security-group'; export * from './listener'; export * from './endpoint-group'; +export * from './endpoint'; diff --git a/packages/@aws-cdk/aws-globalaccelerator/lib/listener.ts b/packages/@aws-cdk/aws-globalaccelerator/lib/listener.ts index 2f29bde4b03c7..39c5c0e4699b1 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/lib/listener.ts +++ b/packages/@aws-cdk/aws-globalaccelerator/lib/listener.ts @@ -1,6 +1,7 @@ import * as cdk from '@aws-cdk/core'; import { Construct } from 'constructs'; import { IAccelerator } from './accelerator'; +import { EndpointGroup, EndpointGroupOptions } from './endpoint-group'; import * as ga from './globalaccelerator.generated'; /** @@ -16,9 +17,9 @@ export interface IListener extends cdk.IResource { } /** - * construct properties for Listener + * Construct options for Listener */ -export interface ListenerProps { +export interface ListenerOptions { /** * Name of the listener * @@ -26,11 +27,6 @@ export interface ListenerProps { */ readonly listenerName?: string; - /** - * The accelerator for this listener - */ - readonly accelerator: IAccelerator; - /** * The list of port ranges for the connections from clients to the accelerator */ @@ -39,18 +35,35 @@ export interface ListenerProps { /** * The protocol for the connections from clients to the accelerator * - * @default TCP + * @default ConnectionProtocol.TCP */ readonly protocol?: ConnectionProtocol; /** * Client affinity to direct all requests from a user to the same endpoint * - * @default NONE + * If you have stateful applications, client affinity lets you direct all + * requests from a user to the same endpoint. + * + * By default, each connection from each client is routed to seperate + * endpoints. Set client affinity to SOURCE_IP to route all connections from + * a single client to the same endpoint. + * + * @default ClientAffinity.NONE */ readonly clientAffinity?: ClientAffinity; } +/** + * Construct properties for Listener + */ +export interface ListenerProps extends ListenerOptions { + /** + * The accelerator for this listener + */ + readonly accelerator: IAccelerator; +} + /** * The list of port ranges for the connections from clients to the accelerator. */ @@ -58,11 +71,14 @@ export interface PortRange { /** * The first port in the range of ports, inclusive. */ - readonly fromPort: number, + readonly fromPort: number; + /** * The last port in the range of ports, inclusive. + * + * @default - same as `fromPort` */ - readonly toPort: number, + readonly toPort?: number; } /** @@ -80,20 +96,20 @@ export enum ConnectionProtocol { } /** - * Client affinity lets you direct all requests from a user to the same endpoint, if you have stateful applications, - * regardless of the port and protocol of the client request. Client affinity gives you control over whether to always - * route each client to the same specific endpoint. If you want a given client to always be routed to the same - * endpoint, set client affinity to SOURCE_IP. + * Client affinity gives you control over whether to always route each client to the same specific endpoint. * * @see https://docs.aws.amazon.com/global-accelerator/latest/dg/about-listeners.html#about-listeners-client-affinity */ export enum ClientAffinity { /** - * default affinity + * Route traffic based on the 5-tuple `(source IP, source port, destination IP, destination port, protocol)` */ NONE = 'NONE', + /** - * affinity by source IP + * Route traffic based on the 2-tuple `(source IP, destination IP)` + * + * The result is that multiple connections from the same client will be routed the same. */ SOURCE_IP = 'SOURCE_IP', } @@ -127,7 +143,7 @@ export class Listener extends cdk.Resource implements IListener { acceleratorArn: props.accelerator.acceleratorArn, portRanges: props.portRanges.map(m => ({ fromPort: m.fromPort, - toPort: m.toPort, + toPort: m.toPort ?? m.fromPort, })), protocol: props.protocol ?? ConnectionProtocol.TCP, clientAffinity: props.clientAffinity ?? ClientAffinity.NONE, @@ -135,6 +151,15 @@ export class Listener extends cdk.Resource implements IListener { this.listenerArn = resource.attrListenerArn; this.listenerName = props.listenerName ?? resource.logicalId; + } + /** + * Add a new endpoint group to this listener + */ + public addEndpointGroup(id: string, options: EndpointGroupOptions = {}) { + return new EndpointGroup(this, id, { + listener: this, + ...options, + }); } } diff --git a/packages/@aws-cdk/aws-globalaccelerator/package.json b/packages/@aws-cdk/aws-globalaccelerator/package.json index 44d8895ed30a3..31fbba06e5bc0 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/package.json +++ b/packages/@aws-cdk/aws-globalaccelerator/package.json @@ -73,30 +73,31 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", "cdk-integ-tools": "0.0.0", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0", + "constructs": "^3.3.69", "@aws-cdk/custom-resources": "0.0.0" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, - "stability": "experimental", - "maturity": "experimental", + "stability": "stable", + "maturity": "stable", "awscdkio": { "announce": false }, diff --git a/packages/@aws-cdk/aws-globalaccelerator/test/globalaccelerator-security-group.test.ts b/packages/@aws-cdk/aws-globalaccelerator/test/globalaccelerator-security-group.test.ts index 20881d152f396..7191988ed2ed6 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/test/globalaccelerator-security-group.test.ts +++ b/packages/@aws-cdk/aws-globalaccelerator/test/globalaccelerator-security-group.test.ts @@ -1,7 +1,7 @@ -import { expect, haveResource, ResourcePart } from '@aws-cdk/assert'; -import { Port } from '@aws-cdk/aws-ec2'; +import { expect, haveResource, ResourcePart } from '@aws-cdk/assert-internal'; +import * as ec2 from '@aws-cdk/aws-ec2'; import * as ga from '../lib'; -import { testFixture, testFixtureAlb } from './util'; +import { testFixture } from './util'; test('custom resource exists', () => { // GIVEN @@ -19,7 +19,7 @@ test('custom resource exists', () => { const endpointGroup = new ga.EndpointGroup(stack, 'Group', { listener }); // WHEN - ga.AcceleratorSecurityGroup.fromVpc(stack, 'GlobalAcceleratorSG', vpc, endpointGroup); + endpointGroup.connectionsPeer('GlobalAcceleratorSG', vpc); // THEN expect(stack).to(haveResource('Custom::AWS', { @@ -45,7 +45,7 @@ test('custom resource exists', () => { InstallLatestAwsSdk: true, }, DependsOn: [ - 'GlobalAcceleratorSGCustomResourceCustomResourcePolicyF3294553', + 'GroupGlobalAcceleratorSGCustomResourceCustomResourcePolicy9C957AD2', 'GroupC77FDACD', ], }, ResourcePart.CompleteDefinition)); @@ -53,7 +53,7 @@ test('custom resource exists', () => { test('can create security group rule', () => { // GIVEN - const { stack, alb, vpc } = testFixtureAlb(); + const { stack, vpc } = testFixture(); const accelerator = new ga.Accelerator(stack, 'Accelerator'); const listener = new ga.Listener(stack, 'Listener', { accelerator, @@ -65,11 +65,12 @@ test('can create security group rule', () => { ], }); const endpointGroup = new ga.EndpointGroup(stack, 'Group', { listener }); - endpointGroup.addLoadBalancer('endpoint', alb); // WHEN - const sg = ga.AcceleratorSecurityGroup.fromVpc(stack, 'GlobalAcceleratorSG', vpc, endpointGroup); - alb.connections.allowFrom(sg, Port.tcp(443)); + const gaSg = endpointGroup.connectionsPeer('GlobalAcceleratorSG', vpc); + const instanceSg = new ec2.SecurityGroup(stack, 'SG', { vpc }); + const instanceConnections = new ec2.Connections({ securityGroups: [instanceSg] }); + instanceConnections.allowFrom(gaSg, ec2.Port.tcp(443)); // THEN expect(stack).to(haveResource('AWS::EC2::SecurityGroupIngress', { @@ -77,13 +78,13 @@ test('can create security group rule', () => { FromPort: 443, GroupId: { 'Fn::GetAtt': [ - 'ALBSecurityGroup8B8624F8', + 'SGADB53937', 'GroupId', ], }, SourceSecurityGroupId: { 'Fn::GetAtt': [ - 'GlobalAcceleratorSGCustomResourceC1DB5287', + 'GroupGlobalAcceleratorSGCustomResource0C8056E9', 'SecurityGroups.0.GroupId', ], }, diff --git a/packages/@aws-cdk/aws-globalaccelerator/test/globalaccelerator.test.ts b/packages/@aws-cdk/aws-globalaccelerator/test/globalaccelerator.test.ts index 72e1c79e586dd..bd46c697ac1c3 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/test/globalaccelerator.test.ts +++ b/packages/@aws-cdk/aws-globalaccelerator/test/globalaccelerator.test.ts @@ -1,6 +1,5 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; -import * as ec2 from '@aws-cdk/aws-ec2'; -import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; +import { Duration } from '@aws-cdk/core'; import * as ga from '../lib'; import { testFixture } from './util'; @@ -52,6 +51,29 @@ test('create listener', () => { })); }); +test('toPort defaults to fromPort if left out', () => { + // GIVEN + const { stack } = testFixture(); + + // WHEN + const accelerator = new ga.Accelerator(stack, 'Accelerator'); + accelerator.addListener('Listener', { + portRanges: [ + { fromPort: 123 }, + ], + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::GlobalAccelerator::Listener', { + PortRanges: [ + { + FromPort: 123, + ToPort: 123, + }, + ], + })); +}); + test('create endpointgroup', () => { // GIVEN const { stack } = testFixture(); @@ -83,73 +105,75 @@ test('create endpointgroup', () => { })); }); -test('addEndpoint', () => { +test('endpointgroup region is the first endpoint\'s region', () => { // GIVEN - const { stack, vpc } = testFixture(); + const { stack } = testFixture(); // WHEN const accelerator = new ga.Accelerator(stack, 'Accelerator'); const listener = new ga.Listener(stack, 'Listener', { accelerator, - portRanges: [ - { - fromPort: 80, - toPort: 80, - }, - ], + portRanges: [{ fromPort: 80 }], }); - const endpointGroup = new ga.EndpointGroup(stack, 'Group', { listener }); - const instance = new ec2.Instance(stack, 'Instance', { - vpc, - machineImage: new ec2.AmazonLinuxImage(), - instanceType: new ec2.InstanceType('t3.small'), + listener.addEndpointGroup('Group', { + endpoints: [ + new ga.RawEndpoint({ + endpointId: 'x-123', + region: 'us-bla-5', + }), + ], }); - endpointGroup.addEndpoint('endpoint', instance.instanceId); // THEN expect(stack).to(haveResourceLike('AWS::GlobalAccelerator::EndpointGroup', { - EndpointConfigurations: [ - { - EndpointId: { - Ref: 'InstanceC1063A87', - }, - }, - ], + EndpointGroupRegion: 'us-bla-5', })); }); -test('addLoadBalancer', () => { +test('endpointgroup with all parameters', () => { // GIVEN - const { stack, vpc } = testFixture(); + const { stack } = testFixture(); // WHEN const accelerator = new ga.Accelerator(stack, 'Accelerator'); - const listener = new ga.Listener(stack, 'Listener', { - accelerator, - portRanges: [ + const listener = accelerator.addListener('Listener', { + portRanges: [{ fromPort: 80 }], + }); + listener.addEndpointGroup('Group', { + region: 'us-bla-5', + healthCheckInterval: Duration.seconds(10), + healthCheckPath: '/ping', + healthCheckPort: 123, + healthCheckProtocol: ga.HealthCheckProtocol.HTTPS, + healthCheckThreshold: 23, + trafficDialPercentage: 86, + portOverrides: [ { - fromPort: 80, - toPort: 80, + listenerPort: 80, + endpointPort: 8080, }, ], }); - const endpointGroup = new ga.EndpointGroup(stack, 'Group', { listener }); - const alb = new elbv2.ApplicationLoadBalancer(stack, 'ALB', { vpc, internetFacing: true }); - endpointGroup.addLoadBalancer('endpoint', alb); // THEN expect(stack).to(haveResourceLike('AWS::GlobalAccelerator::EndpointGroup', { - EndpointConfigurations: [ + EndpointGroupRegion: 'us-bla-5', + HealthCheckIntervalSeconds: 10, + HealthCheckPath: '/ping', + HealthCheckPort: 123, + HealthCheckProtocol: 'HTTPS', + PortOverrides: [ { - EndpointId: { - Ref: 'ALBAEE750D2', - }, + EndpointPort: 8080, + ListenerPort: 80, }, ], + ThresholdCount: 23, + TrafficDialPercentage: 86, })); }); -test('addElasticIpAddress', () => { +test('addEndpoint', () => { // GIVEN const { stack } = testFixture(); @@ -164,56 +188,26 @@ test('addElasticIpAddress', () => { }, ], }); - const endpointGroup = new ga.EndpointGroup(stack, 'Group', { listener }); - const eip = new ec2.CfnEIP(stack, 'ElasticIpAddress'); - endpointGroup.addElasticIpAddress('endpoint', eip); - - // THEN - expect(stack).to(haveResourceLike('AWS::GlobalAccelerator::EndpointGroup', { - EndpointConfigurations: [ - { - EndpointId: { - 'Fn::GetAtt': [ - 'ElasticIpAddress', - 'AllocationId', - ], - }, - }, - ], - })); -}); -test('addEc2Instance', () => { - // GIVEN - const { stack, vpc } = testFixture(); - // WHEN - const accelerator = new ga.Accelerator(stack, 'Accelerator'); - const listener = new ga.Listener(stack, 'Listener', { - accelerator, - portRanges: [ - { - fromPort: 80, - toPort: 80, - }, + listener.addEndpointGroup('Group', { + endpoints: [ + new ga.RawEndpoint({ + endpointId: 'i-123', + preserveClientIp: true, + weight: 30, + }), ], }); - const endpointGroup = new ga.EndpointGroup(stack, 'Group', { listener }); - const instance = new ec2.Instance(stack, 'Instance', { - vpc, - machineImage: new ec2.AmazonLinuxImage(), - instanceType: new ec2.InstanceType('t3.small'), - }); - endpointGroup.addEc2Instance('endpoint', instance); // THEN expect(stack).to(haveResourceLike('AWS::GlobalAccelerator::EndpointGroup', { EndpointConfigurations: [ { - EndpointId: { - Ref: 'InstanceC1063A87', - }, + EndpointId: 'i-123', + ClientIPPreservationEnabled: true, + Weight: 30, }, ], })); -}); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-globalaccelerator/test/util.ts b/packages/@aws-cdk/aws-globalaccelerator/test/util.ts index 9cf60a33a2064..0ad64f2329cf2 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/test/util.ts +++ b/packages/@aws-cdk/aws-globalaccelerator/test/util.ts @@ -1,55 +1,10 @@ import * as ec2 from '@aws-cdk/aws-ec2'; -import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import { App, Stack } from '@aws-cdk/core'; -import { Construct } from 'constructs'; export function testFixture() { - const { stack, app } = testFixtureNoVpc(); - const vpc = new ec2.Vpc(stack, 'VPC'); - - return { stack, vpc, app }; -} - -export function testFixtureNoVpc() { const app = new App(); const stack = new Stack(app, 'Stack'); - return { stack, app }; -} - -export function testFixtureAlb() { - const { stack, app, vpc } = testFixture(); - const alb = new elbv2.ApplicationLoadBalancer(stack, 'ALB', { vpc, internetFacing: true }); - - return { stack, app, alb, vpc }; -} - -export function testFixtureNlb() { - const { stack, app, vpc } = testFixture(); - const nlb = new elbv2.NetworkLoadBalancer(stack, 'NLB', { vpc, internetFacing: true }); - - return { stack, app, nlb }; -} - -export function testFixtureEip() { - const { stack, app } = testFixtureNoVpc(); - const eip = new ec2.CfnEIP(stack, 'ElasticIpAddress'); - - return { stack, app, eip }; -} - -export function testFixtureEc2() { - const { stack, app, vpc } = testFixture(); - const instance = new ec2.Instance(stack, 'Ec2', { - vpc, - machineImage: new ec2.AmazonLinuxImage(), - instanceType: new ec2.InstanceType('t3.small'), - }); - - return { stack, app, instance }; -} + const vpc = new ec2.Vpc(stack, 'VPC'); -export class TestStack extends Stack { - constructor(scope: Construct, id: string) { - super(scope, id); - } -} + return { stack, vpc, app }; +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-glue/jest.config.js b/packages/@aws-cdk/aws-glue/jest.config.js index cd664e1d069e5..54e28beb9798b 100644 --- a/packages/@aws-cdk/aws-glue/jest.config.js +++ b/packages/@aws-cdk/aws-glue/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-glue/package.json b/packages/@aws-cdk/aws-glue/package.json index 3f6a8fa63ceba..22ba5fa62de53 100644 --- a/packages/@aws-cdk/aws-glue/package.json +++ b/packages/@aws-cdk/aws-glue/package.json @@ -71,14 +71,15 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "@aws-cdk/cx-api": "0.0.0", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", @@ -86,7 +87,7 @@ "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -95,7 +96,7 @@ "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-glue/test/connection.test.ts b/packages/@aws-cdk/aws-glue/test/connection.test.ts index 5846bf161fa69..c61cc6197130d 100644 --- a/packages/@aws-cdk/aws-glue/test/connection.test.ts +++ b/packages/@aws-cdk/aws-glue/test/connection.test.ts @@ -1,7 +1,7 @@ -import * as cdkassert from '@aws-cdk/assert'; +import * as cdkassert from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as glue from '../lib'; test('a connection with connection properties', () => { diff --git a/packages/@aws-cdk/aws-glue/test/database.test.ts b/packages/@aws-cdk/aws-glue/test/database.test.ts index c23c290b0960d..f5ad6461ee190 100644 --- a/packages/@aws-cdk/aws-glue/test/database.test.ts +++ b/packages/@aws-cdk/aws-glue/test/database.test.ts @@ -1,6 +1,6 @@ import { deepEqual, throws } from 'assert'; -import { expect } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { expect } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import { Stack } from '@aws-cdk/core'; import * as glue from '../lib'; diff --git a/packages/@aws-cdk/aws-glue/test/schema.test.ts b/packages/@aws-cdk/aws-glue/test/schema.test.ts index f7910dc0bd852..2155655e27e6d 100644 --- a/packages/@aws-cdk/aws-glue/test/schema.test.ts +++ b/packages/@aws-cdk/aws-glue/test/schema.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { doesNotThrow, equal, throws } from 'assert'; import { Schema } from '../lib'; diff --git a/packages/@aws-cdk/aws-glue/test/security-configuration.test.ts b/packages/@aws-cdk/aws-glue/test/security-configuration.test.ts index cd94a660dfcb3..ce89c393e5301 100644 --- a/packages/@aws-cdk/aws-glue/test/security-configuration.test.ts +++ b/packages/@aws-cdk/aws-glue/test/security-configuration.test.ts @@ -1,7 +1,7 @@ -import * as cdkassert from '@aws-cdk/assert'; +import * as cdkassert from '@aws-cdk/assert-internal'; import * as kms from '@aws-cdk/aws-kms'; import * as cdk from '@aws-cdk/core'; -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as glue from '../lib'; test('throws when a security configuration has no encryption config', () => { diff --git a/packages/@aws-cdk/aws-glue/test/table.test.ts b/packages/@aws-cdk/aws-glue/test/table.test.ts index e31c879208aa2..5125c2f5fa411 100644 --- a/packages/@aws-cdk/aws-glue/test/table.test.ts +++ b/packages/@aws-cdk/aws-glue/test/table.test.ts @@ -1,6 +1,6 @@ import { deepEqual, doesNotThrow, equal, notEqual, ok } from 'assert'; -import { expect as cdkExpect, haveResource, ResourcePart } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { expect as cdkExpect, haveResource, ResourcePart } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as s3 from '@aws-cdk/aws-s3'; diff --git a/packages/@aws-cdk/aws-greengrass/package.json b/packages/@aws-cdk/aws-greengrass/package.json index 666c2f02b99f3..b7bb106d71430 100644 --- a/packages/@aws-cdk/aws-greengrass/package.json +++ b/packages/@aws-cdk/aws-greengrass/package.json @@ -73,18 +73,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-greengrass/test/greengrass.test.ts b/packages/@aws-cdk/aws-greengrass/test/greengrass.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-greengrass/test/greengrass.test.ts +++ b/packages/@aws-cdk/aws-greengrass/test/greengrass.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-greengrassv2/package.json b/packages/@aws-cdk/aws-greengrassv2/package.json index 68d9557122c34..a891481eb42d0 100644 --- a/packages/@aws-cdk/aws-greengrassv2/package.json +++ b/packages/@aws-cdk/aws-greengrassv2/package.json @@ -73,18 +73,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-greengrassv2/test/greengrass.test.ts b/packages/@aws-cdk/aws-greengrassv2/test/greengrass.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-greengrassv2/test/greengrass.test.ts +++ b/packages/@aws-cdk/aws-greengrassv2/test/greengrass.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-groundstation/.eslintrc.js b/packages/@aws-cdk/aws-groundstation/.eslintrc.js new file mode 100644 index 0000000000000..61dd8dd001f63 --- /dev/null +++ b/packages/@aws-cdk/aws-groundstation/.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-groundstation/.gitignore b/packages/@aws-cdk/aws-groundstation/.gitignore new file mode 100644 index 0000000000000..62ebc95d75ce6 --- /dev/null +++ b/packages/@aws-cdk/aws-groundstation/.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-groundstation/.npmignore b/packages/@aws-cdk/aws-groundstation/.npmignore new file mode 100644 index 0000000000000..e4486030fcb17 --- /dev/null +++ b/packages/@aws-cdk/aws-groundstation/.npmignore @@ -0,0 +1,28 @@ +# 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 +test/ diff --git a/packages/@aws-cdk/aws-groundstation/LICENSE b/packages/@aws-cdk/aws-groundstation/LICENSE new file mode 100644 index 0000000000000..28e4bdcec77ec --- /dev/null +++ b/packages/@aws-cdk/aws-groundstation/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-2021 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-groundstation/NOTICE b/packages/@aws-cdk/aws-groundstation/NOTICE new file mode 100644 index 0000000000000..5fc3826926b5b --- /dev/null +++ b/packages/@aws-cdk/aws-groundstation/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/aws-groundstation/README.md b/packages/@aws-cdk/aws-groundstation/README.md new file mode 100644 index 0000000000000..85fdbd3aa4247 --- /dev/null +++ b/packages/@aws-cdk/aws-groundstation/README.md @@ -0,0 +1,20 @@ +# AWS::GroundStation 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]) are always stable and safe to use. +> +> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib + +--- + + + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts +import groundstation = require('@aws-cdk/aws-groundstation'); +``` diff --git a/packages/@aws-cdk/aws-groundstation/jest.config.js b/packages/@aws-cdk/aws-groundstation/jest.config.js new file mode 100644 index 0000000000000..54e28beb9798b --- /dev/null +++ b/packages/@aws-cdk/aws-groundstation/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-groundstation/lib/index.ts b/packages/@aws-cdk/aws-groundstation/lib/index.ts new file mode 100644 index 0000000000000..6b16a692a7002 --- /dev/null +++ b/packages/@aws-cdk/aws-groundstation/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::GroundStation CloudFormation Resources: +export * from './groundstation.generated'; diff --git a/packages/@aws-cdk/aws-groundstation/package.json b/packages/@aws-cdk/aws-groundstation/package.json new file mode 100644 index 0000000000000..db78ba45da026 --- /dev/null +++ b/packages/@aws-cdk/aws-groundstation/package.json @@ -0,0 +1,101 @@ +{ + "name": "@aws-cdk/aws-groundstation", + "version": "0.0.0", + "description": "The CDK Construct Library for AWS::GroundStation", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "projectReferences": true, + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.GroundStation", + "packageId": "Amazon.CDK.AWS.GroundStation", + "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.groundstation", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "groundstation" + } + }, + "python": { + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 1" + ], + "distName": "aws-cdk.aws-groundstation", + "module": "aws_cdk.aws_groundstation" + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-groundstation" + }, + "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": "yarn build && yarn test", + "build+test+package": "yarn build+test && yarn package", + "compat": "cdk-compat", + "gen": "cfn2ts", + "rosetta:extract": "yarn --silent jsii-rosetta extract" + }, + "cdk-build": { + "cloudformation": "AWS::GroundStation", + "jest": true, + "env": { + "AWSLINT_BASE_CONSTRUCT": "true" + } + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::GroundStation", + "aws-groundstation" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@types/jest": "^26.0.23", + "@aws-cdk/assert-internal": "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 + }, + "publishConfig": { + "tag": "latest" + } +} diff --git a/packages/@aws-cdk/aws-groundstation/test/groundstation.test.ts b/packages/@aws-cdk/aws-groundstation/test/groundstation.test.ts new file mode 100644 index 0000000000000..c4505ad966984 --- /dev/null +++ b/packages/@aws-cdk/aws-groundstation/test/groundstation.test.ts @@ -0,0 +1,6 @@ +import '@aws-cdk/assert-internal/jest'; +import {} from '../lib'; + +test('No tests are specified for this package', () => { + expect(true).toBe(true); +}); diff --git a/packages/@aws-cdk/aws-guardduty/package.json b/packages/@aws-cdk/aws-guardduty/package.json index 2d772252718cb..16fbd30cfd959 100644 --- a/packages/@aws-cdk/aws-guardduty/package.json +++ b/packages/@aws-cdk/aws-guardduty/package.json @@ -71,19 +71,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-guardduty/test/guardduty.test.ts b/packages/@aws-cdk/aws-guardduty/test/guardduty.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-guardduty/test/guardduty.test.ts +++ b/packages/@aws-cdk/aws-guardduty/test/guardduty.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-iam/README.md b/packages/@aws-cdk/aws-iam/README.md index 8cf5978aaa7c6..b54a0bff34fc4 100644 --- a/packages/@aws-cdk/aws-iam/README.md +++ b/packages/@aws-cdk/aws-iam/README.md @@ -433,6 +433,18 @@ const user = User.fromUserAttributes(stack, 'MyImportedUserByAttributes', { }); ``` +To add a user to a group (both for a new and imported user/group): + +```ts +const user = new User(this, 'MyUser'); // or User.fromUserName(stack, 'User', 'johnsmith'); +const group = new Group(this, 'MyGroup'); // or Group.fromGroupArn(stack, 'Group', 'arn:aws:iam::account-id:group/group-name'); + +user.addToGroup(group); +// or +group.addUser(user); +``` + + ## Features * Policy name uniqueness is enforced. If two policies by the same name are attached to the same diff --git a/packages/@aws-cdk/aws-iam/lib/grant.ts b/packages/@aws-cdk/aws-iam/lib/grant.ts index 6529db181c712..f648d6a4572c3 100644 --- a/packages/@aws-cdk/aws-iam/lib/grant.ts +++ b/packages/@aws-cdk/aws-iam/lib/grant.ts @@ -5,7 +5,6 @@ import { IGrantable, IPrincipal } from './principals'; /** * Basic options for a grant operation * - * @experimental */ export interface CommonGrantOptions { /** @@ -29,7 +28,6 @@ export interface CommonGrantOptions { /** * Options for a grant operation * - * @experimental */ export interface GrantWithResourceOptions extends CommonGrantOptions { /** @@ -53,7 +51,6 @@ export interface GrantWithResourceOptions extends CommonGrantOptions { /** * Options for a grant operation that only applies to principals * - * @experimental */ export interface GrantOnPrincipalOptions extends CommonGrantOptions { /** @@ -67,7 +64,6 @@ export interface GrantOnPrincipalOptions extends CommonGrantOptions { /** * Options for a grant operation to both identity and resource * - * @experimental */ export interface GrantOnPrincipalAndResourceOptions extends CommonGrantOptions { /** diff --git a/packages/@aws-cdk/aws-iam/lib/oidc-provider.ts b/packages/@aws-cdk/aws-iam/lib/oidc-provider.ts index ec70c6d152cbe..ab6d81dd30b90 100644 --- a/packages/@aws-cdk/aws-iam/lib/oidc-provider.ts +++ b/packages/@aws-cdk/aws-iam/lib/oidc-provider.ts @@ -15,7 +15,6 @@ const RESOURCE_TYPE = 'Custom::AWSCDKOpenIdConnectProvider'; /** * Represents an IAM OpenID Connect provider. * - * @experimental */ export interface IOpenIdConnectProvider extends IResource { /** @@ -31,7 +30,6 @@ export interface IOpenIdConnectProvider extends IResource { /** * Initialization properties for `OpenIdConnectProvider`. - * @experimental */ export interface OpenIdConnectProviderProps { /** @@ -101,7 +99,6 @@ export interface OpenIdConnectProviderProps { * @see http://openid.net/connect * @see https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_oidc.html * - * @experimental * @resource AWS::CloudFormation::CustomResource */ export class OpenIdConnectProvider extends Resource implements IOpenIdConnectProvider { diff --git a/packages/@aws-cdk/aws-iam/lib/principals.ts b/packages/@aws-cdk/aws-iam/lib/principals.ts index 6295b8fa966e9..02bde4cfb4cd2 100644 --- a/packages/@aws-cdk/aws-iam/lib/principals.ts +++ b/packages/@aws-cdk/aws-iam/lib/principals.ts @@ -75,7 +75,6 @@ export interface AddToPrincipalPolicyResult { /** * Whether the statement was added to the identity's policies. * - * @experimental */ readonly statementAdded: boolean; @@ -83,7 +82,6 @@ export interface AddToPrincipalPolicyResult { * Dependable which allows depending on the policy change being applied * * @default - Required if `statementAdded` is true. - * @experimental */ readonly policyDependable?: cdk.IDependable; } diff --git a/packages/@aws-cdk/aws-iam/lib/role.ts b/packages/@aws-cdk/aws-iam/lib/role.ts index 9b81e4f174152..756a0f23832ec 100644 --- a/packages/@aws-cdk/aws-iam/lib/role.ts +++ b/packages/@aws-cdk/aws-iam/lib/role.ts @@ -144,7 +144,6 @@ export interface FromRoleArnOptions { * * @default true * - * @experimental */ readonly mutable?: boolean; } diff --git a/packages/@aws-cdk/aws-iam/lib/saml-provider.ts b/packages/@aws-cdk/aws-iam/lib/saml-provider.ts index 33712adb60ed2..5b2709ce6fe3d 100644 --- a/packages/@aws-cdk/aws-iam/lib/saml-provider.ts +++ b/packages/@aws-cdk/aws-iam/lib/saml-provider.ts @@ -91,7 +91,7 @@ export class SamlProvider extends Resource implements ISamlProvider { } const samlProvider = new CfnSAMLProvider(this, 'Resource', { - name: this.physicalName, + name: props.name, samlMetadataDocument: props.metadataDocument.xml, }); diff --git a/packages/@aws-cdk/aws-iam/lib/user.ts b/packages/@aws-cdk/aws-iam/lib/user.ts index 5c8f6418a9bb8..4874e84f791df 100644 --- a/packages/@aws-cdk/aws-iam/lib/user.ts +++ b/packages/@aws-cdk/aws-iam/lib/user.ts @@ -1,7 +1,7 @@ import { Arn, Aws, Lazy, Resource, SecretValue, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { IGroup } from './group'; -import { CfnUser } from './iam.generated'; +import { CfnUser, CfnUserToGroupAddition } from './iam.generated'; import { IIdentity } from './identity-base'; import { IManagedPolicy } from './managed-policy'; import { Policy } from './policy'; @@ -181,6 +181,7 @@ export class User extends Resource implements IIdentity, IUser { public readonly policyFragment: PrincipalPolicyFragment = new ArnPrincipal(attrs.userArn).policyFragment; private readonly attachedPolicies = new AttachedPolicies(); private defaultPolicy?: Policy; + private groupId = 0; public addToPolicy(statement: PolicyStatement): boolean { return this.addToPrincipalPolicy(statement).statementAdded; @@ -195,8 +196,12 @@ export class User extends Resource implements IIdentity, IUser { return { statementAdded: true, policyDependable: this.defaultPolicy }; } - public addToGroup(_group: IGroup): void { - throw new Error('Cannot add imported User to Group'); + public addToGroup(group: IGroup): void { + new CfnUserToGroupAddition(Stack.of(group), `${this.userName}Group${this.groupId}`, { + groupName: group.groupName, + users: [this.userName], + }); + this.groupId += 1; } public attachInlinePolicy(policy: Policy): void { @@ -229,7 +234,7 @@ export class User extends Resource implements IIdentity, IUser { public readonly userArn: string; /** - * Returns the permissions boundary attached to this user + * Returns the permissions boundary attached to this user */ public readonly permissionsBoundary?: IManagedPolicy; diff --git a/packages/@aws-cdk/aws-iam/package.json b/packages/@aws-cdk/aws-iam/package.json index 76cd09b7b2d9a..e681fbdce8bff 100644 --- a/packages/@aws-cdk/aws-iam/package.json +++ b/packages/@aws-cdk/aws-iam/package.json @@ -78,23 +78,26 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/aws-lambda": "^8.10.76", + "@types/jest": "^26.0.23", + "@types/sinon": "^9.0.11", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "jest": "^26.6.3", "pkglint": "0.0.0", - "sinon": "^9.2.4" + "sinon": "^9.2.4", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", "@aws-cdk/region-info": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", "@aws-cdk/region-info": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "engines": { diff --git a/packages/@aws-cdk/aws-iam/test/auto-cross-stack-refs.test.ts b/packages/@aws-cdk/aws-iam/test/auto-cross-stack-refs.test.ts index c4b752645abd3..1f8384c600fb9 100644 --- a/packages/@aws-cdk/aws-iam/test/auto-cross-stack-refs.test.ts +++ b/packages/@aws-cdk/aws-iam/test/auto-cross-stack-refs.test.ts @@ -1,5 +1,5 @@ -import { SynthUtils } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { SynthUtils } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import * as iam from '../lib'; diff --git a/packages/@aws-cdk/aws-iam/test/cross-account.test.ts b/packages/@aws-cdk/aws-iam/test/cross-account.test.ts index c3a45ec730580..21ca3ce48c945 100644 --- a/packages/@aws-cdk/aws-iam/test/cross-account.test.ts +++ b/packages/@aws-cdk/aws-iam/test/cross-account.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import * as constructs from 'constructs'; import * as iam from '../lib'; diff --git a/packages/@aws-cdk/aws-iam/test/escape-hatch.test.ts b/packages/@aws-cdk/aws-iam/test/escape-hatch.test.ts index 4aa2ce2e9ddb8..b9467638c7307 100644 --- a/packages/@aws-cdk/aws-iam/test/escape-hatch.test.ts +++ b/packages/@aws-cdk/aws-iam/test/escape-hatch.test.ts @@ -1,7 +1,7 @@ // tests for the L1 escape hatches (overrides). those are in the IAM module // because we want to verify them end-to-end, as a complement to the unit // tests in the @aws-cdk/core module -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Stack } from '@aws-cdk/core'; import * as iam from '../lib'; diff --git a/packages/@aws-cdk/aws-iam/test/grant.test.ts b/packages/@aws-cdk/aws-iam/test/grant.test.ts index d9b6131dc967d..04b2466ea21da 100644 --- a/packages/@aws-cdk/aws-iam/test/grant.test.ts +++ b/packages/@aws-cdk/aws-iam/test/grant.test.ts @@ -1,5 +1,5 @@ -import { ResourcePart } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { ResourcePart } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import { CfnResource, Resource, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; import * as iam from '../lib'; diff --git a/packages/@aws-cdk/aws-iam/test/group.test.ts b/packages/@aws-cdk/aws-iam/test/group.test.ts index e18c10338538a..d8b7c6fb47913 100644 --- a/packages/@aws-cdk/aws-iam/test/group.test.ts +++ b/packages/@aws-cdk/aws-iam/test/group.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { App, Stack } from '@aws-cdk/core'; import { Group, ManagedPolicy, User } from '../lib'; diff --git a/packages/@aws-cdk/aws-iam/test/immutable-role.test.ts b/packages/@aws-cdk/aws-iam/test/immutable-role.test.ts index 343c437c494e4..3ba5c870f8659 100644 --- a/packages/@aws-cdk/aws-iam/test/immutable-role.test.ts +++ b/packages/@aws-cdk/aws-iam/test/immutable-role.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Stack } from '@aws-cdk/core'; import * as iam from '../lib'; diff --git a/packages/@aws-cdk/aws-iam/test/lazy-role.test.ts b/packages/@aws-cdk/aws-iam/test/lazy-role.test.ts index 69a1fb41d2d45..34d8919ccd14c 100644 --- a/packages/@aws-cdk/aws-iam/test/lazy-role.test.ts +++ b/packages/@aws-cdk/aws-iam/test/lazy-role.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import * as iam from '../lib'; diff --git a/packages/@aws-cdk/aws-iam/test/managed-policy.test.ts b/packages/@aws-cdk/aws-iam/test/managed-policy.test.ts index ba4769d7dfd14..3561ed4f79f19 100644 --- a/packages/@aws-cdk/aws-iam/test/managed-policy.test.ts +++ b/packages/@aws-cdk/aws-iam/test/managed-policy.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import { Group, ManagedPolicy, PolicyDocument, PolicyStatement, Role, ServicePrincipal, User } from '../lib'; 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 b0beb5d5843f1..805e7bbb66ac0 100644 --- a/packages/@aws-cdk/aws-iam/test/oidc-provider.test.ts +++ b/packages/@aws-cdk/aws-iam/test/oidc-provider.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { App, Stack, Token } from '@aws-cdk/core'; import * as sinon from 'sinon'; import * as iam from '../lib'; diff --git a/packages/@aws-cdk/aws-iam/test/permissions-boundary.test.ts b/packages/@aws-cdk/aws-iam/test/permissions-boundary.test.ts index 99a14de55f2e1..46d840b17159b 100644 --- a/packages/@aws-cdk/aws-iam/test/permissions-boundary.test.ts +++ b/packages/@aws-cdk/aws-iam/test/permissions-boundary.test.ts @@ -1,5 +1,5 @@ -import { ABSENT } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { ABSENT } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import { App, Stack } from '@aws-cdk/core'; import * as iam from '../lib'; diff --git a/packages/@aws-cdk/aws-iam/test/policy-document.test.ts b/packages/@aws-cdk/aws-iam/test/policy-document.test.ts index bd3bd6fd31aa3..e3cc579fb1c16 100644 --- a/packages/@aws-cdk/aws-iam/test/policy-document.test.ts +++ b/packages/@aws-cdk/aws-iam/test/policy-document.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Lazy, Stack, Token } from '@aws-cdk/core'; import { AccountPrincipal, Anyone, AnyPrincipal, ArnPrincipal, CanonicalUserPrincipal, CompositePrincipal, diff --git a/packages/@aws-cdk/aws-iam/test/policy-statement.test.ts b/packages/@aws-cdk/aws-iam/test/policy-statement.test.ts index 089fa34dba74e..929343ac240c7 100644 --- a/packages/@aws-cdk/aws-iam/test/policy-statement.test.ts +++ b/packages/@aws-cdk/aws-iam/test/policy-statement.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Stack } from '@aws-cdk/core'; import { AnyPrincipal, Group, PolicyDocument, PolicyStatement } from '../lib'; diff --git a/packages/@aws-cdk/aws-iam/test/policy.test.ts b/packages/@aws-cdk/aws-iam/test/policy.test.ts index d2ff50aa4dbb8..cb6c2fc88cf52 100644 --- a/packages/@aws-cdk/aws-iam/test/policy.test.ts +++ b/packages/@aws-cdk/aws-iam/test/policy.test.ts @@ -1,5 +1,5 @@ -import { ResourcePart } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { ResourcePart } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import { App, CfnResource, Stack } from '@aws-cdk/core'; import { AnyPrincipal, CfnPolicy, Group, Policy, PolicyDocument, PolicyStatement, Role, ServicePrincipal, User } from '../lib'; diff --git a/packages/@aws-cdk/aws-iam/test/principals.test.ts b/packages/@aws-cdk/aws-iam/test/principals.test.ts index 43ed8433c47f6..ed23d7eb0ce09 100644 --- a/packages/@aws-cdk/aws-iam/test/principals.test.ts +++ b/packages/@aws-cdk/aws-iam/test/principals.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { App, CfnOutput, Stack } from '@aws-cdk/core'; import * as iam from '../lib'; diff --git a/packages/@aws-cdk/aws-iam/test/role.from-role-arn.test.ts b/packages/@aws-cdk/aws-iam/test/role.from-role-arn.test.ts index afe6fb576f298..9faffb99b836e 100644 --- a/packages/@aws-cdk/aws-iam/test/role.from-role-arn.test.ts +++ b/packages/@aws-cdk/aws-iam/test/role.from-role-arn.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert/jest'; -import { App, CfnElement, Lazy, Stack } from '@aws-cdk/core'; +import '@aws-cdk/assert-internal/jest'; +import { App, Aws, CfnElement, Lazy, Stack } from '@aws-cdk/core'; import { AnyPrincipal, ArnPrincipal, IRole, Policy, PolicyStatement, Role } from '../lib'; /* eslint-disable quote-props */ @@ -519,6 +519,21 @@ describe('IAM Role.fromRoleArn', () => { }); }); }); + + describe('for an incorrect ARN', () => { + beforeEach(() => { + roleStack = new Stack(app, 'RoleStack'); + }); + + describe("that accidentally skipped the 'region' fragment of the ARN", () => { + test('throws an exception, indicating that error', () => { + expect(() => { + Role.fromRoleArn(roleStack, 'Role', + `arn:${Aws.PARTITION}:iam:${Aws.ACCOUNT_ID}:role/AwsCicd-${Aws.REGION}-CodeBuildRole`); + }).toThrow(/The `resource` component \(6th component\) of an ARN is required:/); + }); + }); + }); }); function somePolicyStatement() { diff --git a/packages/@aws-cdk/aws-iam/test/role.test.ts b/packages/@aws-cdk/aws-iam/test/role.test.ts index 8f0415c45598d..1e64f8a9a9369 100644 --- a/packages/@aws-cdk/aws-iam/test/role.test.ts +++ b/packages/@aws-cdk/aws-iam/test/role.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Duration, Stack, App } from '@aws-cdk/core'; import { AnyPrincipal, ArnPrincipal, CompositePrincipal, FederatedPrincipal, ManagedPolicy, PolicyStatement, Role, ServicePrincipal, User, Policy, PolicyDocument } from '../lib'; diff --git a/packages/@aws-cdk/aws-iam/test/saml-provider.test.ts b/packages/@aws-cdk/aws-iam/test/saml-provider.test.ts index 1878e65c51a14..83ade3741fb3a 100644 --- a/packages/@aws-cdk/aws-iam/test/saml-provider.test.ts +++ b/packages/@aws-cdk/aws-iam/test/saml-provider.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Stack } from '@aws-cdk/core'; import { SamlMetadataDocument, SamlProvider } from '../lib'; @@ -17,6 +17,18 @@ test('SAML provider', () => { }); }); +test('SAML provider name', () => { + new SamlProvider(stack, 'Provider', { + metadataDocument: SamlMetadataDocument.fromXml('document'), + name: 'provider-name', + }); + + expect(stack).toHaveResource('AWS::IAM::SAMLProvider', { + SamlMetadataDocument: 'document', + Name: 'provider-name', + }); +}); + test('throws with invalid name', () => { expect(() => new SamlProvider(stack, 'Provider', { name: 'invalid name', diff --git a/packages/@aws-cdk/aws-iam/test/user.test.ts b/packages/@aws-cdk/aws-iam/test/user.test.ts index 4a59a86d4a45d..5cc42ae015619 100644 --- a/packages/@aws-cdk/aws-iam/test/user.test.ts +++ b/packages/@aws-cdk/aws-iam/test/user.test.ts @@ -1,6 +1,6 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { App, SecretValue, Stack } from '@aws-cdk/core'; -import { ManagedPolicy, Policy, PolicyStatement, User } from '../lib'; +import { Group, ManagedPolicy, Policy, PolicyStatement, User } from '../lib'; describe('IAM user', () => { test('default user', () => { @@ -177,4 +177,35 @@ describe('IAM user', () => { }, }); }); + + test('addToGroup for imported user', () => { + // GIVEN + const stack = new Stack(); + const user = User.fromUserName(stack, 'ImportedUser', 'john'); + const group = new Group(stack, 'Group'); + const otherGroup = new Group(stack, 'OtherGroup'); + + // WHEN + user.addToGroup(group); + otherGroup.addUser(user); + + // THEN + expect(stack).toHaveResource('AWS::IAM::UserToGroupAddition', { + GroupName: { + Ref: 'GroupC77FDACD', + }, + Users: [ + 'john', + ], + }); + + expect(stack).toHaveResource('AWS::IAM::UserToGroupAddition', { + GroupName: { + Ref: 'OtherGroup85E5C653', + }, + Users: [ + 'john', + ], + }); + }); }); diff --git a/packages/@aws-cdk/aws-imagebuilder/package.json b/packages/@aws-cdk/aws-imagebuilder/package.json index 25cf2f2c92657..5a46b27b57ae7 100644 --- a/packages/@aws-cdk/aws-imagebuilder/package.json +++ b/packages/@aws-cdk/aws-imagebuilder/package.json @@ -73,10 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-imagebuilder/test/imagebuilder.test.ts b/packages/@aws-cdk/aws-imagebuilder/test/imagebuilder.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-imagebuilder/test/imagebuilder.test.ts +++ b/packages/@aws-cdk/aws-imagebuilder/test/imagebuilder.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-inspector/package.json b/packages/@aws-cdk/aws-inspector/package.json index a94beb9c3ab2e..4dd122dd74ed4 100644 --- a/packages/@aws-cdk/aws-inspector/package.json +++ b/packages/@aws-cdk/aws-inspector/package.json @@ -71,19 +71,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-inspector/test/inspector.test.ts b/packages/@aws-cdk/aws-inspector/test/inspector.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-inspector/test/inspector.test.ts +++ b/packages/@aws-cdk/aws-inspector/test/inspector.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-iot/package.json b/packages/@aws-cdk/aws-iot/package.json index baec64baf8142..eafe42218f351 100644 --- a/packages/@aws-cdk/aws-iot/package.json +++ b/packages/@aws-cdk/aws-iot/package.json @@ -71,19 +71,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-iot/test/iot.test.ts b/packages/@aws-cdk/aws-iot/test/iot.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-iot/test/iot.test.ts +++ b/packages/@aws-cdk/aws-iot/test/iot.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-iot1click/package.json b/packages/@aws-cdk/aws-iot1click/package.json index 4000a6cd6721d..6415b79eb5455 100644 --- a/packages/@aws-cdk/aws-iot1click/package.json +++ b/packages/@aws-cdk/aws-iot1click/package.json @@ -72,18 +72,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-iot1click/test/iot1click.test.ts b/packages/@aws-cdk/aws-iot1click/test/iot1click.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-iot1click/test/iot1click.test.ts +++ b/packages/@aws-cdk/aws-iot1click/test/iot1click.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-iotanalytics/package.json b/packages/@aws-cdk/aws-iotanalytics/package.json index e3b33ffa331b8..cef522564fd76 100644 --- a/packages/@aws-cdk/aws-iotanalytics/package.json +++ b/packages/@aws-cdk/aws-iotanalytics/package.json @@ -73,18 +73,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-iotanalytics/test/iotanalytics.test.ts b/packages/@aws-cdk/aws-iotanalytics/test/iotanalytics.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-iotanalytics/test/iotanalytics.test.ts +++ b/packages/@aws-cdk/aws-iotanalytics/test/iotanalytics.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-iotevents/package.json b/packages/@aws-cdk/aws-iotevents/package.json index d0ecd71421f76..6bb31f8bac0ba 100644 --- a/packages/@aws-cdk/aws-iotevents/package.json +++ b/packages/@aws-cdk/aws-iotevents/package.json @@ -73,18 +73,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-iotevents/test/iotevents.test.ts b/packages/@aws-cdk/aws-iotevents/test/iotevents.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-iotevents/test/iotevents.test.ts +++ b/packages/@aws-cdk/aws-iotevents/test/iotevents.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-iotfleethub/.eslintrc.js b/packages/@aws-cdk/aws-iotfleethub/.eslintrc.js new file mode 100644 index 0000000000000..61dd8dd001f63 --- /dev/null +++ b/packages/@aws-cdk/aws-iotfleethub/.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-iotfleethub/.gitignore b/packages/@aws-cdk/aws-iotfleethub/.gitignore new file mode 100644 index 0000000000000..62ebc95d75ce6 --- /dev/null +++ b/packages/@aws-cdk/aws-iotfleethub/.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-iotfleethub/.npmignore b/packages/@aws-cdk/aws-iotfleethub/.npmignore new file mode 100644 index 0000000000000..e4486030fcb17 --- /dev/null +++ b/packages/@aws-cdk/aws-iotfleethub/.npmignore @@ -0,0 +1,28 @@ +# 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 +test/ diff --git a/packages/@aws-cdk/aws-iotfleethub/LICENSE b/packages/@aws-cdk/aws-iotfleethub/LICENSE new file mode 100644 index 0000000000000..28e4bdcec77ec --- /dev/null +++ b/packages/@aws-cdk/aws-iotfleethub/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-2021 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-iotfleethub/NOTICE b/packages/@aws-cdk/aws-iotfleethub/NOTICE new file mode 100644 index 0000000000000..5fc3826926b5b --- /dev/null +++ b/packages/@aws-cdk/aws-iotfleethub/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/aws-iotfleethub/README.md b/packages/@aws-cdk/aws-iotfleethub/README.md new file mode 100644 index 0000000000000..8a07a0f02d3ee --- /dev/null +++ b/packages/@aws-cdk/aws-iotfleethub/README.md @@ -0,0 +1,20 @@ +# AWS::IoTFleetHub 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]) are always stable and safe to use. +> +> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib + +--- + + + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts +import iotfleethub = require('@aws-cdk/aws-iotfleethub'); +``` diff --git a/packages/@aws-cdk/aws-iotfleethub/jest.config.js b/packages/@aws-cdk/aws-iotfleethub/jest.config.js new file mode 100644 index 0000000000000..54e28beb9798b --- /dev/null +++ b/packages/@aws-cdk/aws-iotfleethub/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-iotfleethub/lib/index.ts b/packages/@aws-cdk/aws-iotfleethub/lib/index.ts new file mode 100644 index 0000000000000..543e80b75f69d --- /dev/null +++ b/packages/@aws-cdk/aws-iotfleethub/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::IoTFleetHub CloudFormation Resources: +export * from './iotfleethub.generated'; diff --git a/packages/@aws-cdk/aws-iotfleethub/package.json b/packages/@aws-cdk/aws-iotfleethub/package.json new file mode 100644 index 0000000000000..8141a2172be4a --- /dev/null +++ b/packages/@aws-cdk/aws-iotfleethub/package.json @@ -0,0 +1,101 @@ +{ + "name": "@aws-cdk/aws-iotfleethub", + "version": "0.0.0", + "description": "The CDK Construct Library for AWS::IoTFleetHub", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "projectReferences": true, + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.IoTFleetHub", + "packageId": "Amazon.CDK.AWS.IoTFleetHub", + "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.iotfleethub", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "iotfleethub" + } + }, + "python": { + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 1" + ], + "distName": "aws-cdk.aws-iotfleethub", + "module": "aws_cdk.aws_iotfleethub" + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-iotfleethub" + }, + "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": "yarn build && yarn test", + "build+test+package": "yarn build+test && yarn package", + "compat": "cdk-compat", + "gen": "cfn2ts", + "rosetta:extract": "yarn --silent jsii-rosetta extract" + }, + "cdk-build": { + "cloudformation": "AWS::IoTFleetHub", + "jest": true, + "env": { + "AWSLINT_BASE_CONSTRUCT": "true" + } + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::IoTFleetHub", + "aws-iotfleethub" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@types/jest": "^26.0.23", + "@aws-cdk/assert-internal": "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 + }, + "publishConfig": { + "tag": "latest" + } +} diff --git a/packages/@aws-cdk/aws-iotfleethub/test/iotfleethub.test.ts b/packages/@aws-cdk/aws-iotfleethub/test/iotfleethub.test.ts new file mode 100644 index 0000000000000..c4505ad966984 --- /dev/null +++ b/packages/@aws-cdk/aws-iotfleethub/test/iotfleethub.test.ts @@ -0,0 +1,6 @@ +import '@aws-cdk/assert-internal/jest'; +import {} from '../lib'; + +test('No tests are specified for this package', () => { + expect(true).toBe(true); +}); diff --git a/packages/@aws-cdk/aws-iotsitewise/package.json b/packages/@aws-cdk/aws-iotsitewise/package.json index e7301a75e3f49..9108aadc41ceb 100644 --- a/packages/@aws-cdk/aws-iotsitewise/package.json +++ b/packages/@aws-cdk/aws-iotsitewise/package.json @@ -73,10 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-iotsitewise/test/iotsitewise.test.ts b/packages/@aws-cdk/aws-iotsitewise/test/iotsitewise.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-iotsitewise/test/iotsitewise.test.ts +++ b/packages/@aws-cdk/aws-iotsitewise/test/iotsitewise.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-iotthingsgraph/package.json b/packages/@aws-cdk/aws-iotthingsgraph/package.json index 59c5396d37c79..f20d59c696eb6 100644 --- a/packages/@aws-cdk/aws-iotthingsgraph/package.json +++ b/packages/@aws-cdk/aws-iotthingsgraph/package.json @@ -73,18 +73,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-iotthingsgraph/test/iotthingsgraph.test.ts b/packages/@aws-cdk/aws-iotthingsgraph/test/iotthingsgraph.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-iotthingsgraph/test/iotthingsgraph.test.ts +++ b/packages/@aws-cdk/aws-iotthingsgraph/test/iotthingsgraph.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-iotwireless/package.json b/packages/@aws-cdk/aws-iotwireless/package.json index df0a35c2bd8fe..d729950fecafd 100644 --- a/packages/@aws-cdk/aws-iotwireless/package.json +++ b/packages/@aws-cdk/aws-iotwireless/package.json @@ -73,10 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-iotwireless/test/iotwireless.test.ts b/packages/@aws-cdk/aws-iotwireless/test/iotwireless.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-iotwireless/test/iotwireless.test.ts +++ b/packages/@aws-cdk/aws-iotwireless/test/iotwireless.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-ivs/package.json b/packages/@aws-cdk/aws-ivs/package.json index ce179233a9efa..6c101281a4146 100644 --- a/packages/@aws-cdk/aws-ivs/package.json +++ b/packages/@aws-cdk/aws-ivs/package.json @@ -83,19 +83,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-ivs/test/ivs.test.ts b/packages/@aws-cdk/aws-ivs/test/ivs.test.ts index 0ed2c6712e0d5..5f4f29e833df7 100644 --- a/packages/@aws-cdk/aws-ivs/test/ivs.test.ts +++ b/packages/@aws-cdk/aws-ivs/test/ivs.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert/jest'; -import { expect as expectStack } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +import { expect as expectStack } from '@aws-cdk/assert-internal'; import { Stack } from '@aws-cdk/core'; import * as ivs from '../lib'; diff --git a/packages/@aws-cdk/aws-kendra/package.json b/packages/@aws-cdk/aws-kendra/package.json index 0ce7d188ea30f..7732f5310c7cc 100644 --- a/packages/@aws-cdk/aws-kendra/package.json +++ b/packages/@aws-cdk/aws-kendra/package.json @@ -73,10 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-kendra/test/kendra.test.ts b/packages/@aws-cdk/aws-kendra/test/kendra.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-kendra/test/kendra.test.ts +++ b/packages/@aws-cdk/aws-kendra/test/kendra.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-kinesis/README.md b/packages/@aws-cdk/aws-kinesis/README.md index ebf5bdb74e3ae..1e7aaf89a5a88 100644 --- a/packages/@aws-cdk/aws-kinesis/README.md +++ b/packages/@aws-cdk/aws-kinesis/README.md @@ -24,6 +24,7 @@ intake and aggregation. - [Read Permissions](#read-permissions) - [Write Permissions](#write-permissions) - [Custom Permissions](#custom-permissions) + - [Metrics](#metrics) ## Streams @@ -192,3 +193,21 @@ const stream = new Stream(stack, 'MyStream'); // give my user permissions to list shards stream.grant(user, 'kinesis:ListShards'); ``` + +### Metrics + +You can use common metrics from your stream to create alarms and/or dashboards. The `stream.metric('MetricName')` method creates a metric with the stream namespace and dimension. You can also use pre-define methods like `stream.metricGetRecordsSuccess()`. To find out more about Kinesis metrics check [Monitoring the Amazon Kinesis Data Streams Service with Amazon CloudWatch](https://docs.aws.amazon.com/streams/latest/dev/monitoring-with-cloudwatch.html). + +```ts +const stream = new Stream(stack, 'MyStream'); + +// Using base metric method passing the metric name +stream.metric('GetRecords.Success'); + +// using pre-defined metric method +stream.metricGetRecordsSuccess(); + +// using pre-defined and overriding the statistic +stream.metricGetRecordsSuccess({ statistic: 'Maximum' }); +``` + diff --git a/packages/@aws-cdk/aws-kinesis/lib/kinesis-fixed-canned-metrics.ts b/packages/@aws-cdk/aws-kinesis/lib/kinesis-fixed-canned-metrics.ts new file mode 100644 index 0000000000000..a10434d947bbf --- /dev/null +++ b/packages/@aws-cdk/aws-kinesis/lib/kinesis-fixed-canned-metrics.ts @@ -0,0 +1,129 @@ +import { KinesisMetrics as CannedMetrics } from './kinesis-canned-metrics.generated'; + +/** + * This class is to consolidate all the metrics from Stream in just one place. + * + * Current generated canned metrics don't match the proper metrics from the service. If it is fixed + * at the source this class can be removed and just use the generated one directly. + * + * Stream Metrics reference: https://docs.aws.amazon.com/streams/latest/dev/monitoring-with-cloudwatch.html + */ +export class KinesisMetrics { + public static getRecordsBytesAverage(dimensions: { StreamName: string }) { + return { + namespace: 'AWS/Kinesis', + metricName: 'GetRecords.Bytes', + dimensions, + statistic: 'Average', + }; + } + public static getRecordsSuccessAverage(dimensions: { StreamName: string }) { + return { + namespace: 'AWS/Kinesis', + metricName: 'GetRecords.Success', + dimensions, + statistic: 'Average', + }; + } + public static getRecordsRecordsAverage(dimensions: { StreamName: string }) { + return { + namespace: 'AWS/Kinesis', + metricName: 'GetRecords.Records', + dimensions, + statistic: 'Average', + }; + } + public static getRecordsLatencyAverage(dimensions: { StreamName: string }) { + return { + namespace: 'AWS/Kinesis', + metricName: 'GetRecords.Latency', + dimensions, + statistic: 'Average', + }; + } + public static putRecordBytesAverage(dimensions: { StreamName: string }) { + return { + namespace: 'AWS/Kinesis', + metricName: 'PutRecord.Bytes', + dimensions, + statistic: 'Average', + }; + } + public static putRecordLatencyAverage(dimensions: { StreamName: string }) { + return { + namespace: 'AWS/Kinesis', + metricName: 'PutRecord.Latency', + dimensions, + statistic: 'Average', + }; + } + public static getRecordsIteratorAgeMillisecondsMaximum(dimensions: { StreamName: string }) { + return CannedMetrics.getRecordsIteratorAgeMillisecondsMaximum(dimensions); + } + public static putRecordSuccessAverage(dimensions: { StreamName: string }) { + return CannedMetrics.putRecordSuccessAverage(dimensions); + } + public static putRecordsBytesAverage(dimensions: { StreamName: string }) { + return CannedMetrics.putRecordsBytesAverage(dimensions); + } + public static putRecordsLatencyAverage(dimensions: { StreamName: string }) { + return { + namespace: 'AWS/Kinesis', + metricName: 'PutRecords.Latency', + dimensions, + statistic: 'Average', + }; + } + public static putRecordsSuccessAverage(dimensions: { StreamName: string }) { + return { + namespace: 'AWS/Kinesis', + metricName: 'PutRecords.Success', + dimensions, + statistic: 'Average', + }; + } + public static putRecordsTotalRecordsAverage(dimensions: { StreamName: string }) { + return { + namespace: 'AWS/Kinesis', + metricName: 'PutRecords.TotalRecords', + dimensions, + statistic: 'Average', + }; + } + public static putRecordsSuccessfulRecordsAverage(dimensions: { StreamName: string }) { + return { + namespace: 'AWS/Kinesis', + metricName: 'PutRecords.SuccessfulRecords', + dimensions, + statistic: 'Average', + }; + } + public static putRecordsFailedRecordsAverage(dimensions: { StreamName: string }) { + return { + namespace: 'AWS/Kinesis', + metricName: 'PutRecords.FailedRecords', + dimensions, + statistic: 'Average', + }; + } + public static putRecordsThrottledRecordsAverage(dimensions: { StreamName: string }) { + return { + namespace: 'AWS/Kinesis', + metricName: 'PutRecords.ThrottledRecords', + dimensions, + statistic: 'Average', + }; + } + public static incomingBytesAverage(dimensions: { StreamName: string }) { + return CannedMetrics.incomingBytesAverage(dimensions); + } + public static incomingRecordsAverage(dimensions: { StreamName: string }) { + return CannedMetrics.incomingRecordsAverage(dimensions); + } + public static readProvisionedThroughputExceededAverage(dimensions: { StreamName: string }) { + return CannedMetrics.readProvisionedThroughputExceededAverage(dimensions); + } + public static writeProvisionedThroughputExceededAverage(dimensions: { StreamName: string }) { + return CannedMetrics.writeProvisionedThroughputExceededAverage(dimensions); + } +} diff --git a/packages/@aws-cdk/aws-kinesis/lib/stream.ts b/packages/@aws-cdk/aws-kinesis/lib/stream.ts index a0e7acef57594..0a73c6b9062f8 100644 --- a/packages/@aws-cdk/aws-kinesis/lib/stream.ts +++ b/packages/@aws-cdk/aws-kinesis/lib/stream.ts @@ -1,7 +1,9 @@ +import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import { Aws, CfnCondition, Duration, Fn, IResolvable, IResource, Resource, Stack, Token } from '@aws-cdk/core'; import { Construct } from 'constructs'; +import { KinesisMetrics } from './kinesis-fixed-canned-metrics'; import { CfnStream } from './kinesis.generated'; const READ_OPERATIONS = [ @@ -72,6 +74,217 @@ export interface IStream extends IResource { * Grant the indicated permissions on this stream to the provided IAM principal. */ grant(grantee: iam.IGrantable, ...actions: string[]): iam.Grant; + + /** + * Return stream metric based from its metric name + * + * @param metricName name of the stream metric + * @param props properties of the metric + */ + metric(metricName: string, props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of bytes retrieved from the Kinesis stream, measured over the specified time period. Minimum, Maximum, + * and Average statistics represent the bytes in a single GetRecords operation for the stream in the specified time + * period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricGetRecordsBytes(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The age of the last record in all GetRecords calls made against a Kinesis stream, measured over the specified time + * period. Age is the difference between the current time and when the last record of the GetRecords call was written + * to the stream. The Minimum and Maximum statistics can be used to track the progress of Kinesis consumer + * applications. A value of zero indicates that the records being read are completely caught up with the stream. + * + * The metric defaults to maximum over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricGetRecordsIteratorAgeMilliseconds(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The time taken per GetRecords operation, measured over the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricGetRecordsLatency(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of records retrieved from the shard, measured over the specified time period. Minimum, Maximum, and + * Average statistics represent the records in a single GetRecords operation for the stream in the specified time + * period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricGetRecords(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of successful GetRecords operations per stream, measured over the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricGetRecordsSuccess(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of bytes successfully put to the Kinesis stream over the specified time period. This metric includes + * bytes from PutRecord and PutRecords operations. Minimum, Maximum, and Average statistics represent the bytes in a + * single put operation for the stream in the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricIncomingBytes(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of records successfully put to the Kinesis stream over the specified time period. This metric includes + * record counts from PutRecord and PutRecords operations. Minimum, Maximum, and Average statistics represent the + * records in a single put operation for the stream in the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricIncomingRecords(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of bytes put to the Kinesis stream using the PutRecord operation over the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricPutRecordBytes(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The time taken per PutRecord operation, measured over the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricPutRecordLatency(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of successful PutRecord operations per Kinesis stream, measured over the specified time period. Average + * reflects the percentage of successful writes to a stream. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricPutRecordSuccess(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of bytes put to the Kinesis stream using the PutRecords operation over the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricPutRecordsBytes(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The time taken per PutRecords operation, measured over the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricPutRecordsLatency(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of PutRecords operations where at least one record succeeded, per Kinesis stream, measured over the + * specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricPutRecordsSuccess(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The total number of records sent in a PutRecords operation per Kinesis data stream, measured over the specified + * time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricPutRecordsTotalRecords(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of successful records in a PutRecords operation per Kinesis data stream, measured over the specified + * time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricPutRecordsSuccessfulRecords(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of records rejected due to internal failures in a PutRecords operation per Kinesis data stream, + * measured over the specified time period. Occasional internal failures are to be expected and should be retried. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricPutRecordsFailedRecords(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of records rejected due to throttling in a PutRecords operation per Kinesis data stream, measured over + * the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricPutRecordsThrottledRecords(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of GetRecords calls throttled for the stream over the specified time period. The most commonly used + * statistic for this metric is Average. + * + * When the Minimum statistic has a value of 1, all records were throttled for the stream during the specified time + * period. + * + * When the Maximum statistic has a value of 0 (zero), no records were throttled for the stream during the specified + * time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties + * + * @param props properties of the metric + * + */ + metricReadProvisionedThroughputExceeded(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of records rejected due to throttling for the stream over the specified time period. This metric + * includes throttling from PutRecord and PutRecords operations. + * + * When the Minimum statistic has a non-zero value, records were being throttled for the stream during the specified + * time period. + * + * When the Maximum statistic has a value of 0 (zero), no records were being throttled for the stream during the + * specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricWriteProvisionedThroughputExceeded(props?: cloudwatch.MetricOptions): cloudwatch.Metric; } /** @@ -168,6 +381,276 @@ abstract class StreamBase extends Resource implements IStream { scope: this, }); } + + /** + * Return stream metric based from its metric name + * + * @param metricName name of the stream metric + * @param props properties of the metric + */ + public metric(metricName: string, props?: cloudwatch.MetricOptions) { + return new cloudwatch.Metric({ + namespace: 'AWS/Kinesis', + metricName, + dimensions: { + StreamName: this.streamName, + }, + ...props, + }).attachTo(this); + } + + /** + * The number of bytes retrieved from the Kinesis stream, measured over the specified time period. Minimum, Maximum, + * and Average statistics represent the bytes in a single GetRecords operation for the stream in the specified time + * period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricGetRecordsBytes(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.getRecordsBytesAverage, props); + } + + /** + * The age of the last record in all GetRecords calls made against a Kinesis stream, measured over the specified time + * period. Age is the difference between the current time and when the last record of the GetRecords call was written + * to the stream. The Minimum and Maximum statistics can be used to track the progress of Kinesis consumer + * applications. A value of zero indicates that the records being read are completely caught up with the stream. + * + * The metric defaults to maximum over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricGetRecordsIteratorAgeMilliseconds(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.getRecordsIteratorAgeMillisecondsMaximum, props); + } + + /** + * The number of successful GetRecords operations per stream, measured over the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricGetRecordsSuccess(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.getRecordsSuccessAverage, props); + } + + /** + * The number of records retrieved from the shard, measured over the specified time period. Minimum, Maximum, and + * Average statistics represent the records in a single GetRecords operation for the stream in the specified time + * period. + * + * average + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricGetRecords(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.getRecordsRecordsAverage, props); + } + + /** + * The number of successful GetRecords operations per stream, measured over the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricGetRecordsLatency(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.getRecordsLatencyAverage, props); + } + + /** + * The number of bytes put to the Kinesis stream using the PutRecord operation over the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricPutRecordBytes(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.putRecordBytesAverage, props); + } + + /** + * The time taken per PutRecord operation, measured over the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricPutRecordLatency(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.putRecordLatencyAverage, props); + } + + /** + * The number of successful PutRecord operations per Kinesis stream, measured over the specified time period. Average + * reflects the percentage of successful writes to a stream. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricPutRecordSuccess(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.putRecordSuccessAverage, props); + } + + /** + * The number of bytes put to the Kinesis stream using the PutRecords operation over the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricPutRecordsBytes(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.putRecordsBytesAverage, props); + } + + /** + * The time taken per PutRecords operation, measured over the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricPutRecordsLatency(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.putRecordsLatencyAverage, props); + } + + /** + * The number of PutRecords operations where at least one record succeeded, per Kinesis stream, measured over the + * specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricPutRecordsSuccess(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.putRecordsSuccessAverage, props); + } + + /** + * The total number of records sent in a PutRecords operation per Kinesis data stream, measured over the specified + * time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricPutRecordsTotalRecords(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.putRecordsTotalRecordsAverage, props); + } + + /** + * The number of successful records in a PutRecords operation per Kinesis data stream, measured over the specified + * time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricPutRecordsSuccessfulRecords(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.putRecordsSuccessfulRecordsAverage, props); + } + + /** + * The number of records rejected due to internal failures in a PutRecords operation per Kinesis data stream, + * measured over the specified time period. Occasional internal failures are to be expected and should be retried. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricPutRecordsFailedRecords(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.putRecordsFailedRecordsAverage, props); + } + + /** + * The number of records rejected due to throttling in a PutRecords operation per Kinesis data stream, measured over + * the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricPutRecordsThrottledRecords(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.putRecordsThrottledRecordsAverage, props); + } + + /** + * The number of bytes successfully put to the Kinesis stream over the specified time period. This metric includes + * bytes from PutRecord and PutRecords operations. Minimum, Maximum, and Average statistics represent the bytes in a + * single put operation for the stream in the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricIncomingBytes(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.incomingBytesAverage, props); + } + + /** + * The number of records successfully put to the Kinesis stream over the specified time period. This metric includes + * record counts from PutRecord and PutRecords operations. Minimum, Maximum, and Average statistics represent the + * records in a single put operation for the stream in the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricIncomingRecords(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.incomingRecordsAverage, props); + } + + /** + * The number of GetRecords calls throttled for the stream over the specified time period. The most commonly used + * statistic for this metric is Average. + * + * When the Minimum statistic has a value of 1, all records were throttled for the stream during the specified time + * period. + * + * When the Maximum statistic has a value of 0 (zero), no records were throttled for the stream during the specified + * time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties + * + * @param props properties of the metric + * + */ + public metricReadProvisionedThroughputExceeded(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.readProvisionedThroughputExceededAverage, props); + } + + /** + * The number of records rejected due to throttling for the stream over the specified time period. This metric + * includes throttling from PutRecord and PutRecords operations. + * + * When the Minimum statistic has a non-zero value, records were being throttled for the stream during the specified + * time period. + * + * When the Maximum statistic has a value of 0 (zero), no records were being throttled for the stream during the + * specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricWriteProvisionedThroughputExceeded(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.writeProvisionedThroughputExceededAverage, props); + } + + // create metrics based on generated KinesisMetrics static methods + private metricFromCannedFunction( + createCannedProps: (dimensions: { StreamName: string }) => cloudwatch.MetricProps, + props?: cloudwatch.MetricOptions): cloudwatch.Metric { + return new cloudwatch.Metric({ + ...createCannedProps({ StreamName: this.streamName }), + ...props, + }).attachTo(this); + } + } /** diff --git a/packages/@aws-cdk/aws-kinesis/package.json b/packages/@aws-cdk/aws-kinesis/package.json index 3c7fd281d363b..524b80508f273 100644 --- a/packages/@aws-cdk/aws-kinesis/package.json +++ b/packages/@aws-cdk/aws-kinesis/package.json @@ -71,27 +71,30 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "@aws-cdk/cx-api": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { + "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { + "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-kinesis/test/integ.stream-dashboard.expected.json b/packages/@aws-cdk/aws-kinesis/test/integ.stream-dashboard.expected.json new file mode 100644 index 0000000000000..28a166e76fd1f --- /dev/null +++ b/packages/@aws-cdk/aws-kinesis/test/integ.stream-dashboard.expected.json @@ -0,0 +1,206 @@ +{ + "Resources": { + "myStream547FAD7F": { + "Type": "AWS::Kinesis::Stream", + "Properties": { + "ShardCount": 1, + "RetentionPeriodHours": 24, + "StreamEncryption": { + "Fn::If": [ + "AwsCdkKinesisEncryptedStreamsUnsupportedRegions", + { + "Ref": "AWS::NoValue" + }, + { + "EncryptionType": "KMS", + "KeyId": "alias/aws/kinesis" + } + ] + } + } + }, + "StreamDashboardAAF4FCF8": { + "Type": "AWS::CloudWatch::Dashboard", + "Properties": { + "DashboardBody": { + "Fn::Join": [ + "", + [ + "{\"widgets\":[{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":0,\"y\":0,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Get records - sum (Bytes)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"GetRecords.Bytes\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\",{\"stat\":\"Sum\"}]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":12,\"y\":0,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Get records iterator age - maximum (Milliseconds)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"GetRecords.IteratorAgeMilliseconds\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\",{\"stat\":\"Maximum\"}]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":0,\"y\":5,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Get records latency - average (Milliseconds)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"GetRecords.Latency\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\"]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":12,\"y\":5,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Get records - sum (Count)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"GetRecords.Records\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\",{\"stat\":\"Sum\"}]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":0,\"y\":10,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Get records success - average (Percent)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"GetRecords.Success\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\"]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":12,\"y\":10,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Incoming data - sum (Bytes)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"IncomingBytes\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\",{\"stat\":\"Sum\"}]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":0,\"y\":15,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Incoming records - sum (Count)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"IncomingRecords\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\",{\"stat\":\"Sum\"}]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":12,\"y\":15,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Put record - sum (Bytes)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"PutRecord.Bytes\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\",{\"stat\":\"Sum\"}]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":0,\"y\":20,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Put record latency - average (Milliseconds)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"PutRecord.Latency\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\"]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":12,\"y\":20,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Put record success - average (Percent)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"PutRecord.Success\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\"]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":0,\"y\":25,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Put records - sum (Bytes)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"PutRecords.Bytes\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\",{\"stat\":\"Sum\"}]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":12,\"y\":25,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Put records latency - average (Milliseconds)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"PutRecords.Latency\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\"]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":0,\"y\":30,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Read throughput exceeded - average (Percent)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"ReadProvisionedThroughputExceeded\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\"]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":12,\"y\":30,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Write throughput exceeded - average (Count)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"WriteProvisionedThroughputExceeded\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\"]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":0,\"y\":35,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Put records successful records - average (Percent)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[{\"label\":\"( count / total ) * 100\",\"expression\":\"( count / total ) * 100\"}],[\"AWS/Kinesis\",\"PutRecords.SuccessfulRecords\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\",{\"visible\":false,\"id\":\"count\"}],[\"AWS/Kinesis\",\"PutRecords.TotalRecords\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\",{\"visible\":false,\"id\":\"total\"}]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":12,\"y\":35,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Put records failed records - average (Percent)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[{\"label\":\"( count / total ) * 100\",\"expression\":\"( count / total ) * 100\"}],[\"AWS/Kinesis\",\"PutRecords.FailedRecords\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\",{\"visible\":false,\"id\":\"count\"}],[\"AWS/Kinesis\",\"PutRecords.TotalRecords\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\",{\"visible\":false,\"id\":\"total\"}]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":0,\"y\":40,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Put records throttled records - average (Percent)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[{\"label\":\"( count / total ) * 100\",\"expression\":\"( count / total ) * 100\"}],[\"AWS/Kinesis\",\"PutRecords.ThrottledRecords\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\",{\"visible\":false,\"id\":\"count\"}],[\"AWS/Kinesis\",\"PutRecords.TotalRecords\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\",{\"visible\":false,\"id\":\"total\"}]],\"yAxis\":{}}}]}" + ] + ] + } + } + } + }, + "Conditions": { + "AwsCdkKinesisEncryptedStreamsUnsupportedRegions": { + "Fn::Or": [ + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "cn-north-1" + ] + }, + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "cn-northwest-1" + ] + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-kinesis/test/integ.stream-dashboard.ts b/packages/@aws-cdk/aws-kinesis/test/integ.stream-dashboard.ts new file mode 100644 index 0000000000000..cb1dcadf749be --- /dev/null +++ b/packages/@aws-cdk/aws-kinesis/test/integ.stream-dashboard.ts @@ -0,0 +1,57 @@ +import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; +import { App, Stack } from '@aws-cdk/core'; +import { Stream } from '../lib'; + +const app = new App(); +const stack = new Stack(app, 'integ-kinesis-stream-dashboard'); + +const stream = new Stream(stack, 'myStream'); + +const dashboard = new cloudwatch.Dashboard(stack, 'StreamDashboard'); + +function graphWidget(title: string, metric: cloudwatch.Metric) { + return new cloudwatch.GraphWidget({ + title, + left: [metric], + width: 12, + height: 5, + }); +} + +function percentGraphWidget(title: string, countMetric: cloudwatch.Metric, totalMetric: cloudwatch.Metric) { + return new cloudwatch.GraphWidget({ + title, + left: [new cloudwatch.MathExpression({ + expression: '( count / total ) * 100', + usingMetrics: { + count: countMetric, + total: totalMetric, + }, + })], + width: 12, + height: 5, + }); +} + +dashboard.addWidgets( + graphWidget('Get records - sum (Bytes)', stream.metricGetRecordsBytes({ statistic: 'Sum' })), + graphWidget('Get records iterator age - maximum (Milliseconds)', stream.metricGetRecordsIteratorAgeMilliseconds()), + graphWidget('Get records latency - average (Milliseconds)', stream.metricGetRecordsLatency()), + graphWidget('Get records - sum (Count)', stream.metricGetRecords({ statistic: 'Sum' })), + graphWidget('Get records success - average (Percent)', stream.metricGetRecordsSuccess()), + graphWidget('Incoming data - sum (Bytes)', stream.metricIncomingBytes({ statistic: 'Sum' })), + graphWidget('Incoming records - sum (Count)', stream.metricIncomingRecords({ statistic: 'Sum' })), + graphWidget('Put record - sum (Bytes)', stream.metricPutRecordBytes({ statistic: 'Sum' })), + graphWidget('Put record latency - average (Milliseconds)', stream.metricPutRecordLatency()), + graphWidget('Put record success - average (Percent)', stream.metricPutRecordSuccess()), + graphWidget('Put records - sum (Bytes)', stream.metricPutRecordsBytes({ statistic: 'Sum' })), + graphWidget('Put records latency - average (Milliseconds)', stream.metricPutRecordsLatency()), + graphWidget('Read throughput exceeded - average (Percent)', stream.metricReadProvisionedThroughputExceeded()), + graphWidget('Write throughput exceeded - average (Count)', stream.metricWriteProvisionedThroughputExceeded()), + percentGraphWidget('Put records successful records - average (Percent)', + stream.metricPutRecordsSuccessfulRecords(), stream.metricPutRecordsTotalRecords()), + percentGraphWidget('Put records failed records - average (Percent)', + stream.metricPutRecordsFailedRecords(), stream.metricPutRecordsTotalRecords()), + percentGraphWidget('Put records throttled records - average (Percent)', + stream.metricPutRecordsThrottledRecords(), stream.metricPutRecordsTotalRecords()), +); diff --git a/packages/@aws-cdk/aws-kinesis/test/integ.stream.ts b/packages/@aws-cdk/aws-kinesis/test/integ.stream.ts index c44aa888f113c..e508ffe71b42b 100644 --- a/packages/@aws-cdk/aws-kinesis/test/integ.stream.ts +++ b/packages/@aws-cdk/aws-kinesis/test/integ.stream.ts @@ -11,4 +11,4 @@ const role = new iam.Role(stack, 'UserRole', { const stream = new Stream(stack, 'myStream'); -stream.grantReadWrite(role); \ No newline at end of file +stream.grantReadWrite(role); diff --git a/packages/@aws-cdk/aws-kinesis/test/stream.test.ts b/packages/@aws-cdk/aws-kinesis/test/stream.test.ts index b295ac73c75b5..388ac8b0caac5 100644 --- a/packages/@aws-cdk/aws-kinesis/test/stream.test.ts +++ b/packages/@aws-cdk/aws-kinesis/test/stream.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert/jest'; -import { arrayWith } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +import { arrayWith } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import { App, Duration, Stack, CfnParameter } from '@aws-cdk/core'; @@ -1329,6 +1329,8 @@ describe('Kinesis data streams', () => { AwsCdkKinesisEncryptedStreamsUnsupportedRegions: { 'Fn::Or': [ { + + 'Fn::Equals': [ { Ref: 'AWS::Region', @@ -1349,4 +1351,207 @@ describe('Kinesis data streams', () => { }, }); }); + + test('basic stream-level metrics (StreamName dimension only)', () => { + // GIVEN + const stack = new Stack(); + + const fiveMinutes = { + amount: 5, + unit: { + label: 'minutes', + isoLabel: 'M', + inMillis: 60000, + }, + }; + + // WHEN + const stream = new Stream(stack, 'MyStream'); + + // THEN + // should resolve the basic metrics (source https://docs.aws.amazon.com/streams/latest/dev/monitoring-with-cloudwatch.html#kinesis-metrics-stream) + expect(stack.resolve(stream.metricGetRecordsBytes())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'GetRecords.Bytes', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricGetRecordsIteratorAgeMilliseconds())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'GetRecords.IteratorAgeMilliseconds', + period: fiveMinutes, + statistic: 'Maximum', + }); + + expect(stack.resolve(stream.metricGetRecordsLatency())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'GetRecords.Latency', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricGetRecords())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'GetRecords.Records', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricGetRecordsSuccess())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'GetRecords.Success', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricIncomingBytes())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'IncomingBytes', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricIncomingRecords())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'IncomingRecords', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricPutRecordsBytes())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'PutRecords.Bytes', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricPutRecordsLatency())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'PutRecords.Latency', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricPutRecordsSuccess())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'PutRecords.Success', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricPutRecordsTotalRecords())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'PutRecords.TotalRecords', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricPutRecordsSuccessfulRecords())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'PutRecords.SuccessfulRecords', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricPutRecordsFailedRecords())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'PutRecords.FailedRecords', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricPutRecordsThrottledRecords())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'PutRecords.ThrottledRecords', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricReadProvisionedThroughputExceeded())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'ReadProvisionedThroughputExceeded', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricWriteProvisionedThroughputExceeded())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'WriteProvisionedThroughputExceeded', + period: fiveMinutes, + statistic: 'Average', + }); + }); + + test('allow to overide metric options', () => { + // GIVEN + const stack = new Stack(); + + const fiveMinutes = { + amount: 5, + unit: { + label: 'minutes', + isoLabel: 'M', + inMillis: 60000, + }, + }; + + // WHEN + const stream = new Stream(stack, 'MyStream'); + + // THEN + expect(stack.resolve(stream.metricGetRecordsBytes())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'GetRecords.Bytes', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricGetRecordsBytes({ + period: Duration.minutes(1), + statistic: 'Maximum', + }))).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'GetRecords.Bytes', + period: { ...fiveMinutes, amount: 1 }, + statistic: 'Maximum', + }); + + expect(stack.resolve(stream.metricIncomingBytes())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'IncomingBytes', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricIncomingBytes({ + period: Duration.minutes(1), + statistic: 'Sum', + }))).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'IncomingBytes', + period: { ...fiveMinutes, amount: 1 }, + statistic: 'Sum', + }); + }); }); diff --git a/packages/@aws-cdk/aws-kinesisanalytics-flink/lib/application.ts b/packages/@aws-cdk/aws-kinesisanalytics-flink/lib/application.ts index 1bcfa0fc4cbbf..d5023494bf91d 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics-flink/lib/application.ts +++ b/packages/@aws-cdk/aws-kinesisanalytics-flink/lib/application.ts @@ -210,7 +210,6 @@ class Import extends ApplicationBase { * * @resource AWS::KinesisAnalyticsV2::Application * - * @experimental */ export class Application extends ApplicationBase { /** diff --git a/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json b/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json index 2d28b8fd4df7e..882289bd8ea55 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json +++ b/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json @@ -64,11 +64,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/assets": "0.0.0", @@ -79,7 +80,7 @@ "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -91,7 +92,7 @@ "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-kinesisanalytics-flink/test/application.test.ts b/packages/@aws-cdk/aws-kinesisanalytics-flink/test/application.test.ts index 6dc35fadd44b6..9123a3ca174ca 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics-flink/test/application.test.ts +++ b/packages/@aws-cdk/aws-kinesisanalytics-flink/test/application.test.ts @@ -1,5 +1,5 @@ -import { arrayWith, objectLike, ResourcePart } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { arrayWith, objectLike, ResourcePart } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as iam from '@aws-cdk/aws-iam'; import * as logs from '@aws-cdk/aws-logs'; import * as s3 from '@aws-cdk/aws-s3'; diff --git a/packages/@aws-cdk/aws-kinesisanalytics/package.json b/packages/@aws-cdk/aws-kinesisanalytics/package.json index c6b67502056e0..dcdd6cae51708 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics/package.json +++ b/packages/@aws-cdk/aws-kinesisanalytics/package.json @@ -74,19 +74,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-kinesisanalytics/test/kinesisanalytics.test.ts b/packages/@aws-cdk/aws-kinesisanalytics/test/kinesisanalytics.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics/test/kinesisanalytics.test.ts +++ b/packages/@aws-cdk/aws-kinesisanalytics/test/kinesisanalytics.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-kinesisfirehose/package.json b/packages/@aws-cdk/aws-kinesisfirehose/package.json index ae2d309ed8e24..096f26f48fc15 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose/package.json +++ b/packages/@aws-cdk/aws-kinesisfirehose/package.json @@ -71,19 +71,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-kinesisfirehose/test/kinesisfirehose.test.ts b/packages/@aws-cdk/aws-kinesisfirehose/test/kinesisfirehose.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose/test/kinesisfirehose.test.ts +++ b/packages/@aws-cdk/aws-kinesisfirehose/test/kinesisfirehose.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-kms/package.json b/packages/@aws-cdk/aws-kms/package.json index 272c610530357..9514c480d7057 100644 --- a/packages/@aws-cdk/aws-kms/package.json +++ b/packages/@aws-cdk/aws-kms/package.json @@ -71,24 +71,25 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-kms/test/alias.test.ts b/packages/@aws-cdk/aws-kms/test/alias.test.ts index 6c4356a7e8f36..3ad224ef6e681 100644 --- a/packages/@aws-cdk/aws-kms/test/alias.test.ts +++ b/packages/@aws-cdk/aws-kms/test/alias.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { ArnPrincipal, PolicyStatement } from '@aws-cdk/aws-iam'; import { App, CfnOutput, Stack } from '@aws-cdk/core'; import { Alias } from '../lib/alias'; diff --git a/packages/@aws-cdk/aws-kms/test/key.test.ts b/packages/@aws-cdk/aws-kms/test/key.test.ts index 38ae0e1e61059..50c23fc265bb7 100644 --- a/packages/@aws-cdk/aws-kms/test/key.test.ts +++ b/packages/@aws-cdk/aws-kms/test/key.test.ts @@ -1,5 +1,5 @@ -import { arrayWith, ResourcePart } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { arrayWith, ResourcePart } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; diff --git a/packages/@aws-cdk/aws-kms/test/via-service-principal.test.ts b/packages/@aws-cdk/aws-kms/test/via-service-principal.test.ts index 53d0d33d02933..0afb8a731376f 100644 --- a/packages/@aws-cdk/aws-kms/test/via-service-principal.test.ts +++ b/packages/@aws-cdk/aws-kms/test/via-service-principal.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '../lib'; diff --git a/packages/@aws-cdk/aws-lakeformation/package.json b/packages/@aws-cdk/aws-lakeformation/package.json index 8c3f72401111d..406d0c43d2983 100644 --- a/packages/@aws-cdk/aws-lakeformation/package.json +++ b/packages/@aws-cdk/aws-lakeformation/package.json @@ -73,18 +73,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-lakeformation/test/lakeformation.test.ts b/packages/@aws-cdk/aws-lakeformation/test/lakeformation.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-lakeformation/test/lakeformation.test.ts +++ b/packages/@aws-cdk/aws-lakeformation/test/lakeformation.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-lambda-destinations/package.json b/packages/@aws-cdk/aws-lambda-destinations/package.json index 096ee2f6fc12f..db6745cd5540e 100644 --- a/packages/@aws-cdk/aws-lambda-destinations/package.json +++ b/packages/@aws-cdk/aws-lambda-destinations/package.json @@ -62,12 +62,13 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-events": "0.0.0", @@ -76,7 +77,7 @@ "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -86,7 +87,7 @@ "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-lambda-destinations/test/destinations.test.ts b/packages/@aws-cdk/aws-lambda-destinations/test/destinations.test.ts index 70dda9ef43893..3be1f3d94f37f 100644 --- a/packages/@aws-cdk/aws-lambda-destinations/test/destinations.test.ts +++ b/packages/@aws-cdk/aws-lambda-destinations/test/destinations.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as events from '@aws-cdk/aws-events'; import * as lambda from '@aws-cdk/aws-lambda'; import * as sns from '@aws-cdk/aws-sns'; diff --git a/packages/@aws-cdk/aws-lambda-event-sources/README.md b/packages/@aws-cdk/aws-lambda-event-sources/README.md index eb4f206c8f3c9..d770e10943c22 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/README.md +++ b/packages/@aws-cdk/aws-lambda-event-sources/README.md @@ -53,6 +53,8 @@ behavior: * __receiveMessageWaitTime__: Will determine [long poll](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-long-polling.html) duration. The default value is 20 seconds. +* __batchSize__: Determines how many records are buffered before invoking your lambda function. +* __maxBatchingWindow__: The maximum amount of time to gather records before invoking the lambda. This increases the likelihood of a full batch at the cost of delayed processing. * __enabled__: If the SQS event source mapping should be enabled. The default is true. ```ts @@ -67,6 +69,7 @@ const queue = new sqs.Queue(this, 'MyQueue', { lambda.addEventSource(new SqsEventSource(queue, { batchSize: 10, // default + maxBatchingWindow: Duration.minutes(5), })); ``` @@ -148,6 +151,7 @@ and add it to your Lambda function. The following parameters will impact Amazon * __parallelizationFactor__: The number of batches to concurrently process on each shard. * __retryAttempts__: The maximum number of times a record should be retried in the event of failure. * __startingPosition__: Will determine where to being consumption, either at the most recent ('LATEST') record or the oldest record ('TRIM_HORIZON'). 'TRIM_HORIZON' will ensure you process all available data, while 'LATEST' will ignore all records that arrived prior to attaching the event source. +* __tumblingWindow__: The duration in seconds of a processing window when using streams. * __enabled__: If the DynamoDB Streams event source mapping should be enabled. The default is true. ```ts @@ -192,6 +196,7 @@ behavior: * __parallelizationFactor__: The number of batches to concurrently process on each shard. * __retryAttempts__: The maximum number of times a record should be retried in the event of failure. * __startingPosition__: Will determine where to being consumption, either at the most recent ('LATEST') record or the oldest record ('TRIM_HORIZON'). 'TRIM_HORIZON' will ensure you process all available data, while 'LATEST' will ignore all records that arrived prior to attaching the event source. +* __tumblingWindow__: The duration in seconds of a processing window when using streams. * __enabled__: If the DynamoDB Streams event source mapping should be enabled. The default is true. ```ts @@ -212,7 +217,7 @@ myFunction.addEventSource(new KinesisEventSource(stream, { You can write Lambda functions to process data either from [Amazon MSK](https://docs.aws.amazon.com/lambda/latest/dg/with-msk.html) or a [self managed Kafka](https://docs.aws.amazon.com/lambda/latest/dg/kafka-smaa.html) cluster. The following code sets up Amazon MSK as an event source for a lambda function. Credentials will need to be configured to access the -MSK cluster, as described in [Username/Password authentication](https://docs.aws.amazon.com/msk/latest/developerguide/msk-password.html). +MSK cluster, as described in [Username/Password authentication](https://docs.aws.amazon.com/msk/latest/developerguide/msk-password.html). ```ts import * as lambda from '@aws-cdk/aws-lambda'; @@ -220,9 +225,8 @@ import * as msk from '@aws-cdk/aws-lambda'; import { Secret } from '@aws-cdk/aws-secretmanager'; import { ManagedKafkaEventSource } from '@aws-cdk/aws-lambda-event-sources'; -// Your MSK cluster -const cluster = msk.Cluster.fromClusterArn(this, 'Cluster', - 'arn:aws:kafka:us-east-1:0123456789019:cluster/SalesCluster/abcd1234-abcd-cafe-abab-9876543210ab-4'); +// Your MSK cluster arn +const cluster = 'arn:aws:kafka:us-east-1:0123456789019:cluster/SalesCluster/abcd1234-abcd-cafe-abab-9876543210ab-4'; // The Kafka topic you want to subscribe to const topic = 'some-cool-topic' @@ -232,7 +236,7 @@ const topic = 'some-cool-topic' const secret = new Secret(this, 'Secret', { secretName: 'AmazonMSK_KafkaSecret' }); myFunction.addEventSource(new ManagedKafkaEventSource({ - cluster: cluster, + clusterArn, topic: topic, secret: secret, batchSize: 100, // default diff --git a/packages/@aws-cdk/aws-lambda-event-sources/lib/kafka.ts b/packages/@aws-cdk/aws-lambda-event-sources/lib/kafka.ts index f0782964d93ce..e4892b41abf6b 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/lib/kafka.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/lib/kafka.ts @@ -2,7 +2,6 @@ import * as crypto from 'crypto'; import { ISecurityGroup, IVpc, SubnetSelection } from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as lambda from '@aws-cdk/aws-lambda'; -import * as msk from '@aws-cdk/aws-msk'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; import { Stack } from '@aws-cdk/core'; import { StreamEventSource, StreamEventSourceProps } from './stream'; @@ -32,7 +31,7 @@ export interface ManagedKafkaEventSourceProps extends KafkaEventSourceProps { /** * an MSK cluster construct */ - readonly cluster: msk.ICluster + readonly clusterArn: string; } /** @@ -103,9 +102,9 @@ export class ManagedKafkaEventSource extends StreamEventSource { public bind(target: lambda.IFunction) { target.addEventSourceMapping( - `KafkaEventSource:${this.innerProps.cluster.clusterArn}${this.innerProps.topic}`, + `KafkaEventSource:${this.innerProps.clusterArn}${this.innerProps.topic}`, this.enrichMappingOptions({ - eventSourceArn: this.innerProps.cluster.clusterArn, + eventSourceArn: this.innerProps.clusterArn, startingPosition: this.innerProps.startingPosition, // From https://docs.aws.amazon.com/msk/latest/developerguide/msk-password.html#msk-password-limitations, "Amazon MSK only supports SCRAM-SHA-512 authentication." sourceAccessConfigurations: [{ type: lambda.SourceAccessConfigurationType.SASL_SCRAM_512_AUTH, uri: this.innerProps.secret.secretArn }], @@ -118,7 +117,7 @@ export class ManagedKafkaEventSource extends StreamEventSource { target.addToRolePolicy(new iam.PolicyStatement( { actions: ['kafka:DescribeCluster', 'kafka:GetBootstrapBrokers', 'kafka:ListScramSecrets'], - resources: [this.innerProps.cluster.clusterArn], + resources: [this.innerProps.clusterArn], }, )); diff --git a/packages/@aws-cdk/aws-lambda-event-sources/lib/sqs.ts b/packages/@aws-cdk/aws-lambda-event-sources/lib/sqs.ts index 88cc1682f2be5..8a67e63fb6199 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/lib/sqs.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/lib/sqs.ts @@ -1,6 +1,6 @@ import * as lambda from '@aws-cdk/aws-lambda'; import * as sqs from '@aws-cdk/aws-sqs'; -import { Names } from '@aws-cdk/core'; +import { Duration, Names, Token } from '@aws-cdk/core'; export interface SqsEventSourceProps { /** @@ -14,6 +14,15 @@ export interface SqsEventSourceProps { */ readonly batchSize?: number; + /** + * The maximum amount of time to gather records before invoking the function. + * + * Valid Range: Minimum value of 0 minutes. Maximum value of 5 minutes. + * + * @default - no batching window. The lambda function will be invoked immediately with the records that are available. + */ + readonly maxBatchingWindow?: Duration; + /** * If the SQS event source mapping should be enabled. * @@ -29,14 +38,28 @@ export class SqsEventSource implements lambda.IEventSource { private _eventSourceMappingId?: string = undefined; constructor(readonly queue: sqs.IQueue, private readonly props: SqsEventSourceProps = { }) { - if (this.props.batchSize !== undefined && (this.props.batchSize < 1 || this.props.batchSize > 10)) { - throw new Error(`Maximum batch size must be between 1 and 10 inclusive (given ${this.props.batchSize})`); + if (this.props.maxBatchingWindow !== undefined) { + if (queue.fifo) { + throw new Error('Batching window is not supported for FIFO queues'); + } + if (!this.props.maxBatchingWindow.isUnresolved() && this.props.maxBatchingWindow.toSeconds() > 300) { + throw new Error(`Maximum batching window must be 300 seconds or less (given ${this.props.maxBatchingWindow.toHumanString()})`); + } + } + if (this.props.batchSize !== undefined && !Token.isUnresolved(this.props.batchSize)) { + if (this.props.maxBatchingWindow !== undefined && (this.props.batchSize < 1 || this.props.batchSize > 10000)) { + throw new Error(`Maximum batch size must be between 1 and 10000 inclusive (given ${this.props.batchSize}) when batching window is specified.`); + } + if (this.props.maxBatchingWindow === undefined && (this.props.batchSize < 1 || this.props.batchSize > 10)) { + throw new Error(`Maximum batch size must be between 1 and 10 inclusive (given ${this.props.batchSize}) when batching window is not specified.`); + } } } public bind(target: lambda.IFunction) { const eventSourceMapping = target.addEventSourceMapping(`SqsEventSource:${Names.nodeUniqueId(this.queue.node)}`, { batchSize: this.props.batchSize, + maxBatchingWindow: this.props.maxBatchingWindow, enabled: this.props.enabled, eventSourceArn: this.queue.queueArn, }); diff --git a/packages/@aws-cdk/aws-lambda-event-sources/lib/stream.ts b/packages/@aws-cdk/aws-lambda-event-sources/lib/stream.ts index 96907b97835fc..c9de62653a93e 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/lib/stream.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/lib/stream.ts @@ -78,6 +78,14 @@ export interface StreamEventSourceProps { */ readonly maxBatchingWindow?: Duration; + /** + * The size of the tumbling windows to group records sent to DynamoDB or Kinesis + * Valid Range: 0 - 15 minutes + * + * @default - None + */ + readonly tumblingWindow?: Duration; + /** * If the stream event source mapping should be enabled. * @@ -106,6 +114,7 @@ export abstract class StreamEventSource implements lambda.IEventSource { retryAttempts: this.props.retryAttempts, parallelizationFactor: this.props.parallelizationFactor, onFailure: this.props.onFailure, + tumblingWindow: this.props.tumblingWindow, enabled: this.props.enabled, }; } diff --git a/packages/@aws-cdk/aws-lambda-event-sources/package.json b/packages/@aws-cdk/aws-lambda-event-sources/package.json index 33906c1f5219e..c58998830ee70 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/package.json +++ b/packages/@aws-cdk/aws-lambda-event-sources/package.json @@ -62,12 +62,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "nodeunit": "^0.11.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-apigateway": "0.0.0", @@ -77,7 +77,6 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kinesis": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", - "@aws-cdk/aws-msk": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-notifications": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", @@ -85,7 +84,7 @@ "@aws-cdk/aws-sns-subscriptions": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -96,7 +95,6 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kinesis": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", - "@aws-cdk/aws-msk": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-notifications": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", @@ -104,7 +102,7 @@ "@aws-cdk/aws-sns-subscriptions": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.dynamodb.expected.json b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.dynamodb.expected.json index 406a123559d74..0f3557acedc33 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.dynamodb.expected.json +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.dynamodb.expected.json @@ -99,6 +99,7 @@ "StreamArn" ] }, + "TumblingWindowInSeconds": 60, "StartingPosition": "TRIM_HORIZON" } }, diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.dynamodb.ts b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.dynamodb.ts index ea5089bf98706..aa4f6f244ee94 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.dynamodb.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.dynamodb.ts @@ -21,6 +21,7 @@ class DynamoEventSourceTest extends cdk.Stack { fn.addEventSource(new DynamoEventSource(queue, { batchSize: 5, startingPosition: lambda.StartingPosition.TRIM_HORIZON, + tumblingWindow: cdk.Duration.seconds(60), })); } } diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesis.expected.json b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesis.expected.json index 54bfa6f32f361..aafb84ca19c72 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesis.expected.json +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesis.expected.json @@ -106,6 +106,7 @@ "Arn" ] }, + "TumblingWindowInSeconds": 60, "StartingPosition": "TRIM_HORIZON" } }, diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesis.ts b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesis.ts index 40dde2a809fc9..212c66e44ec11 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesis.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesis.ts @@ -13,6 +13,7 @@ class KinesisEventSourceTest extends cdk.Stack { fn.addEventSource(new KinesisEventSource(stream, { startingPosition: lambda.StartingPosition.TRIM_HORIZON, + tumblingWindow: cdk.Duration.seconds(60), })); } } diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/test.api.ts b/packages/@aws-cdk/aws-lambda-event-sources/test/test.api.ts index 85c189ca92886..b4aea8a304a16 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/test.api.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/test.api.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as lambda from '@aws-cdk/aws-lambda'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/test.dynamo.ts b/packages/@aws-cdk/aws-lambda-event-sources/test/test.dynamo.ts index 41d8535d90235..71397ba92607b 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/test.dynamo.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/test.dynamo.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as dynamodb from '@aws-cdk/aws-dynamodb'; import * as lambda from '@aws-cdk/aws-lambda'; import * as sqs from '@aws-cdk/aws-sqs'; @@ -76,6 +76,33 @@ export = { test.done(); }, + 'specific tumblingWindow'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const table = new dynamodb.Table(stack, 'T', { + partitionKey: { + name: 'id', + type: dynamodb.AttributeType.STRING, + }, + stream: dynamodb.StreamViewType.NEW_IMAGE, + }); + + // WHEN + fn.addEventSource(new sources.DynamoEventSource(table, { + batchSize: 50, + startingPosition: lambda.StartingPosition.LATEST, + tumblingWindow: cdk.Duration.seconds(60), + })); + + // THEN + expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TumblingWindowInSeconds: 60, + })); + + test.done(); + }, + 'specific batch size'(test: Test) { // GIVEN const stack = new cdk.Stack(); diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/test.kafka.ts b/packages/@aws-cdk/aws-lambda-event-sources/test/test.kafka.ts index 9cf1af9e50507..be63ce81245e6 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/test.kafka.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/test.kafka.ts @@ -1,7 +1,6 @@ -import { arrayWith, expect, haveResource } from '@aws-cdk/assert'; +import { arrayWith, expect, haveResource } from '@aws-cdk/assert-internal'; import { SecurityGroup, SubnetType, Vpc } from '@aws-cdk/aws-ec2'; import * as lambda from '@aws-cdk/aws-lambda'; -import * as msk from '@aws-cdk/aws-msk'; import { Secret } from '@aws-cdk/aws-secretsmanager'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; @@ -14,14 +13,14 @@ export = { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); - const cluster = msk.Cluster.fromClusterArn(stack, 'Cluster', 'some-arn'); + const clusterArn = 'some-arn'; const kafkaTopic = 'some-topic'; const secret = new Secret(stack, 'Secret', { secretName: 'AmazonMSK_KafkaSecret' }); // WHEN fn.addEventSource(new sources.ManagedKafkaEventSource( { - cluster: cluster, + clusterArn, topic: kafkaTopic, secret: secret, startingPosition: lambda.StartingPosition.TRIM_HORIZON, @@ -48,7 +47,7 @@ export = { 'kafka:ListScramSecrets', ], Effect: 'Allow', - Resource: cluster.clusterArn, + Resource: clusterArn, }, ], Version: '2012-10-17', @@ -62,7 +61,7 @@ export = { })); expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { - EventSourceArn: cluster.clusterArn, + EventSourceArn: clusterArn, FunctionName: { Ref: 'Fn9270CBC0', }, diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/test.kinesis.ts b/packages/@aws-cdk/aws-lambda-event-sources/test/test.kinesis.ts index 76e437de0ae34..dc3ff6e6637d1 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/test.kinesis.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/test.kinesis.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as kinesis from '@aws-cdk/aws-kinesis'; import * as lambda from '@aws-cdk/aws-lambda'; import * as cdk from '@aws-cdk/core'; @@ -76,6 +76,38 @@ export = { test.done(); }, + 'specific tumblingWindowInSeconds'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const stream = new kinesis.Stream(stack, 'S'); + + // WHEN + fn.addEventSource(new sources.KinesisEventSource(stream, { + batchSize: 50, + startingPosition: lambda.StartingPosition.LATEST, + tumblingWindow: cdk.Duration.seconds(60), + })); + + // THEN + expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + 'EventSourceArn': { + 'Fn::GetAtt': [ + 'S509448A1', + 'Arn', + ], + }, + 'FunctionName': { + 'Ref': 'Fn9270CBC0', + }, + 'BatchSize': 50, + 'StartingPosition': 'LATEST', + 'TumblingWindowInSeconds': 60, + })); + + test.done(); + }, + 'specific batch size'(test: Test) { // GIVEN const stack = new cdk.Stack(); diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/test.s3.ts b/packages/@aws-cdk/aws-lambda-event-sources/test/test.s3.ts index b78f8c98fb8fe..f4ab1b3f75d5b 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/test.s3.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/test.s3.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/test.sns.ts b/packages/@aws-cdk/aws-lambda-event-sources/test/test.sns.ts index 2c82ea19c42e0..bc7204d056491 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/test.sns.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/test.sns.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as sns from '@aws-cdk/aws-sns'; import * as sqs from '@aws-cdk/aws-sqs'; import * as cdk from '@aws-cdk/core'; @@ -59,7 +59,7 @@ export = { deadLetterQueue: queue, filterPolicy: { Field: sns.SubscriptionFilter.stringFilter({ - whitelist: ['A', 'B'], + allowlist: ['A', 'B'], }), }, }; diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/test.sqs.ts b/packages/@aws-cdk/aws-lambda-event-sources/test/test.sqs.ts index fd02dda47a304..0840546569c4e 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/test.sqs.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/test.sqs.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as sqs from '@aws-cdk/aws-sqs'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; @@ -85,6 +85,30 @@ export = { test.done(); }, + 'unresolved batch size'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const q = new sqs.Queue(stack, 'Q'); + const batchSize : number = 500; + + // WHEN + fn.addEventSource(new sources.SqsEventSource(q, { + batchSize: cdk.Lazy.number({ + produce() { + return batchSize; + }, + }), + })); + + // THEN + expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + 'BatchSize': 500, + })); + + test.done(); + }, + 'fails if batch size is < 1'(test: Test) { // GIVEN const stack = new cdk.Stack(); @@ -94,7 +118,7 @@ export = { // WHEN/THEN test.throws(() => fn.addEventSource(new sources.SqsEventSource(q, { batchSize: 0, - })), /Maximum batch size must be between 1 and 10 inclusive \(given 0\)/); + })), /Maximum batch size must be between 1 and 10 inclusive \(given 0\) when batching window is not specified\./); test.done(); }, @@ -108,7 +132,92 @@ export = { // WHEN/THEN test.throws(() => fn.addEventSource(new sources.SqsEventSource(q, { batchSize: 11, - })), /Maximum batch size must be between 1 and 10 inclusive \(given 11\)/); + })), /Maximum batch size must be between 1 and 10 inclusive \(given 11\) when batching window is not specified\./); + + test.done(); + }, + + 'batch size is > 10 and batch window is defined'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const q = new sqs.Queue(stack, 'Q'); + + // WHEN + fn.addEventSource(new sources.SqsEventSource(q, { + batchSize: 1000, + maxBatchingWindow: cdk.Duration.minutes(5), + })); + + // THEN + expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + 'BatchSize': 1000, + 'MaximumBatchingWindowInSeconds': 300, + })); + + test.done(); + }, + + 'fails if batch size is > 10000 and batch window is defined'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const q = new sqs.Queue(stack, 'Q'); + + // WHEN/THEN + test.throws(() => fn.addEventSource(new sources.SqsEventSource(q, { + batchSize: 11000, + maxBatchingWindow: cdk.Duration.minutes(5), + })), /Maximum batch size must be between 1 and 10000 inclusive/i); + + test.done(); + }, + + 'specific batch window'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const q = new sqs.Queue(stack, 'Q'); + + // WHEN + fn.addEventSource(new sources.SqsEventSource(q, { + maxBatchingWindow: cdk.Duration.minutes(5), + })); + + // THEN + expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + 'MaximumBatchingWindowInSeconds': 300, + })); + + test.done(); + }, + + 'fails if batch window defined for FIFO queue'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const q = new sqs.Queue(stack, 'Q', { + fifo: true, + }); + + // WHEN/THEN + test.throws(() => fn.addEventSource(new sources.SqsEventSource(q, { + maxBatchingWindow: cdk.Duration.minutes(5), + })), /Batching window is not supported for FIFO queues/); + + test.done(); + }, + + 'fails if batch window is > 5'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const q = new sqs.Queue(stack, 'Q'); + + // WHEN/THEN + test.throws(() => fn.addEventSource(new sources.SqsEventSource(q, { + maxBatchingWindow: cdk.Duration.minutes(7), + })), /Maximum batching window must be 300 seconds or less/i); test.done(); }, diff --git a/packages/@aws-cdk/aws-lambda-go/.eslintrc.js b/packages/@aws-cdk/aws-lambda-go/.eslintrc.js new file mode 100644 index 0000000000000..61dd8dd001f63 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/.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-lambda-go/.gitignore b/packages/@aws-cdk/aws-lambda-go/.gitignore new file mode 100644 index 0000000000000..5a6d23ad32d07 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/.gitignore @@ -0,0 +1,20 @@ +*.js +tsconfig.json +*.js.map +*.d.ts +*.generated.ts +dist +lib/generated/resources.ts +.jsii + +.LAST_BUILD +.nyc_output +coverage +nyc.config.js +.LAST_PACKAGE +*.snk + +!.eslintrc.js +!jest.config.js + +junit.xml diff --git a/packages/@aws-cdk/aws-lambda-go/.npmignore b/packages/@aws-cdk/aws-lambda-go/.npmignore new file mode 100644 index 0000000000000..94b89531c7268 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/.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 +test/ diff --git a/packages/@aws-cdk/aws-lambda-go/LICENSE b/packages/@aws-cdk/aws-lambda-go/LICENSE new file mode 100644 index 0000000000000..28e4bdcec77ec --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/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-2021 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-lambda-go/NOTICE b/packages/@aws-cdk/aws-lambda-go/NOTICE new file mode 100644 index 0000000000000..5fc3826926b5b --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/aws-lambda-go/README.md b/packages/@aws-cdk/aws-lambda-go/README.md new file mode 100644 index 0000000000000..5fb2907b0bf7a --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/README.md @@ -0,0 +1,256 @@ +# Amazon Lambda Golang Library + + +--- + +![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 library provides constructs for Golang Lambda functions. + +To use this module you will either need to have `Go` installed (`go1.11` or later) or `Docker` installed. +See [Local Bundling](#local-bundling)/[Docker Bundling](#docker-bundling) for more information. + +This module also requires that your Golang application is +using a Go version >= 1.11 and is using [Go modules](https://golang.org/ref/mod). + +## Go Function + +Define a `GoFunction`: + +```ts +new lambda.GoFunction(this, 'handler', { + entry: 'app/cmd/api' +}); +``` + +By default, if `entry` points to a directory, then the construct will assume there is a Go entry file (i.e. `main.go`). +Let's look at an example Go project: + +```bash +lamda-app +├── cmd +│   └── api +│   └── main.go +├── go.mod +├── go.sum +├── pkg +│   ├── auth +│   │   └── auth.go +│   └── middleware +│   └── middleware.go +└── vendor + ├── github.com + │   └── aws + │   └── aws-lambda-go + └── modules.txt +``` + +With the above layout I could either provide the `entry` as `lambda-app/cmd/api` or `lambda-app/cmd/api/main.go`, either will work. +When the construct builds the golang binary this will be translated `go build ./cmd/api` & `go build ./cmd/api/main.go` respectively. +The construct will figure out where it needs to run the `go build` command from, in this example it would be from +the `lambda-app` directory. It does this by determining the [mod file path](#mod-file-path), which is explained in the +next section. + +### mod file path + +The `GoFunction` tries to automatically determine your project root, that is +the root of your golang project. This is usually where the top level `go.mod` file or +`vendor` folder of your project is located. When bundling in a Docker container, the +`moduleDir` is used as the source (`/asset-input`) for the volume mounted in +the container. + +The CDK will walk up parent folders starting from +the current working directory until it finds a folder containing a `go.mod` file. + +Alternatively, you can specify the `moduleDir` prop manually. In this case you +need to ensure that this path includes `entry` and any module/dependencies used +by your function. Otherwise bundling will fail. + +## Runtime + +The `GoFunction` can be used with either the `GO_1_X` runtime or the provided runtimes (`PROVIDED`/`PROVIDED_AL2`). +By default it will use the `PROVIDED_AL2` runtime. The `GO_1_X` runtime does not support things like +[Lambda Extensions](https://docs.aws.amazon.com/lambda/latest/dg/using-extensions.html), whereas the provided runtimes do. +The [aws-lambda-go](https://github.com/aws/aws-lambda-go) library has built in support for the provided runtime as long as +you name the handler `bootstrap` (which we do by default). + +## Dependencies + +The construct will attempt to figure out how to handle the dependencies for your function. It will +do this by determining whether or not you are vendoring your dependencies. It makes this determination +by looking to see if there is a `vendor` folder at the [mod file path](#mod-file-path). + +With this information the construct can determine what commands to run. You will +generally fall into two scenarios: + +1. You are using vendoring (indicated by the presence of a `vendor` folder) + In this case `go build` will be run with `-mod=vendor` set +2. You are not using vendoring (indicated by the absence of a `vendor` folder) + If you are not vendoring then `go build` will be run without `-mod=vendor` + since the default behavior is to download dependencies + +All other properties of `lambda.Function` are supported, see also the [AWS Lambda construct library](https://github.com/aws/aws-cdk/tree/master/packages/%40aws-cdk/aws-lambda). + +## Environment + +By default the following environment variables are set for you: + +* `GOOS=linux` +* `GOARCH=amd64` +* `GO111MODULE=on` + +Use the `environment` prop to define additional environment variables when go runs: + +```ts +new lambda.GoFunction(this, 'handler', { + entry: 'app/cmd/api', + bundling: { + environment: { + HELLO: 'WORLD', + }, + }, +}); +``` + +## Local Bundling + +If `Go` is installed locally and the version is >= `go1.11` then it will be used to bundle your code in your environment. Otherwise, bundling will happen in a [Lambda compatible Docker container](https://hub.docker.com/layers/lambci/lambda/build-go1.x/images/sha256-e14dab718ed0bb06b2243825c5993e494a6969de7c01754ad7e80dacfce9b0cf?context=explore). + +For macOS the recommended approach is to install `Go` as Docker volume performance is really poor. + +`Go` can be installed by following the [installation docs](https://golang.org/doc/install). + + +## Docker + +To force bundling in a docker container even if `Go` is available in your environment, set the `forceDockerBundling` prop to `true`. This is useful if you want to make sure that your function is built in a consistent Lambda compatible environment. + +Use the `buildArgs` prop to pass build arguments when building the bundling image: + +```ts +new lambda.GoFunction(this, 'handler', { + entry: 'app/cmd/api', + bundling: { + buildArgs: { + HTTPS_PROXY: 'https://127.0.0.1:3001', + }, + }, +}); +``` + +Use the `bundling.dockerImage` prop to use a custom bundling image: + +```ts +new lambda.GoFunction(this, 'handler', { + entry: 'app/cmd/api', + bundling: { + dockerImage: cdk.DockerImage.fromBuild('/path/to/Dockerfile'), + }, +}); +``` + +Use the `bundling.goBuildFlags` prop to pass additional build flags to `go build`: + +```ts +new lambda.GoFunction(this, 'handler', { + entry: 'app/cmd/api', + bundling: { + goBuildFlags: ['-ldflags "-s -w"'], + }, +}); +``` + +## Command hooks + +It is possible to run additional commands by specifying the `commandHooks` prop: + +```ts +new lambda.GoFunction(this, 'handler', { + bundling: { + commandHooks: { + // run tests + beforeBundling(inputDir: string): string[] { + return ['go test ./cmd/api -v']; + }, + // ... + }, + }, +}); +``` + +The following hooks are available: + +* `beforeBundling`: runs before all bundling commands +* `afterBundling`: runs after all bundling commands + +They all receive the directory containing the `go.mod` file (`inputDir`) and the +directory where the bundled asset will be output (`outputDir`). They must return +an array of commands to run. Commands are chained with `&&`. + +The commands will run in the environment in which bundling occurs: inside the +container for Docker bundling or on the host OS for local bundling. + +## Additional considerations + +Depending on how you structure your Golang application, you may want to change the `assetHashType` parameter. +By default this parameter is set to `AssetHashType.OUTPUT` which means that the CDK will calculate the asset hash +(and determine whether or not your code has changed) based on the Golang executable that is created. + +If you specify `AssetHashType.SOURCE`, the CDK will calculate the asset hash by looking at the folder +that contains your `go.mod` file. If you are deploying a single Lambda function, or you want to redeploy +all of your functions if anything changes, then `AssetHashType.SOURCE` will probaby work. + + +For example, if my app looked like this: + +```bash +lamda-app +├── cmd +│   └── api +│   └── main.go +├── go.mod +├── go.sum +└── pkg +    └── auth +       └── auth.go +``` + +With this structure I would provide the `entry` as `cmd/api` which means that the CDK +will determine that the protect root is `lambda-app` (it contains the `go.mod` file). +Since I only have a single Lambda function, and any update to files within the `lambda-app` directory +should trigger a new deploy, I could specify `AssetHashType.SOURCE`. + +On the other hand, if I had a project that deployed mmultiple Lambda functions, for example: + +```bash +lamda-app +├── cmd +│   ├── api +│   │   └── main.go +│   └── anotherApi +│   └── main.go +├── go.mod +├── go.sum +└── pkg +    ├── auth +    │   └── auth.go +    └── middleware +    └── middleware.go +``` + +Then I would most likely want `AssetHashType.OUTPUT`. With `OUTPUT` +the CDK will only recognize changes if the Golang executable has changed, +and Go only includes dependencies that are used in the executable. So in this case +if `cmd/api` used the `auth` & `middleware` packages, but `cmd/anotherApi` did not, then +an update to `auth` or `middleware` would only trigger an update to the `cmd/api` Lambda +Function. diff --git a/packages/@aws-cdk/aws-lambda-go/jest.config.js b/packages/@aws-cdk/aws-lambda-go/jest.config.js new file mode 100644 index 0000000000000..33885f40aacf1 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/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-lambda-go/lib/Dockerfile b/packages/@aws-cdk/aws-lambda-go/lib/Dockerfile new file mode 100644 index 0000000000000..149d117cffdb9 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/lib/Dockerfile @@ -0,0 +1,12 @@ +# The correct AWS SAM build image based on the runtime of the function will be +# passed as build arg. The default allows to do `docker build .` when testing. +ARG IMAGE=lambci/lambda:build-go1.x +FROM $IMAGE + +# set the GOCACHE +ENV GOCACHE=$GOPATH/.cache/go-build + +# Ensure all users can write to GOPATH +RUN chmod -R 777 $GOPATH + +CMD [ "go" ] diff --git a/packages/@aws-cdk/aws-lambda-go/lib/bundling.ts b/packages/@aws-cdk/aws-lambda-go/lib/bundling.ts new file mode 100644 index 0000000000000..fd320cce90aed --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/lib/bundling.ts @@ -0,0 +1,201 @@ +import * as os from 'os'; +import * as path from 'path'; +import { AssetCode, Code, Runtime } from '@aws-cdk/aws-lambda'; +import * as cdk from '@aws-cdk/core'; +import { BundlingOptions } from './types'; +import { exec, findUp, getGoBuildVersion } from './util'; + +/** + * Options for bundling + */ +export interface BundlingProps extends BundlingOptions { + /** + * Directory containing your go.mod file + * + * This will accept either a directory path containing a `go.mod` file + * or a filepath to your `go.mod` file (i.e. `path/to/go.mod`). + * + * This will be used as the source of the volume mounted in the Docker + * container and will be the directory where it will run `go build` from. + * + * @default - the path is found by walking up parent directories searching for + * a `go.mod` file from the location of `entry` + */ + readonly moduleDir: string; + + /** + * The path to the folder or file that contains the main application entry point files for the project. + * + * This accepts either a path to a directory or file. + * + * If a directory path is provided then it will assume there is a Go entry file (i.e. `main.go`) and + * will construct the build command using the directory path. + * + * For example, if you provide the entry as: + * + * entry: 'my-lambda-app/cmd/api' + * + * Then the `go build` command would be: + * + * `go build ./cmd/api` + * + * If a path to a file is provided then it will use the filepath in the build command. + * + * For example, if you provide the entry as: + * + * entry: 'my-lambda-app/cmd/api/main.go' + * + * Then the `go build` command would be: + * + * `go build ./cmd/api/main.go` + */ + readonly entry: string; + + /** + * The runtime of the lambda function + */ + readonly runtime: Runtime; +} + +/** + * Bundling + */ +export class Bundling implements cdk.BundlingOptions { + + public static bundle(options: BundlingProps): AssetCode { + const bundling = new Bundling(options); + + return Code.fromAsset(path.dirname(options.moduleDir), { + assetHashType: options.assetHashType ?? cdk.AssetHashType.OUTPUT, + assetHash: options.assetHash, + bundling: { + image: bundling.image, + command: bundling.command, + environment: bundling.environment, + local: bundling.local, + }, + }); + } + + public static clearRunsLocallyCache(): void { // for tests + this.runsLocally = undefined; + } + + private static runsLocally?: boolean; + + // Core bundling options + public readonly image: cdk.DockerImage; + public readonly command: string[]; + public readonly environment?: { [key: string]: string }; + public readonly local?: cdk.ILocalBundling; + + private readonly relativeEntryPath: string; + + constructor(private readonly props: BundlingProps) { + Bundling.runsLocally = Bundling.runsLocally + ?? getGoBuildVersion() + ?? false; + + const projectRoot = path.dirname(props.moduleDir); + this.relativeEntryPath = `./${path.relative(projectRoot, path.resolve(props.entry))}`; + + const cgoEnabled = props.cgoEnabled ? '1' : '0'; + + const environment = { + CGO_ENABLED: cgoEnabled, + GO111MODULE: 'on', + GOARCH: 'amd64', + GOOS: 'linux', + ...props.environment, + }; + + // Docker bundling + const shouldBuildImage = props.forcedDockerBundling || !Bundling.runsLocally; + this.image = shouldBuildImage + ? props.dockerImage ?? cdk.DockerImage.fromBuild(path.join(__dirname, '../lib'), { + buildArgs: { + ...props.buildArgs ?? {}, + IMAGE: Runtime.GO_1_X.bundlingImage.image, // always use the GO_1_X build image + }, + }) + : cdk.DockerImage.fromRegistry('dummy'); // Do not build if we don't need to + + const bundlingCommand = this.createBundlingCommand(cdk.AssetStaging.BUNDLING_INPUT_DIR, cdk.AssetStaging.BUNDLING_OUTPUT_DIR); + this.command = ['bash', '-c', bundlingCommand]; + this.environment = environment; + + // Local bundling + if (!props.forcedDockerBundling) { // only if Docker is not forced + + const osPlatform = os.platform(); + const createLocalCommand = (outputDir: string) => this.createBundlingCommand(projectRoot, outputDir, osPlatform); + + this.local = { + tryBundle(outputDir: string) { + if (Bundling.runsLocally == false) { + process.stderr.write('go build cannot run locally. Switching to Docker bundling.\n'); + return false; + } + + const localCommand = createLocalCommand(outputDir); + exec( + osPlatform === 'win32' ? 'cmd' : 'bash', + [ + osPlatform === 'win32' ? '/c' : '-c', + localCommand, + ], + { + env: { ...process.env, ...environment ?? {} }, + stdio: [ // show output + 'ignore', // ignore stdio + process.stderr, // redirect stdout to stderr + 'inherit', // inherit stderr + ], + cwd: path.dirname(props.moduleDir), + windowsVerbatimArguments: osPlatform === 'win32', + }, + ); + return true; + }, + }; + } + } + + public createBundlingCommand(inputDir: string, outputDir: string, osPlatform: NodeJS.Platform = 'linux'): string { + const pathJoin = osPathJoin(osPlatform); + + const hasVendor = findUp('vendor', path.dirname(this.props.entry)); + + const goBuildCommand: string = [ + 'go', 'build', + hasVendor ? '-mod=vendor': '', + '-o', `${pathJoin(outputDir, 'bootstrap')}`, + `${this.props.goBuildFlags ? this.props.goBuildFlags.join(' ') : ''}`, + `${this.relativeEntryPath.replace(/\\/g, '/')}`, + ].filter(c => !!c).join(' '); + + return chain([ + ...this.props.commandHooks?.beforeBundling(inputDir, outputDir) ?? [], + goBuildCommand, + ...this.props.commandHooks?.afterBundling(inputDir, outputDir) ?? [], + ]); + } +} + +/** + * Platform specific path join + */ +function osPathJoin(platform: NodeJS.Platform) { + return function(...paths: string[]): string { + const joined = path.join(...paths); + // If we are on win32 but need posix style paths + if (os.platform() === 'win32' && platform !== 'win32') { + return joined.replace(/\\/g, '/'); + } + return joined; + }; +} + +function chain(commands: string[]): string { + return commands.filter(c => !!c).join(' && '); +} diff --git a/packages/@aws-cdk/aws-lambda-go/lib/function.ts b/packages/@aws-cdk/aws-lambda-go/lib/function.ts new file mode 100644 index 0000000000000..3b915e859cef3 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/lib/function.ts @@ -0,0 +1,121 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import * as lambda from '@aws-cdk/aws-lambda'; +import { Bundling } from './bundling'; +import { BundlingOptions } from './types'; +import { findUp } from './util'; + +// keep this import separate from other imports to reduce chance for merge conflicts with v2-main +// eslint-disable-next-line no-duplicate-imports, import/order +import { Construct } from '@aws-cdk/core'; + +/** + * Properties for a GolangFunction + */ +export interface GoFunctionProps extends lambda.FunctionOptions { + /** + * The path to the folder or file that contains the main application entry point files for the project. + * + * This accepts either a path to a directory or file. + * + * If a directory path is provided then it will assume there is a Go entry file (i.e. `main.go`) and + * will construct the build command using the directory path. + * + * For example, if you provide the entry as: + * + * entry: 'my-lambda-app/cmd/api' + * + * Then the `go build` command would be: + * + * `go build ./cmd/api` + * + * If a path to a file is provided then it will use the filepath in the build command. + * + * For example, if you provide the entry as: + * + * entry: 'my-lambda-app/cmd/api/main.go' + * + * Then the `go build` command would be: + * + * `go build ./cmd/api/main.go` + */ + readonly entry: string; + + /** + * The runtime environment. Only runtimes of the Golang family and provided family are supported. + * + * @default lambda.Runtime.PROVIDED_AL2 + */ + readonly runtime?: lambda.Runtime; + + /** + * Directory containing your go.mod file + * + * This will accept either a directory path containing a `go.mod` file + * or a filepath to your `go.mod` file (i.e. `path/to/go.mod`). + * + * This will be used as the source of the volume mounted in the Docker + * container and will be the directory where it will run `go build` from. + * + * @default - the path is found by walking up parent directories searching for + * a `go.mod` file from the location of `entry` + */ + readonly moduleDir?: string; + + /** + * Bundling options + * + * @default - use default bundling options + */ + readonly bundling?: BundlingOptions; +} + +/** + * A Golang Lambda function + */ +export class GoFunction extends lambda.Function { + constructor(scope: Construct, id: string, props: GoFunctionProps) { + if (props.runtime && (props.runtime.family !== lambda.RuntimeFamily.GO && props.runtime.family != lambda.RuntimeFamily.OTHER)) { + throw new Error('Only `go` and `provided` runtimes are supported.'); + } + + const entry = path.resolve(props.entry); + + // Find the project root + let moduleDir: string; + if (props.moduleDir) { + const parsedModuleDir = path.parse(props.moduleDir); + if (parsedModuleDir.base && parsedModuleDir.ext && parsedModuleDir.base === 'go.mod') { + if (!fs.existsSync(props.moduleDir)) { + throw new Error(`go.mod file at ${props.moduleDir} doesn't exist`); + } + } else if (parsedModuleDir.base && parsedModuleDir.ext && parsedModuleDir.base != 'go.mod') { + throw new Error('moduleDir is specifying a file that is not go.mod'); + } else if (!fs.existsSync(path.join(props.moduleDir, 'go.mod'))) { + throw new Error(`go.mod file at ${props.moduleDir} doesn't exist`); + } + moduleDir = props.moduleDir; + } else { + const modFile = findUp('go.mod', entry); + if (!modFile) { + throw new Error ('Cannot find go.mod. Please specify it with `moduleDir`.'); + } + moduleDir = modFile; + } + + const runtime = props.runtime ?? lambda.Runtime.PROVIDED_AL2; + + super(scope, id, { + ...props, + runtime, + code: Bundling.bundle({ + ...props.bundling ?? {}, + entry, + runtime, + moduleDir, + }), + handler: 'bootstrap', // setting name to bootstrap so that the 'provided' runtime can also be used + }); + } +} + diff --git a/packages/@aws-cdk/aws-lambda-go/lib/index.ts b/packages/@aws-cdk/aws-lambda-go/lib/index.ts new file mode 100644 index 0000000000000..f1fdff0ce2e4c --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/lib/index.ts @@ -0,0 +1,2 @@ +export * from './function'; +export * from './types'; diff --git a/packages/@aws-cdk/aws-lambda-go/lib/types.ts b/packages/@aws-cdk/aws-lambda-go/lib/types.ts new file mode 100644 index 0000000000000..bcd334809be33 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/lib/types.ts @@ -0,0 +1,132 @@ +import { AssetHashType, DockerImage } from '@aws-cdk/core'; + +/** + * Bundling options + */ +export interface BundlingOptions { + /** + * Environment variables defined when go runs. + * + * @default - no environment variables are defined. + */ + readonly environment?: { [key: string]: string; }; + + /** + * Force bundling in a Docker container even if local bundling is + * possible. + * + * @default - false + */ + readonly forcedDockerBundling?: boolean; + + /** + * A custom bundling Docker image. + * + * @default - use the Docker image provided by @aws-cdk/aws-lambda-go + */ + readonly dockerImage?: DockerImage; + + /** + * List of additional flags to use while building. + * + * For example: + * ['ldflags "-s -w"'] + * + * @default - none + */ + readonly goBuildFlags?: string[]; + + /** + * Build arguments to pass when building the bundling image. + * + * @default - no build arguments are passed + */ + readonly buildArgs?: { [key:string] : string }; + + /** + * Determines how the asset hash is calculated. Assets will + * get rebuilt and uploaded only if their hash has changed. + * + * If the asset hash is set to `OUTPUT` (default), the hash is calculated + * after bundling. This means that any change in the output will cause + * the asset to be invalidated and uploaded. Bear in mind that the + * go binary that is output can be different depending on the environment + * that it was compiled in. If you want to control when the output is changed + * it is recommended that you use immutable build images such as + * `public.ecr.aws/bitnami/golang:1.16.3-debian-10-r16`. + * + * If the asset hash is set to `SOURCE`, then only changes to the source + * directory will cause the asset to rebuild. If your go project has multiple + * Lambda functions this means that an update to any one function could cause + * all the functions to be rebuilt and uploaded. + * + * @default - AssetHashType.OUTPUT. If `assetHash` is also specified, + * the default is `CUSTOM`. + */ + readonly assetHashType?: AssetHashType; + + /** + * Specify a custom hash for this asset. If `assetHashType` is set it must + * be set to `AssetHashType.CUSTOM`. For consistency, this custom hash will + * be SHA256 hashed and encoded as hex. The resulting hash will be the 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. If you chose to customize the hash, you will + * need to make sure it is updated every time the asset changes, or otherwise it is + * possible that some deployments will not be invalidated. + * + * @default - based on `assetHashType` + */ + readonly assetHash?: string; + + /** + * Command hooks + * + * @default - do not run additional commands + */ + readonly commandHooks?: ICommandHooks; + + /** + * Whether or not to enable cgo during go build + * + * This will set the CGO_ENABLED environment variable + * + * @default - false + */ + readonly cgoEnabled?: boolean; +} + +/** + * Command hooks + * + * These commands will run in the environment in which bundling occurs: inside + * the container for Docker bundling or on the host OS for local bundling. + * + * Commands are chained with `&&`. + * + * @example + * { + * // Run tests prior to bundling + * beforeBundling(inputDir: string, outputDir: string): string[] { + * return [`go test -mod=vendor ./...`]; + * } + * // ... + * } + */ +export interface ICommandHooks { + /** + * Returns commands to run before bundling. + * + * Commands are chained with `&&`. + */ + beforeBundling(inputDir: string, outputDir: string): string[]; + + /** + * Returns commands to run after bundling. + * + * Commands are chained with `&&`. + */ + afterBundling(inputDir: string, outputDir: string): string[]; +} diff --git a/packages/@aws-cdk/aws-lambda-go/lib/util.ts b/packages/@aws-cdk/aws-lambda-go/lib/util.ts new file mode 100644 index 0000000000000..84ff188848f55 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/lib/util.ts @@ -0,0 +1,58 @@ +import { spawnSync, SpawnSyncOptions } from 'child_process'; +import * as fs from 'fs'; +import * as path from 'path'; + +const GO_VERSION_REGEX = /go([0-9]{1,4})+?(\.([0-9]{1,4}))+?(\.([0-9]{1,4}))?/; + +export function getGoBuildVersion(): boolean | undefined { + try { + const go = spawnSync('go', ['version']); + if (go.status !== 0 || go.error) { + return undefined; + } + const goVersion = go.stdout.toString().split(' ')[2].match(GO_VERSION_REGEX); + if (!goVersion || goVersion[3] <= '11') { + return undefined; + } else { + return true; + } + } catch (err) { + return undefined; + } +} + +/** + * Spawn sync with error handling + */ +export function exec(cmd: string, args: string[], options?: SpawnSyncOptions) { + const proc = spawnSync(cmd, args, options); + + if (proc.error) { + throw proc.error; + } + + if (proc.status !== 0) { + if (proc.stdout || proc.stderr) { + throw new Error(`[Status ${proc.status}] stdout: ${proc.stdout?.toString().trim()}\n\n\nstderr: ${proc.stderr?.toString().trim()}`); + } + throw new Error(`${cmd} exited with status ${proc.status}`); + } + + return proc; +} + +export function findUp(name: string, directory: string = process.cwd()): string | undefined { + const absoluteDirectory = path.resolve(directory); + + const file = path.join(directory, name); + if (fs.existsSync(file)) { + return file; + } + + const { root } = path.parse(absoluteDirectory); + if (absoluteDirectory == root) { + return undefined; + } + + return findUp(name, path.dirname(absoluteDirectory)); +} diff --git a/packages/@aws-cdk/aws-lambda-go/package.json b/packages/@aws-cdk/aws-lambda-go/package.json new file mode 100644 index 0000000000000..2850bac097417 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/package.json @@ -0,0 +1,98 @@ +{ + "name": "@aws-cdk/aws-lambda-go", + "version": "0.0.0", + "description": "The CDK Construct Library for AWS Lambda in Golang", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "targets": { + "java": { + "package": "software.amazon.awscdk.services.lambda.go", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "lambda-go" + } + }, + "dotnet": { + "namespace": "Amazon.CDK.AWS.Lambda.Go", + "packageId": "Amazon.CDK.AWS.Lambda.Go", + "signAssembly": true, + "assemblyOriginatorKeyFile": "../../key.snk", + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png" + }, + "python": { + "distName": "aws-cdk.aws-lambda-go", + "module": "aws_cdk.aws_lambda_go", + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 1" + ] + } + }, + "projectReferences": true + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-lambda-go" + }, + "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", + "build+test+package": "yarn build+test && yarn package", + "build+test": "yarn build && yarn test", + "compat": "cdk-compat", + "rosetta:extract": "yarn --silent jsii-rosetta extract" + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "lambda" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", + "cdk-build-tools": "0.0.0", + "cdk-integ-tools": "0.0.0", + "pkglint": "0.0.0" + }, + "dependencies": { + "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" + }, + "homepage": "https://github.com/aws/aws-cdk", + "peerDependencies": { + "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" + }, + "engines": { + "node": ">= 10.13.0 <13 || >=13.7.0" + }, + "stability": "experimental", + "maturity": "experimental", + "awscdkio": { + "announce": false + }, + "cdk-build": { + "jest": true + }, + "publishConfig": { + "tag": "latest" + } +} diff --git a/packages/@aws-cdk/aws-lambda-go/test/bundling.test.ts b/packages/@aws-cdk/aws-lambda-go/test/bundling.test.ts new file mode 100644 index 0000000000000..c6a743a422719 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/test/bundling.test.ts @@ -0,0 +1,316 @@ +import * as child_process from 'child_process'; +import * as os from 'os'; +import * as path from 'path'; +import { Code, Runtime } from '@aws-cdk/aws-lambda'; +import { AssetHashType, DockerImage } from '@aws-cdk/core'; +import { Bundling } from '../lib/bundling'; +import * as util from '../lib/util'; + +jest.mock('@aws-cdk/aws-lambda'); +const fromAssetMock = jest.spyOn(DockerImage, 'fromBuild'); +let getGoBuildVersionMock = jest.spyOn(util, 'getGoBuildVersion'); + +beforeEach(() => { + jest.clearAllMocks(); + jest.resetAllMocks(); + Bundling.clearRunsLocallyCache(); + getGoBuildVersionMock.mockReturnValue(true); + fromAssetMock.mockReturnValue({ + image: 'built-image', + cp: () => 'built-image', + run: () => {}, + toJSON: () => 'build-image', + }); +}); + +const moduleDir = '/project/go.mod'; +const entry = '/project/cmd/api'; + +test('bundling', () => { + Bundling.bundle({ + entry, + runtime: Runtime.GO_1_X, + moduleDir, + forcedDockerBundling: true, + environment: { + KEY: 'value', + }, + }); + + expect(Code.fromAsset).toHaveBeenCalledWith(path.dirname(moduleDir), { + assetHashType: AssetHashType.OUTPUT, + bundling: expect.objectContaining({ + environment: { + KEY: 'value', + CGO_ENABLED: '0', + GO111MODULE: 'on', + GOARCH: 'amd64', + GOOS: 'linux', + }, + command: [ + 'bash', '-c', + [ + 'go build -o /asset-output/bootstrap ./cmd/api', + ].join(' && '), + ], + }), + }); +}); + +test('bundling with file as entry', () => { + Bundling.bundle({ + entry: '/project/main.go', + runtime: Runtime.GO_1_X, + moduleDir, + }); + + expect(Code.fromAsset).toHaveBeenCalledWith('/project', { + assetHashType: AssetHashType.OUTPUT, + bundling: expect.objectContaining({ + command: [ + 'bash', '-c', + [ + 'go build -o /asset-output/bootstrap ./main.go', + ].join(' && '), + ], + }), + }); +}); + +test('bundling with file in subdirectory as entry', () => { + Bundling.bundle({ + entry: '/project/cmd/api/main.go', + runtime: Runtime.GO_1_X, + moduleDir, + }); + + expect(Code.fromAsset).toHaveBeenCalledWith('/project', { + assetHashType: AssetHashType.OUTPUT, + bundling: expect.objectContaining({ + command: [ + 'bash', '-c', + [ + 'go build -o /asset-output/bootstrap ./cmd/api/main.go', + ].join(' && '), + ], + }), + }); +}); + +test('bundling with file other than main.go in subdirectory as entry', () => { + Bundling.bundle({ + entry: '/project/cmd/api/api.go', + runtime: Runtime.GO_1_X, + moduleDir, + }); + + expect(Code.fromAsset).toHaveBeenCalledWith('/project', { + assetHashType: AssetHashType.OUTPUT, + bundling: expect.objectContaining({ + command: [ + 'bash', '-c', + [ + 'go build -o /asset-output/bootstrap ./cmd/api/api.go', + ].join(' && '), + ], + }), + }); +}); + +test('go with Windows paths', () => { + const osPlatformMock = jest.spyOn(os, 'platform').mockReturnValue('win32'); + Bundling.bundle({ + entry: 'C:\\my-project\\cmd\\api', + runtime: Runtime.GO_1_X, + moduleDir: 'C:\\my-project\\go.mod', + forcedDockerBundling: true, + }); + + expect(Code.fromAsset).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({ + assetHashType: AssetHashType.OUTPUT, + bundling: expect.objectContaining({ + command: expect.arrayContaining([ + expect.stringContaining('cmd/api'), + ]), + }), + })); + osPlatformMock.mockRestore(); +}); + +test('with Docker build args', () => { + Bundling.bundle({ + entry, + runtime: Runtime.GO_1_X, + moduleDir, + forcedDockerBundling: true, + buildArgs: { + HELLO: 'WORLD', + }, + }); + expect(fromAssetMock).toHaveBeenCalledWith(expect.stringMatching(/lib$/), expect.objectContaining({ + buildArgs: expect.objectContaining({ + HELLO: 'WORLD', + }), + })); +}); + +test('Local bundling', () => { + const spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValue({ + status: 0, + stderr: Buffer.from('stderr'), + stdout: Buffer.from('go version go1.15 linux/amd64'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + + const bundler = new Bundling({ + moduleDir, + entry, + environment: { + KEY: 'value', + }, + runtime: Runtime.PROVIDED_AL2, + }); + + expect(bundler.local).toBeDefined(); + + const tryBundle = bundler.local?.tryBundle('/outdir', { image: Runtime.GO_1_X.bundlingDockerImage }); + expect(tryBundle).toBe(true); + + expect(spawnSyncMock).toHaveBeenCalledWith( + 'bash', + expect.arrayContaining(['-c', expect.stringContaining('cmd/api')]), + expect.objectContaining({ + env: expect.objectContaining({ KEY: 'value' }), + cwd: expect.stringContaining('/project'), + }), + ); + + // Docker image is not built + expect(fromAssetMock).not.toHaveBeenCalled(); +}); + +test('Incorrect go version', () => { + getGoBuildVersionMock.mockReturnValueOnce(false); + + const bundler = new Bundling({ + entry, + moduleDir, + runtime: Runtime.PROVIDED_AL2, + }); + + const tryBundle = bundler.local?.tryBundle('/outdir', { image: Runtime.GO_1_X.bundlingDockerImage }); + + expect(tryBundle).toBe(false); +}); + + +test('Custom bundling docker image', () => { + Bundling.bundle({ + entry, + moduleDir, + runtime: Runtime.GO_1_X, + forcedDockerBundling: true, + dockerImage: DockerImage.fromRegistry('my-custom-image'), + }); + + expect(Code.fromAsset).toHaveBeenCalledWith('/project', { + assetHashType: AssetHashType.OUTPUT, + bundling: expect.objectContaining({ + image: { image: 'my-custom-image' }, + }), + }); +}); + +test('Go build flags can be passed', () => { + Bundling.bundle({ + entry, + runtime: Runtime.GO_1_X, + moduleDir, + environment: { + KEY: 'value', + }, + goBuildFlags: ['-ldflags "-s -w"'], + }); + + expect(Code.fromAsset).toHaveBeenCalledWith('/project', { + assetHashType: AssetHashType.OUTPUT, + bundling: expect.objectContaining({ + environment: { + KEY: 'value', + CGO_ENABLED: '0', + GO111MODULE: 'on', + GOARCH: 'amd64', + GOOS: 'linux', + }, + command: [ + 'bash', '-c', + [ + 'go build -o /asset-output/bootstrap -ldflags "-s -w" ./cmd/api', + ].join(' && '), + ], + }), + }); +}); + +test('AssetHashType can be specified', () => { + Bundling.bundle({ + entry, + runtime: Runtime.GO_1_X, + moduleDir, + environment: { + KEY: 'value', + }, + assetHashType: AssetHashType.OUTPUT, + }); + + expect(Code.fromAsset).toHaveBeenCalledWith('/project', { + assetHashType: AssetHashType.OUTPUT, + bundling: expect.objectContaining({ + environment: { + KEY: 'value', + CGO_ENABLED: '0', + GO111MODULE: 'on', + GOARCH: 'amd64', + GOOS: 'linux', + }, + command: [ + 'bash', '-c', + [ + 'go build -o /asset-output/bootstrap ./cmd/api', + ].join(' && '), + ], + }), + }); +}); + + +test('with command hooks', () => { + Bundling.bundle({ + entry, + moduleDir, + runtime: Runtime.PROVIDED_AL2, + commandHooks: { + beforeBundling(inputDir: string, outputDir: string): string[] { + return [ + `echo hello > ${inputDir}/a.txt`, + `cp ${inputDir}/a.txt ${outputDir}`, + ]; + }, + afterBundling(inputDir: string, outputDir: string): string[] { + return [`cp ${inputDir}/b.txt ${outputDir}/txt`]; + }, + }, + }); + + expect(Code.fromAsset).toHaveBeenCalledWith(path.dirname(moduleDir), { + assetHashType: AssetHashType.OUTPUT, + bundling: expect.objectContaining({ + command: [ + 'bash', '-c', + expect.stringMatching(/^echo hello > \/asset-input\/a.txt && cp \/asset-input\/a.txt \/asset-output && .+ && cp \/asset-input\/b.txt \/asset-output\/txt$/), + ], + }), + }); +}); diff --git a/packages/@aws-cdk/aws-lambda-go/test/docker.test.ts b/packages/@aws-cdk/aws-lambda-go/test/docker.test.ts new file mode 100644 index 0000000000000..d619d9f0fb91d --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/test/docker.test.ts @@ -0,0 +1,15 @@ +import { spawnSync } from 'child_process'; +import * as path from 'path'; + +beforeAll(() => { + spawnSync('docker', ['build', '--build-arg', 'IMAGE=public.ecr.aws/bitnami/golang:1.15', '-t', 'golang', path.join(__dirname, '../lib')]); +}); + +test('golang is available', async () => { + const proc = spawnSync('docker', [ + 'run', 'golang', + 'sh', '-c', + 'go version', + ]); + expect(proc.status).toEqual(0); +}); diff --git a/packages/@aws-cdk/aws-lambda-go/test/function.test.ts b/packages/@aws-cdk/aws-lambda-go/test/function.test.ts new file mode 100644 index 0000000000000..472dc39fc769f --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/test/function.test.ts @@ -0,0 +1,147 @@ +import '@aws-cdk/assert-internal/jest'; +import * as path from 'path'; +import { Runtime } from '@aws-cdk/aws-lambda'; +import { Stack } from '@aws-cdk/core'; +import { GoFunction } from '../lib'; +import { Bundling } from '../lib/bundling'; + +jest.mock('../lib/bundling', () => { + return { + Bundling: { + bundle: jest.fn().mockReturnValue({ + bind: () => { + return { s3Location: 'code' }; + }, + bindToResource: () => { return; }, + }), + }, + }; +}); + +let stack: Stack; +beforeEach(() => { + stack = new Stack(); + jest.clearAllMocks(); +}); + +test('GoFunction with defaults', () => { + // WHEN + new GoFunction(stack, 'handler', { + entry: path.join(__dirname, 'lambda-handler-vendor/cmd/api'), + }); + + expect(Bundling.bundle).toHaveBeenCalledWith(expect.objectContaining({ + entry: expect.stringMatching(/@aws-cdk\/aws-lambda-go\/test\/lambda-handler-vendor\/cmd\/api$/), + })); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + Handler: 'bootstrap', + Runtime: 'provided.al2', + }); +}); + +test('GoFunction with using provided runtime', () => { + // WHEN + new GoFunction(stack, 'handler', { + entry: 'test/lambda-handler-vendor/cmd/api', + runtime: Runtime.PROVIDED, + }); + + expect(Bundling.bundle).toHaveBeenCalledWith(expect.objectContaining({ + entry: expect.stringMatching(/@aws-cdk\/aws-lambda-go\/test\/lambda-handler-vendor\/cmd\/api$/), + })); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + Handler: 'bootstrap', + Runtime: 'provided', + }); +}); + +test('GoFunction with using golang runtime', () => { + // WHEN + new GoFunction(stack, 'handler', { + entry: 'test/lambda-handler-vendor/cmd/api', + runtime: Runtime.GO_1_X, + }); + + expect(Bundling.bundle).toHaveBeenCalledWith(expect.objectContaining({ + entry: expect.stringMatching(/@aws-cdk\/aws-lambda-go\/test\/lambda-handler-vendor\/cmd\/api$/), + })); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + Handler: 'bootstrap', + Runtime: 'go1.x', + }); +}); + +test('GoFunction with container env vars', () => { + // WHEN + new GoFunction(stack, 'handler', { + entry: 'test/lambda-handler-vendor/cmd/api', + bundling: { + environment: { + KEY: 'VALUE', + }, + }, + }); + + expect(Bundling.bundle).toHaveBeenCalledWith(expect.objectContaining({ + environment: { + KEY: 'VALUE', + }, + })); +}); + +test('throws with the wrong runtime family', () => { + expect(() => new GoFunction(stack, 'handler', { + entry: 'test/lambda-handler-vendor/cmd/api', + runtime: Runtime.PYTHON_3_8, + })).toThrow(/Only `go` and `provided` runtimes are supported/); +}); + +test('resolves entry to an absolute path', () => { + // WHEN + new GoFunction(stack, 'fn', { + entry: 'test/lambda-handler-vendor/cmd/api/main.go', + }); + + expect(Bundling.bundle).toHaveBeenCalledWith(expect.objectContaining({ + entry: expect.stringMatching(/@aws-cdk\/aws-lambda-go\/test\/lambda-handler-vendor\/cmd\/api\/main.go$/), + })); +}); + +test('throws with no existing go.mod file', () => { + expect(() => new GoFunction(stack, 'handler', { + entry: 'test/lambda-handler-vendor/cmd/api', + moduleDir: '/does/not/exist/go.mod', + })).toThrow(/go.mod file at \/does\/not\/exist\/go.mod doesn't exist/); +}); + +test('throws with incorrect moduleDir file', () => { + expect(() => new GoFunction(stack, 'handler', { + entry: 'test/lambda-handler-vendor/cmd/api', + moduleDir: '/does/not/exist.mod', + })).toThrow(/moduleDir is specifying a file that is not go.mod/); +}); + +test('custom moduleDir can be used', () => { + new GoFunction(stack, 'handler', { + entry: 'test/lambda-handler-vendor/cmd/api', + moduleDir: 'test/lambda-handler-vendor', + }); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + Handler: 'bootstrap', + }); +}); + +test('custom moduleDir with file path can be used', () => { + new GoFunction(stack, 'handler', { + entry: 'test/lambda-handler-vendor/cmd/api', + moduleDir: 'test/lambda-handler-vendor/go.mod', + }); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + Handler: 'bootstrap', + }); +}); diff --git a/packages/@aws-cdk/aws-lambda-go/test/integ.function.expected.json b/packages/@aws-cdk/aws-lambda-go/test/integ.function.expected.json new file mode 100644 index 0000000000000..9ae6cc08830e8 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/test/integ.function.expected.json @@ -0,0 +1,103 @@ +{ + "Resources": { + "gohandlerdockerServiceRole70394790": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "gohandlerdockerAE04F1B8": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "AssetParameters4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1S3Bucket62A8237E" + }, + "S3Key": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1S3VersionKey1C4F3B50" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1S3VersionKey1C4F3B50" + } + ] + } + ] + } + ] + ] + } + }, + "Role": { + "Fn::GetAtt": [ + "gohandlerdockerServiceRole70394790", + "Arn" + ] + }, + "Handler": "bootstrap", + "Runtime": "provided.al2" + }, + "DependsOn": [ + "gohandlerdockerServiceRole70394790" + ] + } + }, + "Parameters": { + "AssetParameters4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1S3Bucket62A8237E": { + "Type": "String", + "Description": "S3 bucket for asset \"4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1\"" + }, + "AssetParameters4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1S3VersionKey1C4F3B50": { + "Type": "String", + "Description": "S3 key for asset version \"4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1\"" + }, + "AssetParameters4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1ArtifactHashBE683488": { + "Type": "String", + "Description": "Artifact hash for asset \"4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1\"" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda-go/test/integ.function.ts b/packages/@aws-cdk/aws-lambda-go/test/integ.function.ts new file mode 100644 index 0000000000000..093597339e8b5 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/test/integ.function.ts @@ -0,0 +1,32 @@ +import * as path from 'path'; +import { App, DockerImage, Stack, StackProps } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import * as lambda from '../lib'; + +/* + * Stack verification steps: + * * aws lambda invoke --function-name --invocation-type Event --payload '"OK"' response.json + */ + +class TestStack extends Stack { + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + + new lambda.GoFunction(this, 'go-handler-docker', { + entry: path.join(__dirname, 'lambda-handler-vendor/cmd/api'), + bundling: { + dockerImage: DockerImage.fromBuild(path.join(__dirname, '../lib'), { + buildArgs: { + IMAGE: 'public.ecr.aws/bitnami/golang:1.16.3-debian-10-r16', + }, + }), + forcedDockerBundling: true, + goBuildFlags: ['-mod=readonly', '-ldflags "-s -w"'], + }, + }); + } +} + +const app = new App(); +new TestStack(app, 'cdk-integ-lambda-golang'); +app.synth(); diff --git a/packages/@aws-cdk/aws-lambda-go/test/lambda-handler-vendor/cmd/api/main.go b/packages/@aws-cdk/aws-lambda-go/test/lambda-handler-vendor/cmd/api/main.go new file mode 100644 index 0000000000000..3dc0f71439536 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/test/lambda-handler-vendor/cmd/api/main.go @@ -0,0 +1,20 @@ +package main + +import ( + "context" + "fmt" + + "github.com/aws/aws-lambda-go/lambda" +) + +type MyEvent struct { + Name string `json:"name"` +} + +func HandleRequest(ctx context.Context, name MyEvent) (string, error) { + return fmt.Sprintf("Hello %s!", name.Name), nil +} + +func main() { + lambda.Start(HandleRequest) +} diff --git a/packages/@aws-cdk/aws-lambda-go/test/lambda-handler-vendor/go.mod b/packages/@aws-cdk/aws-lambda-go/test/lambda-handler-vendor/go.mod new file mode 100644 index 0000000000000..24ac2f8c41afa --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/test/lambda-handler-vendor/go.mod @@ -0,0 +1,10 @@ +module aws-lambda-golang + +go 1.16 + +require ( + github.com/aws/aws-lambda-go v1.19.1 + github.com/kr/text v0.2.0 // indirect + github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect + gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect +) diff --git a/packages/@aws-cdk/aws-lambda-go/test/lambda-handler-vendor/go.sum b/packages/@aws-cdk/aws-lambda-go/test/lambda-handler-vendor/go.sum new file mode 100644 index 0000000000000..94f7ebf0f685e --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/test/lambda-handler-vendor/go.sum @@ -0,0 +1,32 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/aws/aws-lambda-go v1.19.1 h1:5iUHbIZ2sG6Yq/J1IN3sWm3+vAB1CWwhI21NffLNuNI= +github.com/aws/aws-lambda-go v1.19.1/go.mod h1:jJmlefzPfGnckuHdXX7/80O3BvUUi12XOkbv4w9SGLU= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/packages/@aws-cdk/aws-lambda-go/test/util.test.ts b/packages/@aws-cdk/aws-lambda-go/test/util.test.ts new file mode 100644 index 0000000000000..dc2b9d350658e --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/test/util.test.ts @@ -0,0 +1,157 @@ +import * as child_process from 'child_process'; +import * as os from 'os'; +import * as path from 'path'; +import { exec, findUp, getGoBuildVersion } from '../lib/util'; + +beforeEach(() => { + jest.clearAllMocks(); +}); + + +describe('findUp', () => { + test('Starting at process.cwd()', () => { + expect(findUp('README.md')).toMatch(/aws-lambda-go\/README.md$/); + }); + + test('Non existing file', () => { + expect(findUp('non-existing-file.unknown')).toBe(undefined); + }); + + test('Starting at a specific path', () => { + expect(findUp('util.test.ts', path.join(__dirname, 'integ-handlers'))).toMatch(/aws-lambda-go\/test\/util.test.ts$/); + }); + + test('Non existing file starting at a non existing relative path', () => { + expect(findUp('not-to-be-found.txt', 'non-existing/relative/path')).toBe(undefined); + }); + + test('Starting at a relative path', () => { + expect(findUp('util.test.ts', 'test/integ-handlers')).toMatch(/aws-lambda-go\/test\/util.test.ts$/); + }); +}); + +describe('exec', () => { + test('normal execution', () => { + const spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValue({ + status: 0, + stderr: Buffer.from('stderr'), + stdout: Buffer.from('stdout'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + + const proc = exec( + 'cmd', + ['arg1', 'arg2'], + { env: { KEY: 'value' } }, + ); + + expect(spawnSyncMock).toHaveBeenCalledWith( + 'cmd', + ['arg1', 'arg2'], + { env: { KEY: 'value' } }, + ); + expect(proc.stdout.toString()).toBe('stdout'); + + spawnSyncMock.mockRestore(); + }); + + test('non zero status', () => { + const spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValue({ + status: 999, + stderr: Buffer.from('error occured'), + stdout: Buffer.from('stdout'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + + expect(() => exec('cmd', ['arg1', 'arg2'])).toThrow('error occured'); + + spawnSyncMock.mockRestore(); + }); + + test('with error', () => { + const spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValue({ + error: new Error('bad error'), + status: 0, + stderr: Buffer.from('stderr'), + stdout: Buffer.from('stdout'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + + expect(() => exec('cmd', ['arg1', 'arg2'])).toThrow(new Error('bad error')); + + spawnSyncMock.mockRestore(); + }); +}); + +describe('getGoBuildVersion', () => { + test('returns the version', () => { + const spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValue({ + status: 0, + stderr: Buffer.from('stderr'), + stdout: Buffer.from('go version go1.15 linux/amd64'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + + expect(getGoBuildVersion()).toBe(true); + expect(spawnSyncMock).toHaveBeenCalledWith('go', ['version']); + + spawnSyncMock.mockRestore(); + }); + + test('returns undefined on non zero status', () => { + const spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValue({ + status: 127, // status error + stderr: Buffer.from('stderr'), + stdout: Buffer.from('stdout'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + + expect(getGoBuildVersion()).toBeUndefined(); + + spawnSyncMock.mockRestore(); + }); + + test('returns undefined on error', () => { + const spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValue({ + error: new Error('bad error'), + status: 0, + stderr: Buffer.from('stderr'), + stdout: Buffer.from('stdout'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + + expect(getGoBuildVersion()).toBeUndefined(); + + spawnSyncMock.mockRestore(); + }); + + test('Windows', () => { + const spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValue({ + status: 0, + stderr: Buffer.from('stderr'), + stdout: Buffer.from('go version go1.15 windows/amd64'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + const osPlatformMock = jest.spyOn(os, 'platform').mockReturnValue('win32'); + + expect(getGoBuildVersion()).toBe(true); + expect(spawnSyncMock).toHaveBeenCalledWith('go', expect.any(Array)); + + spawnSyncMock.mockRestore(); + osPlatformMock.mockRestore(); + }); +}); diff --git a/packages/@aws-cdk/aws-lambda-nodejs/README.md b/packages/@aws-cdk/aws-lambda-nodejs/README.md index d11602c5e656e..7a1662dc26fb2 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/README.md +++ b/packages/@aws-cdk/aws-lambda-nodejs/README.md @@ -3,13 +3,7 @@ --- -![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. +![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge) --- @@ -17,8 +11,6 @@ This library provides constructs for Node.js Lambda functions. -To use this module, you will need to have Docker installed. - ## Node.js Function Define a `NodejsFunction`: @@ -67,7 +59,7 @@ used by your function. Otherwise bundling will fail. ## Local bundling If `esbuild` is available it will be used to bundle your code in your environment. Otherwise, -bundling will happen in a [Lambda compatible Docker container](https://hub.docker.com/r/amazon/aws-sam-cli-build-image-nodejs12.x). +bundling will happen in a [Lambda compatible Docker container](https://gallery.ecr.aws/sam/build-nodejs12.x). For macOS the recommendend approach is to install `esbuild` as Docker volume performance is really poor. @@ -145,6 +137,8 @@ new lambda.NodejsFunction(this, 'my-handler', { }, define: { // Replace strings during build time 'process.env.API_KEY': JSON.stringify('xxx-xxxx-xxx'), + 'process.env.PRODUCTION': JSON.stringify(true), + 'process.env.NUMBER': JSON.stringify(123), }, logLevel: LogLevel.SILENT, // defaults to LogLevel.WARNING keepNames: true, // defaults to false diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/Dockerfile b/packages/@aws-cdk/aws-lambda-nodejs/lib/Dockerfile index a92d2fd2092cc..27fe83af43c35 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/Dockerfile +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/Dockerfile @@ -1,6 +1,6 @@ # The correct AWS SAM build image based on the runtime of the function will be # passed as build arg. The default allows to do `docker build .` when testing. -ARG IMAGE=amazon/aws-sam-cli-build-image-nodejs12.x +ARG IMAGE=public.ecr.aws/sam/build-nodejs12.x FROM $IMAGE # Install yarn diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts index 536ca1ea7646a..8624dce8c1359 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts @@ -48,7 +48,7 @@ export class Bundling implements cdk.BundlingOptions { private static runsLocally?: boolean; // Core bundling options - public readonly image: cdk.BundlingDockerImage; + public readonly image: cdk.DockerImage; public readonly command: string[]; public readonly environment?: { [key: string]: string }; public readonly workingDirectory: string; @@ -78,14 +78,14 @@ export class Bundling implements cdk.BundlingOptions { // Docker bundling const shouldBuildImage = props.forceDockerBundling || !Bundling.runsLocally; this.image = shouldBuildImage - ? props.dockerImage ?? cdk.BundlingDockerImage.fromAsset(path.join(__dirname, '../lib'), { + ? props.dockerImage ?? cdk.DockerImage.fromBuild(path.join(__dirname, '../lib'), { buildArgs: { ...props.buildArgs ?? {}, IMAGE: props.runtime.bundlingDockerImage.image, ESBUILD_VERSION: props.esbuildVersion ?? ESBUILD_VERSION, }, }) - : cdk.BundlingDockerImage.fromRegistry('dummy'); // Do not build if we don't need to + : cdk.DockerImage.fromRegistry('dummy'); // Do not build if we don't need to const bundlingCommand = this.createBundlingCommand(cdk.AssetStaging.BUNDLING_INPUT_DIR, cdk.AssetStaging.BUNDLING_OUTPUT_DIR); this.command = ['bash', '-c', bundlingCommand]; @@ -148,7 +148,7 @@ export class Bundling implements cdk.BundlingOptions { ...this.props.sourceMap ? ['--sourcemap'] : [], ...this.externals.map(external => `--external:${external}`), ...loaders.map(([ext, name]) => `--loader:${ext}=${name}`), - ...defines.map(([key, value]) => `--define:${key}=${value}`), + ...defines.map(([key, value]) => `--define:${key}=${JSON.stringify(value)}`), ...this.props.logLevel ? [`--log-level=${this.props.logLevel}`] : [], ...this.props.keepNames ? ['--keep-names'] : [], ...this.relativeTsconfigPath ? [`--tsconfig=${pathJoin(inputDir, this.relativeTsconfigPath)}`] : [], diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts index afa3d93d21a9b..49e9b40b5cd5d 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts @@ -3,7 +3,7 @@ import * as path from 'path'; import * as lambda from '@aws-cdk/aws-lambda'; import { Bundling } from './bundling'; import { BundlingOptions } from './types'; -import { callsites, findUp, LockFile, nodeMajorVersion } from './util'; +import { callsites, findUp, LockFile } from './util'; // keep this import separate from other imports to reduce chance for merge conflicts with v2-main // eslint-disable-next-line no-duplicate-imports, import/order @@ -34,8 +34,7 @@ export interface NodejsFunctionProps extends lambda.FunctionOptions { * The runtime environment. Only runtimes of the Node.js family are * supported. * - * @default - `NODEJS_14_X` if `process.versions.node` >= '14.0.0', - * `NODEJS_12_X` otherwise. + * @default Runtime.NODEJS_14_X */ readonly runtime?: lambda.Runtime; @@ -105,10 +104,7 @@ export class NodejsFunction extends lambda.Function { // Entry and defaults const entry = path.resolve(findEntry(id, props.entry)); const handler = props.handler ?? 'handler'; - const defaultRunTime = nodeMajorVersion() >= 14 - ? lambda.Runtime.NODEJS_14_X - : lambda.Runtime.NODEJS_12_X; - const runtime = props.runtime ?? defaultRunTime; + const runtime = props.runtime ?? lambda.Runtime.NODEJS_14_X; super(scope, id, { ...props, diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts index 537523abb4f3b..6752d8ca725a1 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts @@ -1,4 +1,4 @@ -import { BundlingDockerImage } from '@aws-cdk/core'; +import { DockerImage } from '@aws-cdk/core'; /** * Bundling options @@ -200,7 +200,7 @@ export interface BundlingOptions { * * @default - use the Docker image provided by @aws-cdk/aws-lambda-nodejs */ - readonly dockerImage?: BundlingDockerImage; + readonly dockerImage?: DockerImage; /** * Command hooks diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/util.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/util.ts index f74030f7376d1..206941f71f66d 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/util.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/util.ts @@ -32,13 +32,6 @@ export function callsites(): CallSite[] { return stack as unknown as CallSite[]; } -/** - * Returns the major version of node installation - */ -export function nodeMajorVersion(): number { - return parseInt(process.versions.node.split('.')[0], 10); -} - /** * Find a file by walking up parent directories */ diff --git a/packages/@aws-cdk/aws-lambda-nodejs/package.json b/packages/@aws-cdk/aws-lambda-nodejs/package.json index c411d343615fe..8578724b9a9bd 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/package.json +++ b/packages/@aws-cdk/aws-lambda-nodejs/package.json @@ -62,33 +62,35 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "@aws-cdk/aws-ec2": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "delay": "5.0.0", - "esbuild": "^0.9.3", - "pkglint": "0.0.0" + "esbuild": "^0.11.18", + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, - "stability": "experimental", - "maturity": "experimental", + "stability": "stable", + "maturity": "stable", "awscdkio": { "announce": false }, + "nozem": false, "cdk-build": { "jest": true }, diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/__snapshots__/bundling.test.js.snap b/packages/@aws-cdk/aws-lambda-nodejs/test/__snapshots__/bundling.test.js.snap new file mode 100644 index 0000000000000..13ae6a72da036 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/__snapshots__/bundling.test.js.snap @@ -0,0 +1,16 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`esbuild bundling with esbuild options 1`] = ` +"(() => { + // test/integ-handlers/define.ts + function handler() { + return [ + \\"VALUE\\", + true, + 7777, + 'this is a \\"test\\"' + ]; + } +})(); +" +`; 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 e6c32c496b2ff..064c8458dbf97 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts @@ -2,7 +2,7 @@ import * as child_process from 'child_process'; import * as os from 'os'; import * as path from 'path'; import { Code, Runtime } from '@aws-cdk/aws-lambda'; -import { AssetHashType, BundlingDockerImage } from '@aws-cdk/core'; +import { AssetHashType, DockerImage } from '@aws-cdk/core'; import { version as delayVersion } from 'delay/package.json'; import { Bundling } from '../lib/bundling'; import { LogLevel } from '../lib/types'; @@ -11,7 +11,7 @@ import * as util from '../lib/util'; jest.mock('@aws-cdk/aws-lambda'); // Mock BundlingDockerImage.fromAsset() to avoid building the image -let fromAssetMock = jest.spyOn(BundlingDockerImage, 'fromAsset'); +let fromAssetMock = jest.spyOn(DockerImage, 'fromBuild'); let getEsBuildVersionMock = jest.spyOn(util, 'getEsBuildVersion'); beforeEach(() => { jest.clearAllMocks(); @@ -169,12 +169,15 @@ test('esbuild bundling with esbuild options', () => { footer: '/* comments */', forceDockerBundling: true, define: { - 'DEBUG': 'true', 'process.env.KEY': JSON.stringify('VALUE'), + 'process.env.BOOL': 'true', + 'process.env.NUMBER': '7777', + 'process.env.STRING': JSON.stringify('this is a "test"'), }, }); // Correctly bundles with esbuild + const defineInstructions = '--define:process.env.KEY="\\"VALUE\\"" --define:process.env.BOOL="true" --define:process.env.NUMBER="7777" --define:process.env.STRING="\\"this is a \\\\\\"test\\\\\\"\\""'; expect(Code.fromAsset).toHaveBeenCalledWith(path.dirname(depsLockFilePath), { assetHashType: AssetHashType.OUTPUT, bundling: expect.objectContaining({ @@ -184,13 +187,17 @@ test('esbuild bundling with esbuild options', () => { 'npx esbuild --bundle "/asset-input/lib/handler.ts"', '--target=es2020 --platform=node --outfile="/asset-output/index.js"', '--minify --sourcemap --external:aws-sdk --loader:.png=dataurl', - '--define:DEBUG=true --define:process.env.KEY="VALUE"', + defineInstructions, '--log-level=silent --keep-names --tsconfig=/asset-input/lib/custom-tsconfig.ts', '--metafile=/asset-output/index.meta.json --banner=\'/* comments */\' --footer=\'/* comments */\'', ].join(' '), ], }), }); + + // Make sure that the define instructions are working as expected with the esbuild CLI + const bundleProcess = util.exec('bash', ['-c', `npx esbuild --bundle ${`${__dirname}/integ-handlers/define.ts`} ${defineInstructions}`]); + expect(bundleProcess.stdout.toString()).toMatchSnapshot(); }); test('Detects yarn.lock', () => { @@ -290,7 +297,7 @@ test('Custom bundling docker image', () => { entry, depsLockFilePath, runtime: Runtime.NODEJS_12_X, - dockerImage: BundlingDockerImage.fromRegistry('my-custom-image'), + dockerImage: DockerImage.fromRegistry('my-custom-image'), forceDockerBundling: true, }); diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/function.test.ts b/packages/@aws-cdk/aws-lambda-nodejs/test/function.test.ts index ce47a718b9e35..cc4544ec6e732 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/function.test.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/function.test.ts @@ -1,20 +1,24 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as fs from 'fs'; import * as path from 'path'; -import { ABSENT } from '@aws-cdk/assert'; +import { ABSENT } from '@aws-cdk/assert-internal'; import { Vpc } from '@aws-cdk/aws-ec2'; -import { Runtime } from '@aws-cdk/aws-lambda'; +import { CodeConfig, Runtime } from '@aws-cdk/aws-lambda'; import { Stack } from '@aws-cdk/core'; import { NodejsFunction } from '../lib'; import { Bundling } from '../lib/bundling'; -import { nodeMajorVersion } from '../lib/util'; jest.mock('../lib/bundling', () => { return { Bundling: { bundle: jest.fn().mockReturnValue({ - bind: () => { - return { inlineCode: 'code' }; + bind: (): CodeConfig => { + return { + s3Location: { + bucketName: 'my-bucket', + objectKey: 'my-key', + }, + }; }, bindToResource: () => { return; }, }), @@ -36,13 +40,9 @@ test('NodejsFunction with .ts handler', () => { entry: expect.stringContaining('function.test.handler1.ts'), // Automatically finds .ts handler file })); - const runtime = nodeMajorVersion() >= 14 - ? Runtime.NODEJS_14_X - : Runtime.NODEJS_12_X; - expect(stack).toHaveResource('AWS::Lambda::Function', { Handler: 'index.handler', - Runtime: runtime.name, + Runtime: 'nodejs14.x', }); }); diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/integ-handlers/define.ts b/packages/@aws-cdk/aws-lambda-nodejs/test/integ-handlers/define.ts new file mode 100644 index 0000000000000..bd66dd3920bab --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/integ-handlers/define.ts @@ -0,0 +1,8 @@ +export function handler() { + return [ + process.env.KEY, + process.env.BOOL, + process.env.NUMBER, + process.env.STRING, + ]; +} diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies.expected.json b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies.expected.json index 75ecb420e7ef5..1800768023419 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies.expected.json +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies.expected.json @@ -36,7 +36,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters2ff0fab1efcce787182abdd9a3c77a111379358a40cb16d90d7eb7c71ed11835S3BucketF29906B2" + "Ref": "AssetParameters5f9b499dbba1111518df1120b55b863471ac359778441164007b5518a70b9746S3Bucket01854DA0" }, "S3Key": { "Fn::Join": [ @@ -49,7 +49,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters2ff0fab1efcce787182abdd9a3c77a111379358a40cb16d90d7eb7c71ed11835S3VersionKey320A7F12" + "Ref": "AssetParameters5f9b499dbba1111518df1120b55b863471ac359778441164007b5518a70b9746S3VersionKey1CC8C283" } ] } @@ -62,7 +62,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters2ff0fab1efcce787182abdd9a3c77a111379358a40cb16d90d7eb7c71ed11835S3VersionKey320A7F12" + "Ref": "AssetParameters5f9b499dbba1111518df1120b55b863471ac359778441164007b5518a70b9746S3VersionKey1CC8C283" } ] } @@ -72,19 +72,19 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "externalServiceRole85A00A90", "Arn" ] }, - "Runtime": "nodejs12.x", "Environment": { "Variables": { "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1" } - } + }, + "Handler": "index.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "externalServiceRole85A00A90" @@ -92,17 +92,17 @@ } }, "Parameters": { - "AssetParameters2ff0fab1efcce787182abdd9a3c77a111379358a40cb16d90d7eb7c71ed11835S3BucketF29906B2": { + "AssetParameters5f9b499dbba1111518df1120b55b863471ac359778441164007b5518a70b9746S3Bucket01854DA0": { "Type": "String", - "Description": "S3 bucket for asset \"2ff0fab1efcce787182abdd9a3c77a111379358a40cb16d90d7eb7c71ed11835\"" + "Description": "S3 bucket for asset \"5f9b499dbba1111518df1120b55b863471ac359778441164007b5518a70b9746\"" }, - "AssetParameters2ff0fab1efcce787182abdd9a3c77a111379358a40cb16d90d7eb7c71ed11835S3VersionKey320A7F12": { + "AssetParameters5f9b499dbba1111518df1120b55b863471ac359778441164007b5518a70b9746S3VersionKey1CC8C283": { "Type": "String", - "Description": "S3 key for asset version \"2ff0fab1efcce787182abdd9a3c77a111379358a40cb16d90d7eb7c71ed11835\"" + "Description": "S3 key for asset version \"5f9b499dbba1111518df1120b55b863471ac359778441164007b5518a70b9746\"" }, - "AssetParameters2ff0fab1efcce787182abdd9a3c77a111379358a40cb16d90d7eb7c71ed11835ArtifactHash9E439F77": { + "AssetParameters5f9b499dbba1111518df1120b55b863471ac359778441164007b5518a70b9746ArtifactHashAA3B8064": { "Type": "String", - "Description": "Artifact hash for asset \"2ff0fab1efcce787182abdd9a3c77a111379358a40cb16d90d7eb7c71ed11835\"" + "Description": "Artifact hash for asset \"5f9b499dbba1111518df1120b55b863471ac359778441164007b5518a70b9746\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/integ.function.expected.json b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.function.expected.json index e41f6a5cc565e..061ad0bc939a7 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/integ.function.expected.json +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.function.expected.json @@ -36,7 +36,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters1f516d02fb984ea91e74064999e8508f09dd0001d2cf198ccc376d2c0fcd14dcS3Bucket499E594B" + "Ref": "AssetParameterse693e416c0e5591cb0eaa424f7526a449f788de8aa8a89f06f27671feaba8031S3Bucket29060E55" }, "S3Key": { "Fn::Join": [ @@ -49,7 +49,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters1f516d02fb984ea91e74064999e8508f09dd0001d2cf198ccc376d2c0fcd14dcS3VersionKey0D51A516" + "Ref": "AssetParameterse693e416c0e5591cb0eaa424f7526a449f788de8aa8a89f06f27671feaba8031S3VersionKeyE68A6B82" } ] } @@ -62,7 +62,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters1f516d02fb984ea91e74064999e8508f09dd0001d2cf198ccc376d2c0fcd14dcS3VersionKey0D51A516" + "Ref": "AssetParameterse693e416c0e5591cb0eaa424f7526a449f788de8aa8a89f06f27671feaba8031S3VersionKeyE68A6B82" } ] } @@ -72,19 +72,19 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "tshandlerServiceRole8876B8E7", "Arn" ] }, - "Runtime": "nodejs12.x", "Environment": { "Variables": { "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1" } - } + }, + "Handler": "index.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "tshandlerServiceRole8876B8E7" @@ -126,7 +126,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters565126ff75ab727f0b3a67e78cf0fa9996426d1458123e8d6ee81c7ea93a6cfaS3BucketDFAA619E" + "Ref": "AssetParameters8bda5a67feb4905ef8b67b45ee665d3e466be7357e6c361ad2aa773e5867db39S3Bucket4A9B4410" }, "S3Key": { "Fn::Join": [ @@ -139,7 +139,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters565126ff75ab727f0b3a67e78cf0fa9996426d1458123e8d6ee81c7ea93a6cfaS3VersionKey2DF01059" + "Ref": "AssetParameters8bda5a67feb4905ef8b67b45ee665d3e466be7357e6c361ad2aa773e5867db39S3VersionKeyA27DDFEA" } ] } @@ -152,7 +152,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters565126ff75ab727f0b3a67e78cf0fa9996426d1458123e8d6ee81c7ea93a6cfaS3VersionKey2DF01059" + "Ref": "AssetParameters8bda5a67feb4905ef8b67b45ee665d3e466be7357e6c361ad2aa773e5867db39S3VersionKeyA27DDFEA" } ] } @@ -162,19 +162,19 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "jshandlerServiceRole781AF366", "Arn" ] }, - "Runtime": "nodejs12.x", "Environment": { "Variables": { "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1" } - } + }, + "Handler": "index.handler", + "Runtime": "nodejs12.x" }, "DependsOn": [ "jshandlerServiceRole781AF366" @@ -758,7 +758,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersb4497848198c9836bf6ea202ecdc73dd7e3bee7c77f78fff0a61d19b8161adc2S3Bucket42C3CE17" + "Ref": "AssetParameters9aa4dd3191867438d7cf78d5509ee4ffc26b9f3954f6d9a2977c478b7728736cS3BucketA6D7D091" }, "S3Key": { "Fn::Join": [ @@ -771,7 +771,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersb4497848198c9836bf6ea202ecdc73dd7e3bee7c77f78fff0a61d19b8161adc2S3VersionKey4389D827" + "Ref": "AssetParameters9aa4dd3191867438d7cf78d5509ee4ffc26b9f3954f6d9a2977c478b7728736cS3VersionKeyD716694C" } ] } @@ -784,7 +784,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersb4497848198c9836bf6ea202ecdc73dd7e3bee7c77f78fff0a61d19b8161adc2S3VersionKey4389D827" + "Ref": "AssetParameters9aa4dd3191867438d7cf78d5509ee4ffc26b9f3954f6d9a2977c478b7728736cS3VersionKeyD716694C" } ] } @@ -794,19 +794,19 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "tshandlervpcServiceRoleF6D326A3", "Arn" ] }, - "Runtime": "nodejs12.x", "Environment": { "Variables": { "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1" } }, + "Handler": "index.handler", + "Runtime": "nodejs12.x", "VpcConfig": { "SecurityGroupIds": [ { @@ -835,41 +835,41 @@ } }, "Parameters": { - "AssetParameters1f516d02fb984ea91e74064999e8508f09dd0001d2cf198ccc376d2c0fcd14dcS3Bucket499E594B": { + "AssetParameterse693e416c0e5591cb0eaa424f7526a449f788de8aa8a89f06f27671feaba8031S3Bucket29060E55": { "Type": "String", - "Description": "S3 bucket for asset \"1f516d02fb984ea91e74064999e8508f09dd0001d2cf198ccc376d2c0fcd14dc\"" + "Description": "S3 bucket for asset \"e693e416c0e5591cb0eaa424f7526a449f788de8aa8a89f06f27671feaba8031\"" }, - "AssetParameters1f516d02fb984ea91e74064999e8508f09dd0001d2cf198ccc376d2c0fcd14dcS3VersionKey0D51A516": { + "AssetParameterse693e416c0e5591cb0eaa424f7526a449f788de8aa8a89f06f27671feaba8031S3VersionKeyE68A6B82": { "Type": "String", - "Description": "S3 key for asset version \"1f516d02fb984ea91e74064999e8508f09dd0001d2cf198ccc376d2c0fcd14dc\"" + "Description": "S3 key for asset version \"e693e416c0e5591cb0eaa424f7526a449f788de8aa8a89f06f27671feaba8031\"" }, - "AssetParameters1f516d02fb984ea91e74064999e8508f09dd0001d2cf198ccc376d2c0fcd14dcArtifactHashECB545C0": { + "AssetParameterse693e416c0e5591cb0eaa424f7526a449f788de8aa8a89f06f27671feaba8031ArtifactHash0218547C": { "Type": "String", - "Description": "Artifact hash for asset \"1f516d02fb984ea91e74064999e8508f09dd0001d2cf198ccc376d2c0fcd14dc\"" + "Description": "Artifact hash for asset \"e693e416c0e5591cb0eaa424f7526a449f788de8aa8a89f06f27671feaba8031\"" }, - "AssetParameters565126ff75ab727f0b3a67e78cf0fa9996426d1458123e8d6ee81c7ea93a6cfaS3BucketDFAA619E": { + "AssetParameters8bda5a67feb4905ef8b67b45ee665d3e466be7357e6c361ad2aa773e5867db39S3Bucket4A9B4410": { "Type": "String", - "Description": "S3 bucket for asset \"565126ff75ab727f0b3a67e78cf0fa9996426d1458123e8d6ee81c7ea93a6cfa\"" + "Description": "S3 bucket for asset \"8bda5a67feb4905ef8b67b45ee665d3e466be7357e6c361ad2aa773e5867db39\"" }, - "AssetParameters565126ff75ab727f0b3a67e78cf0fa9996426d1458123e8d6ee81c7ea93a6cfaS3VersionKey2DF01059": { + "AssetParameters8bda5a67feb4905ef8b67b45ee665d3e466be7357e6c361ad2aa773e5867db39S3VersionKeyA27DDFEA": { "Type": "String", - "Description": "S3 key for asset version \"565126ff75ab727f0b3a67e78cf0fa9996426d1458123e8d6ee81c7ea93a6cfa\"" + "Description": "S3 key for asset version \"8bda5a67feb4905ef8b67b45ee665d3e466be7357e6c361ad2aa773e5867db39\"" }, - "AssetParameters565126ff75ab727f0b3a67e78cf0fa9996426d1458123e8d6ee81c7ea93a6cfaArtifactHashF74A21AB": { + "AssetParameters8bda5a67feb4905ef8b67b45ee665d3e466be7357e6c361ad2aa773e5867db39ArtifactHash13E6F6BF": { "Type": "String", - "Description": "Artifact hash for asset \"565126ff75ab727f0b3a67e78cf0fa9996426d1458123e8d6ee81c7ea93a6cfa\"" + "Description": "Artifact hash for asset \"8bda5a67feb4905ef8b67b45ee665d3e466be7357e6c361ad2aa773e5867db39\"" }, - "AssetParametersb4497848198c9836bf6ea202ecdc73dd7e3bee7c77f78fff0a61d19b8161adc2S3Bucket42C3CE17": { + "AssetParameters9aa4dd3191867438d7cf78d5509ee4ffc26b9f3954f6d9a2977c478b7728736cS3BucketA6D7D091": { "Type": "String", - "Description": "S3 bucket for asset \"b4497848198c9836bf6ea202ecdc73dd7e3bee7c77f78fff0a61d19b8161adc2\"" + "Description": "S3 bucket for asset \"9aa4dd3191867438d7cf78d5509ee4ffc26b9f3954f6d9a2977c478b7728736c\"" }, - "AssetParametersb4497848198c9836bf6ea202ecdc73dd7e3bee7c77f78fff0a61d19b8161adc2S3VersionKey4389D827": { + "AssetParameters9aa4dd3191867438d7cf78d5509ee4ffc26b9f3954f6d9a2977c478b7728736cS3VersionKeyD716694C": { "Type": "String", - "Description": "S3 key for asset version \"b4497848198c9836bf6ea202ecdc73dd7e3bee7c77f78fff0a61d19b8161adc2\"" + "Description": "S3 key for asset version \"9aa4dd3191867438d7cf78d5509ee4ffc26b9f3954f6d9a2977c478b7728736c\"" }, - "AssetParametersb4497848198c9836bf6ea202ecdc73dd7e3bee7c77f78fff0a61d19b8161adc2ArtifactHash7EA2459D": { + "AssetParameters9aa4dd3191867438d7cf78d5509ee4ffc26b9f3954f6d9a2977c478b7728736cArtifactHashF03B1BE8": { "Type": "String", - "Description": "Artifact hash for asset \"b4497848198c9836bf6ea202ecdc73dd7e3bee7c77f78fff0a61d19b8161adc2\"" + "Description": "Artifact hash for asset \"9aa4dd3191867438d7cf78d5509ee4ffc26b9f3954f6d9a2977c478b7728736c\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda-python/README.md b/packages/@aws-cdk/aws-lambda-python/README.md index 7f9afc15072b9..77c9fee5a6f7b 100644 --- a/packages/@aws-cdk/aws-lambda-python/README.md +++ b/packages/@aws-cdk/aws-lambda-python/README.md @@ -41,7 +41,7 @@ All other properties of `lambda.Function` are supported, see also the [AWS Lambd ## Module Dependencies If `requirements.txt` or `Pipfile` exists at the entry path, the construct will handle installing -all required modules in a [Lambda compatible Docker container](https://hub.docker.com/r/amazon/aws-sam-cli-build-image-python3.7) +all required modules in a [Lambda compatible Docker container](https://gallery.ecr.aws/sam/build-python3.7) according to the `runtime`. **Lambda with a requirements.txt** diff --git a/packages/@aws-cdk/aws-lambda-python/lib/Dockerfile b/packages/@aws-cdk/aws-lambda-python/lib/Dockerfile index 057512cf4a35c..ab45f0480735f 100644 --- a/packages/@aws-cdk/aws-lambda-python/lib/Dockerfile +++ b/packages/@aws-cdk/aws-lambda-python/lib/Dockerfile @@ -1,6 +1,6 @@ # The correct AWS SAM build image based on the runtime of the function will be # passed as build arg. The default allows to do `docker build .` when testing. -ARG IMAGE=amazon/aws-sam-cli-build-image-python3.7 +ARG IMAGE=public.ecr.aws/sam/build-python3.7 FROM $IMAGE # Ensure rsync is installed diff --git a/packages/@aws-cdk/aws-lambda-python/lib/Dockerfile.dependencies b/packages/@aws-cdk/aws-lambda-python/lib/Dockerfile.dependencies index 536887fd69a9a..6793987212603 100644 --- a/packages/@aws-cdk/aws-lambda-python/lib/Dockerfile.dependencies +++ b/packages/@aws-cdk/aws-lambda-python/lib/Dockerfile.dependencies @@ -1,6 +1,6 @@ # The correct AWS SAM build image based on the runtime of the function will be # passed as build arg. The default allows to do `docker build .` when testing. -ARG IMAGE=amazon/aws-sam-cli-build-image-python3.7 +ARG IMAGE=public.ecr.aws/sam/build-python3.7 FROM $IMAGE # Ensure rsync is installed diff --git a/packages/@aws-cdk/aws-lambda-python/lib/bundling.ts b/packages/@aws-cdk/aws-lambda-python/lib/bundling.ts index a4446611d9a9d..5a3228a78fef7 100644 --- a/packages/@aws-cdk/aws-lambda-python/lib/bundling.ts +++ b/packages/@aws-cdk/aws-lambda-python/lib/bundling.ts @@ -98,7 +98,7 @@ export function bundle(options: BundlingOptions): lambda.Code { // copy Dockerfile to workdir fs.copyFileSync(path.join(__dirname, dockerfile), path.join(stagedir, dockerfile)); - const image = cdk.BundlingDockerImage.fromAsset(stagedir, { + const image = cdk.DockerImage.fromBuild(stagedir, { buildArgs: { IMAGE: runtime.bundlingDockerImage.image, }, diff --git a/packages/@aws-cdk/aws-lambda-python/lib/layer.ts b/packages/@aws-cdk/aws-lambda-python/lib/layer.ts index 3299781bb413c..1a9684e224580 100644 --- a/packages/@aws-cdk/aws-lambda-python/lib/layer.ts +++ b/packages/@aws-cdk/aws-lambda-python/lib/layer.ts @@ -26,7 +26,6 @@ export interface PythonLayerVersionProps extends lambda.LayerVersionOptions { /** * A lambda layer version. * - * @experimental */ export class PythonLayerVersion extends lambda.LayerVersion { constructor(scope: Construct, id: string, props: PythonLayerVersionProps) { diff --git a/packages/@aws-cdk/aws-lambda-python/package.json b/packages/@aws-cdk/aws-lambda-python/package.json index f22b2076ee43f..e324128af4845 100644 --- a/packages/@aws-cdk/aws-lambda-python/package.json +++ b/packages/@aws-cdk/aws-lambda-python/package.json @@ -62,23 +62,24 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" @@ -91,6 +92,9 @@ "cdk-build": { "jest": true }, + "nozem": { + "ostools": ["docker"] + }, "publishConfig": { "tag": "latest" } diff --git a/packages/@aws-cdk/aws-lambda-python/test/function.test.ts b/packages/@aws-cdk/aws-lambda-python/test/function.test.ts index d1f9d64241b61..a6bc4778e14f2 100644 --- a/packages/@aws-cdk/aws-lambda-python/test/function.test.ts +++ b/packages/@aws-cdk/aws-lambda-python/test/function.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Code, Runtime } from '@aws-cdk/aws-lambda'; import { AssetHashType, AssetOptions, Stack } from '@aws-cdk/core'; import { PythonFunction } from '../lib'; diff --git a/packages/@aws-cdk/aws-lambda-python/test/integ.function.expected.json b/packages/@aws-cdk/aws-lambda-python/test/integ.function.expected.json index 45fb46b70aeb9..6ed7f497e9ee0 100644 --- a/packages/@aws-cdk/aws-lambda-python/test/integ.function.expected.json +++ b/packages/@aws-cdk/aws-lambda-python/test/integ.function.expected.json @@ -36,7 +36,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters79d8f328899b90e2c16929e9393ebf344f098abde8981abdff0168fc9b0589acS3Bucket424FEB44" + "Ref": "AssetParameters5b8ff93384af5b488025e13b274c2dd894e474a810f1a406af1aeb4edbba6a3cS3Bucket5B146B0B" }, "S3Key": { "Fn::Join": [ @@ -49,7 +49,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters79d8f328899b90e2c16929e9393ebf344f098abde8981abdff0168fc9b0589acS3VersionKeyCEB2635C" + "Ref": "AssetParameters5b8ff93384af5b488025e13b274c2dd894e474a810f1a406af1aeb4edbba6a3cS3VersionKeyC0C8A627" } ] } @@ -62,7 +62,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters79d8f328899b90e2c16929e9393ebf344f098abde8981abdff0168fc9b0589acS3VersionKeyCEB2635C" + "Ref": "AssetParameters5b8ff93384af5b488025e13b274c2dd894e474a810f1a406af1aeb4edbba6a3cS3VersionKeyC0C8A627" } ] } @@ -87,17 +87,17 @@ } }, "Parameters": { - "AssetParameters79d8f328899b90e2c16929e9393ebf344f098abde8981abdff0168fc9b0589acS3Bucket424FEB44": { + "AssetParameters5b8ff93384af5b488025e13b274c2dd894e474a810f1a406af1aeb4edbba6a3cS3Bucket5B146B0B": { "Type": "String", - "Description": "S3 bucket for asset \"79d8f328899b90e2c16929e9393ebf344f098abde8981abdff0168fc9b0589ac\"" + "Description": "S3 bucket for asset \"5b8ff93384af5b488025e13b274c2dd894e474a810f1a406af1aeb4edbba6a3c\"" }, - "AssetParameters79d8f328899b90e2c16929e9393ebf344f098abde8981abdff0168fc9b0589acS3VersionKeyCEB2635C": { + "AssetParameters5b8ff93384af5b488025e13b274c2dd894e474a810f1a406af1aeb4edbba6a3cS3VersionKeyC0C8A627": { "Type": "String", - "Description": "S3 key for asset version \"79d8f328899b90e2c16929e9393ebf344f098abde8981abdff0168fc9b0589ac\"" + "Description": "S3 key for asset version \"5b8ff93384af5b488025e13b274c2dd894e474a810f1a406af1aeb4edbba6a3c\"" }, - "AssetParameters79d8f328899b90e2c16929e9393ebf344f098abde8981abdff0168fc9b0589acArtifactHashE38133D4": { + "AssetParameters5b8ff93384af5b488025e13b274c2dd894e474a810f1a406af1aeb4edbba6a3cArtifactHashB6A7723E": { "Type": "String", - "Description": "Artifact hash for asset \"79d8f328899b90e2c16929e9393ebf344f098abde8981abdff0168fc9b0589ac\"" + "Description": "Artifact hash for asset \"5b8ff93384af5b488025e13b274c2dd894e474a810f1a406af1aeb4edbba6a3c\"" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-lambda-python/test/integ.function.pipenv.expected.json b/packages/@aws-cdk/aws-lambda-python/test/integ.function.pipenv.expected.json index aa7bc5fbbcd68..6766584717e3d 100644 --- a/packages/@aws-cdk/aws-lambda-python/test/integ.function.pipenv.expected.json +++ b/packages/@aws-cdk/aws-lambda-python/test/integ.function.pipenv.expected.json @@ -36,7 +36,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters50fe6f46cf18fb257f00fed007da5c80fbf5dee08bec37fe765c50188eecae0bS3Bucket4125B4E4" + "Ref": "AssetParameters1a697367cf267ba8a72f772b462c503dd5a6e7bcdd8cb353d89604e9d18802eeS3BucketADC4FFB3" }, "S3Key": { "Fn::Join": [ @@ -49,7 +49,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters50fe6f46cf18fb257f00fed007da5c80fbf5dee08bec37fe765c50188eecae0bS3VersionKey1CF28CF5" + "Ref": "AssetParameters1a697367cf267ba8a72f772b462c503dd5a6e7bcdd8cb353d89604e9d18802eeS3VersionKey784D7689" } ] } @@ -62,7 +62,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters50fe6f46cf18fb257f00fed007da5c80fbf5dee08bec37fe765c50188eecae0bS3VersionKey1CF28CF5" + "Ref": "AssetParameters1a697367cf267ba8a72f772b462c503dd5a6e7bcdd8cb353d89604e9d18802eeS3VersionKey784D7689" } ] } @@ -121,7 +121,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters314bcf2cee9a5b01d3be2c2815602d1d784611fac220dde672aca6cb54299076S3BucketD6F6E4F2" + "Ref": "AssetParameters8eb49c58869010ec84a5b407369006e9cb5fdf9667d8609638d6fa59265fc3ecS3Bucket5B706387" }, "S3Key": { "Fn::Join": [ @@ -134,7 +134,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters314bcf2cee9a5b01d3be2c2815602d1d784611fac220dde672aca6cb54299076S3VersionKeyE0B47D8E" + "Ref": "AssetParameters8eb49c58869010ec84a5b407369006e9cb5fdf9667d8609638d6fa59265fc3ecS3VersionKey48CF3C03" } ] } @@ -147,7 +147,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters314bcf2cee9a5b01d3be2c2815602d1d784611fac220dde672aca6cb54299076S3VersionKeyE0B47D8E" + "Ref": "AssetParameters8eb49c58869010ec84a5b407369006e9cb5fdf9667d8609638d6fa59265fc3ecS3VersionKey48CF3C03" } ] } @@ -206,7 +206,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters11846740cde0308720709e44dce627bf1ceb557ee9d0dbb556a05632da565ef2S3BucketE17A9F3E" + "Ref": "AssetParameters992750d379dbbe94426dbd352099e3344b9edcfd098a56691b53eafaeb227b10S3Bucket9E9FE80F" }, "S3Key": { "Fn::Join": [ @@ -219,7 +219,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters11846740cde0308720709e44dce627bf1ceb557ee9d0dbb556a05632da565ef2S3VersionKey0A0F7F93" + "Ref": "AssetParameters992750d379dbbe94426dbd352099e3344b9edcfd098a56691b53eafaeb227b10S3VersionKeyFFAE128A" } ] } @@ -232,7 +232,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters11846740cde0308720709e44dce627bf1ceb557ee9d0dbb556a05632da565ef2S3VersionKey0A0F7F93" + "Ref": "AssetParameters992750d379dbbe94426dbd352099e3344b9edcfd098a56691b53eafaeb227b10S3VersionKeyFFAE128A" } ] } @@ -257,41 +257,41 @@ } }, "Parameters": { - "AssetParameters50fe6f46cf18fb257f00fed007da5c80fbf5dee08bec37fe765c50188eecae0bS3Bucket4125B4E4": { + "AssetParameters1a697367cf267ba8a72f772b462c503dd5a6e7bcdd8cb353d89604e9d18802eeS3BucketADC4FFB3": { "Type": "String", - "Description": "S3 bucket for asset \"50fe6f46cf18fb257f00fed007da5c80fbf5dee08bec37fe765c50188eecae0b\"" + "Description": "S3 bucket for asset \"1a697367cf267ba8a72f772b462c503dd5a6e7bcdd8cb353d89604e9d18802ee\"" }, - "AssetParameters50fe6f46cf18fb257f00fed007da5c80fbf5dee08bec37fe765c50188eecae0bS3VersionKey1CF28CF5": { + "AssetParameters1a697367cf267ba8a72f772b462c503dd5a6e7bcdd8cb353d89604e9d18802eeS3VersionKey784D7689": { "Type": "String", - "Description": "S3 key for asset version \"50fe6f46cf18fb257f00fed007da5c80fbf5dee08bec37fe765c50188eecae0b\"" + "Description": "S3 key for asset version \"1a697367cf267ba8a72f772b462c503dd5a6e7bcdd8cb353d89604e9d18802ee\"" }, - "AssetParameters50fe6f46cf18fb257f00fed007da5c80fbf5dee08bec37fe765c50188eecae0bArtifactHashC28E4EDF": { + "AssetParameters1a697367cf267ba8a72f772b462c503dd5a6e7bcdd8cb353d89604e9d18802eeArtifactHash76BB0F66": { "Type": "String", - "Description": "Artifact hash for asset \"50fe6f46cf18fb257f00fed007da5c80fbf5dee08bec37fe765c50188eecae0b\"" + "Description": "Artifact hash for asset \"1a697367cf267ba8a72f772b462c503dd5a6e7bcdd8cb353d89604e9d18802ee\"" }, - "AssetParameters314bcf2cee9a5b01d3be2c2815602d1d784611fac220dde672aca6cb54299076S3BucketD6F6E4F2": { + "AssetParameters8eb49c58869010ec84a5b407369006e9cb5fdf9667d8609638d6fa59265fc3ecS3Bucket5B706387": { "Type": "String", - "Description": "S3 bucket for asset \"314bcf2cee9a5b01d3be2c2815602d1d784611fac220dde672aca6cb54299076\"" + "Description": "S3 bucket for asset \"8eb49c58869010ec84a5b407369006e9cb5fdf9667d8609638d6fa59265fc3ec\"" }, - "AssetParameters314bcf2cee9a5b01d3be2c2815602d1d784611fac220dde672aca6cb54299076S3VersionKeyE0B47D8E": { + "AssetParameters8eb49c58869010ec84a5b407369006e9cb5fdf9667d8609638d6fa59265fc3ecS3VersionKey48CF3C03": { "Type": "String", - "Description": "S3 key for asset version \"314bcf2cee9a5b01d3be2c2815602d1d784611fac220dde672aca6cb54299076\"" + "Description": "S3 key for asset version \"8eb49c58869010ec84a5b407369006e9cb5fdf9667d8609638d6fa59265fc3ec\"" }, - "AssetParameters314bcf2cee9a5b01d3be2c2815602d1d784611fac220dde672aca6cb54299076ArtifactHash45C2DF56": { + "AssetParameters8eb49c58869010ec84a5b407369006e9cb5fdf9667d8609638d6fa59265fc3ecArtifactHashD17A32B8": { "Type": "String", - "Description": "Artifact hash for asset \"314bcf2cee9a5b01d3be2c2815602d1d784611fac220dde672aca6cb54299076\"" + "Description": "Artifact hash for asset \"8eb49c58869010ec84a5b407369006e9cb5fdf9667d8609638d6fa59265fc3ec\"" }, - "AssetParameters11846740cde0308720709e44dce627bf1ceb557ee9d0dbb556a05632da565ef2S3BucketE17A9F3E": { + "AssetParameters992750d379dbbe94426dbd352099e3344b9edcfd098a56691b53eafaeb227b10S3Bucket9E9FE80F": { "Type": "String", - "Description": "S3 bucket for asset \"11846740cde0308720709e44dce627bf1ceb557ee9d0dbb556a05632da565ef2\"" + "Description": "S3 bucket for asset \"992750d379dbbe94426dbd352099e3344b9edcfd098a56691b53eafaeb227b10\"" }, - "AssetParameters11846740cde0308720709e44dce627bf1ceb557ee9d0dbb556a05632da565ef2S3VersionKey0A0F7F93": { + "AssetParameters992750d379dbbe94426dbd352099e3344b9edcfd098a56691b53eafaeb227b10S3VersionKeyFFAE128A": { "Type": "String", - "Description": "S3 key for asset version \"11846740cde0308720709e44dce627bf1ceb557ee9d0dbb556a05632da565ef2\"" + "Description": "S3 key for asset version \"992750d379dbbe94426dbd352099e3344b9edcfd098a56691b53eafaeb227b10\"" }, - "AssetParameters11846740cde0308720709e44dce627bf1ceb557ee9d0dbb556a05632da565ef2ArtifactHash743A82BD": { + "AssetParameters992750d379dbbe94426dbd352099e3344b9edcfd098a56691b53eafaeb227b10ArtifactHashCAE919EE": { "Type": "String", - "Description": "Artifact hash for asset \"11846740cde0308720709e44dce627bf1ceb557ee9d0dbb556a05632da565ef2\"" + "Description": "Artifact hash for asset \"992750d379dbbe94426dbd352099e3344b9edcfd098a56691b53eafaeb227b10\"" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-lambda-python/test/integ.function.poetry.expected.json b/packages/@aws-cdk/aws-lambda-python/test/integ.function.poetry.expected.json index c2ad372f25649..9b5e2aba2f075 100644 --- a/packages/@aws-cdk/aws-lambda-python/test/integ.function.poetry.expected.json +++ b/packages/@aws-cdk/aws-lambda-python/test/integ.function.poetry.expected.json @@ -36,7 +36,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters3bc4d0e28b60c2b2468004185dabbe33a91c04563872cafb35b5b71e8a8f33d4S3Bucket68AF28A9" + "Ref": "AssetParameters75ddddb47479a218a15821c4afd818c51d26c8340cbbe49f6eca0b7b802e3923S3Bucket1A5FBFC5" }, "S3Key": { "Fn::Join": [ @@ -49,7 +49,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters3bc4d0e28b60c2b2468004185dabbe33a91c04563872cafb35b5b71e8a8f33d4S3VersionKeyACC0084B" + "Ref": "AssetParameters75ddddb47479a218a15821c4afd818c51d26c8340cbbe49f6eca0b7b802e3923S3VersionKey67EF2E81" } ] } @@ -62,7 +62,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters3bc4d0e28b60c2b2468004185dabbe33a91c04563872cafb35b5b71e8a8f33d4S3VersionKeyACC0084B" + "Ref": "AssetParameters75ddddb47479a218a15821c4afd818c51d26c8340cbbe49f6eca0b7b802e3923S3VersionKey67EF2E81" } ] } @@ -121,7 +121,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersc1614067648b8b7e151e321ce82879d259a2b8f2bd10dddd61f0f2ce26287c17S3Bucket980A99E7" + "Ref": "AssetParameters929810b8fc5030a232173abd44cd2d54f4735eece74ac8cf1c34e7b9dd9161a3S3Bucket0ECFE319" }, "S3Key": { "Fn::Join": [ @@ -134,7 +134,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersc1614067648b8b7e151e321ce82879d259a2b8f2bd10dddd61f0f2ce26287c17S3VersionKeyC4E1E9B5" + "Ref": "AssetParameters929810b8fc5030a232173abd44cd2d54f4735eece74ac8cf1c34e7b9dd9161a3S3VersionKeyA373952D" } ] } @@ -147,7 +147,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersc1614067648b8b7e151e321ce82879d259a2b8f2bd10dddd61f0f2ce26287c17S3VersionKeyC4E1E9B5" + "Ref": "AssetParameters929810b8fc5030a232173abd44cd2d54f4735eece74ac8cf1c34e7b9dd9161a3S3VersionKeyA373952D" } ] } @@ -206,7 +206,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters3610bde00ecd0013f7806e2ab0e80d7ac26232cd3ffc2934b5ca28fef120bdf6S3Bucket91AABE39" + "Ref": "AssetParameters5a08158e59eb223498febeed20bc4005c3e81534f6c47bd7d8a2079f256f25d0S3BucketDB10730C" }, "S3Key": { "Fn::Join": [ @@ -219,7 +219,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters3610bde00ecd0013f7806e2ab0e80d7ac26232cd3ffc2934b5ca28fef120bdf6S3VersionKeyEE0FAD90" + "Ref": "AssetParameters5a08158e59eb223498febeed20bc4005c3e81534f6c47bd7d8a2079f256f25d0S3VersionKeyE7AE1114" } ] } @@ -232,7 +232,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters3610bde00ecd0013f7806e2ab0e80d7ac26232cd3ffc2934b5ca28fef120bdf6S3VersionKeyEE0FAD90" + "Ref": "AssetParameters5a08158e59eb223498febeed20bc4005c3e81534f6c47bd7d8a2079f256f25d0S3VersionKeyE7AE1114" } ] } @@ -257,41 +257,41 @@ } }, "Parameters": { - "AssetParameters3bc4d0e28b60c2b2468004185dabbe33a91c04563872cafb35b5b71e8a8f33d4S3Bucket68AF28A9": { + "AssetParameters75ddddb47479a218a15821c4afd818c51d26c8340cbbe49f6eca0b7b802e3923S3Bucket1A5FBFC5": { "Type": "String", - "Description": "S3 bucket for asset \"3bc4d0e28b60c2b2468004185dabbe33a91c04563872cafb35b5b71e8a8f33d4\"" + "Description": "S3 bucket for asset \"75ddddb47479a218a15821c4afd818c51d26c8340cbbe49f6eca0b7b802e3923\"" }, - "AssetParameters3bc4d0e28b60c2b2468004185dabbe33a91c04563872cafb35b5b71e8a8f33d4S3VersionKeyACC0084B": { + "AssetParameters75ddddb47479a218a15821c4afd818c51d26c8340cbbe49f6eca0b7b802e3923S3VersionKey67EF2E81": { "Type": "String", - "Description": "S3 key for asset version \"3bc4d0e28b60c2b2468004185dabbe33a91c04563872cafb35b5b71e8a8f33d4\"" + "Description": "S3 key for asset version \"75ddddb47479a218a15821c4afd818c51d26c8340cbbe49f6eca0b7b802e3923\"" }, - "AssetParameters3bc4d0e28b60c2b2468004185dabbe33a91c04563872cafb35b5b71e8a8f33d4ArtifactHashC2D4B1C3": { + "AssetParameters75ddddb47479a218a15821c4afd818c51d26c8340cbbe49f6eca0b7b802e3923ArtifactHash122807F1": { "Type": "String", - "Description": "Artifact hash for asset \"3bc4d0e28b60c2b2468004185dabbe33a91c04563872cafb35b5b71e8a8f33d4\"" + "Description": "Artifact hash for asset \"75ddddb47479a218a15821c4afd818c51d26c8340cbbe49f6eca0b7b802e3923\"" }, - "AssetParametersc1614067648b8b7e151e321ce82879d259a2b8f2bd10dddd61f0f2ce26287c17S3Bucket980A99E7": { + "AssetParameters929810b8fc5030a232173abd44cd2d54f4735eece74ac8cf1c34e7b9dd9161a3S3Bucket0ECFE319": { "Type": "String", - "Description": "S3 bucket for asset \"c1614067648b8b7e151e321ce82879d259a2b8f2bd10dddd61f0f2ce26287c17\"" + "Description": "S3 bucket for asset \"929810b8fc5030a232173abd44cd2d54f4735eece74ac8cf1c34e7b9dd9161a3\"" }, - "AssetParametersc1614067648b8b7e151e321ce82879d259a2b8f2bd10dddd61f0f2ce26287c17S3VersionKeyC4E1E9B5": { + "AssetParameters929810b8fc5030a232173abd44cd2d54f4735eece74ac8cf1c34e7b9dd9161a3S3VersionKeyA373952D": { "Type": "String", - "Description": "S3 key for asset version \"c1614067648b8b7e151e321ce82879d259a2b8f2bd10dddd61f0f2ce26287c17\"" + "Description": "S3 key for asset version \"929810b8fc5030a232173abd44cd2d54f4735eece74ac8cf1c34e7b9dd9161a3\"" }, - "AssetParametersc1614067648b8b7e151e321ce82879d259a2b8f2bd10dddd61f0f2ce26287c17ArtifactHash5B02FA4D": { + "AssetParameters929810b8fc5030a232173abd44cd2d54f4735eece74ac8cf1c34e7b9dd9161a3ArtifactHash196D379D": { "Type": "String", - "Description": "Artifact hash for asset \"c1614067648b8b7e151e321ce82879d259a2b8f2bd10dddd61f0f2ce26287c17\"" + "Description": "Artifact hash for asset \"929810b8fc5030a232173abd44cd2d54f4735eece74ac8cf1c34e7b9dd9161a3\"" }, - "AssetParameters3610bde00ecd0013f7806e2ab0e80d7ac26232cd3ffc2934b5ca28fef120bdf6S3Bucket91AABE39": { + "AssetParameters5a08158e59eb223498febeed20bc4005c3e81534f6c47bd7d8a2079f256f25d0S3BucketDB10730C": { "Type": "String", - "Description": "S3 bucket for asset \"3610bde00ecd0013f7806e2ab0e80d7ac26232cd3ffc2934b5ca28fef120bdf6\"" + "Description": "S3 bucket for asset \"5a08158e59eb223498febeed20bc4005c3e81534f6c47bd7d8a2079f256f25d0\"" }, - "AssetParameters3610bde00ecd0013f7806e2ab0e80d7ac26232cd3ffc2934b5ca28fef120bdf6S3VersionKeyEE0FAD90": { + "AssetParameters5a08158e59eb223498febeed20bc4005c3e81534f6c47bd7d8a2079f256f25d0S3VersionKeyE7AE1114": { "Type": "String", - "Description": "S3 key for asset version \"3610bde00ecd0013f7806e2ab0e80d7ac26232cd3ffc2934b5ca28fef120bdf6\"" + "Description": "S3 key for asset version \"5a08158e59eb223498febeed20bc4005c3e81534f6c47bd7d8a2079f256f25d0\"" }, - "AssetParameters3610bde00ecd0013f7806e2ab0e80d7ac26232cd3ffc2934b5ca28fef120bdf6ArtifactHash09CEB444": { + "AssetParameters5a08158e59eb223498febeed20bc4005c3e81534f6c47bd7d8a2079f256f25d0ArtifactHashF5CC0D13": { "Type": "String", - "Description": "Artifact hash for asset \"3610bde00ecd0013f7806e2ab0e80d7ac26232cd3ffc2934b5ca28fef120bdf6\"" + "Description": "Artifact hash for asset \"5a08158e59eb223498febeed20bc4005c3e81534f6c47bd7d8a2079f256f25d0\"" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-lambda-python/test/integ.function.project.expected.json b/packages/@aws-cdk/aws-lambda-python/test/integ.function.project.expected.json index aa13e73295e64..68838ca5bb2f0 100644 --- a/packages/@aws-cdk/aws-lambda-python/test/integ.function.project.expected.json +++ b/packages/@aws-cdk/aws-lambda-python/test/integ.function.project.expected.json @@ -5,7 +5,7 @@ "Properties": { "Content": { "S3Bucket": { - "Ref": "AssetParameterse174a6a88cb48eb510c29b2bf0203c181cfa059320745e6ae6429e522b36c66eS3Bucket7A00FCB4" + "Ref": "AssetParameters66cf329731482a1903f36e710c64efa07dd7fc320739e9a1c0d915fe3cfa3aa0S3BucketF123FCA1" }, "S3Key": { "Fn::Join": [ @@ -18,7 +18,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameterse174a6a88cb48eb510c29b2bf0203c181cfa059320745e6ae6429e522b36c66eS3VersionKey8BF2F9D6" + "Ref": "AssetParameters66cf329731482a1903f36e710c64efa07dd7fc320739e9a1c0d915fe3cfa3aa0S3VersionKey6FABFCA9" } ] } @@ -31,7 +31,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameterse174a6a88cb48eb510c29b2bf0203c181cfa059320745e6ae6429e522b36c66eS3VersionKey8BF2F9D6" + "Ref": "AssetParameters66cf329731482a1903f36e710c64efa07dd7fc320739e9a1c0d915fe3cfa3aa0S3VersionKey6FABFCA9" } ] } @@ -82,7 +82,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters907ec4b12820d4b2dc64e7f0f1f1f6267c1db622bc42aa57f5361efa12b1aafbS3Bucket16F02289" + "Ref": "AssetParameters2355f1daf8ff0670c3287d5f2b9bf5061dce576b20f03dddb2f016ba7a203c86S3Bucket03A296A2" }, "S3Key": { "Fn::Join": [ @@ -95,7 +95,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters907ec4b12820d4b2dc64e7f0f1f1f6267c1db622bc42aa57f5361efa12b1aafbS3VersionKeyDAF0A5BD" + "Ref": "AssetParameters2355f1daf8ff0670c3287d5f2b9bf5061dce576b20f03dddb2f016ba7a203c86S3VersionKey90B885D0" } ] } @@ -108,7 +108,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters907ec4b12820d4b2dc64e7f0f1f1f6267c1db622bc42aa57f5361efa12b1aafbS3VersionKeyDAF0A5BD" + "Ref": "AssetParameters2355f1daf8ff0670c3287d5f2b9bf5061dce576b20f03dddb2f016ba7a203c86S3VersionKey90B885D0" } ] } @@ -138,29 +138,29 @@ } }, "Parameters": { - "AssetParameterse174a6a88cb48eb510c29b2bf0203c181cfa059320745e6ae6429e522b36c66eS3Bucket7A00FCB4": { + "AssetParameters66cf329731482a1903f36e710c64efa07dd7fc320739e9a1c0d915fe3cfa3aa0S3BucketF123FCA1": { "Type": "String", - "Description": "S3 bucket for asset \"e174a6a88cb48eb510c29b2bf0203c181cfa059320745e6ae6429e522b36c66e\"" + "Description": "S3 bucket for asset \"66cf329731482a1903f36e710c64efa07dd7fc320739e9a1c0d915fe3cfa3aa0\"" }, - "AssetParameterse174a6a88cb48eb510c29b2bf0203c181cfa059320745e6ae6429e522b36c66eS3VersionKey8BF2F9D6": { + "AssetParameters66cf329731482a1903f36e710c64efa07dd7fc320739e9a1c0d915fe3cfa3aa0S3VersionKey6FABFCA9": { "Type": "String", - "Description": "S3 key for asset version \"e174a6a88cb48eb510c29b2bf0203c181cfa059320745e6ae6429e522b36c66e\"" + "Description": "S3 key for asset version \"66cf329731482a1903f36e710c64efa07dd7fc320739e9a1c0d915fe3cfa3aa0\"" }, - "AssetParameterse174a6a88cb48eb510c29b2bf0203c181cfa059320745e6ae6429e522b36c66eArtifactHash2DECF34E": { + "AssetParameters66cf329731482a1903f36e710c64efa07dd7fc320739e9a1c0d915fe3cfa3aa0ArtifactHash0384F1C8": { "Type": "String", - "Description": "Artifact hash for asset \"e174a6a88cb48eb510c29b2bf0203c181cfa059320745e6ae6429e522b36c66e\"" + "Description": "Artifact hash for asset \"66cf329731482a1903f36e710c64efa07dd7fc320739e9a1c0d915fe3cfa3aa0\"" }, - "AssetParameters907ec4b12820d4b2dc64e7f0f1f1f6267c1db622bc42aa57f5361efa12b1aafbS3Bucket16F02289": { + "AssetParameters2355f1daf8ff0670c3287d5f2b9bf5061dce576b20f03dddb2f016ba7a203c86S3Bucket03A296A2": { "Type": "String", - "Description": "S3 bucket for asset \"907ec4b12820d4b2dc64e7f0f1f1f6267c1db622bc42aa57f5361efa12b1aafb\"" + "Description": "S3 bucket for asset \"2355f1daf8ff0670c3287d5f2b9bf5061dce576b20f03dddb2f016ba7a203c86\"" }, - "AssetParameters907ec4b12820d4b2dc64e7f0f1f1f6267c1db622bc42aa57f5361efa12b1aafbS3VersionKeyDAF0A5BD": { + "AssetParameters2355f1daf8ff0670c3287d5f2b9bf5061dce576b20f03dddb2f016ba7a203c86S3VersionKey90B885D0": { "Type": "String", - "Description": "S3 key for asset version \"907ec4b12820d4b2dc64e7f0f1f1f6267c1db622bc42aa57f5361efa12b1aafb\"" + "Description": "S3 key for asset version \"2355f1daf8ff0670c3287d5f2b9bf5061dce576b20f03dddb2f016ba7a203c86\"" }, - "AssetParameters907ec4b12820d4b2dc64e7f0f1f1f6267c1db622bc42aa57f5361efa12b1aafbArtifactHashD7592B0F": { + "AssetParameters2355f1daf8ff0670c3287d5f2b9bf5061dce576b20f03dddb2f016ba7a203c86ArtifactHash937218E0": { "Type": "String", - "Description": "Artifact hash for asset \"907ec4b12820d4b2dc64e7f0f1f1f6267c1db622bc42aa57f5361efa12b1aafb\"" + "Description": "Artifact hash for asset \"2355f1daf8ff0670c3287d5f2b9bf5061dce576b20f03dddb2f016ba7a203c86\"" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-lambda-python/test/integ.function.py38.expected.json b/packages/@aws-cdk/aws-lambda-python/test/integ.function.py38.expected.json index c49f5e312d873..df601bc92acd9 100644 --- a/packages/@aws-cdk/aws-lambda-python/test/integ.function.py38.expected.json +++ b/packages/@aws-cdk/aws-lambda-python/test/integ.function.py38.expected.json @@ -36,7 +36,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters6cc4994756d4085a860e734568c92826773e52c22c58894ce368b1e698da413dS3Bucket74CBB570" + "Ref": "AssetParameters29cd01a5fe529da311cdec40c163fb1c04b1b3dc8caadff0ea696fb6e63610feS3Bucket38F00249" }, "S3Key": { "Fn::Join": [ @@ -49,7 +49,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6cc4994756d4085a860e734568c92826773e52c22c58894ce368b1e698da413dS3VersionKey3CBAF21A" + "Ref": "AssetParameters29cd01a5fe529da311cdec40c163fb1c04b1b3dc8caadff0ea696fb6e63610feS3VersionKey60957E7E" } ] } @@ -62,7 +62,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6cc4994756d4085a860e734568c92826773e52c22c58894ce368b1e698da413dS3VersionKey3CBAF21A" + "Ref": "AssetParameters29cd01a5fe529da311cdec40c163fb1c04b1b3dc8caadff0ea696fb6e63610feS3VersionKey60957E7E" } ] } @@ -87,17 +87,17 @@ } }, "Parameters": { - "AssetParameters6cc4994756d4085a860e734568c92826773e52c22c58894ce368b1e698da413dS3Bucket74CBB570": { + "AssetParameters29cd01a5fe529da311cdec40c163fb1c04b1b3dc8caadff0ea696fb6e63610feS3Bucket38F00249": { "Type": "String", - "Description": "S3 bucket for asset \"6cc4994756d4085a860e734568c92826773e52c22c58894ce368b1e698da413d\"" + "Description": "S3 bucket for asset \"29cd01a5fe529da311cdec40c163fb1c04b1b3dc8caadff0ea696fb6e63610fe\"" }, - "AssetParameters6cc4994756d4085a860e734568c92826773e52c22c58894ce368b1e698da413dS3VersionKey3CBAF21A": { + "AssetParameters29cd01a5fe529da311cdec40c163fb1c04b1b3dc8caadff0ea696fb6e63610feS3VersionKey60957E7E": { "Type": "String", - "Description": "S3 key for asset version \"6cc4994756d4085a860e734568c92826773e52c22c58894ce368b1e698da413d\"" + "Description": "S3 key for asset version \"29cd01a5fe529da311cdec40c163fb1c04b1b3dc8caadff0ea696fb6e63610fe\"" }, - "AssetParameters6cc4994756d4085a860e734568c92826773e52c22c58894ce368b1e698da413dArtifactHash750F3AF8": { + "AssetParameters29cd01a5fe529da311cdec40c163fb1c04b1b3dc8caadff0ea696fb6e63610feArtifactHash29C18922": { "Type": "String", - "Description": "Artifact hash for asset \"6cc4994756d4085a860e734568c92826773e52c22c58894ce368b1e698da413d\"" + "Description": "Artifact hash for asset \"29cd01a5fe529da311cdec40c163fb1c04b1b3dc8caadff0ea696fb6e63610fe\"" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-lambda-python/test/integ.function.requirements.removed.expected.json b/packages/@aws-cdk/aws-lambda-python/test/integ.function.requirements.removed.expected.json index c70f4a0ca8933..131ca14b5e5c9 100644 --- a/packages/@aws-cdk/aws-lambda-python/test/integ.function.requirements.removed.expected.json +++ b/packages/@aws-cdk/aws-lambda-python/test/integ.function.requirements.removed.expected.json @@ -36,7 +36,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters6fa8e0c54d06a6402126a86fab5da1fa1397bcce628a0fb56f8356a2edf6280dS3Bucket2F189DB9" + "Ref": "AssetParameterse6fadc5eeabdb3ea6ecd571e8ec74e7943cd34cd4ec9d46d0506a200e6163a93S3BucketBA49B914" }, "S3Key": { "Fn::Join": [ @@ -49,7 +49,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6fa8e0c54d06a6402126a86fab5da1fa1397bcce628a0fb56f8356a2edf6280dS3VersionKeyDF03C812" + "Ref": "AssetParameterse6fadc5eeabdb3ea6ecd571e8ec74e7943cd34cd4ec9d46d0506a200e6163a93S3VersionKey74688352" } ] } @@ -62,7 +62,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6fa8e0c54d06a6402126a86fab5da1fa1397bcce628a0fb56f8356a2edf6280dS3VersionKeyDF03C812" + "Ref": "AssetParameterse6fadc5eeabdb3ea6ecd571e8ec74e7943cd34cd4ec9d46d0506a200e6163a93S3VersionKey74688352" } ] } @@ -87,17 +87,17 @@ } }, "Parameters": { - "AssetParameters6fa8e0c54d06a6402126a86fab5da1fa1397bcce628a0fb56f8356a2edf6280dS3Bucket2F189DB9": { + "AssetParameterse6fadc5eeabdb3ea6ecd571e8ec74e7943cd34cd4ec9d46d0506a200e6163a93S3BucketBA49B914": { "Type": "String", - "Description": "S3 bucket for asset \"6fa8e0c54d06a6402126a86fab5da1fa1397bcce628a0fb56f8356a2edf6280d\"" + "Description": "S3 bucket for asset \"e6fadc5eeabdb3ea6ecd571e8ec74e7943cd34cd4ec9d46d0506a200e6163a93\"" }, - "AssetParameters6fa8e0c54d06a6402126a86fab5da1fa1397bcce628a0fb56f8356a2edf6280dS3VersionKeyDF03C812": { + "AssetParameterse6fadc5eeabdb3ea6ecd571e8ec74e7943cd34cd4ec9d46d0506a200e6163a93S3VersionKey74688352": { "Type": "String", - "Description": "S3 key for asset version \"6fa8e0c54d06a6402126a86fab5da1fa1397bcce628a0fb56f8356a2edf6280d\"" + "Description": "S3 key for asset version \"e6fadc5eeabdb3ea6ecd571e8ec74e7943cd34cd4ec9d46d0506a200e6163a93\"" }, - "AssetParameters6fa8e0c54d06a6402126a86fab5da1fa1397bcce628a0fb56f8356a2edf6280dArtifactHash1F692755": { + "AssetParameterse6fadc5eeabdb3ea6ecd571e8ec74e7943cd34cd4ec9d46d0506a200e6163a93ArtifactHash6870D06D": { "Type": "String", - "Description": "Artifact hash for asset \"6fa8e0c54d06a6402126a86fab5da1fa1397bcce628a0fb56f8356a2edf6280d\"" + "Description": "Artifact hash for asset \"e6fadc5eeabdb3ea6ecd571e8ec74e7943cd34cd4ec9d46d0506a200e6163a93\"" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-lambda-python/test/integ.function.vpc.expected.json b/packages/@aws-cdk/aws-lambda-python/test/integ.function.vpc.expected.json index 6787327a15e40..1efa22d57d44f 100644 --- a/packages/@aws-cdk/aws-lambda-python/test/integ.function.vpc.expected.json +++ b/packages/@aws-cdk/aws-lambda-python/test/integ.function.vpc.expected.json @@ -296,7 +296,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters83be407310ab5911f40fa4934091a233f92ce3be1d81c48846f30fa0a9330530S3Bucket82392CBF" + "Ref": "AssetParameters5b8ff93384af5b488025e13b274c2dd894e474a810f1a406af1aeb4edbba6a3cS3Bucket5B146B0B" }, "S3Key": { "Fn::Join": [ @@ -309,7 +309,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters83be407310ab5911f40fa4934091a233f92ce3be1d81c48846f30fa0a9330530S3VersionKey292822E7" + "Ref": "AssetParameters5b8ff93384af5b488025e13b274c2dd894e474a810f1a406af1aeb4edbba6a3cS3VersionKeyC0C8A627" } ] } @@ -322,7 +322,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters83be407310ab5911f40fa4934091a233f92ce3be1d81c48846f30fa0a9330530S3VersionKey292822E7" + "Ref": "AssetParameters5b8ff93384af5b488025e13b274c2dd894e474a810f1a406af1aeb4edbba6a3cS3VersionKeyC0C8A627" } ] } @@ -368,17 +368,17 @@ } }, "Parameters": { - "AssetParameters83be407310ab5911f40fa4934091a233f92ce3be1d81c48846f30fa0a9330530S3Bucket82392CBF": { + "AssetParameters5b8ff93384af5b488025e13b274c2dd894e474a810f1a406af1aeb4edbba6a3cS3Bucket5B146B0B": { "Type": "String", - "Description": "S3 bucket for asset \"83be407310ab5911f40fa4934091a233f92ce3be1d81c48846f30fa0a9330530\"" + "Description": "S3 bucket for asset \"5b8ff93384af5b488025e13b274c2dd894e474a810f1a406af1aeb4edbba6a3c\"" }, - "AssetParameters83be407310ab5911f40fa4934091a233f92ce3be1d81c48846f30fa0a9330530S3VersionKey292822E7": { + "AssetParameters5b8ff93384af5b488025e13b274c2dd894e474a810f1a406af1aeb4edbba6a3cS3VersionKeyC0C8A627": { "Type": "String", - "Description": "S3 key for asset version \"83be407310ab5911f40fa4934091a233f92ce3be1d81c48846f30fa0a9330530\"" + "Description": "S3 key for asset version \"5b8ff93384af5b488025e13b274c2dd894e474a810f1a406af1aeb4edbba6a3c\"" }, - "AssetParameters83be407310ab5911f40fa4934091a233f92ce3be1d81c48846f30fa0a9330530ArtifactHash8818CE02": { + "AssetParameters5b8ff93384af5b488025e13b274c2dd894e474a810f1a406af1aeb4edbba6a3cArtifactHashB6A7723E": { "Type": "String", - "Description": "Artifact hash for asset \"83be407310ab5911f40fa4934091a233f92ce3be1d81c48846f30fa0a9330530\"" + "Description": "Artifact hash for asset \"5b8ff93384af5b488025e13b274c2dd894e474a810f1a406af1aeb4edbba6a3c\"" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-lambda-python/test/layer.test.ts b/packages/@aws-cdk/aws-lambda-python/test/layer.test.ts index 255adb0dae646..ff828301ee7f3 100644 --- a/packages/@aws-cdk/aws-lambda-python/test/layer.test.ts +++ b/packages/@aws-cdk/aws-lambda-python/test/layer.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as path from 'path'; import { Runtime } from '@aws-cdk/aws-lambda'; import { Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-lambda/README.md b/packages/@aws-cdk/aws-lambda/README.md index ae21d6ea9216e..ca67608a5e19f 100644 --- a/packages/@aws-cdk/aws-lambda/README.md +++ b/packages/@aws-cdk/aws-lambda/README.md @@ -451,19 +451,19 @@ Example with Python: new lambda.Function(this, 'Function', { code: lambda.Code.fromAsset(path.join(__dirname, 'my-python-handler'), { bundling: { - image: lambda.Runtime.PYTHON_3_6.bundlingDockerImage, + image: lambda.Runtime.PYTHON_3_8.bundlingImage, command: [ 'bash', '-c', 'pip install -r requirements.txt -t /asset-output && cp -au . /asset-output' ], }, }), - runtime: lambda.Runtime.PYTHON_3_6, + runtime: lambda.Runtime.PYTHON_3_8, handler: 'index.handler', }); ``` -Runtimes expose a `bundlingDockerImage` property that points to the [AWS SAM](https://github.com/awslabs/aws-sam-cli) build image. +Runtimes expose a `bundlingImage` property that points to the [AWS SAM](https://github.com/awslabs/aws-sam-cli) build image. Use `cdk.DockerImage.fromRegistry(image)` to use an existing image or `cdk.DockerImage.fromBuild(path)` to build a specific image: 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 239bf58671b7e..924868449a973 100644 --- a/packages/@aws-cdk/aws-lambda/lib/event-source-mapping.ts +++ b/packages/@aws-cdk/aws-lambda/lib/event-source-mapping.ts @@ -168,6 +168,17 @@ export interface EventSourceMappingOptions { */ readonly kafkaTopic?: string; + /** + * The size of the tumbling windows to group records sent to DynamoDB or Kinesis + * + * @see https://docs.aws.amazon.com/lambda/latest/dg/with-ddb.html#services-ddb-windows + * + * Valid Range: 0 - 15 minutes + * + * @default - None + */ + readonly tumblingWindow?: cdk.Duration; + /** * A list of host and port pairs that are the addresses of the Kafka brokers in a self managed "bootstrap" Kafka cluster * that a Kafka client connects to initially to bootstrap itself. @@ -269,6 +280,10 @@ export class EventSourceMapping extends cdk.Resource implements IEventSourceMapp } }); + if (props.tumblingWindow && !cdk.Token.isUnresolved(props.tumblingWindow) && props.tumblingWindow.toSeconds() > 900) { + throw new Error(`tumblingWindow cannot be over 900 seconds, got ${props.tumblingWindow.toSeconds()}`); + } + let destinationConfig; @@ -296,6 +311,7 @@ export class EventSourceMapping extends cdk.Resource implements IEventSourceMapp maximumRetryAttempts: props.retryAttempts, parallelizationFactor: props.parallelizationFactor, topics: props.kafkaTopic !== undefined ? [props.kafkaTopic] : undefined, + tumblingWindowInSeconds: props.tumblingWindow?.toSeconds(), sourceAccessConfigurations: props.sourceAccessConfigurations?.map((o) => {return { type: o.type.type, uri: o.uri };}), selfManagedEventSource, }); diff --git a/packages/@aws-cdk/aws-lambda/lib/filesystem.ts b/packages/@aws-cdk/aws-lambda/lib/filesystem.ts index 388db50e045ec..e27e643cbd6d7 100644 --- a/packages/@aws-cdk/aws-lambda/lib/filesystem.ts +++ b/packages/@aws-cdk/aws-lambda/lib/filesystem.ts @@ -5,7 +5,6 @@ import { IDependable, Stack } from '@aws-cdk/core'; /** * FileSystem configurations for the Lambda function - * @experimental */ export interface FileSystemConfig { /** @@ -42,7 +41,6 @@ export interface FileSystemConfig { /** * Represents the filesystem for the Lambda function - * @experimental */ export class FileSystem { /** diff --git a/packages/@aws-cdk/aws-lambda/lib/function-base.ts b/packages/@aws-cdk/aws-lambda/lib/function-base.ts index 3ea52d5c3433b..f5e7b383f8196 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function-base.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function-base.ts @@ -175,7 +175,7 @@ export interface FunctionAttributes { readonly sameEnvironment?: boolean; } -export abstract class FunctionBase extends Resource implements IFunction { +export abstract class FunctionBase extends Resource implements IFunction, ec2.IClientVpnConnectionHandler { /** * The principal this Lambda Function is running as */ diff --git a/packages/@aws-cdk/aws-lambda/lib/image-function.ts b/packages/@aws-cdk/aws-lambda/lib/image-function.ts index b53b6216894bf..a53f303c88b78 100644 --- a/packages/@aws-cdk/aws-lambda/lib/image-function.ts +++ b/packages/@aws-cdk/aws-lambda/lib/image-function.ts @@ -25,7 +25,6 @@ export abstract class DockerImageCode { * Use an existing ECR image as the Lambda code. * @param repository the ECR repository that the image is in * @param props properties to further configure the selected image - * @experimental */ public static fromEcr(repository: ecr.IRepository, props?: EcrImageCodeProps): DockerImageCode { return { @@ -39,7 +38,6 @@ export abstract class DockerImageCode { * Create an ECR image from the specified asset and bind it as the Lambda code. * @param directory the directory from which the asset must be created * @param props properties to further configure the selected image - * @experimental */ public static fromImageAsset(directory: string, props: AssetImageCodeProps = {}): DockerImageCode { return { diff --git a/packages/@aws-cdk/aws-lambda/lib/log-retention.ts b/packages/@aws-cdk/aws-lambda/lib/log-retention.ts index e499764f96e20..3fe6db5e81880 100644 --- a/packages/@aws-cdk/aws-lambda/lib/log-retention.ts +++ b/packages/@aws-cdk/aws-lambda/lib/log-retention.ts @@ -3,8 +3,6 @@ import { Construct } from 'constructs'; /** * Retry options for all AWS API calls. - * - * @deprecated use `LogRetentionRetryOptions` from '@aws-cdk/aws-logs' instead */ export interface LogRetentionRetryOptions extends logs.LogRetentionRetryOptions { } diff --git a/packages/@aws-cdk/aws-lambda/lib/runtime.ts b/packages/@aws-cdk/aws-lambda/lib/runtime.ts index 0f26813b8c4a9..e354e5862cc6e 100644 --- a/packages/@aws-cdk/aws-lambda/lib/runtime.ts +++ b/packages/@aws-cdk/aws-lambda/lib/runtime.ts @@ -1,4 +1,4 @@ -import { BundlingDockerImage } from '@aws-cdk/core'; +import { BundlingDockerImage, DockerImage } from '@aws-cdk/core'; export interface LambdaRuntimeProps { /** @@ -9,7 +9,7 @@ export interface LambdaRuntimeProps { /** * The Docker image name to be used for bundling in this runtime. - * @default - the latest docker image "amazon/aws-sam-cli-build-image-" from https://hub.docker.com/u/amazon + * @default - the latest docker image "amazon/public.ecr.aws/sam/build-" from https://gallery.ecr.aws */ readonly bundlingDockerImage?: string; @@ -209,16 +209,24 @@ export class Runtime { public readonly family?: RuntimeFamily; /** - * The bundling Docker image for this runtime. + * DEPRECATED + * @deprecated use `bundlingImage` */ public readonly bundlingDockerImage: BundlingDockerImage; - constructor(name: string, family?: RuntimeFamily, props: LambdaRuntimeProps = { }) { + /** + * The bundling Docker image for this runtime. + */ + public readonly bundlingImage: DockerImage; + + constructor(name: string, family?: RuntimeFamily, props: LambdaRuntimeProps = {}) { this.name = name; this.supportsInlineCode = !!props.supportsInlineCode; this.family = family; - const imageName = props.bundlingDockerImage ?? `amazon/aws-sam-cli-build-image-${name}`; - this.bundlingDockerImage = BundlingDockerImage.fromRegistry(imageName); + + const imageName = props.bundlingDockerImage ?? `public.ecr.aws/sam/build-${name}`; + this.bundlingDockerImage = DockerImage.fromRegistry(imageName); + this.bundlingImage = this.bundlingDockerImage; this.supportsCodeGuruProfiling = props.supportsCodeGuruProfiling ?? false; Runtime.ALL.push(this); @@ -230,7 +238,7 @@ export class Runtime { public runtimeEquals(other: Runtime): boolean { return other.name === this.name && - other.family === this.family && - other.supportsInlineCode === this.supportsInlineCode; + other.family === this.family && + other.supportsInlineCode === this.supportsInlineCode; } } diff --git a/packages/@aws-cdk/aws-lambda/package.json b/packages/@aws-cdk/aws-lambda/package.json index 6eab5cd11b870..3fdc26ada0d5e 100644 --- a/packages/@aws-cdk/aws-lambda/package.json +++ b/packages/@aws-cdk/aws-lambda/package.json @@ -75,15 +75,16 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", - "@types/aws-lambda": "^8.10.72", + "@types/jest": "^26.0.23", + "@types/aws-lambda": "^8.10.76", "@types/lodash": "^4.14.168", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "jest": "^26.6.3", "lodash": "^4.17.21", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-applicationautoscaling": "0.0.0", @@ -103,7 +104,7 @@ "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -124,7 +125,7 @@ "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" @@ -179,6 +180,9 @@ "awscdkio": { "announce": false }, + "nozem": { + "ostools": ["docker"] + }, "maturity": "stable", "publishConfig": { "tag": "latest" diff --git a/packages/@aws-cdk/aws-lambda/test/alias.test.ts b/packages/@aws-cdk/aws-lambda/test/alias.test.ts index 1f25aa1a6a823..bfe85e7acddd2 100644 --- a/packages/@aws-cdk/aws-lambda/test/alias.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/alias.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert/jest'; -import { arrayWith, objectLike } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +import { arrayWith, objectLike } from '@aws-cdk/assert-internal'; import * as appscaling from '@aws-cdk/aws-applicationautoscaling'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import { Lazy, Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-lambda/test/code-signing-config.test.ts b/packages/@aws-cdk/aws-lambda/test/code-signing-config.test.ts index 6f6c1047f5453..7b38e2cb7e178 100644 --- a/packages/@aws-cdk/aws-lambda/test/code-signing-config.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/code-signing-config.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as signer from '@aws-cdk/aws-signer'; import * as cdk from '@aws-cdk/core'; import * as lambda from '../lib'; diff --git a/packages/@aws-cdk/aws-lambda/test/code.test.ts b/packages/@aws-cdk/aws-lambda/test/code.test.ts index c976f0a1dabf2..958dfe9fc7a56 100644 --- a/packages/@aws-cdk/aws-lambda/test/code.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/code.test.ts @@ -1,6 +1,6 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as path from 'path'; -import { ABSENT, ResourcePart } from '@aws-cdk/assert'; +import { ABSENT, ResourcePart } from '@aws-cdk/assert-internal'; import * as ecr from '@aws-cdk/aws-ecr'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; diff --git a/packages/@aws-cdk/aws-lambda/test/event-source-mapping.test.ts b/packages/@aws-cdk/aws-lambda/test/event-source-mapping.test.ts index 5d833a2d865c6..bbefe9f5fce3d 100644 --- a/packages/@aws-cdk/aws-lambda/test/event-source-mapping.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/event-source-mapping.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import { Code, EventSourceMapping, Function, Runtime } from '../lib'; @@ -261,4 +261,35 @@ describe('event source mapping', () => { SelfManagedEventSource: { Endpoints: { KafkaBootstrapServers: kafkaBootstrapServers } }, }); }); -}); + + test('throws if tumblingWindow > 900 seconds', () => { + const stack = new cdk.Stack(); + const fn = new Function(stack, 'fn', { + handler: 'index.handler', + code: Code.fromInline('exports.handler = ${handler.toString()}'), + runtime: Runtime.NODEJS_10_X, + }); + + expect(() => new EventSourceMapping(stack, 'test', { + target: fn, + eventSourceArn: '', + tumblingWindow: cdk.Duration.seconds(901), + })).toThrow(/tumblingWindow cannot be over 900 seconds/); + }); + + test('accepts if tumblingWindow is a token', () => { + const stack = new cdk.Stack(); + const fn = new Function(stack, 'fn', { + handler: 'index.handler', + code: Code.fromInline('exports.handler = ${handler.toString()}'), + runtime: Runtime.NODEJS_10_X, + }); + const lazyDuration = cdk.Duration.seconds(cdk.Lazy.number({ produce: () => 60 })); + + new EventSourceMapping(stack, 'test', { + target: fn, + eventSourceArn: '', + tumblingWindow: lazyDuration, + }); + }); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda/test/function-hash.test.ts b/packages/@aws-cdk/aws-lambda/test/function-hash.test.ts index d4e9e59d93b80..97ce20f0a77b8 100644 --- a/packages/@aws-cdk/aws-lambda/test/function-hash.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/function-hash.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as path from 'path'; import { CfnOutput, Stack } from '@aws-cdk/core'; import * as lambda from '../lib'; diff --git a/packages/@aws-cdk/aws-lambda/test/function.test.ts b/packages/@aws-cdk/aws-lambda/test/function.test.ts index 50cf6b0c9b72b..e4ac71c25c8d1 100644 --- a/packages/@aws-cdk/aws-lambda/test/function.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/function.test.ts @@ -1,6 +1,6 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as path from 'path'; -import { ABSENT, ResourcePart, SynthUtils } from '@aws-cdk/assert'; +import { ABSENT, ResourcePart, SynthUtils } from '@aws-cdk/assert-internal'; import { ProfilingGroup } from '@aws-cdk/aws-codeguruprofiler'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as efs from '@aws-cdk/aws-efs'; @@ -8,8 +8,8 @@ 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 sqs from '@aws-cdk/aws-sqs'; import * as signer from '@aws-cdk/aws-signer'; +import * as sqs from '@aws-cdk/aws-sqs'; import * as cdk from '@aws-cdk/core'; import * as constructs from 'constructs'; import * as _ from 'lodash'; diff --git a/packages/@aws-cdk/aws-lambda/test/integ.bundling.expected.json b/packages/@aws-cdk/aws-lambda/test/integ.bundling.expected.json index f91b4ba673c9e..75863fbac5fab 100644 --- a/packages/@aws-cdk/aws-lambda/test/integ.bundling.expected.json +++ b/packages/@aws-cdk/aws-lambda/test/integ.bundling.expected.json @@ -36,7 +36,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersfbf992a3e922c30f9aed74db034a1ec115ec16544160e6820e5d2463bf1e29d1S3BucketF4EA3D4A" + "Ref": "AssetParameters4096fd7ad39dc95026cb4c6254d2421d276c3170018ff7abdb41197d50ebd47bS3Bucket48F36117" }, "S3Key": { "Fn::Join": [ @@ -49,7 +49,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersfbf992a3e922c30f9aed74db034a1ec115ec16544160e6820e5d2463bf1e29d1S3VersionKey50AB224E" + "Ref": "AssetParameters4096fd7ad39dc95026cb4c6254d2421d276c3170018ff7abdb41197d50ebd47bS3VersionKey5B24FA75" } ] } @@ -62,7 +62,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersfbf992a3e922c30f9aed74db034a1ec115ec16544160e6820e5d2463bf1e29d1S3VersionKey50AB224E" + "Ref": "AssetParameters4096fd7ad39dc95026cb4c6254d2421d276c3170018ff7abdb41197d50ebd47bS3VersionKey5B24FA75" } ] } @@ -72,13 +72,13 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "FunctionServiceRole675BB04A", "Arn" ] }, + "Handler": "index.handler", "Runtime": "python3.6" }, "DependsOn": [ @@ -87,17 +87,17 @@ } }, "Parameters": { - "AssetParametersfbf992a3e922c30f9aed74db034a1ec115ec16544160e6820e5d2463bf1e29d1S3BucketF4EA3D4A": { + "AssetParameters4096fd7ad39dc95026cb4c6254d2421d276c3170018ff7abdb41197d50ebd47bS3Bucket48F36117": { "Type": "String", - "Description": "S3 bucket for asset \"fbf992a3e922c30f9aed74db034a1ec115ec16544160e6820e5d2463bf1e29d1\"" + "Description": "S3 bucket for asset \"4096fd7ad39dc95026cb4c6254d2421d276c3170018ff7abdb41197d50ebd47b\"" }, - "AssetParametersfbf992a3e922c30f9aed74db034a1ec115ec16544160e6820e5d2463bf1e29d1S3VersionKey50AB224E": { + "AssetParameters4096fd7ad39dc95026cb4c6254d2421d276c3170018ff7abdb41197d50ebd47bS3VersionKey5B24FA75": { "Type": "String", - "Description": "S3 key for asset version \"fbf992a3e922c30f9aed74db034a1ec115ec16544160e6820e5d2463bf1e29d1\"" + "Description": "S3 key for asset version \"4096fd7ad39dc95026cb4c6254d2421d276c3170018ff7abdb41197d50ebd47b\"" }, - "AssetParametersfbf992a3e922c30f9aed74db034a1ec115ec16544160e6820e5d2463bf1e29d1ArtifactHashDD1BB80E": { + "AssetParameters4096fd7ad39dc95026cb4c6254d2421d276c3170018ff7abdb41197d50ebd47bArtifactHashFE4A3131": { "Type": "String", - "Description": "Artifact hash for asset \"fbf992a3e922c30f9aed74db034a1ec115ec16544160e6820e5d2463bf1e29d1\"" + "Description": "Artifact hash for asset \"4096fd7ad39dc95026cb4c6254d2421d276c3170018ff7abdb41197d50ebd47b\"" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-lambda/test/integ.bundling.ts b/packages/@aws-cdk/aws-lambda/test/integ.bundling.ts index 6dfd3be463caf..ba662242262c3 100644 --- a/packages/@aws-cdk/aws-lambda/test/integ.bundling.ts +++ b/packages/@aws-cdk/aws-lambda/test/integ.bundling.ts @@ -18,7 +18,7 @@ class TestStack extends Stack { const fn = new lambda.Function(this, 'Function', { code: lambda.Code.fromAsset(assetPath, { bundling: { - image: lambda.Runtime.PYTHON_3_6.bundlingDockerImage, + image: lambda.Runtime.PYTHON_3_6.bundlingImage, command: [ 'bash', '-c', [ 'cp -au . /asset-output', diff --git a/packages/@aws-cdk/aws-lambda/test/integ.lambda.filesystem.expected.json b/packages/@aws-cdk/aws-lambda/test/integ.lambda.filesystem.expected.json index 3d17a0e6ca6bf..6d9334ab8999f 100644 --- a/packages/@aws-cdk/aws-lambda/test/integ.lambda.filesystem.expected.json +++ b/packages/@aws-cdk/aws-lambda/test/integ.lambda.filesystem.expected.json @@ -453,6 +453,7 @@ "Efs9E8BF36B": { "Type": "AWS::EFS::FileSystem", "Properties": { + "Encrypted": true, "FileSystemTags": [ { "Key": "Name", @@ -738,17 +739,14 @@ "Code": { "ZipFile": "\nimport json\nimport os\nimport string\nimport random\nimport datetime\n\nMSG_FILE_PATH = '/mnt/msg/content'\n\ndef randomString(stringLength=10):\n letters = string.ascii_lowercase\n return ''.join(random.choice(letters) for i in range(stringLength))\n\ndef lambda_handler(event, context):\n with open(MSG_FILE_PATH, 'a') as f:\n f.write(f\"{datetime.datetime.utcnow():%Y-%m-%d-%H:%M:%S} \" + randomString(5) + ' ')\n\n file = open(MSG_FILE_PATH, \"r\")\n file_content = file.read()\n file.close()\n\n return {\n 'statusCode': 200,\n 'body': str(file_content)\n }\n" }, - "Handler": "index.lambda_handler", "Role": { "Fn::GetAtt": [ "MyLambdaServiceRole4539ECB6", "Arn" ] }, - "Runtime": "python3.7", "FileSystemConfigs": [ { - "LocalMountPath": "/mnt/msg", "Arn": { "Fn::Join": [ "", @@ -771,9 +769,12 @@ } ] ] - } + }, + "LocalMountPath": "/mnt/msg" } ], + "Handler": "index.lambda_handler", + "Runtime": "python3.7", "VpcConfig": { "SecurityGroupIds": [ { @@ -983,17 +984,14 @@ "Code": { "ZipFile": "\nimport json\nimport os\nimport string\nimport random\nimport datetime\n\nMSG_FILE_PATH = '/mnt/msg/content'\n\ndef randomString(stringLength=10):\n letters = string.ascii_lowercase\n return ''.join(random.choice(letters) for i in range(stringLength))\n\ndef lambda_handler(event, context):\n with open(MSG_FILE_PATH, 'a') as f:\n f.write(f\"{datetime.datetime.utcnow():%Y-%m-%d-%H:%M:%S} \" + randomString(5) + ' ')\n\n file = open(MSG_FILE_PATH, \"r\")\n file_content = file.read()\n file.close()\n\n return {\n 'statusCode': 200,\n 'body': str(file_content)\n }\n" }, - "Handler": "index.lambda_handler", "Role": { "Fn::GetAtt": [ "MyLambda2ServiceRoleD09B370C", "Arn" ] }, - "Runtime": "python3.7", "FileSystemConfigs": [ { - "LocalMountPath": "/mnt/msg", "Arn": { "Fn::Join": [ "", @@ -1016,9 +1014,12 @@ } ] ] - } + }, + "LocalMountPath": "/mnt/msg" } ], + "Handler": "index.lambda_handler", + "Runtime": "python3.7", "VpcConfig": { "SecurityGroupIds": [ { diff --git a/packages/@aws-cdk/aws-lambda/test/lambda-version.test.ts b/packages/@aws-cdk/aws-lambda/test/lambda-version.test.ts index 20b040a135a7b..c5daabab66b5d 100644 --- a/packages/@aws-cdk/aws-lambda/test/lambda-version.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/lambda-version.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import * as lambda from '../lib'; diff --git a/packages/@aws-cdk/aws-lambda/test/layers.test.ts b/packages/@aws-cdk/aws-lambda/test/layers.test.ts index 4a8f0e94ed6cb..3d8cc9d70de6f 100644 --- a/packages/@aws-cdk/aws-lambda/test/layers.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/layers.test.ts @@ -1,6 +1,6 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as path from 'path'; -import { canonicalizeTemplate, ResourcePart, SynthUtils } from '@aws-cdk/assert'; +import { canonicalizeTemplate, ResourcePart, SynthUtils } from '@aws-cdk/assert-internal'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; diff --git a/packages/@aws-cdk/aws-lambda/test/runtime.test.ts b/packages/@aws-cdk/aws-lambda/test/runtime.test.ts index e90d7535d8045..1b16b12c697b9 100644 --- a/packages/@aws-cdk/aws-lambda/test/runtime.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/runtime.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as lambda from '../lib'; describe('runtime', () => { @@ -43,7 +43,7 @@ describe('runtime', () => { const runtime = new lambda.Runtime('my-runtime-name'); // THEN - expect(runtime.bundlingDockerImage.image).toEqual('amazon/aws-sam-cli-build-image-my-runtime-name'); + expect(runtime.bundlingDockerImage.image).toEqual('public.ecr.aws/sam/build-my-runtime-name'); }); test('overridde to bundlingDockerImage points to the correct image', () => { diff --git a/packages/@aws-cdk/aws-lambda/test/singleton-lambda.test.ts b/packages/@aws-cdk/aws-lambda/test/singleton-lambda.test.ts index 28eebb1a0c284..ebe9a5c5253cd 100644 --- a/packages/@aws-cdk/aws-lambda/test/singleton-lambda.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/singleton-lambda.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert/jest'; -import { ResourcePart } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +import { ResourcePart } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import * as lambda from '../lib'; diff --git a/packages/@aws-cdk/aws-lambda/test/vpc-lambda.test.ts b/packages/@aws-cdk/aws-lambda/test/vpc-lambda.test.ts index 8c3dde47306b3..2ecd2819becf5 100644 --- a/packages/@aws-cdk/aws-lambda/test/vpc-lambda.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/vpc-lambda.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import * as lambda from '../lib'; diff --git a/packages/@aws-cdk/aws-licensemanager/package.json b/packages/@aws-cdk/aws-licensemanager/package.json index 951f8982392ab..18956a928aaf5 100644 --- a/packages/@aws-cdk/aws-licensemanager/package.json +++ b/packages/@aws-cdk/aws-licensemanager/package.json @@ -73,10 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-licensemanager/test/licensemanager.test.ts b/packages/@aws-cdk/aws-licensemanager/test/licensemanager.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-licensemanager/test/licensemanager.test.ts +++ b/packages/@aws-cdk/aws-licensemanager/test/licensemanager.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-logs-destinations/package.json b/packages/@aws-cdk/aws-logs-destinations/package.json index a4edf4ce3473b..3d1ce13174cf7 100644 --- a/packages/@aws-cdk/aws-logs-destinations/package.json +++ b/packages/@aws-cdk/aws-logs-destinations/package.json @@ -62,12 +62,13 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", @@ -75,7 +76,7 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -84,7 +85,7 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-logs-destinations/test/kinesis.test.ts b/packages/@aws-cdk/aws-logs-destinations/test/kinesis.test.ts index f09090995823e..42c87261d60b2 100644 --- a/packages/@aws-cdk/aws-logs-destinations/test/kinesis.test.ts +++ b/packages/@aws-cdk/aws-logs-destinations/test/kinesis.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as kinesis from '@aws-cdk/aws-kinesis'; import * as logs from '@aws-cdk/aws-logs'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-logs-destinations/test/lambda.test.ts b/packages/@aws-cdk/aws-logs-destinations/test/lambda.test.ts index 07e333e488ea7..e1323ae0f45a9 100644 --- a/packages/@aws-cdk/aws-logs-destinations/test/lambda.test.ts +++ b/packages/@aws-cdk/aws-logs-destinations/test/lambda.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as lambda from '@aws-cdk/aws-lambda'; import * as logs from '@aws-cdk/aws-logs'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-logs/package.json b/packages/@aws-cdk/aws-logs/package.json index b5bded382ba10..7af39bdef71e5 100644 --- a/packages/@aws-cdk/aws-logs/package.json +++ b/packages/@aws-cdk/aws-logs/package.json @@ -70,8 +70,9 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", + "@types/aws-lambda": "^8.10.76", + "@types/sinon": "^9.0.11", "aws-sdk": "^2.848.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", @@ -80,7 +81,8 @@ "nock": "^13.0.11", "nodeunit": "^0.11.3", "pkglint": "0.0.0", - "sinon": "^9.2.4" + "sinon": "^9.2.4", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", @@ -88,7 +90,7 @@ "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -97,7 +99,7 @@ "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-logs/test/test.destination.ts b/packages/@aws-cdk/aws-logs/test/test.destination.ts index 89a9054d01655..e98cb2b232576 100644 --- a/packages/@aws-cdk/aws-logs/test/test.destination.ts +++ b/packages/@aws-cdk/aws-logs/test/test.destination.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk/aws-logs/test/test.log-retention.ts b/packages/@aws-cdk/aws-logs/test/test.log-retention.ts index 1de0c4d7b777c..1a8401f63f058 100644 --- a/packages/@aws-cdk/aws-logs/test/test.log-retention.ts +++ b/packages/@aws-cdk/aws-logs/test/test.log-retention.ts @@ -1,4 +1,4 @@ -import { ABSENT, countResources, expect, haveResource } from '@aws-cdk/assert'; +import { ABSENT, countResources, expect, haveResource } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk/aws-logs/test/test.loggroup.ts b/packages/@aws-cdk/aws-logs/test/test.loggroup.ts index 333ae71a976c3..7c1e66c339d10 100644 --- a/packages/@aws-cdk/aws-logs/test/test.loggroup.ts +++ b/packages/@aws-cdk/aws-logs/test/test.loggroup.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, matchTemplate } from '@aws-cdk/assert'; +import { expect, haveResource, matchTemplate } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import { CfnParameter, RemovalPolicy, Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-logs/test/test.logstream.ts b/packages/@aws-cdk/aws-logs/test/test.logstream.ts index 8a8b8cbb56a1c..a69adfab3d640 100644 --- a/packages/@aws-cdk/aws-logs/test/test.logstream.ts +++ b/packages/@aws-cdk/aws-logs/test/test.logstream.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import { Stack } from '@aws-cdk/core'; import { Test } from 'nodeunit'; import { LogGroup, LogStream } from '../lib'; diff --git a/packages/@aws-cdk/aws-logs/test/test.metricfilter.ts b/packages/@aws-cdk/aws-logs/test/test.metricfilter.ts index e5a5c2aef32a2..c311bdfd732c1 100644 --- a/packages/@aws-cdk/aws-logs/test/test.metricfilter.ts +++ b/packages/@aws-cdk/aws-logs/test/test.metricfilter.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import { Metric } from '@aws-cdk/aws-cloudwatch'; import { Stack } from '@aws-cdk/core'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk/aws-logs/test/test.subscriptionfilter.ts b/packages/@aws-cdk/aws-logs/test/test.subscriptionfilter.ts index 0aef93813a7b7..3dcfe6a37d2c3 100644 --- a/packages/@aws-cdk/aws-logs/test/test.subscriptionfilter.ts +++ b/packages/@aws-cdk/aws-logs/test/test.subscriptionfilter.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import { Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk/aws-lookoutmetrics/.eslintrc.js b/packages/@aws-cdk/aws-lookoutmetrics/.eslintrc.js new file mode 100644 index 0000000000000..61dd8dd001f63 --- /dev/null +++ b/packages/@aws-cdk/aws-lookoutmetrics/.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-lookoutmetrics/.gitignore b/packages/@aws-cdk/aws-lookoutmetrics/.gitignore new file mode 100644 index 0000000000000..62ebc95d75ce6 --- /dev/null +++ b/packages/@aws-cdk/aws-lookoutmetrics/.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-lookoutmetrics/.npmignore b/packages/@aws-cdk/aws-lookoutmetrics/.npmignore new file mode 100644 index 0000000000000..e4486030fcb17 --- /dev/null +++ b/packages/@aws-cdk/aws-lookoutmetrics/.npmignore @@ -0,0 +1,28 @@ +# 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 +test/ diff --git a/packages/@aws-cdk/aws-lookoutmetrics/LICENSE b/packages/@aws-cdk/aws-lookoutmetrics/LICENSE new file mode 100644 index 0000000000000..28e4bdcec77ec --- /dev/null +++ b/packages/@aws-cdk/aws-lookoutmetrics/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-2021 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-lookoutmetrics/NOTICE b/packages/@aws-cdk/aws-lookoutmetrics/NOTICE new file mode 100644 index 0000000000000..5fc3826926b5b --- /dev/null +++ b/packages/@aws-cdk/aws-lookoutmetrics/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/aws-lookoutmetrics/README.md b/packages/@aws-cdk/aws-lookoutmetrics/README.md new file mode 100644 index 0000000000000..0c10b9250d502 --- /dev/null +++ b/packages/@aws-cdk/aws-lookoutmetrics/README.md @@ -0,0 +1,20 @@ +# AWS::LookoutMetrics 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]) are always stable and safe to use. +> +> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib + +--- + + + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts +import lookoutmetrics = require('@aws-cdk/aws-lookoutmetrics'); +``` diff --git a/packages/@aws-cdk/aws-lookoutmetrics/jest.config.js b/packages/@aws-cdk/aws-lookoutmetrics/jest.config.js new file mode 100644 index 0000000000000..54e28beb9798b --- /dev/null +++ b/packages/@aws-cdk/aws-lookoutmetrics/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-lookoutmetrics/lib/index.ts b/packages/@aws-cdk/aws-lookoutmetrics/lib/index.ts new file mode 100644 index 0000000000000..2e57104cd8582 --- /dev/null +++ b/packages/@aws-cdk/aws-lookoutmetrics/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::LookoutMetrics CloudFormation Resources: +export * from './lookoutmetrics.generated'; diff --git a/packages/@aws-cdk/aws-lookoutmetrics/package.json b/packages/@aws-cdk/aws-lookoutmetrics/package.json new file mode 100644 index 0000000000000..c2971b0d20209 --- /dev/null +++ b/packages/@aws-cdk/aws-lookoutmetrics/package.json @@ -0,0 +1,101 @@ +{ + "name": "@aws-cdk/aws-lookoutmetrics", + "version": "0.0.0", + "description": "The CDK Construct Library for AWS::LookoutMetrics", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "projectReferences": true, + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.LookoutMetrics", + "packageId": "Amazon.CDK.AWS.LookoutMetrics", + "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.lookoutmetrics", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "lookoutmetrics" + } + }, + "python": { + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 1" + ], + "distName": "aws-cdk.aws-lookoutmetrics", + "module": "aws_cdk.aws_lookoutmetrics" + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-lookoutmetrics" + }, + "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": "yarn build && yarn test", + "build+test+package": "yarn build+test && yarn package", + "compat": "cdk-compat", + "gen": "cfn2ts", + "rosetta:extract": "yarn --silent jsii-rosetta extract" + }, + "cdk-build": { + "cloudformation": "AWS::LookoutMetrics", + "jest": true, + "env": { + "AWSLINT_BASE_CONSTRUCT": "true" + } + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::LookoutMetrics", + "aws-lookoutmetrics" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@types/jest": "^26.0.23", + "@aws-cdk/assert-internal": "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 + }, + "publishConfig": { + "tag": "latest" + } +} diff --git a/packages/@aws-cdk/aws-lookoutmetrics/test/lookoutmetrics.test.ts b/packages/@aws-cdk/aws-lookoutmetrics/test/lookoutmetrics.test.ts new file mode 100644 index 0000000000000..c4505ad966984 --- /dev/null +++ b/packages/@aws-cdk/aws-lookoutmetrics/test/lookoutmetrics.test.ts @@ -0,0 +1,6 @@ +import '@aws-cdk/assert-internal/jest'; +import {} from '../lib'; + +test('No tests are specified for this package', () => { + expect(true).toBe(true); +}); diff --git a/packages/@aws-cdk/aws-lookoutvision/package.json b/packages/@aws-cdk/aws-lookoutvision/package.json index 0a812168e8241..0834033c7ae3b 100644 --- a/packages/@aws-cdk/aws-lookoutvision/package.json +++ b/packages/@aws-cdk/aws-lookoutvision/package.json @@ -75,10 +75,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-lookoutvision/test/lookoutvision.test.ts b/packages/@aws-cdk/aws-lookoutvision/test/lookoutvision.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-lookoutvision/test/lookoutvision.test.ts +++ b/packages/@aws-cdk/aws-lookoutvision/test/lookoutvision.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-macie/package.json b/packages/@aws-cdk/aws-macie/package.json index 7e2851d383765..c6a8387bfe91e 100644 --- a/packages/@aws-cdk/aws-macie/package.json +++ b/packages/@aws-cdk/aws-macie/package.json @@ -73,10 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-macie/test/macie.test.ts b/packages/@aws-cdk/aws-macie/test/macie.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-macie/test/macie.test.ts +++ b/packages/@aws-cdk/aws-macie/test/macie.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-managedblockchain/package.json b/packages/@aws-cdk/aws-managedblockchain/package.json index c94f2391242fb..af0f11adc1349 100644 --- a/packages/@aws-cdk/aws-managedblockchain/package.json +++ b/packages/@aws-cdk/aws-managedblockchain/package.json @@ -73,18 +73,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-managedblockchain/test/managedblockchain.test.ts b/packages/@aws-cdk/aws-managedblockchain/test/managedblockchain.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-managedblockchain/test/managedblockchain.test.ts +++ b/packages/@aws-cdk/aws-managedblockchain/test/managedblockchain.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-mediaconnect/package.json b/packages/@aws-cdk/aws-mediaconnect/package.json index dbfd544d52dd2..b0c34a4125d98 100644 --- a/packages/@aws-cdk/aws-mediaconnect/package.json +++ b/packages/@aws-cdk/aws-mediaconnect/package.json @@ -73,10 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-mediaconnect/test/mediaconnect.test.ts b/packages/@aws-cdk/aws-mediaconnect/test/mediaconnect.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-mediaconnect/test/mediaconnect.test.ts +++ b/packages/@aws-cdk/aws-mediaconnect/test/mediaconnect.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-mediaconvert/package.json b/packages/@aws-cdk/aws-mediaconvert/package.json index 938a726f92183..9ec2a9930fdc7 100644 --- a/packages/@aws-cdk/aws-mediaconvert/package.json +++ b/packages/@aws-cdk/aws-mediaconvert/package.json @@ -73,18 +73,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-mediaconvert/test/mediaconvert.test.ts b/packages/@aws-cdk/aws-mediaconvert/test/mediaconvert.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-mediaconvert/test/mediaconvert.test.ts +++ b/packages/@aws-cdk/aws-mediaconvert/test/mediaconvert.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-medialive/package.json b/packages/@aws-cdk/aws-medialive/package.json index 16ecfadc7c1bb..b25d9bf03a805 100644 --- a/packages/@aws-cdk/aws-medialive/package.json +++ b/packages/@aws-cdk/aws-medialive/package.json @@ -73,18 +73,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-medialive/test/medialive.test.ts b/packages/@aws-cdk/aws-medialive/test/medialive.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-medialive/test/medialive.test.ts +++ b/packages/@aws-cdk/aws-medialive/test/medialive.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-mediapackage/package.json b/packages/@aws-cdk/aws-mediapackage/package.json index 40913de5b816e..74a784a91dcaf 100644 --- a/packages/@aws-cdk/aws-mediapackage/package.json +++ b/packages/@aws-cdk/aws-mediapackage/package.json @@ -73,10 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-mediapackage/test/mediapackage.test.ts b/packages/@aws-cdk/aws-mediapackage/test/mediapackage.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-mediapackage/test/mediapackage.test.ts +++ b/packages/@aws-cdk/aws-mediapackage/test/mediapackage.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-mediastore/package.json b/packages/@aws-cdk/aws-mediastore/package.json index 46878264355f9..00ff06822b6f3 100644 --- a/packages/@aws-cdk/aws-mediastore/package.json +++ b/packages/@aws-cdk/aws-mediastore/package.json @@ -73,18 +73,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-mediastore/test/mediastore.test.ts b/packages/@aws-cdk/aws-mediastore/test/mediastore.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-mediastore/test/mediastore.test.ts +++ b/packages/@aws-cdk/aws-mediastore/test/mediastore.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-msk/package.json b/packages/@aws-cdk/aws-msk/package.json index efa91da07d39f..6336c02aa4316 100644 --- a/packages/@aws-cdk/aws-msk/package.json +++ b/packages/@aws-cdk/aws-msk/package.json @@ -73,18 +73,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-msk/test/msk.test.ts b/packages/@aws-cdk/aws-msk/test/msk.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-msk/test/msk.test.ts +++ b/packages/@aws-cdk/aws-msk/test/msk.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-mwaa/package.json b/packages/@aws-cdk/aws-mwaa/package.json index 17a5ba80b55f1..2dbff02703748 100644 --- a/packages/@aws-cdk/aws-mwaa/package.json +++ b/packages/@aws-cdk/aws-mwaa/package.json @@ -73,10 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-mwaa/test/mwaa.test.ts b/packages/@aws-cdk/aws-mwaa/test/mwaa.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-mwaa/test/mwaa.test.ts +++ b/packages/@aws-cdk/aws-mwaa/test/mwaa.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-neptune/lib/cluster.ts b/packages/@aws-cdk/aws-neptune/lib/cluster.ts index f3c735b78f2c7..4420659499a59 100644 --- a/packages/@aws-cdk/aws-neptune/lib/cluster.ts +++ b/packages/@aws-cdk/aws-neptune/lib/cluster.ts @@ -503,7 +503,7 @@ export class DatabaseCluster extends DatabaseClusterBase implements IDatabaseClu dbClusterIdentifier: cluster.ref, dbInstanceIdentifier: instanceIdentifier, // Instance properties - dbInstanceClass: props.instanceType, + dbInstanceClass: props.instanceType._instanceType, dbParameterGroupName: props.parameterGroup?.parameterGroupName, }); diff --git a/packages/@aws-cdk/aws-neptune/lib/instance.ts b/packages/@aws-cdk/aws-neptune/lib/instance.ts index 8459c710577c8..12920fe95444b 100644 --- a/packages/@aws-cdk/aws-neptune/lib/instance.ts +++ b/packages/@aws-cdk/aws-neptune/lib/instance.ts @@ -10,59 +10,92 @@ import { IParameterGroup } from './parameter-group'; * Possible Instances Types to use in Neptune cluster * used for defining {@link DatabaseInstanceProps.instanceType}. */ -export enum InstanceType { +export class InstanceType { + /** * db.r5.large */ - R5_LARGE = 'db.r5.large', + public static readonly R5_LARGE = InstanceType.of('db.r5.large'); + /** * db.r5.xlarge */ - R5_XLARGE = 'db.r5.xlarge', + public static readonly R5_XLARGE = InstanceType.of('db.r5.xlarge'); + /** * db.r5.2xlarge */ - R5_2XLARGE = 'db.r5.2xlarge', + public static readonly R5_2XLARGE = InstanceType.of('db.r5.2xlarge'); + /** * db.r5.4xlarge */ - R5_4XLARGE = 'db.r5.4xlarge', + public static readonly R5_4XLARGE = InstanceType.of('db.r5.4xlarge'); + /** * db.r5.8xlarge */ - R5_8XLARGE = 'db.r5.8xlarge', + public static readonly R5_8XLARGE = InstanceType.of('db.r5.8xlarge'); + /** * db.r5.12xlarge */ - R5_12XLARGE = 'db.r5.12xlarge', + public static readonly R5_12XLARGE = InstanceType.of('db.r5.12xlarge'); + /** * db.r5.24xlarge */ - R5_24XLARGE = 'db.r5.24xlarge', + public static readonly R5_24XLARGE = InstanceType.of('db.r5.24xlarge'); + /** * db.r4.large */ - R4_LARGE = 'db.r4.large', + public static readonly R4_LARGE = InstanceType.of('db.r4.large'); + /** * db.r4.xlarge */ - R4_XLARGE = 'db.r4.xlarge', + public static readonly R4_XLARGE = InstanceType.of('db.r4.xlarge'); + /** * db.r4.2xlarge */ - R4_2XLARGE = 'db.r4.2xlarge', + public static readonly R4_2XLARGE = InstanceType.of('db.r4.2xlarge'); + /** * db.r4.4xlarge */ - R4_4XLARGE = 'db.r4.4xlarge', + public static readonly R4_4XLARGE = InstanceType.of('db.r4.4xlarge'); + /** * db.r4.8xlarge */ - R4_8XLARGE = 'db.r4.8xlarge', + public static readonly R4_8XLARGE = InstanceType.of('db.r4.8xlarge'); + /** * db.t3.medium */ - T3_MEDIUM = 'db.t3.medium' + public static readonly T3_MEDIUM = InstanceType.of('db.t3.medium'); + + /** + * Build an InstanceType from given string or token, such as CfnParameter. + */ + public static of(instanceType: string): InstanceType { + return new InstanceType(instanceType); + } + + /** + * @internal + */ + readonly _instanceType: string; + + private constructor(instanceType: string) { + if (cdk.Token.isUnresolved(instanceType) || instanceType.startsWith('db.')) { + this._instanceType = instanceType; + } else { + throw new Error(`instance type must start with 'db.'; (got ${instanceType})`); + } + } } /** @@ -212,7 +245,7 @@ export class DatabaseInstance extends cdk.Resource implements IDatabaseInstance const instance = new CfnDBInstance(this, 'Resource', { dbClusterIdentifier: props.cluster.clusterIdentifier, - dbInstanceClass: props.instanceType, + dbInstanceClass: props.instanceType._instanceType, availabilityZone: props.availabilityZone, dbInstanceIdentifier: props.dbInstanceName, dbParameterGroupName: props.parameterGroup?.parameterGroupName, diff --git a/packages/@aws-cdk/aws-neptune/lib/parameter-group.ts b/packages/@aws-cdk/aws-neptune/lib/parameter-group.ts index 3cfacf061f19c..75b95495fa278 100644 --- a/packages/@aws-cdk/aws-neptune/lib/parameter-group.ts +++ b/packages/@aws-cdk/aws-neptune/lib/parameter-group.ts @@ -1,6 +1,6 @@ import { IResource, Resource } from '@aws-cdk/core'; import { Construct } from 'constructs'; -import { CfnDBClusterParameterGroup } from './neptune.generated'; +import { CfnDBClusterParameterGroup, CfnDBParameterGroup } from './neptune.generated'; /** * Properties for a parameter group @@ -123,7 +123,7 @@ export class ParameterGroup extends Resource implements IParameterGroup { constructor(scope: Construct, id: string, props: ParameterGroupProps) { super(scope, id); - const resource = new CfnDBClusterParameterGroup(this, 'Resource', { + const resource = new CfnDBParameterGroup(this, 'Resource', { name: props.parameterGroupName, description: props.description || 'Instance parameter group for neptune db instances', family: 'neptune1', diff --git a/packages/@aws-cdk/aws-neptune/package.json b/packages/@aws-cdk/aws-neptune/package.json index 5afe6d91322a2..ecdc6186f0069 100644 --- a/packages/@aws-cdk/aws-neptune/package.json +++ b/packages/@aws-cdk/aws-neptune/package.json @@ -72,25 +72,26 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-neptune/test/cluster.test.ts b/packages/@aws-cdk/aws-neptune/test/cluster.test.ts index 842b907e76ea0..24e61c8be34a1 100644 --- a/packages/@aws-cdk/aws-neptune/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-neptune/test/cluster.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert/jest'; -import { ABSENT, ResourcePart } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +import { ABSENT, ResourcePart } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; diff --git a/packages/@aws-cdk/aws-neptune/test/instance.test.ts b/packages/@aws-cdk/aws-neptune/test/instance.test.ts index 4dcfc75e243ac..dff005199ffc7 100644 --- a/packages/@aws-cdk/aws-neptune/test/instance.test.ts +++ b/packages/@aws-cdk/aws-neptune/test/instance.test.ts @@ -1,4 +1,4 @@ -import { expect as expectCDK, haveOutput, haveResource, ResourcePart } from '@aws-cdk/assert'; +import { expect as expectCDK, haveOutput, haveResource, ResourcePart } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import * as constructs from 'constructs'; @@ -106,6 +106,40 @@ describe('DatabaseInstance', () => { DBParameterGroupName: { Ref: 'ParamsA8366201' }, })); }); + + test('instance type from CfnParameter', () => { + // GIVEN + const stack = testStack(); + + const instanceType = new cdk.CfnParameter(stack, 'NeptuneInstaneType', { + description: 'Instance type of graph database Neptune', + type: 'String', + allowedValues: [ + 'db.r5.xlarge', + 'db.r5.2xlarge', + 'db.r5.4xlarge', + 'db.r5.8xlarge', + 'db.r5.12xlarge', + ], + default: 'db.r5.8xlarge', + }); + // WHEN + new DatabaseInstance(stack, 'Instance', { + cluster: stack.cluster, + instanceType: InstanceType.of(instanceType.valueAsString), + }); + + // THEN + expectCDK(stack).to(haveResource('AWS::Neptune::DBInstance', { + DBInstanceClass: { + Ref: 'NeptuneInstaneType', + }, + })); + }); + + test('instance type from string throws if missing db prefix', () => { + expect(() => { InstanceType.of('r5.xlarge');}).toThrowError(/instance type must start with 'db.'/); + }); }); class TestStack extends cdk.Stack { @@ -128,4 +162,4 @@ class TestStack extends cdk.Stack { function testStack() { const stack = new TestStack(undefined, undefined, { env: { account: '12345', region: 'us-test-1' } }); return stack; -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-neptune/test/parameter-group.test.ts b/packages/@aws-cdk/aws-neptune/test/parameter-group.test.ts index 6ba6ff6562d76..3267f70aed062 100644 --- a/packages/@aws-cdk/aws-neptune/test/parameter-group.test.ts +++ b/packages/@aws-cdk/aws-neptune/test/parameter-group.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import { Stack } from '@aws-cdk/core'; import { ClusterParameterGroup, ParameterGroup } from '../lib'; @@ -39,7 +39,7 @@ describe('ClusterParameterGroup', () => { }); // THEN - expect(stack).to(haveResource('AWS::Neptune::DBClusterParameterGroup', { + expect(stack).to(haveResource('AWS::Neptune::DBParameterGroup', { Description: 'desc', Parameters: { key: 'value', diff --git a/packages/@aws-cdk/aws-neptune/test/subnet-group.test.ts b/packages/@aws-cdk/aws-neptune/test/subnet-group.test.ts index e6c75013716c8..675b2cf89a920 100644 --- a/packages/@aws-cdk/aws-neptune/test/subnet-group.test.ts +++ b/packages/@aws-cdk/aws-neptune/test/subnet-group.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import { Stack } from '@aws-cdk/core'; import { SubnetGroup } from '../lib'; diff --git a/packages/@aws-cdk/aws-networkfirewall/package.json b/packages/@aws-cdk/aws-networkfirewall/package.json index 8c218072fe92b..389850a3e50c6 100644 --- a/packages/@aws-cdk/aws-networkfirewall/package.json +++ b/packages/@aws-cdk/aws-networkfirewall/package.json @@ -73,10 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-networkfirewall/test/networkfirewall.test.ts b/packages/@aws-cdk/aws-networkfirewall/test/networkfirewall.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-networkfirewall/test/networkfirewall.test.ts +++ b/packages/@aws-cdk/aws-networkfirewall/test/networkfirewall.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-networkmanager/package.json b/packages/@aws-cdk/aws-networkmanager/package.json index 9c38f74d32916..8532a917c0b58 100644 --- a/packages/@aws-cdk/aws-networkmanager/package.json +++ b/packages/@aws-cdk/aws-networkmanager/package.json @@ -73,10 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-networkmanager/test/networkmanager.test.ts b/packages/@aws-cdk/aws-networkmanager/test/networkmanager.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-networkmanager/test/networkmanager.test.ts +++ b/packages/@aws-cdk/aws-networkmanager/test/networkmanager.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-nimblestudio/.eslintrc.js b/packages/@aws-cdk/aws-nimblestudio/.eslintrc.js new file mode 100644 index 0000000000000..61dd8dd001f63 --- /dev/null +++ b/packages/@aws-cdk/aws-nimblestudio/.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-nimblestudio/.gitignore b/packages/@aws-cdk/aws-nimblestudio/.gitignore new file mode 100644 index 0000000000000..62ebc95d75ce6 --- /dev/null +++ b/packages/@aws-cdk/aws-nimblestudio/.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-nimblestudio/.npmignore b/packages/@aws-cdk/aws-nimblestudio/.npmignore new file mode 100644 index 0000000000000..e4486030fcb17 --- /dev/null +++ b/packages/@aws-cdk/aws-nimblestudio/.npmignore @@ -0,0 +1,28 @@ +# 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 +test/ diff --git a/packages/@aws-cdk/aws-nimblestudio/LICENSE b/packages/@aws-cdk/aws-nimblestudio/LICENSE new file mode 100644 index 0000000000000..28e4bdcec77ec --- /dev/null +++ b/packages/@aws-cdk/aws-nimblestudio/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-2021 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-nimblestudio/NOTICE b/packages/@aws-cdk/aws-nimblestudio/NOTICE new file mode 100644 index 0000000000000..5fc3826926b5b --- /dev/null +++ b/packages/@aws-cdk/aws-nimblestudio/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/aws-nimblestudio/README.md b/packages/@aws-cdk/aws-nimblestudio/README.md new file mode 100644 index 0000000000000..ff5936d0e9147 --- /dev/null +++ b/packages/@aws-cdk/aws-nimblestudio/README.md @@ -0,0 +1,20 @@ +# AWS::NimbleStudio 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]) are always stable and safe to use. +> +> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib + +--- + + + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts +import nimblestudio = require('@aws-cdk/aws-nimblestudio'); +``` diff --git a/packages/@aws-cdk/aws-nimblestudio/jest.config.js b/packages/@aws-cdk/aws-nimblestudio/jest.config.js new file mode 100644 index 0000000000000..54e28beb9798b --- /dev/null +++ b/packages/@aws-cdk/aws-nimblestudio/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-nimblestudio/lib/index.ts b/packages/@aws-cdk/aws-nimblestudio/lib/index.ts new file mode 100644 index 0000000000000..15c195efc6e6a --- /dev/null +++ b/packages/@aws-cdk/aws-nimblestudio/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::NimbleStudio CloudFormation Resources: +export * from './nimblestudio.generated'; diff --git a/packages/@aws-cdk/aws-nimblestudio/package.json b/packages/@aws-cdk/aws-nimblestudio/package.json new file mode 100644 index 0000000000000..ad996a406ab31 --- /dev/null +++ b/packages/@aws-cdk/aws-nimblestudio/package.json @@ -0,0 +1,101 @@ +{ + "name": "@aws-cdk/aws-nimblestudio", + "version": "0.0.0", + "description": "The CDK Construct Library for AWS::NimbleStudio", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "projectReferences": true, + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.NimbleStudio", + "packageId": "Amazon.CDK.AWS.NimbleStudio", + "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.nimblestudio", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "nimblestudio" + } + }, + "python": { + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 1" + ], + "distName": "aws-cdk.aws-nimblestudio", + "module": "aws_cdk.aws_nimblestudio" + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-nimblestudio" + }, + "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": "yarn build && yarn test", + "build+test+package": "yarn build+test && yarn package", + "compat": "cdk-compat", + "gen": "cfn2ts", + "rosetta:extract": "yarn --silent jsii-rosetta extract" + }, + "cdk-build": { + "cloudformation": "AWS::NimbleStudio", + "jest": true, + "env": { + "AWSLINT_BASE_CONSTRUCT": "true" + } + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::NimbleStudio", + "aws-nimblestudio" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@types/jest": "^26.0.23", + "@aws-cdk/assert-internal": "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 + }, + "publishConfig": { + "tag": "latest" + } +} diff --git a/packages/@aws-cdk/aws-nimblestudio/test/nimblestudio.test.ts b/packages/@aws-cdk/aws-nimblestudio/test/nimblestudio.test.ts new file mode 100644 index 0000000000000..c4505ad966984 --- /dev/null +++ b/packages/@aws-cdk/aws-nimblestudio/test/nimblestudio.test.ts @@ -0,0 +1,6 @@ +import '@aws-cdk/assert-internal/jest'; +import {} from '../lib'; + +test('No tests are specified for this package', () => { + expect(true).toBe(true); +}); diff --git a/packages/@aws-cdk/aws-opsworks/package.json b/packages/@aws-cdk/aws-opsworks/package.json index b00cff3b7056e..d85cc277ce33c 100644 --- a/packages/@aws-cdk/aws-opsworks/package.json +++ b/packages/@aws-cdk/aws-opsworks/package.json @@ -71,19 +71,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-opsworks/test/opsworks.test.ts b/packages/@aws-cdk/aws-opsworks/test/opsworks.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-opsworks/test/opsworks.test.ts +++ b/packages/@aws-cdk/aws-opsworks/test/opsworks.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-opsworkscm/package.json b/packages/@aws-cdk/aws-opsworkscm/package.json index 3c102533e89dc..1dc82ec196ef6 100644 --- a/packages/@aws-cdk/aws-opsworkscm/package.json +++ b/packages/@aws-cdk/aws-opsworkscm/package.json @@ -73,18 +73,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-opsworkscm/test/opsworkscm.test.ts b/packages/@aws-cdk/aws-opsworkscm/test/opsworkscm.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-opsworkscm/test/opsworkscm.test.ts +++ b/packages/@aws-cdk/aws-opsworkscm/test/opsworkscm.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-pinpoint/package.json b/packages/@aws-cdk/aws-pinpoint/package.json index ed7fe94c40090..3b40bc91a515c 100644 --- a/packages/@aws-cdk/aws-pinpoint/package.json +++ b/packages/@aws-cdk/aws-pinpoint/package.json @@ -73,18 +73,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-pinpoint/test/pinpoint.test.ts b/packages/@aws-cdk/aws-pinpoint/test/pinpoint.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-pinpoint/test/pinpoint.test.ts +++ b/packages/@aws-cdk/aws-pinpoint/test/pinpoint.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-pinpointemail/package.json b/packages/@aws-cdk/aws-pinpointemail/package.json index 5f98fa3d04e24..c051cfd621e43 100644 --- a/packages/@aws-cdk/aws-pinpointemail/package.json +++ b/packages/@aws-cdk/aws-pinpointemail/package.json @@ -73,18 +73,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-pinpointemail/test/pinpointemail.test.ts b/packages/@aws-cdk/aws-pinpointemail/test/pinpointemail.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-pinpointemail/test/pinpointemail.test.ts +++ b/packages/@aws-cdk/aws-pinpointemail/test/pinpointemail.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-qldb/package.json b/packages/@aws-cdk/aws-qldb/package.json index 257716f07faea..1857513cb738a 100644 --- a/packages/@aws-cdk/aws-qldb/package.json +++ b/packages/@aws-cdk/aws-qldb/package.json @@ -73,18 +73,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-qldb/test/qldb.test.ts b/packages/@aws-cdk/aws-qldb/test/qldb.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-qldb/test/qldb.test.ts +++ b/packages/@aws-cdk/aws-qldb/test/qldb.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-quicksight/package.json b/packages/@aws-cdk/aws-quicksight/package.json index 14526eb10a35a..16b54c3f40a2e 100644 --- a/packages/@aws-cdk/aws-quicksight/package.json +++ b/packages/@aws-cdk/aws-quicksight/package.json @@ -75,10 +75,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-quicksight/test/quicksight.test.ts b/packages/@aws-cdk/aws-quicksight/test/quicksight.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-quicksight/test/quicksight.test.ts +++ b/packages/@aws-cdk/aws-quicksight/test/quicksight.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-ram/package.json b/packages/@aws-cdk/aws-ram/package.json index 2ca7d27497147..0a5bdfcc9bc41 100644 --- a/packages/@aws-cdk/aws-ram/package.json +++ b/packages/@aws-cdk/aws-ram/package.json @@ -73,18 +73,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-ram/test/ram.test.ts b/packages/@aws-cdk/aws-ram/test/ram.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-ram/test/ram.test.ts +++ b/packages/@aws-cdk/aws-ram/test/ram.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-rds/README.md b/packages/@aws-cdk/aws-rds/README.md index cb431cecbcd10..c336f5c7c240e 100644 --- a/packages/@aws-cdk/aws-rds/README.md +++ b/packages/@aws-cdk/aws-rds/README.md @@ -247,6 +247,7 @@ It's also possible to create user credentials together with the instance/cluster ```ts const myUserSecret = new rds.DatabaseSecret(this, 'MyUserSecret', { username: 'myuser', + secretName: 'my-user-secret', // optional, defaults to a CloudFormation-generated name masterSecret: instance.secret, excludeCharacters: '{}[]()\'"/\\', // defaults to the set " %+~`#$&*()|[]{}:;<>?!'/@\"\\" }); diff --git a/packages/@aws-cdk/aws-rds/lib/cluster-engine.ts b/packages/@aws-cdk/aws-rds/lib/cluster-engine.ts index 7e75162761a33..96346bcb9e03f 100644 --- a/packages/@aws-cdk/aws-rds/lib/cluster-engine.ts +++ b/packages/@aws-cdk/aws-rds/lib/cluster-engine.ts @@ -332,6 +332,8 @@ export class AuroraMysqlEngineVersion { public static readonly VER_2_09_0 = AuroraMysqlEngineVersion.builtIn_5_7('2.09.0'); /** Version "5.7.mysql_aurora.2.09.1". */ public static readonly VER_2_09_1 = AuroraMysqlEngineVersion.builtIn_5_7('2.09.1'); + /** Version "5.7.mysql_aurora.2.09.2". */ + public static readonly VER_2_09_2 = AuroraMysqlEngineVersion.builtIn_5_7('2.09.2'); /** * Create a new AuroraMysqlEngineVersion with an arbitrary version. diff --git a/packages/@aws-cdk/aws-rds/lib/cluster.ts b/packages/@aws-cdk/aws-rds/lib/cluster.ts index a3f06555afdb9..faedab239f82f 100644 --- a/packages/@aws-cdk/aws-rds/lib/cluster.ts +++ b/packages/@aws-cdk/aws-rds/lib/cluster.ts @@ -4,7 +4,8 @@ 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, Duration, RemovalPolicy, Resource, Token } from '@aws-cdk/core'; +import { Annotations, Duration, FeatureFlags, RemovalPolicy, Resource, Token } from '@aws-cdk/core'; +import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; import { IClusterEngine } from './cluster-engine'; import { DatabaseClusterAttributes, IDatabaseCluster } from './cluster-ref'; @@ -221,6 +222,14 @@ interface DatabaseClusterBaseProps { * @default - a new subnet group will be created. */ readonly subnetGroup?: ISubnetGroup; + + /** + * Whether to enable mapping of AWS Identity and Access Management (IAM) accounts + * to database accounts. + * + * @default false + */ + readonly iamAuthentication?: boolean; } /** @@ -289,8 +298,6 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { * Never undefined. */ public readonly engine?: IClusterEngine; - public readonly instanceIdentifiers: string[] = []; - public readonly instanceEndpoints: Endpoint[] = []; protected readonly newCfnProps: CfnDBClusterProps; protected readonly securityGroups: ec2.ISecurityGroup[]; @@ -340,17 +347,22 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { const clusterParameterGroupConfig = clusterParameterGroup?.bindToCluster({}); this.engine = props.engine; + const clusterIdentifier = FeatureFlags.of(this).isEnabled(cxapi.RDS_LOWERCASE_DB_IDENTIFIER) + ? props.clusterIdentifier?.toLowerCase() + : props.clusterIdentifier; + this.newCfnProps = { // Basic engine: props.engine.engineType, engineVersion: props.engine.engineVersion?.fullVersion, - dbClusterIdentifier: props.clusterIdentifier, + dbClusterIdentifier: clusterIdentifier, 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: defaultDeletionProtection(props.deletionProtection, props.removalPolicy), + enableIamDatabaseAuthentication: props.iamAuthentication, // Admin backupRetentionPeriod: props.backup?.retention?.toDays(), preferredBackupWindow: props.backup?.preferredWindow, @@ -467,6 +479,8 @@ export class DatabaseCluster extends DatabaseClusterNew { public readonly clusterEndpoint: Endpoint; public readonly clusterReadEndpoint: Endpoint; public readonly connections: ec2.Connections; + public readonly instanceIdentifiers: string[]; + public readonly instanceEndpoints: Endpoint[]; /** * The secret attached to this cluster @@ -519,7 +533,9 @@ export class DatabaseCluster extends DatabaseClusterNew { } setLogRetention(this, props); - createInstances(this, props, this.subnetGroup); + const createdInstances = createInstances(this, props, this.subnetGroup); + this.instanceIdentifiers = createdInstances.instanceIdentifiers; + this.instanceEndpoints = createdInstances.instanceEndpoints; } /** @@ -588,6 +604,8 @@ export class DatabaseClusterFromSnapshot extends DatabaseClusterNew { public readonly clusterEndpoint: Endpoint; public readonly clusterReadEndpoint: Endpoint; public readonly connections: ec2.Connections; + public readonly instanceIdentifiers: string[]; + public readonly instanceEndpoints: Endpoint[]; constructor(scope: Construct, id: string, props: DatabaseClusterFromSnapshotProps) { super(scope, id, props); @@ -611,7 +629,9 @@ export class DatabaseClusterFromSnapshot extends DatabaseClusterNew { cluster.applyRemovalPolicy(props.removalPolicy ?? RemovalPolicy.SNAPSHOT); setLogRetention(this, props); - createInstances(this, props, this.subnetGroup); + const createdInstances = createInstances(this, props, this.subnetGroup); + this.instanceIdentifiers = createdInstances.instanceIdentifiers; + this.instanceEndpoints = createdInstances.instanceEndpoints; } } @@ -651,6 +671,9 @@ interface InstanceConfig { */ function createInstances(cluster: DatabaseClusterNew, props: DatabaseClusterBaseProps, subnetGroup: ISubnetGroup): InstanceConfig { const instanceCount = props.instances != null ? props.instances : 2; + if (Token.isUnresolved(instanceCount)) { + throw new Error('The number of instances an RDS Cluster consists of cannot be provided as a deploy-time only value!'); + } if (instanceCount < 1) { throw new Error('At least one instance is required'); } diff --git a/packages/@aws-cdk/aws-rds/lib/database-secret.ts b/packages/@aws-cdk/aws-rds/lib/database-secret.ts index 0df046424a420..0a0537b23a63e 100644 --- a/packages/@aws-cdk/aws-rds/lib/database-secret.ts +++ b/packages/@aws-cdk/aws-rds/lib/database-secret.ts @@ -14,6 +14,13 @@ export interface DatabaseSecretProps { */ readonly username: string; + /** + * A name for the secret. + * + * @default - A name is generated by CloudFormation. + */ + readonly secretName?: string; + /** * The KMS key to use to encrypt the secret. * @@ -60,6 +67,7 @@ export class DatabaseSecret extends secretsmanager.Secret { super(scope, id, { encryptionKey: props.encryptionKey, description: `Generated by the CDK for stack: ${Aws.STACK_NAME}`, + secretName: props.secretName, generateSecretString: { passwordLength: 30, // Oracle password cannot have more than 30 characters secretStringTemplate: JSON.stringify({ diff --git a/packages/@aws-cdk/aws-rds/lib/instance-engine.ts b/packages/@aws-cdk/aws-rds/lib/instance-engine.ts index 3b35ad1c87ce1..b1d67f65ce2b8 100644 --- a/packages/@aws-cdk/aws-rds/lib/instance-engine.ts +++ b/packages/@aws-cdk/aws-rds/lib/instance-engine.ts @@ -156,36 +156,81 @@ abstract class InstanceEngineBase implements IInstanceEngine { * (those returned by {@link DatabaseInstanceEngine.mariaDb}). */ export class MariaDbEngineVersion { - /** Version "10.0" (only a major version, without a specific minor version). */ + /** + * Version "10.0" (only a major version, without a specific minor version). + * @deprecated MariaDB 10.0 will reach end of life on May 18, 2021 + */ public static readonly VER_10_0 = MariaDbEngineVersion.of('10.0', '10.0'); - /** Version "10.0.17". */ + /** + * Version "10.0.17". + * @deprecated MariaDB 10.0 will reach end of life on May 18, 2021 + */ public static readonly VER_10_0_17 = MariaDbEngineVersion.of('10.0.17', '10.0'); - /** Version "10.0.24". */ + /** + * Version "10.0.24". + * @deprecated MariaDB 10.0 will reach end of life on May 18, 2021 + */ public static readonly VER_10_0_24 = MariaDbEngineVersion.of('10.0.24', '10.0'); - /** Version "10.0.28". */ + /** + * Version "10.0.28". + * @deprecated MariaDB 10.0 will reach end of life on May 18, 2021 + */ public static readonly VER_10_0_28 = MariaDbEngineVersion.of('10.0.28', '10.0'); - /** Version "10.0.31". */ + /** + * Version "10.0.31". + * @deprecated MariaDB 10.0 will reach end of life on May 18, 2021 + */ public static readonly VER_10_0_31 = MariaDbEngineVersion.of('10.0.31', '10.0'); - /** Version "10.0.32". */ + /** + * Version "10.0.32". + * @deprecated MariaDB 10.0 will reach end of life on May 18, 2021 + */ public static readonly VER_10_0_32 = MariaDbEngineVersion.of('10.0.32', '10.0'); - /** Version "10.0.34". */ + /** + * Version "10.0.34". + * @deprecated MariaDB 10.0 will reach end of life on May 18, 2021 + */ public static readonly VER_10_0_34 = MariaDbEngineVersion.of('10.0.34', '10.0'); - /** Version "10.0.35". */ + /** + * Version "10.0.35". + * @deprecated MariaDB 10.0 will reach end of life on May 18, 2021 + */ public static readonly VER_10_0_35 = MariaDbEngineVersion.of('10.0.35', '10.0'); - /** Version "10.1" (only a major version, without a specific minor version). */ + /** + * Version "10.1" (only a major version, without a specific minor version). + * @deprecated MariaDB 10.1 will reach end of life on May 18, 2021 + */ public static readonly VER_10_1 = MariaDbEngineVersion.of('10.1', '10.1'); - /** Version "10.1.14". */ + /** + * Version "10.1.14". + * @deprecated MariaDB 10.1 will reach end of life on May 18, 2021 + */ public static readonly VER_10_1_14 = MariaDbEngineVersion.of('10.1.14', '10.1'); - /** Version "10.1.19". */ + /** + * Version "10.1.19". + * @deprecated MariaDB 10.1 will reach end of life on May 18, 2021 + */ public static readonly VER_10_1_19 = MariaDbEngineVersion.of('10.1.19', '10.1'); - /** Version "10.1.23". */ + /** + * Version "10.1.23". + * @deprecated MariaDB 10.1 will reach end of life on May 18, 2021 + */ public static readonly VER_10_1_23 = MariaDbEngineVersion.of('10.1.23', '10.1'); - /** Version "10.1.26". */ + /** + * Version "10.1.26". + * @deprecated MariaDB 10.1 will reach end of life on May 18, 2021 + */ public static readonly VER_10_1_26 = MariaDbEngineVersion.of('10.1.26', '10.1'); - /** Version "10.1.31". */ + /** + * Version "10.1.31". + * @deprecated MariaDB 10.1 will reach end of life on May 18, 2021 + */ public static readonly VER_10_1_31 = MariaDbEngineVersion.of('10.1.31', '10.1'); - /** Version "10.1.34". */ + /** + * Version "10.1.34". + * @deprecated MariaDB 10.1 will reach end of life on May 18, 2021 + */ public static readonly VER_10_1_34 = MariaDbEngineVersion.of('10.1.34', '10.1'); /** Version "10.2" (only a major version, without a specific minor version). */ @@ -198,6 +243,8 @@ export class MariaDbEngineVersion { public static readonly VER_10_2_15 = MariaDbEngineVersion.of('10.2.15', '10.2'); /** Version "10.2.21". */ public static readonly VER_10_2_21 = MariaDbEngineVersion.of('10.2.21', '10.2'); + /** Version "10.2.32". */ + public static readonly VER_10_2_32 = MariaDbEngineVersion.of('10.2.32', '10.2'); /** Version "10.3" (only a major version, without a specific minor version). */ public static readonly VER_10_3 = MariaDbEngineVersion.of('10.3', '10.3'); @@ -282,41 +329,102 @@ class MariaDbInstanceEngine extends InstanceEngineBase { * (those returned by {@link DatabaseInstanceEngine.mysql}). */ export class MysqlEngineVersion { - /** Version "5.5" (only a major version, without a specific minor version). */ + /** + * Version "5.5" (only a major version, without a specific minor version). + * @deprecated MySQL 5.5 will reach end of life on May 25, 2021 + */ public static readonly VER_5_5 = MysqlEngineVersion.of('5.5', '5.5'); - /** Version "5.5.46". */ + /** + * Version "5.5.46". + * @deprecated MySQL 5.5 will reach end of life on May 25, 2021 + */ public static readonly VER_5_5_46 = MysqlEngineVersion.of('5.5.46', '5.5'); - /** Version "5.5.53". */ + /** + * Version "5.5.53". + * @deprecated MySQL 5.5 will reach end of life on May 25, 2021 + */ public static readonly VER_5_5_53 = MysqlEngineVersion.of('5.5.53', '5.5'); - /** Version "5.5.57". */ + /** + * Version "5.5.57". + * @deprecated MySQL 5.5 will reach end of life on May 25, 2021 + */ public static readonly VER_5_5_57 = MysqlEngineVersion.of('5.5.57', '5.5'); - /** Version "5.5.59". */ + /** + * Version "5.5.59". + * @deprecated MySQL 5.5 will reach end of life on May 25, 2021 + */ public static readonly VER_5_5_59 = MysqlEngineVersion.of('5.5.59', '5.5'); - /** Version "5.5.61". */ + /** + * Version "5.5.61". + * @deprecated MySQL 5.5 will reach end of life on May 25, 2021 + */ public static readonly VER_5_5_61 = MysqlEngineVersion.of('5.5.61', '5.5'); - /** Version "5.6" (only a major version, without a specific minor version). */ + /** + * Version "5.6" (only a major version, without a specific minor version). + * @deprecated MySQL 5.6 will reach end of life on August 3, 2021 + */ public static readonly VER_5_6 = MysqlEngineVersion.of('5.6', '5.6'); - /** Version "5.6.34". */ + /** + * Version "5.6.34". + * @deprecated MySQL 5.6 will reach end of life on August 3, 2021 + */ public static readonly VER_5_6_34 = MysqlEngineVersion.of('5.6.34', '5.6'); - /** Version "5.6.35". */ + /** + * Version "5.6.35". + * @deprecated MySQL 5.6 will reach end of life on August 3, 2021 + */ public static readonly VER_5_6_35 = MysqlEngineVersion.of('5.6.35', '5.6'); - /** Version "5.6.37". */ + /** + * Version "5.6.37". + * @deprecated MySQL 5.6 will reach end of life on August 3, 2021 + */ public static readonly VER_5_6_37 = MysqlEngineVersion.of('5.6.37', '5.6'); - /** Version "5.6.39". */ + /** + * Version "5.6.39". + * @deprecated MySQL 5.6 will reach end of life on August 3, 2021 + */ public static readonly VER_5_6_39 = MysqlEngineVersion.of('5.6.39', '5.6'); - /** Version "5.6.40". */ + /** + * Version "5.6.40". + * @deprecated MySQL 5.6 will reach end of life on August 3, 2021 + */ public static readonly VER_5_6_40 = MysqlEngineVersion.of('5.6.40', '5.6'); - /** Version "5.6.41". */ + /** + * Version "5.6.41". + * @deprecated MySQL 5.6 will reach end of life on August 3, 2021 + */ public static readonly VER_5_6_41 = MysqlEngineVersion.of('5.6.41', '5.6'); - /** Version "5.6.43". */ + /** + * Version "5.6.43". + * @deprecated MySQL 5.6 will reach end of life on August 3, 2021 + */ public static readonly VER_5_6_43 = MysqlEngineVersion.of('5.6.43', '5.6'); - /** Version "5.6.44". */ + /** + * Version "5.6.44". + * @deprecated MySQL 5.6 will reach end of life on August 3, 2021 + */ public static readonly VER_5_6_44 = MysqlEngineVersion.of('5.6.44', '5.6'); - /** Version "5.6.46". */ + /** + * Version "5.6.46". + * @deprecated MySQL 5.6 will reach end of life on August 3, 2021 + */ public static readonly VER_5_6_46 = MysqlEngineVersion.of('5.6.46', '5.6'); - /** Version "5.6.48". */ + /** + * Version "5.6.48". + * @deprecated MySQL 5.6 will reach end of life on August 3, 2021 + */ public static readonly VER_5_6_48 = MysqlEngineVersion.of('5.6.48', '5.6'); + /** + * Version "5.6.49". + * @deprecated MySQL 5.6 will reach end of life on August 3, 2021 + */ + public static readonly VER_5_6_49 = MysqlEngineVersion.of('5.6.49', '5.6'); + /** + * Version "5.6.51". + * @deprecated MySQL 5.6 will reach end of life on August 3, 2021 + */ + public static readonly VER_5_6_51 = MysqlEngineVersion.of('5.6.51', '5.6'); /** Version "5.7" (only a major version, without a specific minor version). */ public static readonly VER_5_7 = MysqlEngineVersion.of('5.7', '5.7'); @@ -344,6 +452,8 @@ export class MysqlEngineVersion { public static readonly VER_5_7_30 = MysqlEngineVersion.of('5.7.30', '5.7'); /** Version "5.7.31". */ public static readonly VER_5_7_31 = MysqlEngineVersion.of('5.7.31', '5.7'); + /** Version "5.7.33". */ + public static readonly VER_5_7_33 = MysqlEngineVersion.of('5.7.33', '5.7'); /** Version "8.0" (only a major version, without a specific minor version). */ public static readonly VER_8_0 = MysqlEngineVersion.of('8.0', '8.0'); @@ -363,6 +473,8 @@ export class MysqlEngineVersion { public static readonly VER_8_0_20 = MysqlEngineVersion.of('8.0.20', '8.0'); /** Version "8.0.21 ". */ public static readonly VER_8_0_21 = MysqlEngineVersion.of('8.0.21', '8.0'); + /** Version "8.0.23". */ + public static readonly VER_8_0_23 = MysqlEngineVersion.of('8.0.23', '8.0'); /** * Create a new MysqlEngineVersion with an arbitrary version. @@ -606,6 +718,16 @@ export class PostgresEngineVersion { * @deprecated PostgreSQL 9.6 will reach end of life in November 2021 */ public static readonly VER_9_6_19 = PostgresEngineVersion.of('9.6.19', '9.6'); + /** + * Version "9.6.20". + * @deprecated PostgreSQL 9.6 will reach end of life in November 2021 + */ + public static readonly VER_9_6_20 = PostgresEngineVersion.of('9.6.20', '9.6'); + /** + * Version "9.6.21". + * @deprecated PostgreSQL 9.6 will reach end of life in November 2021 + */ + public static readonly VER_9_6_21 = PostgresEngineVersion.of('9.6.21', '9.6'); /** Version "10" (only a major version, without a specific minor version). */ public static readonly VER_10 = PostgresEngineVersion.of('10', '10'); @@ -633,6 +755,10 @@ export class PostgresEngineVersion { public static readonly VER_10_13 = PostgresEngineVersion.of('10.13', '10', { s3Import: true }); /** Version "10.14". */ public static readonly VER_10_14 = PostgresEngineVersion.of('10.14', '10', { s3Import: true }); + /** Version "10.15". */ + public static readonly VER_10_15 = PostgresEngineVersion.of('10.15', '10', { s3Import: true }); + /** Version "10.16". */ + public static readonly VER_10_16 = PostgresEngineVersion.of('10.16', '10', { s3Import: true }); /** Version "11" (only a major version, without a specific minor version). */ public static readonly VER_11 = PostgresEngineVersion.of('11', '11', { s3Import: true }); @@ -652,6 +778,10 @@ export class PostgresEngineVersion { public static readonly VER_11_8 = PostgresEngineVersion.of('11.8', '11', { s3Import: true }); /** Version "11.9". */ public static readonly VER_11_9 = PostgresEngineVersion.of('11.9', '11', { s3Import: true }); + /** Version "11.10". */ + public static readonly VER_11_10 = PostgresEngineVersion.of('11.10', '11', { s3Import: true }); + /** Version "11.11". */ + public static readonly VER_11_11 = PostgresEngineVersion.of('11.11', '11', { s3Import: true }); /** Version "12" (only a major version, without a specific minor version). */ public static readonly VER_12 = PostgresEngineVersion.of('12', '12', { s3Import: true }); @@ -663,6 +793,15 @@ export class PostgresEngineVersion { public static readonly VER_12_4 = PostgresEngineVersion.of('12.4', '12', { s3Import: true }); /** Version "12.5". */ public static readonly VER_12_5 = PostgresEngineVersion.of('12.5', '12', { s3Import: true }); + /** Version "12.6". */ + public static readonly VER_12_6 = PostgresEngineVersion.of('12.6', '12', { s3Import: true }); + + /** Version "13" (only a major version, without a specific minor version). */ + public static readonly VER_13 = PostgresEngineVersion.of('13', '13', { s3Import: true }); + /** Version "13.1". */ + public static readonly VER_13_1 = PostgresEngineVersion.of('13.1', '13', { s3Import: true }); + /** Version "13.2". */ + public static readonly VER_13_2 = PostgresEngineVersion.of('13.2', '13', { s3Import: true }); /** * Create a new PostgresEngineVersion with an arbitrary version. diff --git a/packages/@aws-cdk/aws-rds/lib/instance.ts b/packages/@aws-cdk/aws-rds/lib/instance.ts index f6bbe5481a112..632e3cfec431b 100644 --- a/packages/@aws-cdk/aws-rds/lib/instance.ts +++ b/packages/@aws-cdk/aws-rds/lib/instance.ts @@ -5,7 +5,8 @@ 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 { Duration, IResource, Lazy, RemovalPolicy, Resource, Stack, Token } from '@aws-cdk/core'; +import { ArnComponents, Duration, FeatureFlags, IResource, Lazy, RemovalPolicy, Resource, Stack, Token } from '@aws-cdk/core'; +import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; import { DatabaseSecret } from './database-secret'; import { Endpoint } from './endpoint'; @@ -186,12 +187,19 @@ export abstract class DatabaseInstanceBase extends Resource implements IDatabase * The instance arn. */ public get instanceArn(): string { - return Stack.of(this).formatArn({ + const commonAnComponents: ArnComponents = { service: 'rds', resource: 'db', sep: ':', + }; + const localArn = Stack.of(this).formatArn({ + ...commonAnComponents, resourceName: this.instanceIdentifier, }); + return this.getResourceArnAttribute(localArn, { + ...commonAnComponents, + resourceName: this.physicalName, + }); } /** @@ -630,7 +638,15 @@ abstract class DatabaseInstanceNew extends DatabaseInstanceBase implements IData protected enableIamAuthentication?: boolean; constructor(scope: Construct, id: string, props: DatabaseInstanceNewProps) { - super(scope, id); + // RDS always lower-cases the ID of the database, so use that for the physical name + // (which is the name used for cross-environment access, so it needs to be correct, + // regardless of the feature flag that changes it in the template for the L1) + const instancePhysicalName = Token.isUnresolved(props.instanceIdentifier) + ? props.instanceIdentifier + : props.instanceIdentifier?.toLowerCase(); + super(scope, id, { + physicalName: instancePhysicalName, + }); this.vpc = props.vpc; if (props.vpcSubnets && props.vpcPlacement) { @@ -687,13 +703,23 @@ abstract class DatabaseInstanceNew extends DatabaseInstanceBase implements IData }); } + const maybeLowercasedInstanceId = FeatureFlags.of(this).isEnabled(cxapi.RDS_LOWERCASE_DB_IDENTIFIER) + ? props.instanceIdentifier?.toLowerCase() + : props.instanceIdentifier; + this.newCfnProps = { autoMinorVersionUpgrade: props.autoMinorVersionUpgrade, availabilityZone: props.multiAz ? undefined : props.availabilityZone, backupRetentionPeriod: props.backupRetention?.toDays(), copyTagsToSnapshot: props.copyTagsToSnapshot ?? true, dbInstanceClass: Lazy.string({ produce: () => `db.${this.instanceType}` }), - dbInstanceIdentifier: props.instanceIdentifier, + dbInstanceIdentifier: Token.isUnresolved(props.instanceIdentifier) + // if the passed identifier is a Token, + // we need to use the physicalName of the database + // (we cannot change its case anyway), + // as it might be used in a cross-environment fashion + ? this.physicalName + : maybeLowercasedInstanceId, dbSubnetGroupName: subnetGroup.subnetGroupName, deleteAutomatedBackups: props.deleteAutomatedBackups, deletionProtection: defaultDeletionProtection(props.deletionProtection, props.removalPolicy), @@ -968,7 +994,7 @@ export class DatabaseInstance extends DatabaseInstanceSource implements IDatabas storageEncrypted: props.storageEncryptionKey ? true : props.storageEncrypted, }); - this.instanceIdentifier = instance.ref; + this.instanceIdentifier = this.getResourceNameAttribute(instance.ref); this.dbInstanceEndpointAddress = instance.attrEndpointAddress; this.dbInstanceEndpointPort = instance.attrEndpointPort; diff --git a/packages/@aws-cdk/aws-rds/lib/private/util.ts b/packages/@aws-cdk/aws-rds/lib/private/util.ts index 0b6e2b72ff0be..df9ace2dbd3bc 100644 --- a/packages/@aws-cdk/aws-rds/lib/private/util.ts +++ b/packages/@aws-cdk/aws-rds/lib/private/util.ts @@ -94,6 +94,7 @@ export function renderCredentials(scope: Construct, engine: IEngine, credentials renderedCredentials = Credentials.fromSecret( new DatabaseSecret(scope, 'Secret', { username: renderedCredentials.username, + secretName: renderedCredentials.secretName, encryptionKey: renderedCredentials.encryptionKey, excludeCharacters: renderedCredentials.excludeCharacters, // if username must be referenced as a string we can safely replace the @@ -131,4 +132,4 @@ export function helperRemovalPolicy(basePolicy?: RemovalPolicy): RemovalPolicy { */ export function renderUnless(value: A, suppressValue: A): A | undefined { return value === suppressValue ? undefined : value; -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-rds/lib/props.ts b/packages/@aws-cdk/aws-rds/lib/props.ts index 9d7cbd40b8042..c57e8ccee8fd6 100644 --- a/packages/@aws-cdk/aws-rds/lib/props.ts +++ b/packages/@aws-cdk/aws-rds/lib/props.ts @@ -126,6 +126,13 @@ export interface BackupProps { * Base options for creating Credentials. */ export interface CredentialsBaseOptions { + /** + * The name of the secret. + * + * @default - A name is generated by CloudFormation. + */ + readonly secretName?: string; + /** * KMS encryption key to encrypt the generated secret. * @@ -232,6 +239,14 @@ export abstract class Credentials { */ public abstract readonly username: string; + /** + * The name to use for the Secret if a new Secret is to be generated in + * SecretsManager for these Credentials. + * + * @default - A name is generated by CloudFormation. + */ + public abstract readonly secretName?: string; + /** * Whether the username should be referenced as a string and not as a dynamic * reference to the username in the secret. diff --git a/packages/@aws-cdk/aws-rds/lib/serverless-cluster.ts b/packages/@aws-cdk/aws-rds/lib/serverless-cluster.ts index 90438cbaa1c79..8375948441f4c 100644 --- a/packages/@aws-cdk/aws-rds/lib/serverless-cluster.ts +++ b/packages/@aws-cdk/aws-rds/lib/serverless-cluster.ts @@ -2,7 +2,8 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; -import { Resource, Duration, Token, Annotations, RemovalPolicy, IResource, Stack, Lazy } from '@aws-cdk/core'; +import { Resource, Duration, Token, Annotations, RemovalPolicy, IResource, Stack, Lazy, FeatureFlags } from '@aws-cdk/core'; +import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; import { IClusterEngine } from './cluster-engine'; import { Endpoint } from './endpoint'; @@ -16,7 +17,6 @@ import { ISubnetGroup, SubnetGroup } from './subnet-group'; /** * Interface representing a serverless database cluster. * - * @experimental */ export interface IServerlessCluster extends IResource, ec2.IConnectable, secretsmanager.ISecretAttachmentTarget { /** @@ -51,7 +51,6 @@ export interface IServerlessCluster extends IResource, ec2.IConnectable, secrets /** * Properties to configure an Aurora Serverless Cluster * - * @experimental */ export interface ServerlessClusterProps { /** @@ -166,7 +165,6 @@ export interface ServerlessClusterProps { /** * Properties that describe an existing cluster instance * - * @experimental */ export interface ServerlessClusterAttributes { /** @@ -217,7 +215,6 @@ export interface ServerlessClusterAttributes { * @see https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless.setting-capacity.html * @see https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless.how-it-works.html#aurora-serverless.architecture * - * @experimental */ export enum AuroraCapacityUnit { /** 1 Aurora Capacity Unit */ @@ -247,7 +244,6 @@ export enum AuroraCapacityUnit { /** * Options for configuring scaling on an Aurora Serverless cluster * - * @experimental */ export interface ServerlessScalingOptions { /** @@ -360,7 +356,6 @@ abstract class ServerlessClusterBase extends Resource implements IServerlessClus * * @resource AWS::RDS::DBCluster * - * @experimental */ export class ServerlessCluster extends ServerlessClusterBase { @@ -438,10 +433,14 @@ export class ServerlessCluster extends ServerlessClusterBase { }), ]; + const clusterIdentifier = FeatureFlags.of(this).isEnabled(cxapi.RDS_LOWERCASE_DB_IDENTIFIER) + ? props.clusterIdentifier?.toLowerCase() + : props.clusterIdentifier; + const cluster = new CfnDBCluster(this, 'Resource', { backupRetentionPeriod: props.backupRetention?.toDays(), databaseName: props.defaultDatabaseName, - dbClusterIdentifier: props.clusterIdentifier, + dbClusterIdentifier: clusterIdentifier, dbClusterParameterGroupName: clusterParameterGroupConfig?.parameterGroupName, dbSubnetGroupName: this.subnetGroup.subnetGroupName, deletionProtection: defaultDeletionProtection(props.deletionProtection, props.removalPolicy), diff --git a/packages/@aws-cdk/aws-rds/lib/subnet-group.ts b/packages/@aws-cdk/aws-rds/lib/subnet-group.ts index be33fb337fe75..373129702b2cc 100644 --- a/packages/@aws-cdk/aws-rds/lib/subnet-group.ts +++ b/packages/@aws-cdk/aws-rds/lib/subnet-group.ts @@ -1,5 +1,5 @@ import * as ec2 from '@aws-cdk/aws-ec2'; -import { IResource, RemovalPolicy, Resource } from '@aws-cdk/core'; +import { IResource, RemovalPolicy, Resource, Token } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { CfnDBSubnetGroup } from './rds.generated'; @@ -77,7 +77,12 @@ export class SubnetGroup extends Resource implements ISubnetGroup { // 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, + // names are actually stored by RDS changed to lowercase on the server side, + // and not lowercasing them in CloudFormation means things like { Ref } + // do not work correctly + dbSubnetGroupName: Token.isUnresolved(props.subnetGroupName) + ? props.subnetGroupName + : props.subnetGroupName?.toLowerCase(), subnetIds, }); diff --git a/packages/@aws-cdk/aws-rds/package.json b/packages/@aws-cdk/aws-rds/package.json index 685b5c399b240..c11aad528afcd 100644 --- a/packages/@aws-cdk/aws-rds/package.json +++ b/packages/@aws-cdk/aws-rds/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "@aws-cdk/aws-events-targets": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/cx-api": "0.0.0", @@ -79,7 +79,8 @@ "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", - "nodeunit-shim": "0.0.0" + "nodeunit-shim": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", @@ -91,7 +92,8 @@ "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "@aws-cdk/cx-api": "0.0.0", + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -104,7 +106,8 @@ "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", - "constructs": "^3.2.0" + "@aws-cdk/cx-api": "0.0.0", + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" @@ -134,7 +137,8 @@ "docs-public-apis:@aws-cdk/aws-rds.SecretRotationApplication.MYSQL_ROTATION_SINGLE_USER", "docs-public-apis:@aws-cdk/aws-rds.SecretRotationApplication.MYSQL_ROTATION_MULTI_USER", "docs-public-apis:@aws-cdk/aws-rds.SecretRotationApplication.MARIADB_ROTATION_SINGLE_USER", - "docs-public-apis:@aws-cdk/aws-rds.SecretRotationApplication.MARIADB_ROTATION_MULTI_USER" + "docs-public-apis:@aws-cdk/aws-rds.SecretRotationApplication.MARIADB_ROTATION_MULTI_USER", + "resource-attribute:@aws-cdk/aws-rds.DatabaseProxy.dbProxyVpcId" ] }, "stability": "stable", diff --git a/packages/@aws-cdk/aws-rds/test/cluster.test.ts b/packages/@aws-cdk/aws-rds/test/cluster.test.ts index 11e60d8068341..9c743b811c818 100644 --- a/packages/@aws-cdk/aws-rds/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-rds/test/cluster.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert/jest'; -import { ABSENT, ResourcePart, SynthUtils } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +import { ABSENT, ResourcePart, SynthUtils } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import { ManagedPolicy, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; @@ -10,7 +10,7 @@ import * as cxapi from '@aws-cdk/cx-api'; import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; import { AuroraEngineVersion, AuroraMysqlEngineVersion, AuroraPostgresEngineVersion, CfnDBCluster, Credentials, DatabaseCluster, - DatabaseClusterEngine, DatabaseClusterFromSnapshot, ParameterGroup, PerformanceInsightRetention, SubnetGroup, + DatabaseClusterEngine, DatabaseClusterFromSnapshot, ParameterGroup, PerformanceInsightRetention, SubnetGroup, DatabaseSecret, } from '../lib'; describe('cluster', () => { @@ -30,6 +30,7 @@ describe('cluster', () => { instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), vpc, }, + iamAuthentication: true, }); // THEN @@ -40,6 +41,7 @@ describe('cluster', () => { MasterUsername: 'admin', MasterUserPassword: 'tooshort', VpcSecurityGroupIds: [{ 'Fn::GetAtt': ['DatabaseSecurityGroup5C91FDCB', 'GroupId'] }], + EnableIAMDatabaseAuthentication: true, }, DeletionPolicy: 'Snapshot', UpdateReplacePolicy: 'Snapshot', @@ -50,8 +52,22 @@ describe('cluster', () => { DeletionPolicy: 'Delete', UpdateReplacePolicy: 'Delete', }, ResourcePart.CompleteDefinition); + }); + test('validates that the number of instances is not a deploy-time value', () => { + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const parameter = new cdk.CfnParameter(stack, 'Param', { type: 'Number' }); + expect(() => { + new DatabaseCluster(stack, 'Database', { + instances: parameter.valueAsNumber, + engine: DatabaseClusterEngine.AURORA, + instanceProps: { + vpc, + }, + }); + }).toThrow('The number of instances an RDS Cluster consists of cannot be provided as a deploy-time only value!'); }); test('can create a cluster with a single instance', () => { @@ -60,7 +76,7 @@ describe('cluster', () => { const vpc = new ec2.Vpc(stack, 'VPC'); // WHEN - new DatabaseCluster(stack, 'Database', { + const cluster = new DatabaseCluster(stack, 'Database', { engine: DatabaseClusterEngine.AURORA, instances: 1, credentials: { @@ -82,7 +98,27 @@ describe('cluster', () => { VpcSecurityGroupIds: [{ 'Fn::GetAtt': ['DatabaseSecurityGroup5C91FDCB', 'GroupId'] }], }); + expect(cluster.instanceIdentifiers).toHaveLength(1); + expect(stack.resolve(cluster.instanceIdentifiers[0])).toEqual({ + Ref: 'DatabaseInstance1844F58FD', + }); + expect(cluster.instanceEndpoints).toHaveLength(1); + expect(stack.resolve(cluster.instanceEndpoints[0])).toEqual({ + hostname: { + 'Fn::GetAtt': ['DatabaseInstance1844F58FD', 'Endpoint.Address'], + }, + port: { + 'Fn::GetAtt': ['DatabaseB269D8BB', 'Endpoint.Port'], + }, + socketAddress: { + 'Fn::Join': ['', [ + { 'Fn::GetAtt': ['DatabaseInstance1844F58FD', 'Endpoint.Address'] }, + ':', + { 'Fn::GetAtt': ['DatabaseB269D8BB', 'Endpoint.Port'] }, + ]], + }, + }); }); test('can create a cluster with imported vpc and security group', () => { @@ -116,8 +152,6 @@ describe('cluster', () => { MasterUserPassword: 'tooshort', VpcSecurityGroupIds: ['SecurityGroupId12345'], }); - - }); test('cluster with parameter group', () => { @@ -150,8 +184,6 @@ describe('cluster', () => { expect(stack).toHaveResource('AWS::RDS::DBCluster', { DBClusterParameterGroupName: { Ref: 'ParamsA8366201' }, }); - - }); test("sets the retention policy of the SubnetGroup to 'Retain' if the Cluster is created with 'Retain'", () => { @@ -172,8 +204,6 @@ describe('cluster', () => { DeletionPolicy: 'Retain', UpdateReplacePolicy: 'Retain', }, ResourcePart.CompleteDefinition); - - }); test('creates a secret when master credentials are not specified', () => { @@ -230,8 +260,6 @@ describe('cluster', () => { SecretStringTemplate: '{"username":"admin"}', }, }); - - }); test('create an encrypted cluster with custom KMS key', () => { @@ -261,8 +289,6 @@ describe('cluster', () => { ], }, }); - - }); test('cluster with instance parameter group', () => { @@ -294,8 +320,6 @@ describe('cluster', () => { Ref: 'ParameterGroup5E32DECB', }, }); - - }); describe('performance insights', () => { @@ -323,8 +347,6 @@ describe('cluster', () => { PerformanceInsightsRetentionPeriod: 731, PerformanceInsightsKMSKeyId: { 'Fn::GetAtt': ['Key961B73FD', 'Arn'] }, }); - - }); test('setting performance insights fields enables performance insights', () => { @@ -348,8 +370,6 @@ describe('cluster', () => { EnablePerformanceInsights: true, PerformanceInsightsRetentionPeriod: 731, }); - - }); test('throws if performance insights fields are set but performance insights is disabled', () => { @@ -370,8 +390,6 @@ describe('cluster', () => { }, }); }).toThrow(/`enablePerformanceInsights` disabled, but `performanceInsightRetention` or `performanceInsightEncryptionKey` was set/); - - }); }); @@ -392,8 +410,6 @@ describe('cluster', () => { expect(stack).toHaveResource('AWS::RDS::DBInstance', { AutoMinorVersionUpgrade: false, }); - - }); test('cluster with allow upgrade of major version', () => { @@ -413,8 +429,6 @@ describe('cluster', () => { expect(stack).toHaveResourceLike('AWS::RDS::DBInstance', { AllowMajorVersionUpgrade: true, }); - - }); test('cluster with disallow remove backups', () => { @@ -434,8 +448,6 @@ describe('cluster', () => { expect(stack).toHaveResourceLike('AWS::RDS::DBInstance', { DeleteAutomatedBackups: false, }); - - }); test('create a cluster using a specific version of MySQL', () => { @@ -462,8 +474,6 @@ describe('cluster', () => { Engine: 'aurora-mysql', EngineVersion: '5.7.mysql_aurora.2.04.4', }); - - }); test('create a cluster using a specific version of Postgresql', () => { @@ -513,8 +523,6 @@ describe('cluster', () => { // THEN expect(stack.resolve(cluster.clusterEndpoint)).not.toEqual(stack.resolve(cluster.clusterReadEndpoint)); - - }); test('imported cluster with imported security group honors allowAllOutbound', () => { @@ -540,8 +548,6 @@ describe('cluster', () => { expect(stack).toHaveResource('AWS::EC2::SecurityGroupEgress', { GroupId: 'sg-123456789', }); - - }); test('can import a cluster with minimal attributes', () => { @@ -567,8 +573,6 @@ describe('cluster', () => { expect(() => cluster.clusterReadEndpoint).toThrow(/Cannot access `clusterReadEndpoint` of an imported cluster/); expect(() => cluster.instanceIdentifiers).toThrow(/Cannot access `instanceIdentifiers` of an imported cluster/); expect(() => cluster.instanceEndpoints).toThrow(/Cannot access `instanceEndpoints` of an imported cluster/); - - }); test('imported cluster can access properties if attributes are provided', () => { @@ -590,8 +594,6 @@ describe('cluster', () => { expect(cluster.clusterReadEndpoint.socketAddress).toEqual('reader-address:3306'); expect(cluster.instanceIdentifiers).toEqual(['identifier']); expect(cluster.instanceEndpoints.map(endpoint => endpoint.socketAddress)).toEqual(['instance-addr:3306']); - - }); test('cluster supports metrics', () => { @@ -1655,12 +1657,13 @@ describe('cluster', () => { const vpc = new ec2.Vpc(stack, 'VPC'); // WHEN - new DatabaseClusterFromSnapshot(stack, 'Database', { + const cluster = new DatabaseClusterFromSnapshot(stack, 'Database', { engine: DatabaseClusterEngine.aurora({ version: AuroraEngineVersion.VER_1_22_2 }), instanceProps: { vpc, }, snapshotIdentifier: 'mySnapshot', + iamAuthentication: true, }); // THEN @@ -1671,6 +1674,7 @@ describe('cluster', () => { DBSubnetGroupName: { Ref: 'DatabaseSubnets56F17B9A' }, VpcSecurityGroupIds: [{ 'Fn::GetAtt': ['DatabaseSecurityGroup5C91FDCB', 'GroupId'] }], SnapshotIdentifier: 'mySnapshot', + EnableIAMDatabaseAuthentication: true, }, DeletionPolicy: 'Snapshot', UpdateReplacePolicy: 'Snapshot', @@ -1678,7 +1682,27 @@ describe('cluster', () => { expect(stack).toCountResources('AWS::RDS::DBInstance', 2); + expect(cluster.instanceIdentifiers).toHaveLength(2); + expect(stack.resolve(cluster.instanceIdentifiers[0])).toEqual({ + Ref: 'DatabaseInstance1844F58FD', + }); + expect(cluster.instanceEndpoints).toHaveLength(2); + expect(stack.resolve(cluster.instanceEndpoints[0])).toEqual({ + hostname: { + 'Fn::GetAtt': ['DatabaseInstance1844F58FD', 'Endpoint.Address'], + }, + port: { + 'Fn::GetAtt': ['DatabaseB269D8BB', 'Endpoint.Port'], + }, + socketAddress: { + 'Fn::Join': ['', [ + { 'Fn::GetAtt': ['DatabaseInstance1844F58FD', 'Endpoint.Address'] }, + ':', + { 'Fn::GetAtt': ['DatabaseB269D8BB', 'Endpoint.Port'] }, + ]], + }, + }); }); test('reuse an existing subnet group', () => { @@ -1763,6 +1787,52 @@ describe('cluster', () => { }); + test('can set custom name to database secret by fromSecret', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const secretName = 'custom-secret-name'; + const secret = new DatabaseSecret(stack, 'Secret', { + username: 'admin', + secretName, + } ); + + // WHEN + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.aurora({ version: AuroraEngineVersion.VER_1_22_2 }), + credentials: Credentials.fromSecret(secret), + instanceProps: { + vpc, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::SecretsManager::Secret', { + Name: secretName, + }); + }); + + test('can set custom name to database secret by fromGeneratedSecret', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const secretName = 'custom-secret-name'; + + // WHEN + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.aurora({ version: AuroraEngineVersion.VER_1_22_2 }), + credentials: Credentials.fromGeneratedSecret('admin', { secretName }), + instanceProps: { + vpc, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::SecretsManager::Secret', { + Name: secretName, + }); + }); + test('can set public accessibility for database cluster with instances in private subnet', () => { // GIVEN const stack = testStack(); @@ -1836,6 +1906,48 @@ describe('cluster', () => { }); + + test('changes the case of the cluster identifier if the lowercaseDbIdentifier feature flag is enabled', () => { + // GIVEN + const app = new cdk.App({ + context: { [cxapi.RDS_LOWERCASE_DB_IDENTIFIER]: true }, + }); + const stack = testStack(app); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + const clusterIdentifier = 'TestClusterIdentifier'; + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA, + instanceProps: { vpc }, + clusterIdentifier, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::RDS::DBCluster', { + DBClusterIdentifier: clusterIdentifier.toLowerCase(), + }); + }); + + test('does not changes the case of the cluster identifier if the lowercaseDbIdentifier feature flag is disabled', () => { + // GIVEN + const app = new cdk.App({ context: { '@aws-cdk/aws-rds:lowercaseDbIdentifier': false } }); + const stack = testStack(app); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + const clusterIdentifier = 'TestClusterIdentifier'; + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA, + instanceProps: { vpc }, + clusterIdentifier, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::RDS::DBCluster', { + DBClusterIdentifier: clusterIdentifier, + }); + }); }); test.each([ diff --git a/packages/@aws-cdk/aws-rds/test/database-secret.test.ts b/packages/@aws-cdk/aws-rds/test/database-secret.test.ts index 97de0085806e0..c05e07e73a0bb 100644 --- a/packages/@aws-cdk/aws-rds/test/database-secret.test.ts +++ b/packages/@aws-cdk/aws-rds/test/database-secret.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import { CfnResource, Stack } from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import { DatabaseSecret } from '../lib'; diff --git a/packages/@aws-cdk/aws-rds/test/database-secretmanager.test.ts b/packages/@aws-cdk/aws-rds/test/database-secretmanager.test.ts index d307c0f05cec6..8914401e189f6 100644 --- a/packages/@aws-cdk/aws-rds/test/database-secretmanager.test.ts +++ b/packages/@aws-cdk/aws-rds/test/database-secretmanager.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, ResourcePart } from '@aws-cdk/assert'; +import { expect, haveResource, ResourcePart } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-rds/test/instance-engine.test.ts b/packages/@aws-cdk/aws-rds/test/instance-engine.test.ts index 2c9f1fddf8076..830ad0c97bd8e 100644 --- a/packages/@aws-cdk/aws-rds/test/instance-engine.test.ts +++ b/packages/@aws-cdk/aws-rds/test/instance-engine.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; diff --git a/packages/@aws-cdk/aws-rds/test/instance.test.ts b/packages/@aws-cdk/aws-rds/test/instance.test.ts index 497bfbea36c32..883f10b93d2db 100644 --- a/packages/@aws-cdk/aws-rds/test/instance.test.ts +++ b/packages/@aws-cdk/aws-rds/test/instance.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert/jest'; -import { ABSENT, ResourcePart, anything } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +import { ABSENT, ResourcePart, anything } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as targets from '@aws-cdk/aws-events-targets'; import { ManagedPolicy, Role, ServicePrincipal, AccountPrincipal } from '@aws-cdk/aws-iam'; @@ -1204,8 +1204,44 @@ describe('instance', () => { MasterUsername: 'postgres', // username is a string MasterUserPassword: '{{resolve:ssm-secure:/dbPassword:1}}', // reference to SSM }); + }); + + test('can set custom name to database secret by fromSecret', () => { + // WHEN + const secretName = 'custom-secret-name'; + const secret = new rds.DatabaseSecret(stack, 'Secret', { + username: 'admin', + secretName, + } ); + new rds.DatabaseInstance(stack, 'Instance', { + engine: rds.DatabaseInstanceEngine.mysql({ + version: rds.MysqlEngineVersion.VER_8_0_19, + }), + credentials: rds.Credentials.fromSecret(secret), + vpc, + }); + // THEN + expect(stack).toHaveResourceLike('AWS::SecretsManager::Secret', { + Name: secretName, + }); + }); + + test('can set custom name to database secret by fromGeneratedSecret', () => { + // WHEN + const secretName = 'custom-secret-name'; + new rds.DatabaseInstance(stack, 'Instance', { + engine: rds.DatabaseInstanceEngine.mysql({ + version: rds.MysqlEngineVersion.VER_8_0_19, + }), + credentials: rds.Credentials.fromGeneratedSecret('admin', { secretName }), + vpc, + }); + // THEN + expect(stack).toHaveResourceLike('AWS::SecretsManager::Secret', { + Name: secretName, + }); }); test('can set publiclyAccessible to false with public subnets', () => { @@ -1243,6 +1279,53 @@ describe('instance', () => { PubliclyAccessible: true, }); }); + + test('changes the case of the cluster identifier if the lowercaseDbIdentifier feature flag is enabled', () => { + // GIVEN + const app = new cdk.App({ + context: { [cxapi.RDS_LOWERCASE_DB_IDENTIFIER]: true }, + }); + stack = new cdk.Stack( app ); + vpc = new ec2.Vpc( stack, 'VPC' ); + + // WHEN + const instanceIdentifier = 'TestInstanceIdentifier'; + new rds.DatabaseInstance( stack, 'DB', { + engine: rds.DatabaseInstanceEngine.mysql({ + version: rds.MysqlEngineVersion.VER_8_0_19, + }), + vpc, + instanceIdentifier, + } ); + + // THEN + expect(stack).toHaveResource('AWS::RDS::DBInstance', { + DBInstanceIdentifier: instanceIdentifier.toLowerCase(), + }); + }); + + test( 'does not changes the case of the cluster identifier if the lowercaseDbIdentifier feature flag is disabled', () => { + // GIVEN + const app = new cdk.App({ context: { '@aws-cdk/aws-rds:lowercaseDbIdentifier': false } }); + stack = new cdk.Stack(app); + vpc = new ec2.Vpc( stack, 'VPC' ); + + // WHEN + const instanceIdentifier = 'TestInstanceIdentifier'; + new rds.DatabaseInstance( stack, 'DB', { + engine: rds.DatabaseInstanceEngine.mysql({ + version: rds.MysqlEngineVersion.VER_8_0_19, + }), + vpc, + instanceIdentifier, + } ); + + // THEN + expect(stack).toHaveResource('AWS::RDS::DBInstance', { + DBInstanceIdentifier: instanceIdentifier, + }); + }); + }); test.each([ @@ -1274,4 +1357,49 @@ test.each([ DeletionPolicy: subnetValue, UpdateReplacePolicy: subnetValue, }, ResourcePart.CompleteDefinition); -}); \ No newline at end of file +}); + +describe('cross-account instance', () => { + test.each([ + ['MyInstance', 'MyInstance', 'myinstance'], + ['PhysicalName.GENERATE_IF_NEEDED', cdk.PhysicalName.GENERATE_IF_NEEDED, 'instancestackncestackinstancec830ba83756a6dfc7154'], + ])("with database identifier '%s' can be referenced from a Stack in a different account", (_, providedInstanceId, expectedInstanceId) => { + const app = new cdk.App(); + const instanceStack = new cdk.Stack(app, 'InstanceStack', { + env: { account: '123', region: 'my-region' }, + }); + const instance = new rds.DatabaseInstance(instanceStack, 'Instance', { + vpc: new ec2.Vpc(instanceStack, 'Vpc'), + engine: rds.DatabaseInstanceEngine.mariaDb({ version: rds.MariaDbEngineVersion.VER_10_5 }), + // physical name set + instanceIdentifier: providedInstanceId, + }); + + const outputStack = new cdk.Stack(app, 'OutputStack', { + env: { account: '456', region: 'my-region' }, + }); + new cdk.CfnOutput(outputStack, 'DatabaseInstanceArn', { + value: instance.instanceArn, + }); + new cdk.CfnOutput(outputStack, 'DatabaseInstanceName', { + value: instance.instanceIdentifier, + }); + + expect(outputStack).toMatchTemplate({ + Outputs: { + DatabaseInstanceArn: { + Value: { + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + `:rds:my-region:123:db:${expectedInstanceId}`, + ]], + }, + }, + DatabaseInstanceName: { + Value: expectedInstanceId, + }, + }, + }); + }); +}); diff --git a/packages/@aws-cdk/aws-rds/test/integ.serverless-cluster.expected.json b/packages/@aws-cdk/aws-rds/test/integ.serverless-cluster.expected.json index 752eae1b22894..bf73e45641f66 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.serverless-cluster.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.serverless-cluster.expected.json @@ -355,10 +355,10 @@ } } }, - "ServerlessDatabaseSubnetsB39719DC": { + "SubnetGroup": { "Type": "AWS::RDS::DBSubnetGroup", "Properties": { - "DBSubnetGroupDescription": "Subnets for Serverless Database database", + "DBSubnetGroupDescription": "My Subnet Group", "SubnetIds": [ { "Ref": "VPCPublicSubnet1SubnetB4246D30" @@ -366,7 +366,8 @@ { "Ref": "VPCPublicSubnet2Subnet74179F39" } - ] + ], + "DBSubnetGroupName": "mynotlowercasesubnetgroupname" } }, "ServerlessDatabaseSecurityGroup1E143FBB": { @@ -417,7 +418,7 @@ "Engine": "aurora-mysql", "DBClusterParameterGroupName": "default.aurora-mysql5.7", "DBSubnetGroupName": { - "Ref": "ServerlessDatabaseSubnetsB39719DC" + "Ref": "SubnetGroup" }, "EngineMode": "serverless", "MasterUsername": "admin", @@ -432,8 +433,8 @@ } ] }, - "UpdateReplacePolicy": "Snapshot", - "DeletionPolicy": "Snapshot" + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/test/integ.serverless-cluster.ts b/packages/@aws-cdk/aws-rds/test/integ.serverless-cluster.ts index d6ae6b8dad980..cb268f4d08667 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.serverless-cluster.ts +++ b/packages/@aws-cdk/aws-rds/test/integ.serverless-cluster.ts @@ -1,6 +1,6 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; -import { DatabaseClusterEngine, ServerlessCluster } from '../lib'; +import * as rds from '../lib'; const app = new cdk.App(); const stack = new cdk.Stack(app, 'aws-cdk-rds-integ'); @@ -8,17 +8,24 @@ const stack = new cdk.Stack(app, 'aws-cdk-rds-integ'); const vpc = new ec2.Vpc(stack, 'VPC', { maxAzs: 2, }); +const subnetGroup = new rds.SubnetGroup(stack, 'SubnetGroup', { + vpc, + vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC }, + description: 'My Subnet Group', + subnetGroupName: 'MyNotLowerCaseSubnetGroupName', +}); -const cluster = new ServerlessCluster(stack, 'Serverless Database', { - engine: DatabaseClusterEngine.AURORA_MYSQL, +const cluster = new rds.ServerlessCluster(stack, 'Serverless Database', { + engine: rds.DatabaseClusterEngine.AURORA_MYSQL, credentials: { username: 'admin', password: cdk.SecretValue.plainText('7959866cacc02c2d243ecfe177464fe6'), }, vpc, vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC }, + subnetGroup, + removalPolicy: cdk.RemovalPolicy.DESTROY, }); - cluster.connections.allowDefaultPortFromAnyIpv4('Open to the world'); app.synth(); diff --git a/packages/@aws-cdk/aws-rds/test/option-group.test.ts b/packages/@aws-cdk/aws-rds/test/option-group.test.ts index b7c6cc851874c..2a058411a72ab 100644 --- a/packages/@aws-cdk/aws-rds/test/option-group.test.ts +++ b/packages/@aws-cdk/aws-rds/test/option-group.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; diff --git a/packages/@aws-cdk/aws-rds/test/parameter-group.test.ts b/packages/@aws-cdk/aws-rds/test/parameter-group.test.ts index 0f9fd73f44e8c..aedfe0a005da6 100644 --- a/packages/@aws-cdk/aws-rds/test/parameter-group.test.ts +++ b/packages/@aws-cdk/aws-rds/test/parameter-group.test.ts @@ -1,4 +1,4 @@ -import { countResources, expect, haveResource } from '@aws-cdk/assert'; +import { countResources, expect, haveResource } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import { DatabaseClusterEngine, ParameterGroup } from '../lib'; diff --git a/packages/@aws-cdk/aws-rds/test/proxy.test.ts b/packages/@aws-cdk/aws-rds/test/proxy.test.ts index a0835879b5d79..5a4a2c2606959 100644 --- a/packages/@aws-cdk/aws-rds/test/proxy.test.ts +++ b/packages/@aws-cdk/aws-rds/test/proxy.test.ts @@ -1,4 +1,4 @@ -import { ABSENT, expect, haveResourceLike, ResourcePart } from '@aws-cdk/assert'; +import { ABSENT, expect, haveResourceLike, ResourcePart } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import { AccountPrincipal, Role } from '@aws-cdk/aws-iam'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; diff --git a/packages/@aws-cdk/aws-rds/test/serverless-cluster.test.ts b/packages/@aws-cdk/aws-rds/test/serverless-cluster.test.ts index e370ff915cb6c..ba157ef9aa6b1 100644 --- a/packages/@aws-cdk/aws-rds/test/serverless-cluster.test.ts +++ b/packages/@aws-cdk/aws-rds/test/serverless-cluster.test.ts @@ -1,8 +1,9 @@ -import { expect, haveResource, haveResourceLike, ResourcePart, SynthUtils } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike, ResourcePart, SynthUtils } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as cdk from '@aws-cdk/core'; +import * as cxapi from '@aws-cdk/cx-api'; import { nodeunitShim, Test } from 'nodeunit-shim'; import { AuroraPostgresEngineVersion, ServerlessCluster, DatabaseClusterEngine, ParameterGroup, AuroraCapacityUnit, DatabaseSecret } from '../lib'; @@ -818,11 +819,56 @@ nodeunitShim({ test.done(); }, -}); + 'changes the case of the cluster identifier if the lowercaseDbIdentifier feature flag is enabled'(test: Test) { + // GIVEN + const app = new cdk.App({ + context: { [cxapi.RDS_LOWERCASE_DB_IDENTIFIER]: true }, + }); + const stack = testStack(app); + const clusterIdentifier = 'TestClusterIdentifier'; + const vpc = ec2.Vpc.fromLookup(stack, 'VPC', { isDefault: true }); + + // WHEN + new ServerlessCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA_MYSQL, + vpc, + clusterIdentifier, + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::RDS::DBCluster', { + DBClusterIdentifier: clusterIdentifier.toLowerCase(), + })); + + test.done(); + }, + + 'does not change the case of the cluster identifier if the lowercaseDbIdentifier feature flag is disabled'(test: Test) { + // GIVEN + const app = new cdk.App({ context: { '@aws-cdk/aws-rds:lowercaseDbIdentifier': false } }); + const stack = testStack(app); + const clusterIdentifier = 'TestClusterIdentifier'; + const vpc = ec2.Vpc.fromLookup(stack, 'VPC', { isDefault: true }); + + // WHEN + new ServerlessCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA_MYSQL, + vpc, + clusterIdentifier, + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::RDS::DBCluster', { + DBClusterIdentifier: clusterIdentifier, + })); + + test.done(); + }, +}); -function testStack() { - const stack = new cdk.Stack(undefined, undefined, { env: { account: '12345', region: 'us-test-1' } }); +function testStack(app?: cdk.App, id?: string): cdk.Stack { + const stack = new cdk.Stack(app, id, { env: { account: '12345', region: 'us-test-1' } }); stack.node.setContext('availability-zones:12345:us-test-1', ['us-test-1a', 'us-test-1b']); return stack; } diff --git a/packages/@aws-cdk/aws-rds/test/sql-server/sql-server.instance-engine.test.ts b/packages/@aws-cdk/aws-rds/test/sql-server/sql-server.instance-engine.test.ts index 4255298f87d10..fb815c95ebee6 100644 --- a/packages/@aws-cdk/aws-rds/test/sql-server/sql-server.instance-engine.test.ts +++ b/packages/@aws-cdk/aws-rds/test/sql-server/sql-server.instance-engine.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; import * as core from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import * as rds from '../../lib'; diff --git a/packages/@aws-cdk/aws-rds/test/subnet-group.test.ts b/packages/@aws-cdk/aws-rds/test/subnet-group.test.ts index c6c16add591ce..565c10c6b6d92 100644 --- a/packages/@aws-cdk/aws-rds/test/subnet-group.test.ts +++ b/packages/@aws-cdk/aws-rds/test/subnet-group.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; @@ -41,7 +41,7 @@ nodeunitShim({ expect(stack).to(haveResource('AWS::RDS::DBSubnetGroup', { DBSubnetGroupDescription: 'My Shared Group', - DBSubnetGroupName: 'SharedGroup', + DBSubnetGroupName: 'sharedgroup', SubnetIds: [ { Ref: 'VPCPrivateSubnet1Subnet8BCA10E0' }, { Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A' }, @@ -51,6 +51,24 @@ nodeunitShim({ test.done(); }, + 'correctly creates a subnet group with a deploy-time value for its name'(test: Test) { + const parameter = new cdk.CfnParameter(stack, 'Parameter'); + new rds.SubnetGroup(stack, 'Group', { + description: 'My Shared Group', + subnetGroupName: parameter.valueAsString, + vpc, + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE }, + }); + + expect(stack).to(haveResourceLike('AWS::RDS::DBSubnetGroup', { + DBSubnetGroupName: { + Ref: 'Parameter', + }, + })); + + test.done(); + }, + 'subnet selection': { 'defaults to private subnets'(test: Test) { new rds.SubnetGroup(stack, 'Group', { diff --git a/packages/@aws-cdk/aws-redshift/package.json b/packages/@aws-cdk/aws-redshift/package.json index cede50f836f54..2be4205d5afe8 100644 --- a/packages/@aws-cdk/aws-redshift/package.json +++ b/packages/@aws-cdk/aws-redshift/package.json @@ -71,11 +71,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", @@ -84,7 +85,7 @@ "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -94,7 +95,7 @@ "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-redshift/test/cluster.test.ts b/packages/@aws-cdk/aws-redshift/test/cluster.test.ts index bb6c966fed284..7731320e8756c 100644 --- a/packages/@aws-cdk/aws-redshift/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-redshift/test/cluster.test.ts @@ -1,5 +1,5 @@ -import { ABSENT, expect as cdkExpect, haveResource, ResourcePart } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { ABSENT, expect as cdkExpect, haveResource, ResourcePart } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as kms from '@aws-cdk/aws-kms'; import * as s3 from '@aws-cdk/aws-s3'; diff --git a/packages/@aws-cdk/aws-redshift/test/parameter-group.test.ts b/packages/@aws-cdk/aws-redshift/test/parameter-group.test.ts index ca5923ee36ba6..c49708b8eb557 100644 --- a/packages/@aws-cdk/aws-redshift/test/parameter-group.test.ts +++ b/packages/@aws-cdk/aws-redshift/test/parameter-group.test.ts @@ -1,4 +1,4 @@ -import { expect as cdkExpect, haveResource } from '@aws-cdk/assert'; +import { expect as cdkExpect, haveResource } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { ClusterParameterGroup } from '../lib'; diff --git a/packages/@aws-cdk/aws-redshift/test/subnet-group.test.ts b/packages/@aws-cdk/aws-redshift/test/subnet-group.test.ts index f2e68491c635d..c27a4998ce76e 100644 --- a/packages/@aws-cdk/aws-redshift/test/subnet-group.test.ts +++ b/packages/@aws-cdk/aws-redshift/test/subnet-group.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import { Stack } from '@aws-cdk/core'; import { ClusterSubnetGroup } from '../lib'; diff --git a/packages/@aws-cdk/aws-resourcegroups/package.json b/packages/@aws-cdk/aws-resourcegroups/package.json index bd1848d6681e9..b93e2693d95cd 100644 --- a/packages/@aws-cdk/aws-resourcegroups/package.json +++ b/packages/@aws-cdk/aws-resourcegroups/package.json @@ -73,10 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-resourcegroups/test/resourcegroups.test.ts b/packages/@aws-cdk/aws-resourcegroups/test/resourcegroups.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-resourcegroups/test/resourcegroups.test.ts +++ b/packages/@aws-cdk/aws-resourcegroups/test/resourcegroups.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-robomaker/package.json b/packages/@aws-cdk/aws-robomaker/package.json index be52d60f6a739..1e3ca117d60e9 100644 --- a/packages/@aws-cdk/aws-robomaker/package.json +++ b/packages/@aws-cdk/aws-robomaker/package.json @@ -73,18 +73,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-robomaker/test/robomaker.test.ts b/packages/@aws-cdk/aws-robomaker/test/robomaker.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-robomaker/test/robomaker.test.ts +++ b/packages/@aws-cdk/aws-robomaker/test/robomaker.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-route53-patterns/package.json b/packages/@aws-cdk/aws-route53-patterns/package.json index b10d3e4ceb714..0dc548943032b 100644 --- a/packages/@aws-cdk/aws-route53-patterns/package.json +++ b/packages/@aws-cdk/aws-route53-patterns/package.json @@ -63,12 +63,13 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", @@ -79,7 +80,7 @@ "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/region-info": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -91,7 +92,7 @@ "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/region-info": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-route53-patterns/test/bucket-website-target.test.ts b/packages/@aws-cdk/aws-route53-patterns/test/bucket-website-target.test.ts index 4dc591a92bc12..a0046ab98d286 100644 --- a/packages/@aws-cdk/aws-route53-patterns/test/bucket-website-target.test.ts +++ b/packages/@aws-cdk/aws-route53-patterns/test/bucket-website-target.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Certificate } from '@aws-cdk/aws-certificatemanager'; import { HostedZone } from '@aws-cdk/aws-route53'; import { App, Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-route53-targets/README.md b/packages/@aws-cdk/aws-route53-targets/README.md index ba9f1ea7e4831..6ab9c8822cae9 100644 --- a/packages/@aws-cdk/aws-route53-targets/README.md +++ b/packages/@aws-cdk/aws-route53-targets/README.md @@ -24,9 +24,10 @@ This library contains Route53 Alias Record targets for: * API Gateway V2 custom domains ```ts + new route53.ARecord(this, 'AliasRecord', { zone, - target: route53.RecordTarget.fromAlias(new alias.ApiGatewayv2Domain(domainName)), + target: route53.RecordTarget.fromAlias(new alias.ApiGatewayv2DomainProperties(domainName.regionalDomainName, domainName.regionalHostedZoneId)), }); ``` diff --git a/packages/@aws-cdk/aws-route53-targets/lib/api-gatewayv2-domain-name.ts b/packages/@aws-cdk/aws-route53-targets/lib/api-gatewayv2-domain-name.ts index b78078fca525a..6aea6f72de59e 100644 --- a/packages/@aws-cdk/aws-route53-targets/lib/api-gatewayv2-domain-name.ts +++ b/packages/@aws-cdk/aws-route53-targets/lib/api-gatewayv2-domain-name.ts @@ -1,16 +1,19 @@ -import * as apigv2 from '@aws-cdk/aws-apigatewayv2'; import * as route53 from '@aws-cdk/aws-route53'; /** * Defines an API Gateway V2 domain name as the alias target. */ -export class ApiGatewayv2Domain implements route53.IAliasRecordTarget { - constructor(private readonly domainName: apigv2.IDomainName) { } +export class ApiGatewayv2DomainProperties implements route53.IAliasRecordTarget { + /** + * @param regionalDomainName the domain name associated with the regional endpoint for this custom domain name. + * @param regionalHostedZoneId the region-specific Amazon Route 53 Hosted Zone ID of the regional endpoint. + */ + constructor(private readonly regionalDomainName: string, private readonly regionalHostedZoneId: string) { } public bind(_record: route53.IRecordSet): route53.AliasRecordTargetConfig { return { - dnsName: this.domainName.regionalDomainName, - hostedZoneId: this.domainName.regionalHostedZoneId, + dnsName: this.regionalDomainName, + hostedZoneId: this.regionalHostedZoneId, }; } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-route53-targets/package.json b/packages/@aws-cdk/aws-route53-targets/package.json index d98999baaab6a..d7014a4e26151 100644 --- a/packages/@aws-cdk/aws-route53-targets/package.json +++ b/packages/@aws-cdk/aws-route53-targets/package.json @@ -62,18 +62,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "@aws-cdk/aws-certificatemanager": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/aws-apigatewayv2": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-apigateway": "0.0.0", - "@aws-cdk/aws-apigatewayv2": "0.0.0", "@aws-cdk/aws-cloudfront": "0.0.0", "@aws-cdk/aws-cognito": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", @@ -85,12 +86,11 @@ "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/region-info": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/aws-apigateway": "0.0.0", - "@aws-cdk/aws-apigatewayv2": "0.0.0", "@aws-cdk/aws-cloudfront": "0.0.0", "@aws-cdk/aws-cognito": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", @@ -102,7 +102,7 @@ "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/region-info": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-route53-targets/test/apigateway-target.test.ts b/packages/@aws-cdk/aws-route53-targets/test/apigateway-target.test.ts index a3762e9b27189..e62c87b59c385 100644 --- a/packages/@aws-cdk/aws-route53-targets/test/apigateway-target.test.ts +++ b/packages/@aws-cdk/aws-route53-targets/test/apigateway-target.test.ts @@ -1,4 +1,4 @@ -import { expect as expectStack, haveResource } from '@aws-cdk/assert'; +import { expect as expectStack, haveResource } from '@aws-cdk/assert-internal'; import * as apigw from '@aws-cdk/aws-apigateway'; import * as acm from '@aws-cdk/aws-certificatemanager'; import * as route53 from '@aws-cdk/aws-route53'; diff --git a/packages/@aws-cdk/aws-route53-targets/test/apigatewayv2-target.test.ts b/packages/@aws-cdk/aws-route53-targets/test/apigatewayv2-target.test.ts index 66a504f630157..d2a66e41bde26 100644 --- a/packages/@aws-cdk/aws-route53-targets/test/apigatewayv2-target.test.ts +++ b/packages/@aws-cdk/aws-route53-targets/test/apigatewayv2-target.test.ts @@ -1,4 +1,4 @@ -import { expect as expectStack, haveResource } from '@aws-cdk/assert'; +import { expect as expectStack, haveResource } from '@aws-cdk/assert-internal'; import * as apigwv2 from '@aws-cdk/aws-apigatewayv2'; import * as acm from '@aws-cdk/aws-certificatemanager'; import * as route53 from '@aws-cdk/aws-route53'; @@ -8,10 +8,10 @@ import * as targets from '../lib'; test('targets.ApiGatewayv2Domain can be used to directly reference a domain', () => { // GIVEN const stack = new Stack(); - const domainName = 'example.com'; - const cert = new acm.Certificate(stack, 'cert', { domainName }); - const dn = new apigwv2.DomainName(stack, 'DN', { - domainName, + const name = 'example.com'; + const cert = new acm.Certificate(stack, 'cert', { domainName: name }); + const domainName = new apigwv2.DomainName(stack, 'DN', { + domainName: name, certificate: cert, }); const zone = new route53.HostedZone(stack, 'zone', { @@ -21,7 +21,7 @@ test('targets.ApiGatewayv2Domain can be used to directly reference a domain', () // WHEN new route53.ARecord(stack, 'A', { zone, - target: route53.RecordTarget.fromAlias(new targets.ApiGatewayv2Domain(dn)), + target: route53.RecordTarget.fromAlias(new targets.ApiGatewayv2DomainProperties(domainName.regionalDomainName, domainName.regionalHostedZoneId)), }); // THEN diff --git a/packages/@aws-cdk/aws-route53-targets/test/bucket-website-target.test.ts b/packages/@aws-cdk/aws-route53-targets/test/bucket-website-target.test.ts index 67b122dfa061a..eebb53b2d488a 100644 --- a/packages/@aws-cdk/aws-route53-targets/test/bucket-website-target.test.ts +++ b/packages/@aws-cdk/aws-route53-targets/test/bucket-website-target.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as route53 from '@aws-cdk/aws-route53'; import * as s3 from '@aws-cdk/aws-s3'; import { App, Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-route53-targets/test/classic-load-balancer-target.test.ts b/packages/@aws-cdk/aws-route53-targets/test/classic-load-balancer-target.test.ts index 728578ede7f7a..a89e1f194b1a6 100644 --- a/packages/@aws-cdk/aws-route53-targets/test/classic-load-balancer-target.test.ts +++ b/packages/@aws-cdk/aws-route53-targets/test/classic-load-balancer-target.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elb from '@aws-cdk/aws-elasticloadbalancing'; import * as route53 from '@aws-cdk/aws-route53'; diff --git a/packages/@aws-cdk/aws-route53-targets/test/cloudfront-target.test.ts b/packages/@aws-cdk/aws-route53-targets/test/cloudfront-target.test.ts index c4cd3deb9eac1..646547cb76bda 100644 --- a/packages/@aws-cdk/aws-route53-targets/test/cloudfront-target.test.ts +++ b/packages/@aws-cdk/aws-route53-targets/test/cloudfront-target.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert/jest'; -import { SynthUtils } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +import { SynthUtils } from '@aws-cdk/assert-internal'; import * as cloudfront from '@aws-cdk/aws-cloudfront'; import * as route53 from '@aws-cdk/aws-route53'; import * as s3 from '@aws-cdk/aws-s3'; diff --git a/packages/@aws-cdk/aws-route53-targets/test/global-accelerator-target.test.ts b/packages/@aws-cdk/aws-route53-targets/test/global-accelerator-target.test.ts index 07db27b92940e..e39862e280951 100644 --- a/packages/@aws-cdk/aws-route53-targets/test/global-accelerator-target.test.ts +++ b/packages/@aws-cdk/aws-route53-targets/test/global-accelerator-target.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as globalaccelerator from '@aws-cdk/aws-globalaccelerator'; import * as route53 from '@aws-cdk/aws-route53'; import { Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-route53-targets/test/interface-vpc-endpoint-target.test.ts b/packages/@aws-cdk/aws-route53-targets/test/interface-vpc-endpoint-target.test.ts index 7bf948e6cfdc9..bd13011e4700d 100644 --- a/packages/@aws-cdk/aws-route53-targets/test/interface-vpc-endpoint-target.test.ts +++ b/packages/@aws-cdk/aws-route53-targets/test/interface-vpc-endpoint-target.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as route53 from '@aws-cdk/aws-route53'; import { Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-route53-targets/test/load-balancer-target.test.ts b/packages/@aws-cdk/aws-route53-targets/test/load-balancer-target.test.ts index 83d069604d36d..d16592d3ec183 100644 --- a/packages/@aws-cdk/aws-route53-targets/test/load-balancer-target.test.ts +++ b/packages/@aws-cdk/aws-route53-targets/test/load-balancer-target.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import * as route53 from '@aws-cdk/aws-route53'; diff --git a/packages/@aws-cdk/aws-route53-targets/test/userpool-domain.test.ts b/packages/@aws-cdk/aws-route53-targets/test/userpool-domain.test.ts index 8b211eddd1cb5..8badcaed9c047 100644 --- a/packages/@aws-cdk/aws-route53-targets/test/userpool-domain.test.ts +++ b/packages/@aws-cdk/aws-route53-targets/test/userpool-domain.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { UserPool, UserPoolDomain } from '@aws-cdk/aws-cognito'; import { ARecord, PublicHostedZone, RecordTarget } from '@aws-cdk/aws-route53'; import { Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-route53/README.md b/packages/@aws-cdk/aws-route53/README.md index 9f36aa7f58765..1c4affa83e3a0 100644 --- a/packages/@aws-cdk/aws-route53/README.md +++ b/packages/@aws-cdk/aws-route53/README.md @@ -60,6 +60,22 @@ new route53.TxtRecord(this, 'TXTRecord', { }); ``` +To add a NS record to your zone: + +```ts +import * as route53 from '@aws-cdk/aws-route53'; + +new route53.NsRecord(this, 'NSRecord', { + zone: myZone, + recordName: 'foo', + values: [ + 'ns-1.awsdns.co.uk.', + 'ns-2.awsdns.com.' + ], + ttl: Duration.minutes(90), // Optional - default is 30 minutes +}); +``` + To add an A record to your zone: ```ts @@ -109,26 +125,45 @@ Constructs are available for A, AAAA, CAA, CNAME, MX, NS, SRV and TXT records. Use the `CaaAmazonRecord` construct to easily restrict certificate authorities allowed to issue certificates for a domain to Amazon only. -To add a NS record to a HostedZone in different account +To add a NS record to a HostedZone in different account you can do the following: + +In the account containing the parent hosted zone: ```ts import * as route53 from '@aws-cdk/aws-route53'; -// In the account containing the HostedZone const parentZone = new route53.PublicHostedZone(this, 'HostedZone', { zoneName: 'someexample.com', - crossAccountZoneDelegationPrincipal: new iam.AccountPrincipal('12345678901') + crossAccountZoneDelegationPrincipal: new iam.AccountPrincipal('12345678901'), + crossAccountZoneDelegationRoleName: 'MyDelegationRole', }); +``` + +In the account containing the child zone to be delegated: + +```ts +import * as iam from '@aws-cdk/aws-iam'; +import * as route53 from '@aws-cdk/aws-route53'; -// In this account const subZone = new route53.PublicHostedZone(this, 'SubZone', { zoneName: 'sub.someexample.com' }); +// import the delegation role by constructing the roleArn +const delegationRoleArn = Stack.of(this).formatArn({ + region: '', // IAM is global in each partition + service: 'iam', + account: 'parent-account-id', + resource: 'role', + resourceName: 'MyDelegationRole', +}); +const delegationRole = iam.Role.fromRoleArn(this, 'DelegationRole', delegationRoleArn); + +// create the record new route53.CrossAccountZoneDelegationRecord(this, 'delegate', { delegatedZone: subZone, - parentHostedZoneId: parentZone.hostedZoneId, - delegationRole: parentZone.crossAccountDelegationRole + parentHostedZoneName: 'someexample.com', // or you can use parentHostedZoneId + delegationRole, }); ``` diff --git a/packages/@aws-cdk/aws-route53/lib/cross-account-zone-delegation-handler/index.ts b/packages/@aws-cdk/aws-route53/lib/cross-account-zone-delegation-handler/index.ts index 3c711d283d7e5..62c3e957d1ff4 100644 --- a/packages/@aws-cdk/aws-route53/lib/cross-account-zone-delegation-handler/index.ts +++ b/packages/@aws-cdk/aws-route53/lib/cross-account-zone-delegation-handler/index.ts @@ -3,7 +3,8 @@ import { Credentials, Route53, STS } from 'aws-sdk'; interface ResourceProperties { AssumeRoleArn: string, - ParentZoneId: string, + ParentZoneName?: string, + ParentZoneId?: string, DelegatedZoneName: string, DelegatedZoneNameServers: string[], TTL: number, @@ -22,13 +23,19 @@ export async function handler(event: AWSLambda.CloudFormationCustomResourceEvent } async function cfnEventHandler(props: ResourceProperties, isDeleteEvent: boolean) { - const { AssumeRoleArn, ParentZoneId, DelegatedZoneName, DelegatedZoneNameServers, TTL } = props; + const { AssumeRoleArn, ParentZoneId, ParentZoneName, DelegatedZoneName, DelegatedZoneNameServers, TTL } = props; + + if (!ParentZoneId && !ParentZoneName) { + throw Error('One of ParentZoneId or ParentZoneName must be specified'); + } const credentials = await getCrossAccountCredentials(AssumeRoleArn); const route53 = new Route53({ credentials }); + const parentZoneId = ParentZoneId ?? await getHostedZoneIdByName(ParentZoneName!, route53); + await route53.changeResourceRecordSets({ - HostedZoneId: ParentZoneId, + HostedZoneId: parentZoneId, ChangeBatch: { Changes: [{ Action: isDeleteEvent ? 'DELETE' : 'UPSERT', @@ -64,3 +71,14 @@ async function getCrossAccountCredentials(roleArn: string): Promise sessionToken: assumedCredentials.SessionToken, }); } + +async function getHostedZoneIdByName(name: string, route53: Route53): Promise { + const zones = await route53.listHostedZonesByName({ DNSName: name }).promise(); + const matchedZones = zones.HostedZones.filter(zone => zone.Name === `${name}.`); + + if (matchedZones.length !== 1) { + throw Error(`Expected one hosted zone to match the given name but found ${matchedZones.length}`); + } + + return matchedZones[0].Id; +} diff --git a/packages/@aws-cdk/aws-route53/lib/hosted-zone.ts b/packages/@aws-cdk/aws-route53/lib/hosted-zone.ts index 1ca835cb258d9..e426d619fe044 100644 --- a/packages/@aws-cdk/aws-route53/lib/hosted-zone.ts +++ b/packages/@aws-cdk/aws-route53/lib/hosted-zone.ts @@ -198,6 +198,13 @@ export interface PublicHostedZoneProps extends CommonHostedZoneProps { * @default - No delegation configuration */ readonly crossAccountZoneDelegationPrincipal?: iam.IPrincipal; + + /** + * The name of the role created for cross account delegation + * + * @default - A role name is generated automatically + */ + readonly crossAccountZoneDelegationRoleName?: string; } /** @@ -244,8 +251,13 @@ export class PublicHostedZone extends HostedZone implements IPublicHostedZone { }); } + if (!props.crossAccountZoneDelegationPrincipal && props.crossAccountZoneDelegationRoleName) { + throw Error('crossAccountZoneDelegationRoleName property is not supported without crossAccountZoneDelegationPrincipal'); + } + if (props.crossAccountZoneDelegationPrincipal) { this.crossAccountZoneDelegationRole = new iam.Role(this, 'CrossAccountZoneDelegationRole', { + roleName: props.crossAccountZoneDelegationRoleName, assumedBy: props.crossAccountZoneDelegationPrincipal, inlinePolicies: { delegation: new iam.PolicyDocument({ @@ -254,6 +266,10 @@ export class PublicHostedZone extends HostedZone implements IPublicHostedZone { actions: ['route53:ChangeResourceRecordSets'], resources: [this.hostedZoneArn], }), + new iam.PolicyStatement({ + actions: ['route53:ListHostedZonesByName'], + resources: ['*'], + }), ], }), }, diff --git a/packages/@aws-cdk/aws-route53/lib/record-set.ts b/packages/@aws-cdk/aws-route53/lib/record-set.ts index a86195f1d0055..57f93931c2097 100644 --- a/packages/@aws-cdk/aws-route53/lib/record-set.ts +++ b/packages/@aws-cdk/aws-route53/lib/record-set.ts @@ -212,7 +212,7 @@ export class RecordSet extends Resource implements IRecordSet { constructor(scope: Construct, id: string, props: RecordSetProps) { super(scope, id); - const ttl = props.target.aliasTarget ? undefined : ((props.ttl && props.ttl.toSeconds()) || 1800).toString(); + const ttl = props.target.aliasTarget ? undefined : ((props.ttl && props.ttl.toSeconds()) ?? 1800).toString(); const recordSet = new CfnRecordSet(this, 'Resource', { hostedZoneId: props.zone.hostedZoneId, @@ -541,6 +541,31 @@ export class MxRecord extends RecordSet { } } +/** + * Construction properties for a NSRecord. + */ +export interface NsRecordProps extends RecordSetOptions { + /** + * The NS values. + */ + readonly values: string[]; +} + +/** + * A DNS NS record + * + * @resource AWS::Route53::RecordSet + */ +export class NsRecord extends RecordSet { + constructor(scope: Construct, id: string, props: NsRecordProps) { + super(scope, id, { + ...props, + recordType: RecordType.NS, + target: RecordTarget.fromValues(...props.values), + }); + } +} + /** * Construction properties for a ZoneDelegationRecord */ @@ -577,10 +602,19 @@ export interface CrossAccountZoneDelegationRecordProps { */ readonly delegatedZone: IHostedZone; + /** + * The hosted zone name in the parent account + * + * @default - no zone name + */ + readonly parentHostedZoneName?: string; + /** * The hosted zone id in the parent account + * + * @default - no zone id */ - readonly parentHostedZoneId: string; + readonly parentHostedZoneId?: string; /** * The delegation role in the parent account @@ -602,6 +636,14 @@ export class CrossAccountZoneDelegationRecord extends CoreConstruct { constructor(scope: Construct, id: string, props: CrossAccountZoneDelegationRecordProps) { super(scope, id); + if (!props.parentHostedZoneName && !props.parentHostedZoneId) { + throw Error('At least one of parentHostedZoneName or parentHostedZoneId is required'); + } + + if (props.parentHostedZoneName && props.parentHostedZoneId) { + throw Error('Only one of parentHostedZoneName and parentHostedZoneId is supported'); + } + const serviceToken = CustomResourceProvider.getOrCreate(this, CROSS_ACCOUNT_ZONE_DELEGATION_RESOURCE_TYPE, { codeDirectory: path.join(__dirname, 'cross-account-zone-delegation-handler'), runtime: CustomResourceProviderRuntime.NODEJS_12_X, @@ -613,6 +655,7 @@ export class CrossAccountZoneDelegationRecord extends CoreConstruct { serviceToken, properties: { AssumeRoleArn: props.delegationRole.roleArn, + ParentZoneName: props.parentHostedZoneName, ParentZoneId: props.parentHostedZoneId, DelegatedZoneName: props.delegatedZone.zoneName, DelegatedZoneNameServers: props.delegatedZone.hostedZoneNameServers!, diff --git a/packages/@aws-cdk/aws-route53/package.json b/packages/@aws-cdk/aws-route53/package.json index 9a22737d55347..004a55507b021 100644 --- a/packages/@aws-cdk/aws-route53/package.json +++ b/packages/@aws-cdk/aws-route53/package.json @@ -71,7 +71,8 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/aws-lambda": "^8.10.76", + "@types/jest": "^26.0.23", "@types/nodeunit": "^0.0.31", "aws-sdk": "^2.848.0", "cdk-build-tools": "0.0.0", @@ -79,7 +80,8 @@ "cfn2ts": "0.0.0", "jest": "^26.6.3", "nodeunit-shim": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", @@ -88,7 +90,7 @@ "@aws-cdk/core": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -98,7 +100,7 @@ "@aws-cdk/core": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" @@ -112,6 +114,7 @@ "props-physical-name:@aws-cdk/aws-route53.CnameRecordProps", "props-physical-name:@aws-cdk/aws-route53.HostedZoneProps", "props-physical-name:@aws-cdk/aws-route53.MxRecordProps", + "props-physical-name:@aws-cdk/aws-route53.NsRecordProps", "props-physical-name:@aws-cdk/aws-route53.PrivateHostedZoneProps", "props-physical-name:@aws-cdk/aws-route53.PublicHostedZoneProps", "props-physical-name:@aws-cdk/aws-route53.RecordSetProps", diff --git a/packages/@aws-cdk/aws-route53/test/cross-account-zone-delegation-handler/index.test.ts b/packages/@aws-cdk/aws-route53/test/cross-account-zone-delegation-handler/index.test.ts index 8c8dcafcbd9c7..04f7a54b5f1a1 100644 --- a/packages/@aws-cdk/aws-route53/test/cross-account-zone-delegation-handler/index.test.ts +++ b/packages/@aws-cdk/aws-route53/test/cross-account-zone-delegation-handler/index.test.ts @@ -6,6 +6,7 @@ const mockStsClient = { }; const mockRoute53Client = { changeResourceRecordSets: jest.fn().mockReturnThis(), + listHostedZonesByName: jest.fn().mockReturnThis(), promise: jest.fn(), }; @@ -20,12 +21,24 @@ jest.mock('aws-sdk', () => { beforeEach(() => { mockStsClient.assumeRole.mockReturnThis(); mockRoute53Client.changeResourceRecordSets.mockReturnThis(); + mockRoute53Client.listHostedZonesByName.mockReturnThis(); }); afterEach(() => { jest.clearAllMocks(); }); +test('throws error if both ParentZoneId and ParentZoneName are not provided', async () => { + // WHEN + const event = getCfnEvent({}, { + ParentZoneId: undefined, + ParentZoneName: undefined, + }); + + // THEN + await expect(invokeHandler(event)).rejects.toThrow(/One of ParentZoneId or ParentZoneName must be specified/); +}); + test('throws error if getting credentials fails', async () => { // GIVEN mockStsClient.promise.mockResolvedValueOnce({ Credentials: undefined }); @@ -43,7 +56,7 @@ test('throws error if getting credentials fails', async () => { }); }); -test('calls create resouce record set with Upsert for Create event', async () => { +test('calls create resource record set with Upsert for Create event', async () => { // GIVEN mockStsClient.promise.mockResolvedValueOnce({ Credentials: { AccessKeyId: 'K', SecretAccessKey: 'S', SessionToken: 'T' } }); mockRoute53Client.promise.mockResolvedValueOnce({}); @@ -70,7 +83,7 @@ test('calls create resouce record set with Upsert for Create event', async () => }); }); -test('calls create resouce record set with DELETE for Delete event', async () => { +test('calls create resource record set with DELETE for Delete event', async () => { // GIVEN mockStsClient.promise.mockResolvedValueOnce({ Credentials: { AccessKeyId: 'K', SecretAccessKey: 'S', SessionToken: 'T' } }); mockRoute53Client.promise.mockResolvedValueOnce({}); @@ -97,7 +110,72 @@ test('calls create resouce record set with DELETE for Delete event', async () => }); }); -function getCfnEvent(event?: Partial): Partial { +test('calls listHostedZonesByName to get zoneId if ParentZoneId is not provided', async () => { + // GIVEN + const parentZoneName = 'some.zone'; + const parentZoneId = 'zone-id'; + + mockStsClient.promise.mockResolvedValueOnce({ Credentials: { AccessKeyId: 'K', SecretAccessKey: 'S', SessionToken: 'T' } }); + mockRoute53Client.promise.mockResolvedValueOnce({ HostedZones: [{ Name: `${parentZoneName}.`, Id: parentZoneId }] }); + mockRoute53Client.promise.mockResolvedValueOnce({}); + + // WHEN + const event = getCfnEvent({}, { + ParentZoneId: undefined, + ParentZoneName: parentZoneName, + }); + await invokeHandler(event); + + // THEN + expect(mockRoute53Client.listHostedZonesByName).toHaveBeenCalledTimes(1); + expect(mockRoute53Client.listHostedZonesByName).toHaveBeenCalledWith({ DNSName: parentZoneName }); + + expect(mockRoute53Client.changeResourceRecordSets).toHaveBeenCalledTimes(1); + expect(mockRoute53Client.changeResourceRecordSets).toHaveBeenCalledWith({ + HostedZoneId: parentZoneId, + ChangeBatch: { + Changes: [{ + Action: 'UPSERT', + ResourceRecordSet: { + Name: 'recordName', + Type: 'NS', + TTL: 172800, + ResourceRecords: [{ Value: 'one' }, { Value: 'two' }], + }, + }], + }, + }); +}); + +test('throws if more than one HostedZones are returnd for the provided ParentHostedZone', async () => { + // GIVEN + const parentZoneName = 'some.zone'; + const parentZoneId = 'zone-id'; + + mockStsClient.promise.mockResolvedValueOnce({ Credentials: { AccessKeyId: 'K', SecretAccessKey: 'S', SessionToken: 'T' } }); + mockRoute53Client.promise.mockResolvedValueOnce({ + HostedZones: [ + { Name: `${parentZoneName}.`, Id: parentZoneId }, + { Name: `${parentZoneName}.`, Id: parentZoneId }, + ], + }); + + // WHEN + const event = getCfnEvent({}, { + ParentZoneId: undefined, + ParentZoneName: parentZoneName, + }); + + // THEN + await expect(invokeHandler(event)).rejects.toThrow(/Expected one hosted zone to match the given name but found 2/); + expect(mockRoute53Client.listHostedZonesByName).toHaveBeenCalledTimes(1); + expect(mockRoute53Client.listHostedZonesByName).toHaveBeenCalledWith({ DNSName: parentZoneName }); +}); + +function getCfnEvent( + event?: Partial, + resourceProps?: any, +): Partial { return { RequestType: 'Create', ResourceProperties: { @@ -107,6 +185,7 @@ function getCfnEvent(event?: Partial { + new PublicHostedZone(stack, 'HostedZone', { + zoneName: 'testZone', + crossAccountZoneDelegationRoleName: 'myrole', + }); + }, /crossAccountZoneDelegationRoleName property is not supported without crossAccountZoneDelegationPrincipal/); + + test.done(); + }, }); diff --git a/packages/@aws-cdk/aws-route53/test/integ.cross-account-zone-delegation.expected.json b/packages/@aws-cdk/aws-route53/test/integ.cross-account-zone-delegation.expected.json index 919a54f8b5051..281fc984d0756 100644 --- a/packages/@aws-cdk/aws-route53/test/integ.cross-account-zone-delegation.expected.json +++ b/packages/@aws-cdk/aws-route53/test/integ.cross-account-zone-delegation.expected.json @@ -58,6 +58,11 @@ ] ] } + }, + { + "Action": "route53:ListHostedZonesByName", + "Effect": "Allow", + "Resource": "*" } ], "Version": "2012-10-17" @@ -67,13 +72,13 @@ ] } }, - "ChildHostedZone4B14AC71": { + "ChildHostedZoneWithZoneId729259E6": { "Type": "AWS::Route53::HostedZone", "Properties": { "Name": "sub.myzone.com." } }, - "DelegationCrossAccountZoneDelegationCustomResourceFADC27F0": { + "DelegationWithZoneIdCrossAccountZoneDelegationCustomResourceFFD766E7": { "Type": "Custom::CrossAccountZoneDelegation", "Properties": { "ServiceToken": { @@ -94,7 +99,7 @@ "DelegatedZoneName": "sub.myzone.com", "DelegatedZoneNameServers": { "Fn::GetAtt": [ - "ChildHostedZone4B14AC71", + "ChildHostedZoneWithZoneId729259E6", "NameServers" ] }, @@ -150,7 +155,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters3c971020239d152fff59dc3bdbabbbc6d3d9140574e45fd4eb7313ced117113aS3Bucket8B462894" + "Ref": "AssetParametersd17df4f90e07a972e8f7b00dddbae8e3eba45a212226d2b714dcd28dded69602S3Bucket200D9216" }, "S3Key": { "Fn::Join": [ @@ -163,7 +168,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters3c971020239d152fff59dc3bdbabbbc6d3d9140574e45fd4eb7313ced117113aS3VersionKeyFDEC5E1D" + "Ref": "AssetParametersd17df4f90e07a972e8f7b00dddbae8e3eba45a212226d2b714dcd28dded69602S3VersionKey0E5C26F0" } ] } @@ -176,7 +181,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters3c971020239d152fff59dc3bdbabbbc6d3d9140574e45fd4eb7313ced117113aS3VersionKeyFDEC5E1D" + "Ref": "AssetParametersd17df4f90e07a972e8f7b00dddbae8e3eba45a212226d2b714dcd28dded69602S3VersionKey0E5C26F0" } ] } @@ -200,20 +205,54 @@ "DependsOn": [ "CustomCrossAccountZoneDelegationCustomResourceProviderRoleED64687B" ] + }, + "ChildHostedZoneWithZoneNameBC2C15F6": { + "Type": "AWS::Route53::HostedZone", + "Properties": { + "Name": "anothersub.myzone.com." + } + }, + "DelegationWithZoneNameCrossAccountZoneDelegationCustomResourceA1A1C94A": { + "Type": "Custom::CrossAccountZoneDelegation", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "CustomCrossAccountZoneDelegationCustomResourceProviderHandler44A84265", + "Arn" + ] + }, + "AssumeRoleArn": { + "Fn::GetAtt": [ + "ParentHostedZoneCrossAccountZoneDelegationRole95B1C36E", + "Arn" + ] + }, + "ParentZoneName": "myzone.com", + "DelegatedZoneName": "anothersub.myzone.com", + "DelegatedZoneNameServers": { + "Fn::GetAtt": [ + "ChildHostedZoneWithZoneNameBC2C15F6", + "NameServers" + ] + }, + "TTL": 172800 + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Parameters": { - "AssetParameters3c971020239d152fff59dc3bdbabbbc6d3d9140574e45fd4eb7313ced117113aS3Bucket8B462894": { + "AssetParametersd17df4f90e07a972e8f7b00dddbae8e3eba45a212226d2b714dcd28dded69602S3Bucket200D9216": { "Type": "String", - "Description": "S3 bucket for asset \"3c971020239d152fff59dc3bdbabbbc6d3d9140574e45fd4eb7313ced117113a\"" + "Description": "S3 bucket for asset \"d17df4f90e07a972e8f7b00dddbae8e3eba45a212226d2b714dcd28dded69602\"" }, - "AssetParameters3c971020239d152fff59dc3bdbabbbc6d3d9140574e45fd4eb7313ced117113aS3VersionKeyFDEC5E1D": { + "AssetParametersd17df4f90e07a972e8f7b00dddbae8e3eba45a212226d2b714dcd28dded69602S3VersionKey0E5C26F0": { "Type": "String", - "Description": "S3 key for asset version \"3c971020239d152fff59dc3bdbabbbc6d3d9140574e45fd4eb7313ced117113a\"" + "Description": "S3 key for asset version \"d17df4f90e07a972e8f7b00dddbae8e3eba45a212226d2b714dcd28dded69602\"" }, - "AssetParameters3c971020239d152fff59dc3bdbabbbc6d3d9140574e45fd4eb7313ced117113aArtifactHash4F367D8C": { + "AssetParametersd17df4f90e07a972e8f7b00dddbae8e3eba45a212226d2b714dcd28dded69602ArtifactHash37FB4D0C": { "Type": "String", - "Description": "Artifact hash for asset \"3c971020239d152fff59dc3bdbabbbc6d3d9140574e45fd4eb7313ced117113a\"" + "Description": "Artifact hash for asset \"d17df4f90e07a972e8f7b00dddbae8e3eba45a212226d2b714dcd28dded69602\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-route53/test/integ.cross-account-zone-delegation.ts b/packages/@aws-cdk/aws-route53/test/integ.cross-account-zone-delegation.ts index 75f9e86152eb0..8ec89ab3ec343 100644 --- a/packages/@aws-cdk/aws-route53/test/integ.cross-account-zone-delegation.ts +++ b/packages/@aws-cdk/aws-route53/test/integ.cross-account-zone-delegation.ts @@ -11,13 +11,24 @@ const parentZone = new PublicHostedZone(stack, 'ParentHostedZone', { crossAccountZoneDelegationPrincipal: new iam.AccountPrincipal(cdk.Aws.ACCOUNT_ID), }); -const childZone = new PublicHostedZone(stack, 'ChildHostedZone', { +// with zoneId +const childZoneWithZoneId = new PublicHostedZone(stack, 'ChildHostedZoneWithZoneId', { zoneName: 'sub.myzone.com', }); -new CrossAccountZoneDelegationRecord(stack, 'Delegation', { - delegatedZone: childZone, +new CrossAccountZoneDelegationRecord(stack, 'DelegationWithZoneId', { + delegatedZone: childZoneWithZoneId, parentHostedZoneId: parentZone.hostedZoneId, delegationRole: parentZone.crossAccountZoneDelegationRole!, }); +// with zoneName +const childZoneWithZoneName = new PublicHostedZone(stack, 'ChildHostedZoneWithZoneName', { + zoneName: 'anothersub.myzone.com', +}); +new CrossAccountZoneDelegationRecord(stack, 'DelegationWithZoneName', { + delegatedZone: childZoneWithZoneName, + parentHostedZoneName: 'myzone.com', + delegationRole: parentZone.crossAccountZoneDelegationRole!, +}); + app.synth(); diff --git a/packages/@aws-cdk/aws-route53/test/integ.vpc-endpoint-service-domain-name.expected.json b/packages/@aws-cdk/aws-route53/test/integ.vpc-endpoint-service-domain-name.expected.json index 5c4f8ee9629df..02dfb6c770668 100644 --- a/packages/@aws-cdk/aws-route53/test/integ.vpc-endpoint-service-domain-name.expected.json +++ b/packages/@aws-cdk/aws-route53/test/integ.vpc-endpoint-service-domain-name.expected.json @@ -936,7 +936,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3Bucket65227904" + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3Bucket4DD075F7" }, "S3Key": { "Fn::Join": [ @@ -949,7 +949,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF" + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7" } ] } @@ -962,7 +962,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF" + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7" } ] } @@ -988,17 +988,17 @@ } }, "Parameters": { - "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3Bucket65227904": { + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3Bucket4DD075F7": { "Type": "String", - "Description": "S3 bucket for asset \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\"" + "Description": "S3 bucket for asset \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" }, - "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF": { + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7": { "Type": "String", - "Description": "S3 key for asset version \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\"" + "Description": "S3 key for asset version \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" }, - "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343ArtifactHash0C561FF5": { + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98ArtifactHash35A756EB": { "Type": "String", - "Description": "Artifact hash for asset \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\"" + "Description": "Artifact hash for asset \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-route53/test/integ.vpc-endpoint-service-domain-name.ts b/packages/@aws-cdk/aws-route53/test/integ.vpc-endpoint-service-domain-name.ts index 672b2133f077b..a2ca642d1137f 100644 --- a/packages/@aws-cdk/aws-route53/test/integ.vpc-endpoint-service-domain-name.ts +++ b/packages/@aws-cdk/aws-route53/test/integ.vpc-endpoint-service-domain-name.ts @@ -1,3 +1,4 @@ +/// !cdk-integ pragma:ignore-assets import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import { Construct } from 'constructs'; diff --git a/packages/@aws-cdk/aws-route53/test/record-set.test.ts b/packages/@aws-cdk/aws-route53/test/record-set.test.ts index 373464f455992..a9d5446185f66 100644 --- a/packages/@aws-cdk/aws-route53/test/record-set.test.ts +++ b/packages/@aws-cdk/aws-route53/test/record-set.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import { Duration, Stack } from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; @@ -68,6 +68,30 @@ nodeunitShim({ test.done(); }, + 'with ttl of 0'(test: Test) { + // GIVEN + const stack = new Stack(); + + const zone = new route53.HostedZone(stack, 'HostedZone', { + zoneName: 'myzone', + }); + + // WHEN + new route53.RecordSet(stack, 'Basic', { + zone, + recordName: 'aa', + recordType: route53.RecordType.CNAME, + target: route53.RecordTarget.fromValues('bbb'), + ttl: Duration.seconds(0), + }); + + // THEN + expect(stack).to(haveResource('AWS::Route53::RecordSet', { + TTL: '0', + })); + test.done(); + }, + 'defaults to zone root'(test: Test) { // GIVEN const stack = new Stack(); @@ -485,6 +509,37 @@ nodeunitShim({ test.done(); }, + 'NS record'(test: Test) { + // GIVEN + const stack = new Stack(); + + const zone = new route53.HostedZone(stack, 'HostedZone', { + zoneName: 'myzone', + }); + + // WHEN + new route53.NsRecord(stack, 'NS', { + zone, + recordName: 'www', + values: ['ns-1.awsdns.co.uk.', 'ns-2.awsdns.com.'], + }); + + // THEN + expect(stack).to(haveResource('AWS::Route53::RecordSet', { + Name: 'www.myzone.', + Type: 'NS', + HostedZoneId: { + Ref: 'HostedZoneDB99F866', + }, + ResourceRecords: [ + 'ns-1.awsdns.co.uk.', + 'ns-2.awsdns.com.', + ], + TTL: '1800', + })); + test.done(); + }, + 'Zone delegation record'(test: Test) { // GIVEN const stack = new Stack(); @@ -515,7 +570,7 @@ nodeunitShim({ test.done(); }, - 'Cross account zone delegation record'(test: Test) { + 'Cross account zone delegation record with parentHostedZoneId'(test: Test) { // GIVEN const stack = new Stack(); const parentZone = new route53.PublicHostedZone(stack, 'ParentHostedZone', { @@ -562,4 +617,84 @@ nodeunitShim({ })); test.done(); }, + + 'Cross account zone delegation record with parentHostedZoneName'(test: Test) { + // GIVEN + const stack = new Stack(); + const parentZone = new route53.PublicHostedZone(stack, 'ParentHostedZone', { + zoneName: 'myzone.com', + crossAccountZoneDelegationPrincipal: new iam.AccountPrincipal('123456789012'), + }); + + // WHEN + const childZone = new route53.PublicHostedZone(stack, 'ChildHostedZone', { + zoneName: 'sub.myzone.com', + }); + new route53.CrossAccountZoneDelegationRecord(stack, 'Delegation', { + delegatedZone: childZone, + parentHostedZoneName: 'myzone.com', + delegationRole: parentZone.crossAccountZoneDelegationRole!, + ttl: Duration.seconds(60), + }); + + // THEN + expect(stack).to(haveResource('Custom::CrossAccountZoneDelegation', { + ServiceToken: { + 'Fn::GetAtt': [ + 'CustomCrossAccountZoneDelegationCustomResourceProviderHandler44A84265', + 'Arn', + ], + }, + AssumeRoleArn: { + 'Fn::GetAtt': [ + 'ParentHostedZoneCrossAccountZoneDelegationRole95B1C36E', + 'Arn', + ], + }, + ParentZoneName: 'myzone.com', + DelegatedZoneName: 'sub.myzone.com', + DelegatedZoneNameServers: { + 'Fn::GetAtt': [ + 'ChildHostedZone4B14AC71', + 'NameServers', + ], + }, + TTL: 60, + })); + test.done(); + }, + + 'Cross account zone delegation record throws when parent id and name both/nither are supplied'(test: Test) { + // GIVEN + const stack = new Stack(); + const parentZone = new route53.PublicHostedZone(stack, 'ParentHostedZone', { + zoneName: 'myzone.com', + crossAccountZoneDelegationPrincipal: new iam.AccountPrincipal('123456789012'), + }); + + // THEN + const childZone = new route53.PublicHostedZone(stack, 'ChildHostedZone', { + zoneName: 'sub.myzone.com', + }); + + test.throws(() => { + new route53.CrossAccountZoneDelegationRecord(stack, 'Delegation1', { + delegatedZone: childZone, + delegationRole: parentZone.crossAccountZoneDelegationRole!, + ttl: Duration.seconds(60), + }); + }, /At least one of parentHostedZoneName or parentHostedZoneId is required/); + + test.throws(() => { + new route53.CrossAccountZoneDelegationRecord(stack, 'Delegation2', { + delegatedZone: childZone, + parentHostedZoneId: parentZone.hostedZoneId, + parentHostedZoneName: parentZone.zoneName, + delegationRole: parentZone.crossAccountZoneDelegationRole!, + ttl: Duration.seconds(60), + }); + }, /Only one of parentHostedZoneName and parentHostedZoneId is supported/); + + test.done(); + }, }); diff --git a/packages/@aws-cdk/aws-route53/test/route53.test.ts b/packages/@aws-cdk/aws-route53/test/route53.test.ts index 8f58486bebcbc..e5dd624163a9b 100644 --- a/packages/@aws-cdk/aws-route53/test/route53.test.ts +++ b/packages/@aws-cdk/aws-route53/test/route53.test.ts @@ -1,4 +1,4 @@ -import { beASupersetOfTemplate, exactlyMatchTemplate, expect, haveResource } from '@aws-cdk/assert'; +import { beASupersetOfTemplate, exactlyMatchTemplate, expect, haveResource } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; diff --git a/packages/@aws-cdk/aws-route53/test/vpc-endpoint-service-domain-name.test.ts b/packages/@aws-cdk/aws-route53/test/vpc-endpoint-service-domain-name.test.ts index c6aa0cdbc50c6..82706fe29d0ea 100644 --- a/packages/@aws-cdk/aws-route53/test/vpc-endpoint-service-domain-name.test.ts +++ b/packages/@aws-cdk/aws-route53/test/vpc-endpoint-service-domain-name.test.ts @@ -1,6 +1,6 @@ /* eslint-disable jest/no-disabled-tests */ -import { expect as cdkExpect, haveResource, haveResourceLike, ResourcePart } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { expect as cdkExpect, haveResource, haveResourceLike, ResourcePart } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import { IVpcEndpointServiceLoadBalancer, VpcEndpointService } from '@aws-cdk/aws-ec2'; import { Stack } from '@aws-cdk/core'; import { PublicHostedZone, VpcEndpointServiceDomainName } from '../lib'; diff --git a/packages/@aws-cdk/aws-route53resolver/package.json b/packages/@aws-cdk/aws-route53resolver/package.json index 79142ad18b7ef..2f297377c17ab 100644 --- a/packages/@aws-cdk/aws-route53resolver/package.json +++ b/packages/@aws-cdk/aws-route53resolver/package.json @@ -72,18 +72,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-route53resolver/test/route53resolver.test.ts b/packages/@aws-cdk/aws-route53resolver/test/route53resolver.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-route53resolver/test/route53resolver.test.ts +++ b/packages/@aws-cdk/aws-route53resolver/test/route53resolver.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-s3-assets/README.md b/packages/@aws-cdk/aws-s3-assets/README.md index 8dae008aa5444..a73cbf0919642 100644 --- a/packages/@aws-cdk/aws-s3-assets/README.md +++ b/packages/@aws-cdk/aws-s3-assets/README.md @@ -3,13 +3,7 @@ --- -![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. +![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge) --- diff --git a/packages/@aws-cdk/aws-s3-assets/lib/asset.ts b/packages/@aws-cdk/aws-s3-assets/lib/asset.ts index 510834a61c634..0777602e788f6 100644 --- a/packages/@aws-cdk/aws-s3-assets/lib/asset.ts +++ b/packages/@aws-cdk/aws-s3-assets/lib/asset.ts @@ -1,5 +1,4 @@ import * as path from 'path'; -import * as assets from '@aws-cdk/assets'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as s3 from '@aws-cdk/aws-s3'; @@ -8,11 +7,14 @@ import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; import { toSymlinkFollow } from './compat'; +// keep this import separate from other imports to reduce chance for merge conflicts with v2-main +// eslint-disable-next-line no-duplicate-imports, import/order +import { CopyOptions } from '@aws-cdk/assets'; // keep this import separate from other imports to reduce chance for merge conflicts with v2-main // eslint-disable-next-line no-duplicate-imports, import/order import { Construct as CoreConstruct } from '@aws-cdk/core'; -export interface AssetOptions extends assets.CopyOptions, cdk.AssetOptions { +export interface AssetOptions extends CopyOptions, cdk.FileCopyOptions, cdk.AssetOptions { /** * A list of principals that should be able to read this asset from S3. * You can use `asset.grantRead(principal)` to grant read permissions later. @@ -125,7 +127,7 @@ export class Asset extends CoreConstruct implements cdk.IAsset { const staging = new cdk.AssetStaging(this, 'Stage', { ...props, sourcePath: path.resolve(props.path), - follow: toSymlinkFollow(props.follow), + follow: props.followSymlinks ?? toSymlinkFollow(props.follow), assetHash: props.assetHash ?? props.sourceHash, }); diff --git a/packages/@aws-cdk/aws-s3-assets/package.json b/packages/@aws-cdk/aws-s3-assets/package.json index 6d03905f64f85..646ca2feb968f 100644 --- a/packages/@aws-cdk/aws-s3-assets/package.json +++ b/packages/@aws-cdk/aws-s3-assets/package.json @@ -69,11 +69,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "pkglint": "0.0.0", - "@aws-cdk/cloud-assembly-schema": "0.0.0" + "@aws-cdk/cloud-assembly-schema": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/assets": "0.0.0", @@ -82,7 +83,7 @@ "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -92,13 +93,13 @@ "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, - "stability": "experimental", - "maturity": "experimental", + "stability": "stable", + "maturity": "stable", "awslint": { "exclude": [ "docs-public-apis:@aws-cdk/aws-s3-assets.AssetOptions", @@ -108,6 +109,9 @@ "awscdkio": { "announce": false }, + "nozem": { + "ostools": ["docker"] + }, "publishConfig": { "tag": "latest" } diff --git a/packages/@aws-cdk/aws-s3-assets/test/asset.test.ts b/packages/@aws-cdk/aws-s3-assets/test/asset.test.ts index 361f5c696d468..ccc93159714ff 100644 --- a/packages/@aws-cdk/aws-s3-assets/test/asset.test.ts +++ b/packages/@aws-cdk/aws-s3-assets/test/asset.test.ts @@ -1,5 +1,5 @@ -import { ResourcePart, SynthUtils } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { ResourcePart, SynthUtils } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as iam from '@aws-cdk/aws-iam'; import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-s3-assets/test/integ.assets.bundling.lit.ts b/packages/@aws-cdk/aws-s3-assets/test/integ.assets.bundling.lit.ts index 38cfe5c2d1e46..a62554bab726a 100644 --- a/packages/@aws-cdk/aws-s3-assets/test/integ.assets.bundling.lit.ts +++ b/packages/@aws-cdk/aws-s3-assets/test/integ.assets.bundling.lit.ts @@ -1,6 +1,6 @@ import * as path from 'path'; import * as iam from '@aws-cdk/aws-iam'; -import { App, BundlingDockerImage, Stack, StackProps } from '@aws-cdk/core'; +import { App, DockerImage, Stack, StackProps } from '@aws-cdk/core'; import { Construct } from 'constructs'; import * as assets from '../lib'; @@ -12,7 +12,7 @@ class TestStack extends Stack { const asset = new assets.Asset(this, 'BundledAsset', { path: path.join(__dirname, 'markdown-asset'), // /asset-input and working directory in the container bundling: { - image: BundlingDockerImage.fromAsset(path.join(__dirname, 'alpine-markdown')), // Build an image + image: DockerImage.fromBuild(path.join(__dirname, 'alpine-markdown')), // Build an image command: [ 'sh', '-c', ` markdown index.md > /asset-output/index.html diff --git a/packages/@aws-cdk/aws-s3-deployment/README.md b/packages/@aws-cdk/aws-s3-deployment/README.md index b0bb1e2d9ebd5..64c3872c59f74 100644 --- a/packages/@aws-cdk/aws-s3-deployment/README.md +++ b/packages/@aws-cdk/aws-s3-deployment/README.md @@ -3,13 +3,7 @@ --- -![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. +![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge) --- @@ -70,6 +64,37 @@ By default, the contents of the destination bucket will **not** be deleted when changed. You can use the option `retainOnDelete: false` to disable this behavior, in which case the contents will be deleted. +Configuring this has a few implications you should be aware of: + +- **Logical ID Changes** + + Changing the logical ID of the `BucketDeployment` construct, without changing the destination + (for example due to refactoring, or intentional ID change) **will result in the deletion of the objects**. + This is because CloudFormation will first create the new resource, which will have no affect, + followed by a deletion of the old resource, which will cause a deletion of the objects, + since the destination hasn't changed, and `retainOnDelete` is `false`. + +- **Destination Changes** + + When the destination bucket or prefix is changed, all files in the previous destination will **first** be + deleted and then uploaded to the new destination location. This could have availablity implications + on your users. + +### General Recommendations + +#### Shared Bucket + +If the destination bucket **is not** dedicated to the specific `BucketDeployment` construct (i.e shared by other entities), +we recommend to always configure the `destinationKeyPrefix` property. This will prevent the deployment from +accidentally deleting data that wasn't uploaded by it. + +#### Dedicated Bucket + +If the destination bucket **is** dedicated, it might be reasonable to skip the prefix configuration, +in which case, we recommend to remove `retainOnDelete: false`, and instead, configure the +[`autoDeleteObjects`](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-s3-readme.html#bucket-deletion) +property on the destination bucket. This will avoid the logical ID problem mentioned above. + ## Prune By default, files in the destination bucket that don't exist in the source will be deleted diff --git a/packages/@aws-cdk/aws-s3-deployment/lib/bucket-deployment.ts b/packages/@aws-cdk/aws-s3-deployment/lib/bucket-deployment.ts index 4ca33864952f3..ca91f036dc5ed 100644 --- a/packages/@aws-cdk/aws-s3-deployment/lib/bucket-deployment.ts +++ b/packages/@aws-cdk/aws-s3-deployment/lib/bucket-deployment.ts @@ -13,6 +13,9 @@ import { ISource, SourceConfig } from './source'; // eslint-disable-next-line no-duplicate-imports, import/order import { Construct as CoreConstruct } from '@aws-cdk/core'; +/** + * Properties for `BucketDeployment`. + */ export interface BucketDeploymentProps { /** * The sources from which to deploy the contents of this bucket. @@ -45,11 +48,10 @@ export interface BucketDeploymentProps { * If this is set to "false", the destination files will be deleted when the * resource is deleted or the destination is updated. * - * NOTICE: if this is set to "false" and destination bucket/prefix is updated, - * all files in the previous destination will first be deleted and then - * uploaded to the new destination location. This could have availablity - * implications on your users. + * NOTICE: Configuring this to "false" might have operational implications. Please + * visit to the package documentation referred below to make sure you fully understand those implications. * + * @see https://github.com/aws/aws-cdk/tree/master/packages/%40aws-cdk/aws-s3-deployment#retain-on-delete * @default true - when resource is deleted/updated, files are retained */ readonly retainOnDelete?: boolean; @@ -179,6 +181,10 @@ export interface BucketDeploymentProps { readonly vpcSubnets?: ec2.SubnetSelection; } +/** + * `BucketDeployment` populates an S3 bucket with the contents of .zip files from + * other S3 buckets or from local disk + */ export class BucketDeployment extends CoreConstruct { constructor(scope: Construct, id: string, props: BucketDeploymentProps) { super(scope, id); @@ -285,17 +291,58 @@ function mapSystemMetadata(metadata: BucketDeploymentProps) { * @see https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html#SysMetadata */ export class CacheControl { + + /** + * Sets 'must-revalidate'. + */ public static mustRevalidate() { return new CacheControl('must-revalidate'); } + + /** + * Sets 'no-cache'. + */ public static noCache() { return new CacheControl('no-cache'); } + + /** + * Sets 'no-transform'. + */ public static noTransform() { return new CacheControl('no-transform'); } + + /** + * Sets 'public'. + */ public static setPublic() { return new CacheControl('public'); } + + /** + * Sets 'private'. + */ public static setPrivate() { return new CacheControl('private'); } + + /** + * Sets 'proxy-revalidate'. + */ public static proxyRevalidate() { return new CacheControl('proxy-revalidate'); } + + /** + * Sets 'max-age='. + */ public static maxAge(t: cdk.Duration) { return new CacheControl(`max-age=${t.toSeconds()}`); } + + /** + * Sets 's-maxage='. + */ public static sMaxAge(t: cdk.Duration) { return new CacheControl(`s-maxage=${t.toSeconds()}`); } + + /** + * Constructs a custom cache control key from the literal value. + */ public static fromString(s: string) { return new CacheControl(s); } - private constructor(public readonly value: any) {} + private constructor( + /** + * The raw cache control setting. + */ + public readonly value: any, + ) {} } /** @@ -304,7 +351,15 @@ export class CacheControl { * @see https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html#SysMetadata */ export enum ServerSideEncryption { + + /** + * 'AES256' + */ AES_256 = 'AES256', + + /** + * 'aws:kms' + */ AWS_KMS = 'aws:kms' } @@ -313,12 +368,40 @@ export enum ServerSideEncryption { * @see https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html#SysMetadata */ export enum StorageClass { + + /** + * 'STANDARD' + */ STANDARD = 'STANDARD', + + /** + * 'REDUCED_REDUNDANCY' + */ REDUCED_REDUNDANCY = 'REDUCED_REDUNDANCY', + + /** + * 'STANDARD_IA' + */ STANDARD_IA = 'STANDARD_IA', + + /** + * 'ONEZONE_IA' + */ ONEZONE_IA = 'ONEZONE_IA', + + /** + * 'INTELLIGENT_TIERING' + */ INTELLIGENT_TIERING = 'INTELLIGENT_TIERING', + + /** + * 'GLACIER' + */ GLACIER = 'GLACIER', + + /** + * 'DEEP_ARCHIVE' + */ DEEP_ARCHIVE = 'DEEP_ARCHIVE' } @@ -347,11 +430,22 @@ export class Expires { */ public static after(t: cdk.Duration) { return Expires.atDate(new Date(Date.now() + t.toMilliseconds())); } + /** + * Create an expiration date from a raw date string. + */ public static fromString(s: string) { return new Expires(s); } - private constructor(public readonly value: any) {} + private constructor( + /** + * The raw expiration date expression. + */ + public readonly value: any, + ) {} } +/** + * Custom user defined metadata. + */ export interface UserDefinedObjectMetadata { /** * Arbitrary metadata key-values diff --git a/packages/@aws-cdk/aws-s3-deployment/lib/source.ts b/packages/@aws-cdk/aws-s3-deployment/lib/source.ts index 558c32556c25c..4eaea3fdc0060 100644 --- a/packages/@aws-cdk/aws-s3-deployment/lib/source.ts +++ b/packages/@aws-cdk/aws-s3-deployment/lib/source.ts @@ -6,6 +6,9 @@ import * as s3_assets from '@aws-cdk/aws-s3-assets'; // eslint-disable-next-line no-duplicate-imports, import/order import { Construct } from '@aws-cdk/core'; +/** + * Source information. + */ export interface SourceConfig { /** * The source bucket to deploy from. diff --git a/packages/@aws-cdk/aws-s3-deployment/package.json b/packages/@aws-cdk/aws-s3-deployment/package.json index e92226c156359..37c01e5a1fe72 100644 --- a/packages/@aws-cdk/aws-s3-deployment/package.json +++ b/packages/@aws-cdk/aws-s3-deployment/package.json @@ -77,13 +77,13 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "@types/jest": "^26.0.21", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-cloudfront": "0.0.0", @@ -94,7 +94,7 @@ "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/lambda-layer-awscli": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -106,45 +106,19 @@ "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/lambda-layer-awscli": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, - "stability": "experimental", - "maturity": "experimental", - "awslint": { - "exclude": [ - "docs-public-apis:@aws-cdk/aws-s3-deployment.Expires.fromString", - "docs-public-apis:@aws-cdk/aws-s3-deployment.BucketDeployment", - "docs-public-apis:@aws-cdk/aws-s3-deployment.CacheControl.fromString", - "docs-public-apis:@aws-cdk/aws-s3-deployment.CacheControl.maxAge", - "docs-public-apis:@aws-cdk/aws-s3-deployment.CacheControl.mustRevalidate", - "docs-public-apis:@aws-cdk/aws-s3-deployment.CacheControl.noCache", - "docs-public-apis:@aws-cdk/aws-s3-deployment.CacheControl.noTransform", - "docs-public-apis:@aws-cdk/aws-s3-deployment.CacheControl.proxyRevalidate", - "docs-public-apis:@aws-cdk/aws-s3-deployment.CacheControl.setPrivate", - "docs-public-apis:@aws-cdk/aws-s3-deployment.CacheControl.setPublic", - "docs-public-apis:@aws-cdk/aws-s3-deployment.CacheControl.sMaxAge", - "docs-public-apis:@aws-cdk/aws-s3-deployment.Expires.value", - "docs-public-apis:@aws-cdk/aws-s3-deployment.CacheControl.value", - "docs-public-apis:@aws-cdk/aws-s3-deployment.BucketDeploymentProps", - "docs-public-apis:@aws-cdk/aws-s3-deployment.SourceConfig", - "docs-public-apis:@aws-cdk/aws-s3-deployment.UserDefinedObjectMetadata", - "docs-public-apis:@aws-cdk/aws-s3-deployment.ServerSideEncryption.AES_256", - "docs-public-apis:@aws-cdk/aws-s3-deployment.ServerSideEncryption.AWS_KMS", - "docs-public-apis:@aws-cdk/aws-s3-deployment.StorageClass.STANDARD", - "docs-public-apis:@aws-cdk/aws-s3-deployment.StorageClass.REDUCED_REDUNDANCY", - "docs-public-apis:@aws-cdk/aws-s3-deployment.StorageClass.STANDARD_IA", - "docs-public-apis:@aws-cdk/aws-s3-deployment.StorageClass.ONEZONE_IA", - "docs-public-apis:@aws-cdk/aws-s3-deployment.StorageClass.INTELLIGENT_TIERING", - "docs-public-apis:@aws-cdk/aws-s3-deployment.StorageClass.GLACIER", - "docs-public-apis:@aws-cdk/aws-s3-deployment.StorageClass.DEEP_ARCHIVE" - ] - }, + "stability": "stable", + "maturity": "stable", "awscdkio": { "announce": false }, + "nozem": { + "ostools": ["dirname", "mktemp", "mkdir", "cp", "docker"] + }, "publishConfig": { "tag": "latest" } diff --git a/packages/@aws-cdk/aws-s3-deployment/test/bucket-deployment.test.ts b/packages/@aws-cdk/aws-s3-deployment/test/bucket-deployment.test.ts index 9639af37a2aa8..c111629e46769 100644 --- a/packages/@aws-cdk/aws-s3-deployment/test/bucket-deployment.test.ts +++ b/packages/@aws-cdk/aws-s3-deployment/test/bucket-deployment.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as path from 'path'; import * as cloudfront from '@aws-cdk/aws-cloudfront'; import * as ec2 from '@aws-cdk/aws-ec2'; diff --git a/packages/@aws-cdk/aws-s3-notifications/package.json b/packages/@aws-cdk/aws-s3-notifications/package.json index 00d38a536ca6a..631f925e9e85e 100644 --- a/packages/@aws-cdk/aws-s3-notifications/package.json +++ b/packages/@aws-cdk/aws-s3-notifications/package.json @@ -62,11 +62,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", @@ -75,7 +76,7 @@ "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -85,7 +86,7 @@ "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" 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 6bd225d17fd0c..4d80618ad8ff3 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 @@ -1,6 +1,6 @@ -// import { SynthUtils } from '@aws-cdk/assert'; -import { ResourcePart } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +// import { SynthUtils } from '@aws-cdk/assert-internal'; +import { ResourcePart } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as lambda from '@aws-cdk/aws-lambda'; import * as s3 from '@aws-cdk/aws-s3'; import { Stack, App } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-s3-notifications/test/notifications.test.ts b/packages/@aws-cdk/aws-s3-notifications/test/notifications.test.ts index 8c826e9217204..7c4894cc2866c 100644 --- a/packages/@aws-cdk/aws-s3-notifications/test/notifications.test.ts +++ b/packages/@aws-cdk/aws-s3-notifications/test/notifications.test.ts @@ -1,5 +1,5 @@ -import { SynthUtils } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { SynthUtils } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as s3 from '@aws-cdk/aws-s3'; import * as sns from '@aws-cdk/aws-sns'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-s3-notifications/test/queue.test.ts b/packages/@aws-cdk/aws-s3-notifications/test/queue.test.ts index 9cc4dad9712c7..22c2edac592c8 100644 --- a/packages/@aws-cdk/aws-s3-notifications/test/queue.test.ts +++ b/packages/@aws-cdk/aws-s3-notifications/test/queue.test.ts @@ -1,5 +1,5 @@ -import { arrayWith, SynthUtils } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { arrayWith, SynthUtils } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as s3 from '@aws-cdk/aws-s3'; import * as sqs from '@aws-cdk/aws-sqs'; import { Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-s3-notifications/test/sns.test.ts b/packages/@aws-cdk/aws-s3-notifications/test/sns.test.ts index de8e63d49163e..2c91becaae188 100644 --- a/packages/@aws-cdk/aws-s3-notifications/test/sns.test.ts +++ b/packages/@aws-cdk/aws-s3-notifications/test/sns.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as s3 from '@aws-cdk/aws-s3'; import * as sns from '@aws-cdk/aws-sns'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-s3/lib/bucket.ts b/packages/@aws-cdk/aws-s3/lib/bucket.ts index ef1cda8a32f1b..002435a234c0c 100644 --- a/packages/@aws-cdk/aws-s3/lib/bucket.ts +++ b/packages/@aws-cdk/aws-s3/lib/bucket.ts @@ -530,7 +530,7 @@ abstract class BucketBase extends Resource implements IBucket { */ public urlForObject(key?: string): string { const stack = Stack.of(this); - const prefix = `https://s3.${stack.region}.${stack.urlSuffix}/`; + const prefix = `https://s3.${this.env.region}.${stack.urlSuffix}/`; if (typeof key !== 'string') { return this.urlJoin(prefix, this.bucketName); } @@ -1502,7 +1502,10 @@ export class Bucket extends BucketBase { Bool: { 'aws:SecureTransport': 'false' }, }, effect: iam.Effect.DENY, - resources: [this.arnForObjects('*')], + resources: [ + this.bucketArn, + this.arnForObjects('*'), + ], principals: [new iam.AnyPrincipal()], }); this.addToResourcePolicy(statement); @@ -1829,7 +1832,7 @@ export class Bucket extends BucketBase { private enableAutoDeleteObjects() { const provider = CustomResourceProvider.getOrCreateProvider(this, AUTO_DELETE_OBJECTS_RESOURCE_TYPE, { codeDirectory: path.join(__dirname, 'auto-delete-objects-handler'), - runtime: CustomResourceProviderRuntime.NODEJS_12, + runtime: CustomResourceProviderRuntime.NODEJS_12_X, description: `Lambda function for auto-deleting objects in ${this.bucketName} S3 bucket.`, }); diff --git a/packages/@aws-cdk/aws-s3/package.json b/packages/@aws-cdk/aws-s3/package.json index 23d3345e1bfd5..d81c3002b3f7a 100644 --- a/packages/@aws-cdk/aws-s3/package.json +++ b/packages/@aws-cdk/aws-s3/package.json @@ -71,12 +71,14 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/aws-lambda": "^8.10.76", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", - "nodeunit-shim": "0.0.0" + "nodeunit-shim": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-events": "0.0.0", @@ -84,7 +86,7 @@ "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -93,7 +95,7 @@ "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-s3/test/aspect.test.ts b/packages/@aws-cdk/aws-s3/test/aspect.test.ts index fb981c8f3e27a..ef0394a4cf9cb 100644 --- a/packages/@aws-cdk/aws-s3/test/aspect.test.ts +++ b/packages/@aws-cdk/aws-s3/test/aspect.test.ts @@ -1,5 +1,5 @@ -// import { expect, haveResource, haveResourceLike, SynthUtils } from '@aws-cdk/assert'; -import { SynthUtils } from '@aws-cdk/assert'; +// import { expect, haveResource, haveResourceLike, SynthUtils } from '@aws-cdk/assert-internal'; +import { SynthUtils } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { IConstruct } from 'constructs'; import { nodeunitShim, Test } from 'nodeunit-shim'; diff --git a/packages/@aws-cdk/aws-s3/test/bucket-policy.test.ts b/packages/@aws-cdk/aws-s3/test/bucket-policy.test.ts index bb3a5fd6de135..3599c1c0e316a 100644 --- a/packages/@aws-cdk/aws-s3/test/bucket-policy.test.ts +++ b/packages/@aws-cdk/aws-s3/test/bucket-policy.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import { AnyPrincipal, PolicyStatement } from '@aws-cdk/aws-iam'; import { RemovalPolicy, Stack, App } from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; diff --git a/packages/@aws-cdk/aws-s3/test/bucket.test.ts b/packages/@aws-cdk/aws-s3/test/bucket.test.ts index 936c807e8da4a..95a8cf377dfc6 100644 --- a/packages/@aws-cdk/aws-s3/test/bucket.test.ts +++ b/packages/@aws-cdk/aws-s3/test/bucket.test.ts @@ -1,6 +1,6 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { EOL } from 'os'; -import { ResourcePart, SynthUtils, arrayWith, objectLike } from '@aws-cdk/assert'; +import { ResourcePart, SynthUtils, arrayWith, objectLike } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as cdk from '@aws-cdk/core'; @@ -307,20 +307,28 @@ describe('bucket', () => { }, 'Effect': 'Deny', 'Principal': '*', - 'Resource': { - 'Fn::Join': [ - '', - [ - { - 'Fn::GetAtt': [ - 'MyBucketF68F3FF0', - 'Arn', - ], - }, - '/*', + 'Resource': [ + { + 'Fn::GetAtt': [ + 'MyBucketF68F3FF0', + 'Arn', ], - ], - }, + }, + { + 'Fn::Join': [ + '', + [ + { + 'Fn::GetAtt': [ + 'MyBucketF68F3FF0', + 'Arn', + ], + }, + '/*', + ], + ], + }, + ], }, ], 'Version': '2012-10-17', @@ -1591,10 +1599,15 @@ describe('bucket', () => { test('urlForObject returns a token with the S3 URL of the token', () => { const stack = new cdk.Stack(); const bucket = new s3.Bucket(stack, 'MyBucket'); + const bucketWithRegion = s3.Bucket.fromBucketAttributes(stack, 'RegionalBucket', { + bucketArn: 'arn:aws:s3:::explicit-region-bucket', + region: 'us-west-2', + }); new cdk.CfnOutput(stack, 'BucketURL', { value: bucket.urlForObject() }); new cdk.CfnOutput(stack, 'MyFileURL', { value: bucket.urlForObject('my/file.txt') }); new cdk.CfnOutput(stack, 'YourFileURL', { value: bucket.urlForObject('/your/file.txt') }); // "/" is optional + new cdk.CfnOutput(stack, 'RegionBucketURL', { value: bucketWithRegion.urlForObject() }); expect(stack).toMatchTemplate({ 'Resources': { @@ -1670,6 +1683,20 @@ describe('bucket', () => { ], }, }, + 'RegionBucketURL': { + 'Value': { + 'Fn::Join': [ + '', + [ + 'https://s3.us-west-2.', + { + 'Ref': 'AWS::URLSuffix', + }, + '/explicit-region-bucket', + ], + ], + }, + }, }, }); @@ -2445,4 +2472,4 @@ describe('bucket', () => { autoDeleteObjects: true, })).toThrow(/Cannot use \'autoDeleteObjects\' property on a bucket without setting removal policy to \'DESTROY\'/); }); -}); \ No newline at end of file +}); diff --git a/packages/@aws-cdk/aws-s3/test/cors.test.ts b/packages/@aws-cdk/aws-s3/test/cors.test.ts index 45daf74c75742..5769c1059640d 100644 --- a/packages/@aws-cdk/aws-s3/test/cors.test.ts +++ b/packages/@aws-cdk/aws-s3/test/cors.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import { Stack } from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import { Bucket, HttpMethods } from '../lib'; diff --git a/packages/@aws-cdk/aws-s3/test/metrics.test.ts b/packages/@aws-cdk/aws-s3/test/metrics.test.ts index c82267afcadd1..bf7e57e04b557 100644 --- a/packages/@aws-cdk/aws-s3/test/metrics.test.ts +++ b/packages/@aws-cdk/aws-s3/test/metrics.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import { Stack } from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import { Bucket } from '../lib'; diff --git a/packages/@aws-cdk/aws-s3/test/notification.test.ts b/packages/@aws-cdk/aws-s3/test/notification.test.ts index a96290643770d..75906826ddeff 100644 --- a/packages/@aws-cdk/aws-s3/test/notification.test.ts +++ b/packages/@aws-cdk/aws-s3/test/notification.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike, ResourcePart } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike, ResourcePart } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import * as s3 from '../lib'; diff --git a/packages/@aws-cdk/aws-s3/test/rules.test.ts b/packages/@aws-cdk/aws-s3/test/rules.test.ts index 8e3a5ea5c3530..6b64f919895e1 100644 --- a/packages/@aws-cdk/aws-s3/test/rules.test.ts +++ b/packages/@aws-cdk/aws-s3/test/rules.test.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import { Duration, Stack } from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import { Bucket, StorageClass } from '../lib'; diff --git a/packages/@aws-cdk/aws-s3objectlambda/.eslintrc.js b/packages/@aws-cdk/aws-s3objectlambda/.eslintrc.js new file mode 100644 index 0000000000000..61dd8dd001f63 --- /dev/null +++ b/packages/@aws-cdk/aws-s3objectlambda/.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-s3objectlambda/.gitignore b/packages/@aws-cdk/aws-s3objectlambda/.gitignore new file mode 100644 index 0000000000000..62ebc95d75ce6 --- /dev/null +++ b/packages/@aws-cdk/aws-s3objectlambda/.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-s3objectlambda/.npmignore b/packages/@aws-cdk/aws-s3objectlambda/.npmignore new file mode 100644 index 0000000000000..e4486030fcb17 --- /dev/null +++ b/packages/@aws-cdk/aws-s3objectlambda/.npmignore @@ -0,0 +1,28 @@ +# 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 +test/ diff --git a/packages/@aws-cdk/aws-s3objectlambda/LICENSE b/packages/@aws-cdk/aws-s3objectlambda/LICENSE new file mode 100644 index 0000000000000..28e4bdcec77ec --- /dev/null +++ b/packages/@aws-cdk/aws-s3objectlambda/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-2021 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-s3objectlambda/NOTICE b/packages/@aws-cdk/aws-s3objectlambda/NOTICE new file mode 100644 index 0000000000000..5fc3826926b5b --- /dev/null +++ b/packages/@aws-cdk/aws-s3objectlambda/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/aws-s3objectlambda/README.md b/packages/@aws-cdk/aws-s3objectlambda/README.md new file mode 100644 index 0000000000000..ebb6f1b79c7e6 --- /dev/null +++ b/packages/@aws-cdk/aws-s3objectlambda/README.md @@ -0,0 +1,20 @@ +# AWS::S3ObjectLambda 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]) are always stable and safe to use. +> +> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib + +--- + + + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts +import s3objectlambda = require('@aws-cdk/aws-s3objectlambda'); +``` diff --git a/packages/@aws-cdk/aws-s3objectlambda/jest.config.js b/packages/@aws-cdk/aws-s3objectlambda/jest.config.js new file mode 100644 index 0000000000000..54e28beb9798b --- /dev/null +++ b/packages/@aws-cdk/aws-s3objectlambda/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-s3objectlambda/lib/index.ts b/packages/@aws-cdk/aws-s3objectlambda/lib/index.ts new file mode 100644 index 0000000000000..791ddcf126933 --- /dev/null +++ b/packages/@aws-cdk/aws-s3objectlambda/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::S3ObjectLambda CloudFormation Resources: +export * from './s3objectlambda.generated'; diff --git a/packages/@aws-cdk/aws-s3objectlambda/package.json b/packages/@aws-cdk/aws-s3objectlambda/package.json new file mode 100644 index 0000000000000..9290f9ae9b2d7 --- /dev/null +++ b/packages/@aws-cdk/aws-s3objectlambda/package.json @@ -0,0 +1,101 @@ +{ + "name": "@aws-cdk/aws-s3objectlambda", + "version": "0.0.0", + "description": "The CDK Construct Library for AWS::S3ObjectLambda", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "projectReferences": true, + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.S3ObjectLambda", + "packageId": "Amazon.CDK.AWS.S3ObjectLambda", + "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.s3objectlambda", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "s3objectlambda" + } + }, + "python": { + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 1" + ], + "distName": "aws-cdk.aws-s3objectlambda", + "module": "aws_cdk.aws_s3objectlambda" + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-s3objectlambda" + }, + "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": "yarn build && yarn test", + "build+test+package": "yarn build+test && yarn package", + "compat": "cdk-compat", + "gen": "cfn2ts", + "rosetta:extract": "yarn --silent jsii-rosetta extract" + }, + "cdk-build": { + "cloudformation": "AWS::S3ObjectLambda", + "jest": true, + "env": { + "AWSLINT_BASE_CONSTRUCT": "true" + } + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::S3ObjectLambda", + "aws-s3objectlambda" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@types/jest": "^26.0.23", + "cdk-build-tools": "0.0.0", + "cfn2ts": "0.0.0", + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "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 + }, + "publishConfig": { + "tag": "latest" + } +} diff --git a/packages/@aws-cdk/aws-s3objectlambda/test/s3objectlambda.test.ts b/packages/@aws-cdk/aws-s3objectlambda/test/s3objectlambda.test.ts new file mode 100644 index 0000000000000..c4505ad966984 --- /dev/null +++ b/packages/@aws-cdk/aws-s3objectlambda/test/s3objectlambda.test.ts @@ -0,0 +1,6 @@ +import '@aws-cdk/assert-internal/jest'; +import {} from '../lib'; + +test('No tests are specified for this package', () => { + expect(true).toBe(true); +}); diff --git a/packages/@aws-cdk/aws-s3outposts/package.json b/packages/@aws-cdk/aws-s3outposts/package.json index 7965518ea1d24..d7d883fa69912 100644 --- a/packages/@aws-cdk/aws-s3outposts/package.json +++ b/packages/@aws-cdk/aws-s3outposts/package.json @@ -75,10 +75,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-s3outposts/test/s3outposts.test.ts b/packages/@aws-cdk/aws-s3outposts/test/s3outposts.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-s3outposts/test/s3outposts.test.ts +++ b/packages/@aws-cdk/aws-s3outposts/test/s3outposts.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-sagemaker/package.json b/packages/@aws-cdk/aws-sagemaker/package.json index 532be18efa37d..dc213cf4ca8c1 100644 --- a/packages/@aws-cdk/aws-sagemaker/package.json +++ b/packages/@aws-cdk/aws-sagemaker/package.json @@ -72,18 +72,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-sagemaker/test/sagemaker.test.ts b/packages/@aws-cdk/aws-sagemaker/test/sagemaker.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-sagemaker/test/sagemaker.test.ts +++ b/packages/@aws-cdk/aws-sagemaker/test/sagemaker.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-sam/package.json b/packages/@aws-cdk/aws-sam/package.json index 52991896dcda8..ed7cad3507755 100644 --- a/packages/@aws-cdk/aws-sam/package.json +++ b/packages/@aws-cdk/aws-sam/package.json @@ -72,21 +72,21 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", - "@types/jest": "^26.0.21", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "jest": "^26.6.3", "pkglint": "0.0.0", - "ts-jest": "^26.5.4" + "ts-jest": "^26.5.5", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-sam/test/application.test.ts b/packages/@aws-cdk/aws-sam/test/application.test.ts index ef41cd0a10385..748eaf75732e9 100644 --- a/packages/@aws-cdk/aws-sam/test/application.test.ts +++ b/packages/@aws-cdk/aws-sam/test/application.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import { CfnApplication } from '../lib'; diff --git a/packages/@aws-cdk/aws-sam/test/function.test.ts b/packages/@aws-cdk/aws-sam/test/function.test.ts index d8dade625be0e..2633c1ea46af3 100644 --- a/packages/@aws-cdk/aws-sam/test/function.test.ts +++ b/packages/@aws-cdk/aws-sam/test/function.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import * as sam from '../lib'; diff --git a/packages/@aws-cdk/aws-sdb/package.json b/packages/@aws-cdk/aws-sdb/package.json index 9c1660f111f4b..4f6e583a82ced 100644 --- a/packages/@aws-cdk/aws-sdb/package.json +++ b/packages/@aws-cdk/aws-sdb/package.json @@ -71,19 +71,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-sdb/test/sdb.test.ts b/packages/@aws-cdk/aws-sdb/test/sdb.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-sdb/test/sdb.test.ts +++ b/packages/@aws-cdk/aws-sdb/test/sdb.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-secretsmanager/README.md b/packages/@aws-cdk/aws-secretsmanager/README.md index 959b73e12a669..0c0f45828e9ef 100644 --- a/packages/@aws-cdk/aws-secretsmanager/README.md +++ b/packages/@aws-cdk/aws-secretsmanager/README.md @@ -180,3 +180,28 @@ const mySecretFromAttrs = secretsmanager.Secret.fromSecretAttributes(stack, 'Sec encryptionKey, }); ``` + +## Replicating secrets + +Secrets can be replicated to multiple regions by specifying `replicaRegions`: + +```ts +new secretsmanager.Secret(this, 'Secret', { + replicaRegions: [ + { + region: 'eu-west-1', + }, + { + region: 'eu-central-1', + encryptionKey: myKey, + } + ] +}); +``` + +Alternatively, use `addReplicaRegion()`: + +```ts +const secret = new secretsmanager.Secret(this, 'Secret'); +secret.addReplicaRegion('eu-west-1'); +``` diff --git a/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts b/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts index 92ca9cad73ee2..f438c5fd21e14 100644 --- a/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts +++ b/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts @@ -1,6 +1,6 @@ import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; -import { FeatureFlags, Fn, IResource, RemovalPolicy, Resource, SecretValue, Stack, Token } from '@aws-cdk/core'; +import { FeatureFlags, Fn, IResource, Lazy, RemovalPolicy, Resource, SecretValue, Stack, Token } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { IConstruct, Construct } from 'constructs'; import { ResourcePolicy } from './policy'; @@ -134,6 +134,30 @@ export interface SecretProps { * @default - Not set. */ readonly removalPolicy?: RemovalPolicy; + + /** + * A list of regions where to replicate this secret. + * + * @default - Secret is not replicated + */ + readonly replicaRegions?: ReplicaRegion[]; +} + +/** + * Secret replica region + */ +export interface ReplicaRegion { + /** + * The name of the region + */ + readonly region: string; + + /** + * The customer-managed encryption key to use for encrypting the secret value. + * + * @default - A default KMS key for the account and region is used. + */ + readonly encryptionKey?: kms.IKey; } /** @@ -408,6 +432,8 @@ export class Secret extends SecretBase { public readonly secretArn: string; public readonly secretName: string; + private replicaRegions: secretsmanager.CfnSecret.ReplicaRegionProperty[] = []; + protected readonly autoCreatePolicy = true; constructor(scope: Construct, id: string, props: SecretProps = {}) { @@ -426,6 +452,7 @@ export class Secret extends SecretBase { kmsKeyId: props.encryptionKey && props.encryptionKey.keyArn, generateSecretString: props.generateSecretString || {}, name: this.physicalName, + replicaRegions: Lazy.any({ produce: () => this.replicaRegions }, { omitEmptyArray: true }), }); if (props.removalPolicy) { @@ -450,6 +477,10 @@ export class Secret extends SecretBase { new kms.ViaServicePrincipal(`secretsmanager.${Stack.of(this).region}.amazonaws.com`, new iam.AccountPrincipal(Stack.of(this).account)); this.encryptionKey?.grantEncryptDecrypt(principal); this.encryptionKey?.grant(principal, 'kms:CreateGrant', 'kms:DescribeKey'); + + for (const replica of props.replicaRegions ?? []) { + this.addReplicaRegion(replica.region, replica.encryptionKey); + } } /** @@ -465,6 +496,24 @@ export class Secret extends SecretBase { ...options, }); } + + /** + * Adds a replica region for the secret + * + * @param region The name of the region + * @param encryptionKey The customer-managed encryption key to use for encrypting the secret value. + */ + public addReplicaRegion(region: string, encryptionKey?: kms.IKey): void { + const stack = Stack.of(this); + if (!Token.isUnresolved(stack.region) && !Token.isUnresolved(region) && region === stack.region) { + throw new Error('Cannot add the region where this stack is deployed as a replica region.'); + } + + this.replicaRegions.push({ + region, + kmsKeyId: encryptionKey?.keyArn, + }); + } } /** diff --git a/packages/@aws-cdk/aws-secretsmanager/package.json b/packages/@aws-cdk/aws-secretsmanager/package.json index fbd131bf94e89..503450cd297b4 100644 --- a/packages/@aws-cdk/aws-secretsmanager/package.json +++ b/packages/@aws-cdk/aws-secretsmanager/package.json @@ -72,11 +72,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", @@ -86,7 +87,7 @@ "@aws-cdk/aws-sam": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/aws-ec2": "0.0.0", @@ -96,7 +97,7 @@ "@aws-cdk/aws-sam": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-secretsmanager/test/integ.replica.expected.json b/packages/@aws-cdk/aws-secretsmanager/test/integ.replica.expected.json new file mode 100644 index 0000000000000..99fd65c02e2b4 --- /dev/null +++ b/packages/@aws-cdk/aws-secretsmanager/test/integ.replica.expected.json @@ -0,0 +1,15 @@ +{ + "Resources": { + "SecretA720EF05": { + "Type": "AWS::SecretsManager::Secret", + "Properties": { + "GenerateSecretString": {}, + "ReplicaRegions": [ + { + "Region": "eu-central-1" + } + ] + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-secretsmanager/test/integ.replica.ts b/packages/@aws-cdk/aws-secretsmanager/test/integ.replica.ts new file mode 100644 index 0000000000000..b172a46eac567 --- /dev/null +++ b/packages/@aws-cdk/aws-secretsmanager/test/integ.replica.ts @@ -0,0 +1,15 @@ +import * as cdk from '@aws-cdk/core'; +import * as secretsmanager from '../lib'; + +class TestStack extends cdk.Stack { + constructor(scope: cdk.App, id: string) { + super(scope, id); + + const secret = new secretsmanager.Secret(this, 'Secret'); + secret.addReplicaRegion('eu-central-1'); + } +} + +const app = new cdk.App(); +new TestStack(app, 'cdk-integ-secrets-replica'); +app.synth(); diff --git a/packages/@aws-cdk/aws-secretsmanager/test/rotation-schedule.test.ts b/packages/@aws-cdk/aws-secretsmanager/test/rotation-schedule.test.ts index 56eff9534a776..e77336732d51b 100644 --- a/packages/@aws-cdk/aws-secretsmanager/test/rotation-schedule.test.ts +++ b/packages/@aws-cdk/aws-secretsmanager/test/rotation-schedule.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as lambda from '@aws-cdk/aws-lambda'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-secretsmanager/test/secret-rotation.test.ts b/packages/@aws-cdk/aws-secretsmanager/test/secret-rotation.test.ts index f2b6b016dd582..e6e4943c2c74a 100644 --- a/packages/@aws-cdk/aws-secretsmanager/test/secret-rotation.test.ts +++ b/packages/@aws-cdk/aws-secretsmanager/test/secret-rotation.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import * as secretsmanager from '../lib'; diff --git a/packages/@aws-cdk/aws-secretsmanager/test/secret.test.ts b/packages/@aws-cdk/aws-secretsmanager/test/secret.test.ts index 73fc366a6eb18..c2ee7200d05bd 100644 --- a/packages/@aws-cdk/aws-secretsmanager/test/secret.test.ts +++ b/packages/@aws-cdk/aws-secretsmanager/test/secret.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert/jest'; -import { expect as assertExpect, ResourcePart } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +import { expect as assertExpect, ResourcePart } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as lambda from '@aws-cdk/aws-lambda'; @@ -1071,3 +1071,28 @@ test('fails if secret policy has no IAM principals', () => { // THEN expect(() => app.synth()).toThrow(/A PolicyStatement used in a resource-based policy must specify at least one IAM principal/); }); + +test('with replication regions', () => { + // WHEN + const secret = new secretsmanager.Secret(stack, 'Secret', { + replicaRegions: [ + { + region: 'eu-west-1', + }, + ], + }); + secret.addReplicaRegion('eu-central-1', kms.Key.fromKeyArn(stack, 'Key', 'arn:aws:kms:eu-central-1:123456789012:key/my-key-id')); + + // THEN + expect(stack).toHaveResource('AWS::SecretsManager::Secret', { + ReplicaRegions: [ + { + Region: 'eu-west-1', + }, + { + KmsKeyId: 'arn:aws:kms:eu-central-1:123456789012:key/my-key-id', + Region: 'eu-central-1', + }, + ], + }); +}); diff --git a/packages/@aws-cdk/aws-securityhub/package.json b/packages/@aws-cdk/aws-securityhub/package.json index 32dc742b38c9c..4ccfef27c4f79 100644 --- a/packages/@aws-cdk/aws-securityhub/package.json +++ b/packages/@aws-cdk/aws-securityhub/package.json @@ -73,18 +73,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-securityhub/test/securityhub.test.ts b/packages/@aws-cdk/aws-securityhub/test/securityhub.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-securityhub/test/securityhub.test.ts +++ b/packages/@aws-cdk/aws-securityhub/test/securityhub.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-servicecatalog/package.json b/packages/@aws-cdk/aws-servicecatalog/package.json index 546f615a66693..ff4a03d2d8458 100644 --- a/packages/@aws-cdk/aws-servicecatalog/package.json +++ b/packages/@aws-cdk/aws-servicecatalog/package.json @@ -71,19 +71,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-servicecatalog/test/servicecatalog.test.ts b/packages/@aws-cdk/aws-servicecatalog/test/servicecatalog.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-servicecatalog/test/servicecatalog.test.ts +++ b/packages/@aws-cdk/aws-servicecatalog/test/servicecatalog.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-servicecatalogappregistry/package.json b/packages/@aws-cdk/aws-servicecatalogappregistry/package.json index 8887c8c0682d6..ada592033fcc8 100644 --- a/packages/@aws-cdk/aws-servicecatalogappregistry/package.json +++ b/packages/@aws-cdk/aws-servicecatalogappregistry/package.json @@ -75,10 +75,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-servicecatalogappregistry/test/servicecatalogappregistry.test.ts b/packages/@aws-cdk/aws-servicecatalogappregistry/test/servicecatalogappregistry.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-servicecatalogappregistry/test/servicecatalogappregistry.test.ts +++ b/packages/@aws-cdk/aws-servicecatalogappregistry/test/servicecatalogappregistry.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-servicediscovery/package.json b/packages/@aws-cdk/aws-servicediscovery/package.json index 4af44ea9879e1..69148f4c9f769 100644 --- a/packages/@aws-cdk/aws-servicediscovery/package.json +++ b/packages/@aws-cdk/aws-servicediscovery/package.json @@ -73,20 +73,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "nodeunit": "^0.11.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -94,7 +94,7 @@ "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-servicediscovery/test/test.instance.ts b/packages/@aws-cdk/aws-servicediscovery/test/test.instance.ts index c06e0a61cccd7..bdf9b3c2005e4 100644 --- a/packages/@aws-cdk/aws-servicediscovery/test/test.instance.ts +++ b/packages/@aws-cdk/aws-servicediscovery/test/test.instance.ts @@ -1,4 +1,4 @@ -import { countResources, expect, haveResource } from '@aws-cdk/assert'; +import { countResources, expect, haveResource } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-servicediscovery/test/test.namespace.ts b/packages/@aws-cdk/aws-servicediscovery/test/test.namespace.ts index df3e2a675bec0..0c78bb91beb4d 100644 --- a/packages/@aws-cdk/aws-servicediscovery/test/test.namespace.ts +++ b/packages/@aws-cdk/aws-servicediscovery/test/test.namespace.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk/aws-servicediscovery/test/test.service.ts b/packages/@aws-cdk/aws-servicediscovery/test/test.service.ts index 45e641f330e6d..eb226228e269d 100644 --- a/packages/@aws-cdk/aws-servicediscovery/test/test.service.ts +++ b/packages/@aws-cdk/aws-servicediscovery/test/test.service.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; diff --git a/packages/@aws-cdk/aws-ses-actions/README.md b/packages/@aws-cdk/aws-ses-actions/README.md index 37d4ff339145a..62ad3d397fb26 100644 --- a/packages/@aws-cdk/aws-ses-actions/README.md +++ b/packages/@aws-cdk/aws-ses-actions/README.md @@ -3,13 +3,7 @@ --- -![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. +![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge) --- diff --git a/packages/@aws-cdk/aws-ses-actions/package.json b/packages/@aws-cdk/aws-ses-actions/package.json index ea141e0c8d37f..1c8644ac79069 100644 --- a/packages/@aws-cdk/aws-ses-actions/package.json +++ b/packages/@aws-cdk/aws-ses-actions/package.json @@ -63,12 +63,13 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", @@ -78,7 +79,7 @@ "@aws-cdk/aws-ses": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -89,13 +90,13 @@ "@aws-cdk/aws-ses": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, - "stability": "experimental", - "maturity": "experimental", + "stability": "stable", + "maturity": "stable", "awslint": { "exclude": [ "docs-public-apis:@aws-cdk/aws-ses-actions.BounceTemplate.MAILBOX_DOES_NOT_EXIST", diff --git a/packages/@aws-cdk/aws-ses-actions/test/actions.test.ts b/packages/@aws-cdk/aws-ses-actions/test/actions.test.ts index d3268e949b7dc..4a425fd51f76b 100644 --- a/packages/@aws-cdk/aws-ses-actions/test/actions.test.ts +++ b/packages/@aws-cdk/aws-ses-actions/test/actions.test.ts @@ -1,5 +1,5 @@ -import { arrayWith, ResourcePart } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { arrayWith, ResourcePart } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as kms from '@aws-cdk/aws-kms'; import * as lambda from '@aws-cdk/aws-lambda'; import * as s3 from '@aws-cdk/aws-s3'; diff --git a/packages/@aws-cdk/aws-ses-actions/test/integ.actions.ts b/packages/@aws-cdk/aws-ses-actions/test/integ.actions.ts index 45d8d61e49e28..a34f6d0b86e0a 100644 --- a/packages/@aws-cdk/aws-ses-actions/test/integ.actions.ts +++ b/packages/@aws-cdk/aws-ses-actions/test/integ.actions.ts @@ -1,3 +1,4 @@ +/// !cdk-integ pragma:ignore-assets import * as kms from '@aws-cdk/aws-kms'; import * as lambda from '@aws-cdk/aws-lambda'; import * as s3 from '@aws-cdk/aws-s3'; diff --git a/packages/@aws-cdk/aws-ses/README.md b/packages/@aws-cdk/aws-ses/README.md index b8543970796ad..b2d36c9785175 100644 --- a/packages/@aws-cdk/aws-ses/README.md +++ b/packages/@aws-cdk/aws-ses/README.md @@ -5,17 +5,7 @@ ![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]) are always stable and safe to use. -> -> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib - -![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. +![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge) --- @@ -108,10 +98,10 @@ new ses.ReceiptFilter(this, 'Filter', { }) ``` -A white list filter is also available: +An allow list filter is also available: ```ts -new ses.WhiteListReceiptFilter(this, 'WhiteList', { +new ses.AllowListReceiptFilter(this, 'AllowList', { ips: [ '10.0.0.0/16', '1.2.3.4/16', diff --git a/packages/@aws-cdk/aws-ses/lib/receipt-filter.ts b/packages/@aws-cdk/aws-ses/lib/receipt-filter.ts index 81ee76d5adbff..9c703207fdf4f 100644 --- a/packages/@aws-cdk/aws-ses/lib/receipt-filter.ts +++ b/packages/@aws-cdk/aws-ses/lib/receipt-filter.ts @@ -70,20 +70,20 @@ export class ReceiptFilter extends Resource { } /** - * Construction properties for a WhiteListReceiptFilter. + * Construction properties for am AllowListReceiptFilter. */ -export interface WhiteListReceiptFilterProps { +export interface AllowListReceiptFilterProps { /** - * A list of ip addresses or ranges to white list. + * A list of ip addresses or ranges to allow list. */ readonly ips: string[]; } /** - * A white list receipt filter. + * An allow list receipt filter. */ -export class WhiteListReceiptFilter extends CoreConstruct { - constructor(scope: Construct, id: string, props: WhiteListReceiptFilterProps) { +export class AllowListReceiptFilter extends CoreConstruct { + constructor(scope: Construct, id: string, props: AllowListReceiptFilterProps) { super(scope, id); new ReceiptFilter(this, 'BlockAll'); @@ -96,3 +96,19 @@ export class WhiteListReceiptFilter extends CoreConstruct { }); } } + +/** + * Construction properties for a WhiteListReceiptFilter. + * @deprecated use `AllowListReceiptFilterProps` + */ +export interface WhiteListReceiptFilterProps extends AllowListReceiptFilterProps { } + +/** + * An allow list receipt filter. + * @deprecated use `AllowListReceiptFilter` + */ +export class WhiteListReceiptFilter extends AllowListReceiptFilter { + constructor(scope: Construct, id: string, props: WhiteListReceiptFilterProps) { + super(scope, id, props); + } +} diff --git a/packages/@aws-cdk/aws-ses/lib/receipt-rule-action.ts b/packages/@aws-cdk/aws-ses/lib/receipt-rule-action.ts index 38f08a03ee425..33b29627c8f5f 100644 --- a/packages/@aws-cdk/aws-ses/lib/receipt-rule-action.ts +++ b/packages/@aws-cdk/aws-ses/lib/receipt-rule-action.ts @@ -1,5 +1,4 @@ import { IReceiptRule } from './receipt-rule'; -import { CfnReceiptRule } from './ses.generated'; /** * An abstract action for a receipt rule. @@ -11,6 +10,194 @@ export interface IReceiptRuleAction { bind(receiptRule: IReceiptRule): ReceiptRuleActionConfig; } +/** + * AddHeaderAction configuration. + */ +export interface AddHeaderActionConfig { + /** + * The name of the header that you want to add to the incoming message + * + * @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-receiptrule-addheaderaction.html#cfn-ses-receiptrule-addheaderaction-headername + */ + readonly headerName: string; + /** + * The content that you want to include in the header. + * + * @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-receiptrule-addheaderaction.html#cfn-ses-receiptrule-addheaderaction-headervalue + */ + readonly headerValue: string; +} + +/** + * BoundAction configuration. + */ +export interface BounceActionConfig { + /** + * Human-readable text to include in the bounce message. + * + * @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-receiptrule-bounceaction.html#cfn-ses-receiptrule-bounceaction-message + */ + readonly message: string; + /** + * The email address of the sender of the bounced email. + * This is the address that the bounce message is sent from. + * + * @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-receiptrule-bounceaction.html#cfn-ses-receiptrule-bounceaction-sender + */ + readonly sender: string; + /** + * The SMTP reply code, as defined by RFC 5321 + * + * @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-receiptrule-bounceaction.html#cfn-ses-receiptrule-bounceaction-smtpreplycode + */ + readonly smtpReplyCode: string; + /** + * The SMTP enhanced status code, as defined by RFC 3463 + * + * @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-receiptrule-bounceaction.html#cfn-ses-receiptrule-bounceaction-statuscode + * + * @default - No status code. + */ + readonly statusCode?: string; + /** + * The Amazon Resource Name (ARN) of the Amazon SNS topic to + * notify when the bounce action is taken. + * + * @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-receiptrule-bounceaction.html#cfn-ses-receiptrule-bounceaction-topicarn + * + * @default - No notification is sent to SNS. + */ + readonly topicArn?: string; +} + +/** + * LambdaAction configuration. + */ +export interface LambdaActionConfig { + /** + * The Amazon Resource Name (ARN) of the AWS Lambda function. + * + * @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-receiptrule-lambdaaction.html#cfn-ses-receiptrule-lambdaaction-functionarn + */ + readonly functionArn: string; + /** + * The invocation type of the AWS Lambda function + * + * @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-receiptrule-lambdaaction.html#cfn-ses-receiptrule-lambdaaction-invocationtype + * + * @default 'Event' + */ + readonly invocationType?: string; + /** + * The Amazon Resource Name (ARN) of the Amazon SNS topic to + * notify when the Lambda action is executed. + * + * @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-receiptrule-lambdaaction.html#cfn-ses-receiptrule-lambdaaction-topicarn + * + * @default - No notification is sent to SNS. + */ + readonly topicArn?: string; +} + +/** + * S3Action configuration. + */ +export interface S3ActionConfig { + /** + * The name of the Amazon S3 bucket that you want to send incoming mail to. + * + * @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-receiptrule-s3action.html#cfn-ses-receiptrule-s3action-bucketname + */ + readonly bucketName: string; + /** + * The customer master key that Amazon SES should use to encrypt your emails before saving + * them to the Amazon S3 bucket. + * + * @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-receiptrule-s3action.html#cfn-ses-receiptrule-s3action-kmskeyarn + * + * @default - Emails are not encrypted. + */ + readonly kmsKeyArn?: string; + /** + * The key prefix of the Amazon S3 bucket. + * + * @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-receiptrule-s3action.html#cfn-ses-receiptrule-s3action-objectkeyprefix + * + * @default - No prefix. + */ + readonly objectKeyPrefix?: string; + /** + * The ARN of the Amazon SNS topic to notify when the message is saved to the Amazon S3 bucket. + * + * @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-receiptrule-s3action.html#cfn-ses-receiptrule-s3action-topicarn + * + * @default - No notification is sent to SNS. + */ + readonly topicArn?: string; +} + +/** + * SNSAction configuration. + */ +export interface SNSActionConfig { + /** + * The encoding to use for the email within the Amazon SNS notification. + * + * @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-receiptrule-snsaction.html#cfn-ses-receiptrule-snsaction-encoding + * + * @default 'UTF-8' + */ + readonly encoding?: string; + /** + * The Amazon Resource Name (ARN) of the Amazon SNS topic to notify. + * + * @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-receiptrule-snsaction.html#cfn-ses-receiptrule-snsaction-topicarn + * + * @default - No notification is sent to SNS. + */ + readonly topicArn?: string; +} + +/** + * StopAction configuration. + */ +export interface StopActionConfig { + /** + * The scope of the StopAction. The only acceptable value is RuleSet. + * + * @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-receiptrule-stopaction.html#cfn-ses-receiptrule-stopaction-scope + */ + readonly scope: string; + /** + * The Amazon Resource Name (ARN) of the Amazon SNS topic to notify when the stop action is taken. + * + * @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-receiptrule-stopaction.html#cfn-ses-receiptrule-stopaction-topicarn + * + * @default - No notification is sent to SNS. + */ + readonly topicArn?: string; +} + +/** + * WorkmailAction configuration. + */ +export interface WorkmailActionConfig { + /** + * The Amazon Resource Name (ARN) of the Amazon WorkMail organization. + * + * @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-receiptrule-workmailaction.html#cfn-ses-receiptrule-workmailaction-organizationarn + */ + readonly organizationArn: string; + /** + * The Amazon Resource Name (ARN) of the Amazon SNS topic to notify when the WorkMail action is called. + * + * @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-receiptrule-workmailaction.html#cfn-ses-receiptrule-workmailaction-topicarn + * + * @default - No notification is sent to SNS. + */ + readonly topicArn?: string; +} + /** * Properties for a receipt rule action. */ @@ -18,39 +205,39 @@ export interface ReceiptRuleActionConfig { /** * Adds a header to the received email. */ - readonly addHeaderAction?: CfnReceiptRule.AddHeaderActionProperty + readonly addHeaderAction?: AddHeaderActionConfig /** * Rejects the received email by returning a bounce response to the sender and, * optionally, publishes a notification to Amazon SNS. */ - readonly bounceAction?: CfnReceiptRule.BounceActionProperty; + readonly bounceAction?: BounceActionConfig; /** * Calls an AWS Lambda function, and optionally, publishes a notification to * Amazon SNS. */ - readonly lambdaAction?: CfnReceiptRule.LambdaActionProperty; + readonly lambdaAction?: LambdaActionConfig; /** * Saves the received message to an Amazon S3 bucket and, optionally, publishes * a notification to Amazon SNS. */ - readonly s3Action?: CfnReceiptRule.S3ActionProperty; + readonly s3Action?: S3ActionConfig; /** * Publishes the email content within a notification to Amazon SNS. */ - readonly snsAction?: CfnReceiptRule.SNSActionProperty; + readonly snsAction?: SNSActionConfig; /** * Terminates the evaluation of the receipt rule set and optionally publishes a * notification to Amazon SNS. */ - readonly stopAction?: CfnReceiptRule.StopActionProperty; + readonly stopAction?: StopActionConfig; /** * Calls Amazon WorkMail and, optionally, publishes a notification to Amazon SNS. */ - readonly workmailAction?: CfnReceiptRule.WorkmailActionProperty; + readonly workmailAction?: WorkmailActionConfig; } diff --git a/packages/@aws-cdk/aws-ses/package.json b/packages/@aws-cdk/aws-ses/package.json index c4fac8762a988..6648518b288f4 100644 --- a/packages/@aws-cdk/aws-ses/package.json +++ b/packages/@aws-cdk/aws-ses/package.json @@ -70,32 +70,33 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/aws-lambda": "^8.10.76", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "nodeunit": "^0.11.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, - "stability": "experimental", - "maturity": "experimental", + "stability": "stable", + "maturity": "stable", "awslint": { "exclude": [ "props-default-doc:@aws-cdk/aws-ses.ReceiptRuleActionConfig.addHeaderAction", diff --git a/packages/@aws-cdk/aws-ses/test/integ.receipt.expected.json b/packages/@aws-cdk/aws-ses/test/integ.receipt.expected.json index 2bb22f110b951..0a9442a97f6a0 100644 --- a/packages/@aws-cdk/aws-ses/test/integ.receipt.expected.json +++ b/packages/@aws-cdk/aws-ses/test/integ.receipt.expected.json @@ -163,7 +163,7 @@ } } }, - "WhiteListBlockAllAE2CDDFF": { + "AllowlistBlockAll7E0A7F11": { "Type": "AWS::SES::ReceiptFilter", "Properties": { "Filter": { @@ -174,7 +174,7 @@ } } }, - "WhiteListAllow1000016F396A7F2": { + "AllowlistAllow1000016E9465A18": { "Type": "AWS::SES::ReceiptFilter", "Properties": { "Filter": { diff --git a/packages/@aws-cdk/aws-ses/test/integ.receipt.ts b/packages/@aws-cdk/aws-ses/test/integ.receipt.ts index 5cf2ae4800ebc..2598496a5ab83 100644 --- a/packages/@aws-cdk/aws-ses/test/integ.receipt.ts +++ b/packages/@aws-cdk/aws-ses/test/integ.receipt.ts @@ -18,7 +18,7 @@ ruleSet.addRule('FirstRule', { ruleSet.addRule('SecondRule'); -new ses.WhiteListReceiptFilter(stack, 'WhiteList', { +new ses.AllowListReceiptFilter(stack, 'Allowlist', { ips: [ '10.0.0.0/16', ], diff --git a/packages/@aws-cdk/aws-ses/test/test.receipt-filter.ts b/packages/@aws-cdk/aws-ses/test/test.receipt-filter.ts index d380d535ad506..7eb95a2d8f97d 100644 --- a/packages/@aws-cdk/aws-ses/test/test.receipt-filter.ts +++ b/packages/@aws-cdk/aws-ses/test/test.receipt-filter.ts @@ -1,7 +1,7 @@ -import { expect } from '@aws-cdk/assert'; +import { expect } from '@aws-cdk/assert-internal'; import { Stack } from '@aws-cdk/core'; import { Test } from 'nodeunit'; -import { ReceiptFilter, ReceiptFilterPolicy, WhiteListReceiptFilter } from '../lib'; +import { AllowListReceiptFilter, ReceiptFilter, ReceiptFilterPolicy } from '../lib'; /* eslint-disable quote-props */ @@ -38,12 +38,12 @@ export = { test.done(); }, - 'can create a white list filter'(test: Test) { + 'can create an allow list filter'(test: Test) { // GIVEN const stack = new Stack(); // WHEN - new WhiteListReceiptFilter(stack, 'WhiteList', { + new AllowListReceiptFilter(stack, 'AllowList', { ips: [ '10.0.0.0/16', '1.2.3.4', @@ -53,7 +53,7 @@ export = { // THEN expect(stack).toMatch({ 'Resources': { - 'WhiteListBlockAllAE2CDDFF': { + 'AllowListBlockAll094C9B97': { 'Type': 'AWS::SES::ReceiptFilter', 'Properties': { 'Filter': { @@ -64,7 +64,7 @@ export = { }, }, }, - 'WhiteListAllow1000016F396A7F2': { + 'AllowListAllow10000164654C092': { 'Type': 'AWS::SES::ReceiptFilter', 'Properties': { 'Filter': { @@ -75,7 +75,7 @@ export = { }, }, }, - 'WhiteListAllow1234A4DDAD4E': { + 'AllowListAllow12345BCAE5C3': { 'Type': 'AWS::SES::ReceiptFilter', 'Properties': { 'Filter': { diff --git a/packages/@aws-cdk/aws-ses/test/test.receipt-rule-set.ts b/packages/@aws-cdk/aws-ses/test/test.receipt-rule-set.ts index 4d308d2f53561..cf4b44f422371 100644 --- a/packages/@aws-cdk/aws-ses/test/test.receipt-rule-set.ts +++ b/packages/@aws-cdk/aws-ses/test/test.receipt-rule-set.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import { Stack } from '@aws-cdk/core'; import { Test } from 'nodeunit'; import { ReceiptRuleSet } from '../lib'; diff --git a/packages/@aws-cdk/aws-ses/test/test.receipt-rule.ts b/packages/@aws-cdk/aws-ses/test/test.receipt-rule.ts index f719e61d3ce87..22962b5df2c3a 100644 --- a/packages/@aws-cdk/aws-ses/test/test.receipt-rule.ts +++ b/packages/@aws-cdk/aws-ses/test/test.receipt-rule.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import { Stack } from '@aws-cdk/core'; import { Test } from 'nodeunit'; import { ReceiptRule, ReceiptRuleSet, TlsPolicy } from '../lib'; diff --git a/packages/@aws-cdk/aws-signer/package.json b/packages/@aws-cdk/aws-signer/package.json index 2baa7ffe143bc..6e3510ffad8e0 100644 --- a/packages/@aws-cdk/aws-signer/package.json +++ b/packages/@aws-cdk/aws-signer/package.json @@ -73,18 +73,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-signer/test/signing-profile.test.ts b/packages/@aws-cdk/aws-signer/test/signing-profile.test.ts index 6148a6be70bda..49ada5da2f596 100644 --- a/packages/@aws-cdk/aws-signer/test/signing-profile.test.ts +++ b/packages/@aws-cdk/aws-signer/test/signing-profile.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import * as signer from '../lib'; diff --git a/packages/@aws-cdk/aws-sns-subscriptions/package.json b/packages/@aws-cdk/aws-sns-subscriptions/package.json index 354b1c386b44e..6efc6c6992166 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/package.json +++ b/packages/@aws-cdk/aws-sns-subscriptions/package.json @@ -62,12 +62,13 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", @@ -75,7 +76,7 @@ "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -84,7 +85,7 @@ "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-sns-subscriptions/test/integ.sns-lambda.ts b/packages/@aws-cdk/aws-sns-subscriptions/test/integ.sns-lambda.ts index 166fa8b982ba2..6b92a97551478 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/test/integ.sns-lambda.ts +++ b/packages/@aws-cdk/aws-sns-subscriptions/test/integ.sns-lambda.ts @@ -29,11 +29,11 @@ class SnsToLambda extends cdk.Stack { topic.addSubscription(new subs.LambdaSubscription(fctionFiltered, { filterPolicy: { color: sns.SubscriptionFilter.stringFilter({ - whitelist: ['red'], + allowlist: ['red'], matchPrefixes: ['bl', 'ye'], }), size: sns.SubscriptionFilter.stringFilter({ - blacklist: ['small', 'medium'], + denylist: ['small', 'medium'], }), price: sns.SubscriptionFilter.numericFilter({ between: { start: 100, stop: 200 }, diff --git a/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts b/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts index 4bd8646176d08..d0583ea182595 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts +++ b/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as lambda from '@aws-cdk/aws-lambda'; import * as sns from '@aws-cdk/aws-sns'; import * as sqs from '@aws-cdk/aws-sqs'; @@ -910,11 +910,11 @@ test('with filter policy', () => { topic.addSubscription(new subs.LambdaSubscription(fction, { filterPolicy: { color: sns.SubscriptionFilter.stringFilter({ - whitelist: ['red'], + allowlist: ['red'], matchPrefixes: ['bl', 'ye'], }), size: sns.SubscriptionFilter.stringFilter({ - blacklist: ['small', 'medium'], + denylist: ['small', 'medium'], }), price: sns.SubscriptionFilter.numericFilter({ between: { start: 100, stop: 200 }, diff --git a/packages/@aws-cdk/aws-sns/README.md b/packages/@aws-cdk/aws-sns/README.md index ca80f72f9aad3..ab7120411df39 100644 --- a/packages/@aws-cdk/aws-sns/README.md +++ b/packages/@aws-cdk/aws-sns/README.md @@ -80,11 +80,11 @@ const fn = new lambda.Function(this, 'Function', ...); topic.addSubscription(new subs.LambdaSubscription(fn, { filterPolicy: { color: sns.SubscriptionFilter.stringFilter({ - whitelist: ['red', 'orange'], + allowlist: ['red', 'orange'], matchPrefixes: ['bl'] }), size: sns.SubscriptionFilter.stringFilter({ - blacklist: ['small', 'medium'], + denylist: ['small', 'medium'], }), price: sns.SubscriptionFilter.numericFilter({ between: { start: 100, stop: 200 }, @@ -161,7 +161,7 @@ const policyDocument = new iam.PolicyDocument({ new iam.PolicyStatement({ actions: ["sns:Subscribe"], principals: [new iam.AnyPrincipal()], - resources: [topic.topicArn] + resources: [topic.topicArn] }), ], }); diff --git a/packages/@aws-cdk/aws-sns/lib/subscription-filter.ts b/packages/@aws-cdk/aws-sns/lib/subscription-filter.ts index 801ac48091294..c6fc1be95d247 100644 --- a/packages/@aws-cdk/aws-sns/lib/subscription-filter.ts +++ b/packages/@aws-cdk/aws-sns/lib/subscription-filter.ts @@ -5,17 +5,30 @@ export interface StringConditions { /** * Match one or more values. * + * @deprecated use `allowlist` * @default - None */ readonly whitelist?: string[]; /** * Match any value that doesn't include any of the specified values. - * + * @deprecated use `denylist` * @default - None */ readonly blacklist?: string[]; + /** + * Match one or more values. + * @default - None + */ + readonly allowlist?: string[]; + + /** + * Match any value that doesn't include any of the specified values. + * @default - None + */ + readonly denylist?: string[]; + /** * Matches values that begins with the specified prefixes. * @@ -45,11 +58,18 @@ export interface BetweenCondition { export interface NumericConditions { /** * Match one or more values. - * + * @deprecated use `allowlist` * @default - None */ readonly whitelist?: number[]; + /** + * Match one or more values. + * + * @default - None + */ + readonly allowlist?: number[]; + /** * Match values that are greater than the specified value. * @@ -103,12 +123,21 @@ export class SubscriptionFilter { public static stringFilter(stringConditions: StringConditions) { const conditions = new Array(); - if (stringConditions.whitelist) { - conditions.push(...stringConditions.whitelist); + if (stringConditions.whitelist && stringConditions.allowlist) { + throw new Error('`whitelist` is deprecated; please use `allowlist` instead'); + } + if (stringConditions.blacklist && stringConditions.denylist) { + throw new Error('`blacklist` is deprecated; please use `denylist` instead'); + } + const allowlist = stringConditions.allowlist ?? stringConditions.whitelist; + const denylist = stringConditions.denylist ?? stringConditions.blacklist; + + if (allowlist) { + conditions.push(...allowlist); } - if (stringConditions.blacklist) { - conditions.push({ 'anything-but': stringConditions.blacklist }); + if (denylist) { + conditions.push({ 'anything-but': denylist }); } if (stringConditions.matchPrefixes) { @@ -124,8 +153,13 @@ export class SubscriptionFilter { public static numericFilter(numericConditions: NumericConditions) { const conditions = new Array(); - if (numericConditions.whitelist) { - conditions.push(...numericConditions.whitelist.map(v => ({ numeric: ['=', v] }))); + if (numericConditions.whitelist && numericConditions.allowlist) { + throw new Error('`whitelist` is deprecated; please use `allowlist` instead'); + } + const allowlist = numericConditions.allowlist ?? numericConditions.whitelist; + + if (allowlist) { + conditions.push(...allowlist.map(v => ({ numeric: ['=', v] }))); } if (numericConditions.greaterThan) { diff --git a/packages/@aws-cdk/aws-sns/package.json b/packages/@aws-cdk/aws-sns/package.json index 4b60a53f24c35..c3be9835be2a9 100644 --- a/packages/@aws-cdk/aws-sns/package.json +++ b/packages/@aws-cdk/aws-sns/package.json @@ -73,14 +73,14 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "nodeunit": "^0.11.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", @@ -89,7 +89,7 @@ "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -99,7 +99,7 @@ "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-sns/test/test.sns.ts b/packages/@aws-cdk/aws-sns/test/test.sns.ts index 5261900f9059b..695166ace86a1 100644 --- a/packages/@aws-cdk/aws-sns/test/test.sns.ts +++ b/packages/@aws-cdk/aws-sns/test/test.sns.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-sns/test/test.subscription.ts b/packages/@aws-cdk/aws-sns/test/test.subscription.ts index f9bafa123cd20..c8ade98bc81d5 100644 --- a/packages/@aws-cdk/aws-sns/test/test.subscription.ts +++ b/packages/@aws-cdk/aws-sns/test/test.subscription.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import { Queue } from '@aws-cdk/aws-sqs'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; @@ -110,12 +110,12 @@ export = { endpoint: 'endpoint', filterPolicy: { color: sns.SubscriptionFilter.stringFilter({ - whitelist: ['red', 'green'], - blacklist: ['white', 'orange'], + allowlist: ['red', 'green'], + denylist: ['white', 'orange'], matchPrefixes: ['bl', 'ye'], }), price: sns.SubscriptionFilter.numericFilter({ - whitelist: [100, 200], + allowlist: [100, 200], between: { start: 300, stop: 350 }, greaterThan: 500, lessThan: 1000, diff --git a/packages/@aws-cdk/aws-sqs/lib/validate-props.ts b/packages/@aws-cdk/aws-sqs/lib/validate-props.ts index 8a1204e21f858..b988e6e7fdf9a 100644 --- a/packages/@aws-cdk/aws-sqs/lib/validate-props.ts +++ b/packages/@aws-cdk/aws-sqs/lib/validate-props.ts @@ -14,5 +14,5 @@ function validateRange(label: string, value: number | undefined, minValue: numbe if (value === undefined || Token.isUnresolved(value)) { return; } const unitSuffix = unit ? ` ${unit}` : ''; if (value < minValue) { throw new Error(`${label} must be ${minValue}${unitSuffix} or more, but ${value} was provided`); } - if (value > maxValue) { throw new Error(`${label} must be ${maxValue}${unitSuffix} of less, but ${value} was provided`); } + if (value > maxValue) { throw new Error(`${label} must be ${maxValue}${unitSuffix} or less, but ${value} was provided`); } } diff --git a/packages/@aws-cdk/aws-sqs/package.json b/packages/@aws-cdk/aws-sqs/package.json index 7b610c64bb71c..878f7d4300c0b 100644 --- a/packages/@aws-cdk/aws-sqs/package.json +++ b/packages/@aws-cdk/aws-sqs/package.json @@ -70,7 +70,6 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@types/nodeunit": "^0.0.31", "aws-sdk": "^2.848.0", @@ -78,14 +77,15 @@ "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "nodeunit": "^0.11.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -93,7 +93,7 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-sqs/test/test.sqs.ts b/packages/@aws-cdk/aws-sqs/test/test.sqs.ts index ea0233578c5a6..f73f8491ae98a 100644 --- a/packages/@aws-cdk/aws-sqs/test/test.sqs.ts +++ b/packages/@aws-cdk/aws-sqs/test/test.sqs.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, ResourcePart } from '@aws-cdk/assert'; +import { expect, haveResource, ResourcePart } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import { CfnParameter, Duration, Stack, App } from '@aws-cdk/core'; @@ -75,7 +75,7 @@ export = { test.throws(() => new sqs.Queue(stack, 'AnotherQueue', { retentionPeriod: Duration.days(15), - }), /message retention period must be 1209600 seconds of less/); + }), /message retention period must be 1209600 seconds or less/); test.done(); }, diff --git a/packages/@aws-cdk/aws-ssm/package.json b/packages/@aws-cdk/aws-ssm/package.json index 234d166c9152f..b2a78d4554a88 100644 --- a/packages/@aws-cdk/aws-ssm/package.json +++ b/packages/@aws-cdk/aws-ssm/package.json @@ -70,20 +70,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "nodeunit": "^0.11.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -91,7 +91,7 @@ "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-ssm/test/test.parameter-store-string.ts b/packages/@aws-cdk/aws-ssm/test/test.parameter-store-string.ts index 0ddeabe61e11a..215a91090bc5c 100644 --- a/packages/@aws-cdk/aws-ssm/test/test.parameter-store-string.ts +++ b/packages/@aws-cdk/aws-ssm/test/test.parameter-store-string.ts @@ -1,4 +1,4 @@ -import { expect } from '@aws-cdk/assert'; +import { expect } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; import * as ssm from '../lib'; diff --git a/packages/@aws-cdk/aws-ssm/test/test.parameter.ts b/packages/@aws-cdk/aws-ssm/test/test.parameter.ts index 9734ddb4fdd9a..8ce26dd03a0c5 100644 --- a/packages/@aws-cdk/aws-ssm/test/test.parameter.ts +++ b/packages/@aws-cdk/aws-ssm/test/test.parameter.ts @@ -1,6 +1,6 @@ /* eslint-disable max-len */ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as cdk from '@aws-cdk/core'; 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 e37ee02c98121..7e6fbae411a59 100644 --- a/packages/@aws-cdk/aws-ssm/test/test.ssm-document.ts +++ b/packages/@aws-cdk/aws-ssm/test/test.ssm-document.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; import * as ssm from '../lib'; diff --git a/packages/@aws-cdk/aws-sso/package.json b/packages/@aws-cdk/aws-sso/package.json index af088e448aff9..53c8ab4499cfe 100644 --- a/packages/@aws-cdk/aws-sso/package.json +++ b/packages/@aws-cdk/aws-sso/package.json @@ -73,10 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-sso/test/sso.test.ts b/packages/@aws-cdk/aws-sso/test/sso.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-sso/test/sso.test.ts +++ b/packages/@aws-cdk/aws-sso/test/sso.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/README.md b/packages/@aws-cdk/aws-stepfunctions-tasks/README.md index 8d024db58e552..0888563679d47 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/README.md +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/README.md @@ -21,59 +21,61 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aw ## Table Of Contents -- [Task](#task) -- [Paths](#paths) - - [InputPath](#inputpath) - - [OutputPath](#outputpath) - - [ResultPath](#resultpath) -- [Parameters](#task-parameters-from-the-state-json) -- [Evaluate Expression](#evaluate-expression) -- [API Gateway](#api-gateway) - - [Call REST API Endpoint](#call-rest-api-endpoint) - - [Call HTTP API Endpoint](#call-http-api-endpoint) -- [Athena](#athena) - - [StartQueryExecution](#startQueryExecution) - - [GetQueryExecution](#getQueryExecution) - - [GetQueryResults](#getQueryResults) - - [StopQueryExecution](#stopQueryExecution) -- [Batch](#batch) - - [SubmitJob](#submitjob) -- [CodeBuild](#codebuild) - - [StartBuild](#startbuild) -- [DynamoDB](#dynamodb) - - [GetItem](#getitem) - - [PutItem](#putitem) - - [DeleteItem](#deleteitem) - - [UpdateItem](#updateitem) -- [ECS](#ecs) - - [RunTask](#runtask) - - [EC2](#ec2) - - [Fargate](#fargate) -- [EMR](#emr) - - [Create Cluster](#create-cluster) - - [Termination Protection](#termination-protection) - - [Terminate Cluster](#terminate-cluster) - - [Add Step](#add-step) - - [Cancel Step](#cancel-step) - - [Modify Instance Fleet](#modify-instance-fleet) - - [Modify Instance Group](#modify-instance-group) -- [EKS](#eks) - - [Call](#call) -- [Glue](#glue) -- [Glue DataBrew](#glue-databrew) -- [Lambda](#lambda) -- [SageMaker](#sagemaker) - - [Create Training Job](#create-training-job) - - [Create Transform Job](#create-transform-job) - - [Create Endpoint](#create-endpoint) - - [Create Endpoint Config](#create-endpoint-config) - - [Create Model](#create-model) - - [Update Endpoint](#update-endpoint) -- [SNS](#sns) -- [Step Functions](#step-functions) - - [Start Execution](#start-execution) - - [Invoke Activity Worker](#invoke-activity) -- [SQS](#sqs) +- [Tasks for AWS Step Functions](#tasks-for-aws-step-functions) + - [Table Of Contents](#table-of-contents) + - [Task](#task) + - [Paths](#paths) + - [InputPath](#inputpath) + - [OutputPath](#outputpath) + - [ResultPath](#resultpath) + - [Task parameters from the state JSON](#task-parameters-from-the-state-json) + - [Evaluate Expression](#evaluate-expression) + - [API Gateway](#api-gateway) + - [Call REST API Endpoint](#call-rest-api-endpoint) + - [Call HTTP API Endpoint](#call-http-api-endpoint) + - [Athena](#athena) + - [StartQueryExecution](#startqueryexecution) + - [GetQueryExecution](#getqueryexecution) + - [GetQueryResults](#getqueryresults) + - [StopQueryExecution](#stopqueryexecution) + - [Batch](#batch) + - [SubmitJob](#submitjob) + - [CodeBuild](#codebuild) + - [StartBuild](#startbuild) + - [DynamoDB](#dynamodb) + - [GetItem](#getitem) + - [PutItem](#putitem) + - [DeleteItem](#deleteitem) + - [UpdateItem](#updateitem) + - [ECS](#ecs) + - [RunTask](#runtask) + - [EC2](#ec2) + - [Fargate](#fargate) + - [EMR](#emr) + - [Create Cluster](#create-cluster) + - [Termination Protection](#termination-protection) + - [Terminate Cluster](#terminate-cluster) + - [Add Step](#add-step) + - [Cancel Step](#cancel-step) + - [Modify Instance Fleet](#modify-instance-fleet) + - [Modify Instance Group](#modify-instance-group) + - [EKS](#eks) + - [Call](#call) + - [Glue](#glue) + - [Glue DataBrew](#glue-databrew) + - [Lambda](#lambda) + - [SageMaker](#sagemaker) + - [Create Training Job](#create-training-job) + - [Create Transform Job](#create-transform-job) + - [Create Endpoint](#create-endpoint) + - [Create Endpoint Config](#create-endpoint-config) + - [Create Model](#create-model) + - [Update Endpoint](#update-endpoint) + - [SNS](#sns) + - [Step Functions](#step-functions) + - [Start Execution](#start-execution) + - [Invoke Activity](#invoke-activity) + - [SQS](#sqs) ## Task @@ -256,7 +258,8 @@ import * as tasks from `@aws-cdk/aws-stepfunctions-tasks`; const httpApi = new apigatewayv2.HttpApi(stack, 'MyHttpApi'); const invokeTask = new tasks.CallApiGatewayHttpApiEndpoint(stack, 'Call HTTP API', { - api: httpApi, + apiId: httpApi.apiId, + apiStack: cdk.Stack.of(httpApi), method: HttpMethod.GET, }); ``` @@ -327,9 +330,9 @@ The [SubmitJob](https://docs.aws.amazon.com/batch/latest/APIReference/API_Submit ```ts fixture=with-batch-job const task = new tasks.BatchSubmitJob(this, 'Submit Job', { - jobDefinition: batchJobDefinition, + jobDefinitionArn: batchJobDefinitionArn, jobName: 'MyJob', - jobQueue: batchQueue, + jobQueueArn: batchQueueArn, }); ``` diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/apigateway/call-http-api.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/apigateway/call-http-api.ts index e06e46c2580b0..4624bcba049a0 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/apigateway/call-http-api.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/apigateway/call-http-api.ts @@ -1,4 +1,3 @@ -import * as apigatewayv2 from '@aws-cdk/aws-apigatewayv2'; import * as iam from '@aws-cdk/aws-iam'; import * as sfn from '@aws-cdk/aws-stepfunctions'; import * as cdk from '@aws-cdk/core'; @@ -11,9 +10,14 @@ import { CallApiGatewayEndpointBaseProps } from './base-types'; */ export interface CallApiGatewayHttpApiEndpointProps extends CallApiGatewayEndpointBaseProps { /** - * API to call + * The Id of the API to call */ - readonly api: apigatewayv2.IHttpApi; + readonly apiId: string; + + /** + * The Stack in which the API is defined + */ + readonly apiStack: cdk.Stack; /** * Name of the stage where the API is deployed to in API Gateway @@ -45,16 +49,16 @@ export class CallApiGatewayHttpApiEndpoint extends CallApiGatewayEndpointBase { } private getApiEndpoint(): string { - const apiStack = cdk.Stack.of(this.props.api); - return `${this.props.api.apiId}.execute-api.${apiStack.region}.${apiStack.urlSuffix}`; + const apiStack = this.props.apiStack; + return `${this.props.apiId}.execute-api.${apiStack.region}.${apiStack.urlSuffix}`; } private getArnForExecuteApi(): string { - const { api, stageName, method, apiPath } = this.props; + const { apiId, stageName, method, apiPath } = this.props; - return cdk.Stack.of(api).formatArn({ + return this.props.apiStack.formatArn({ service: 'execute-api', - resource: api.apiId, + resource: apiId, sep: '/', resourceName: `${stageName}/${method}${apiPath}`, }); diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/athena/get-query-execution.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/athena/get-query-execution.ts index 555a42f107cd8..6a9eaab73eb4b 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/athena/get-query-execution.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/athena/get-query-execution.ts @@ -5,7 +5,6 @@ import { integrationResourceArn, validatePatternSupported } from '../private/tas /** * Properties for getting a Query Execution - * @experimental */ export interface AthenaGetQueryExecutionProps extends sfn.TaskStateBaseProps { /** @@ -20,7 +19,6 @@ export interface AthenaGetQueryExecutionProps extends sfn.TaskStateBaseProps { * Get an Athena Query Execution as a Task * * @see https://docs.aws.amazon.com/step-functions/latest/dg/connect-athena.html - * @experimental */ export class AthenaGetQueryExecution extends sfn.TaskStateBase { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/athena/get-query-results.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/athena/get-query-results.ts index 4adc8cd4ce379..07ec38efa97e1 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/athena/get-query-results.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/athena/get-query-results.ts @@ -5,7 +5,6 @@ import { integrationResourceArn, validatePatternSupported } from '../private/tas /** * Properties for getting a Query Results - * @experimental */ export interface AthenaGetQueryResultsProps extends sfn.TaskStateBaseProps { /** @@ -34,7 +33,6 @@ export interface AthenaGetQueryResultsProps extends sfn.TaskStateBaseProps { * Get an Athena Query Results as a Task * * @see https://docs.aws.amazon.com/step-functions/latest/dg/connect-athena.html - * @experimental */ export class AthenaGetQueryResults extends sfn.TaskStateBase { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/athena/start-query-execution.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/athena/start-query-execution.ts index 893bb55af6b02..146f8c7d1cd48 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/athena/start-query-execution.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/athena/start-query-execution.ts @@ -8,7 +8,6 @@ import { integrationResourceArn, validatePatternSupported } from '../private/tas /** * Properties for starting a Query Execution - * @experimental */ export interface AthenaStartQueryExecutionProps extends sfn.TaskStateBaseProps { /** @@ -49,7 +48,6 @@ export interface AthenaStartQueryExecutionProps extends sfn.TaskStateBaseProps { * Start an Athena Query as a Task * * @see https://docs.aws.amazon.com/step-functions/latest/dg/connect-athena.html - * @experimental */ export class AthenaStartQueryExecution extends sfn.TaskStateBase { @@ -226,7 +224,6 @@ export class AthenaStartQueryExecution extends sfn.TaskStateBase { * Location of query result along with S3 bucket configuration * * @see https://docs.aws.amazon.com/athena/latest/APIReference/API_ResultConfiguration.html - * @experimental */ export interface ResultConfiguration { @@ -250,7 +247,6 @@ export interface ResultConfiguration { * Encryption Configuration of the S3 bucket * * @see https://docs.aws.amazon.com/athena/latest/APIReference/API_EncryptionConfiguration.html - * @experimental */ export interface EncryptionConfiguration { @@ -273,7 +269,6 @@ export interface EncryptionConfiguration { * Encryption Options of the S3 bucket * * @see https://docs.aws.amazon.com/athena/latest/APIReference/API_EncryptionConfiguration.html#athena-Type-EncryptionConfiguration-EncryptionOption - * @experimental */ export enum EncryptionOption { /** @@ -302,7 +297,6 @@ export enum EncryptionOption { * Database and data catalog context in which the query execution occurs * * @see https://docs.aws.amazon.com/athena/latest/APIReference/API_QueryExecutionContext.html - * @experimental */ export interface QueryExecutionContext { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/athena/stop-query-execution.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/athena/stop-query-execution.ts index 7a51559a79631..a7c44cebfb4a0 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/athena/stop-query-execution.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/athena/stop-query-execution.ts @@ -5,7 +5,6 @@ import { integrationResourceArn, validatePatternSupported } from '../private/tas /** * Properties for stoping a Query Execution - * @experimental */ export interface AthenaStopQueryExecutionProps extends sfn.TaskStateBaseProps { /** @@ -18,7 +17,6 @@ export interface AthenaStopQueryExecutionProps extends sfn.TaskStateBaseProps { * Stop an Athena Query Execution as a Task * * @see https://docs.aws.amazon.com/step-functions/latest/dg/connect-athena.html - * @experimental */ export class AthenaStopQueryExecution extends sfn.TaskStateBase { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/batch/run-batch-job.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/batch/run-batch-job.ts index 80c4eb28140be..9ee1cae598095 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/batch/run-batch-job.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/batch/run-batch-job.ts @@ -1,4 +1,3 @@ -import * as batch from '@aws-cdk/aws-batch'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as sfn from '@aws-cdk/aws-stepfunctions'; @@ -88,9 +87,9 @@ export interface JobDependency { */ export interface RunBatchJobProps { /** - * The job definition used by this job. + * The arn of the job definition used by this job. */ - readonly jobDefinition: batch.IJobDefinition; + readonly jobDefinitionArn: string; /** * The name of the job. @@ -100,9 +99,9 @@ export interface RunBatchJobProps { readonly jobName: string; /** - * The job queue into which the job is submitted. + * The arn of the job queue into which the job is submitted. */ - readonly jobQueue: batch.IJobQueue; + readonly jobQueueArn: string; /** * The array size can be between 2 and 10,000. @@ -242,9 +241,9 @@ export class RunBatchJob implements sfn.IStepFunctionsTask { ), policyStatements: this.configurePolicyStatements(_task), parameters: { - JobDefinition: this.props.jobDefinition.jobDefinitionArn, + JobDefinition: this.props.jobDefinitionArn, JobName: this.props.jobName, - JobQueue: this.props.jobQueue.jobQueueArn, + JobQueue: this.props.jobQueueArn, Parameters: this.props.payload, ArrayProperties: @@ -287,7 +286,7 @@ export class RunBatchJob implements sfn.IStepFunctionsTask { resource: 'job-definition', resourceName: '*', }), - this.props.jobQueue.jobQueueArn, + this.props.jobQueueArn, ], actions: ['batch:SubmitJob'], }), diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/batch/submit-job.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/batch/submit-job.ts index 8064c5e0fe712..0fe43f42e21ac 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/batch/submit-job.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/batch/submit-job.ts @@ -1,4 +1,3 @@ -import * as batch from '@aws-cdk/aws-batch'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as sfn from '@aws-cdk/aws-stepfunctions'; @@ -87,9 +86,9 @@ export interface BatchJobDependency { */ export interface BatchSubmitJobProps extends sfn.TaskStateBaseProps { /** - * The job definition used by this job. + * The arn of the job definition used by this job. */ - readonly jobDefinition: batch.IJobDefinition; + readonly jobDefinitionArn: string; /** * The name of the job. @@ -99,9 +98,9 @@ export interface BatchSubmitJobProps extends sfn.TaskStateBaseProps { readonly jobName: string; /** - * The job queue into which the job is submitted. + * The arn of the job queue into which the job is submitted. */ - readonly jobQueue: batch.IJobQueue; + readonly jobQueueArn: string; /** * The array size can be between 2 and 10,000. @@ -220,9 +219,9 @@ export class BatchSubmitJob extends sfn.TaskStateBase { return { Resource: integrationResourceArn('batch', 'submitJob', this.integrationPattern), Parameters: sfn.FieldUtils.renderObject({ - JobDefinition: this.props.jobDefinition.jobDefinitionArn, + JobDefinition: this.props.jobDefinitionArn, JobName: this.props.jobName, - JobQueue: this.props.jobQueue.jobQueueArn, + JobQueue: this.props.jobQueueArn, Parameters: this.props.payload?.value, ArrayProperties: this.props.arraySize !== undefined @@ -265,7 +264,7 @@ export class BatchSubmitJob extends sfn.TaskStateBase { resource: 'job-definition', resourceName: '*', }), - this.props.jobQueue.jobQueueArn, + this.props.jobQueueArn, ], actions: ['batch:SubmitJob'], }), diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/databrew/start-job-run.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/databrew/start-job-run.ts index 75b6abcb6edda..538e0392c842e 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/databrew/start-job-run.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/databrew/start-job-run.ts @@ -6,7 +6,6 @@ import { integrationResourceArn, validatePatternSupported } from '../private/tas /** * Properties for starting a job run with StartJobRun - * @experimental */ export interface GlueDataBrewStartJobRunProps extends sfn.TaskStateBaseProps { @@ -20,7 +19,6 @@ export interface GlueDataBrewStartJobRunProps extends sfn.TaskStateBaseProps { * Start a Job run as a Task * * @see https://docs.aws.amazon.com/step-functions/latest/dg/connect-databrew.html - * @experimental */ export class GlueDataBrewStartJobRun extends sfn.TaskStateBase { @@ -35,7 +33,6 @@ export class GlueDataBrewStartJobRun extends sfn.TaskStateBase { private readonly integrationPattern: sfn.IntegrationPattern; /** - * @experimental */ constructor(scope: Construct, id: string, private readonly props: GlueDataBrewStartJobRunProps) { super(scope, id, props); diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/eks/call.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/eks/call.ts index 8cbf3fcca5886..5e4bcda8a9b64 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/eks/call.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/eks/call.ts @@ -6,7 +6,6 @@ import { integrationResourceArn, validatePatternSupported } from '../private/tas /** * Properties for calling a EKS endpoint with EksCall - * @experimental */ export interface EksCallProps extends sfn.TaskStateBaseProps { @@ -43,7 +42,6 @@ export interface EksCallProps extends sfn.TaskStateBaseProps { * Call a EKS endpoint as a Task * * @see https://docs.aws.amazon.com/step-functions/latest/dg/connect-eks.html - * @experimental */ export class EksCall extends sfn.TaskStateBase { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-add-step.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-add-step.ts index 83fe924866e95..6e966ea738b2e 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-add-step.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-add-step.ts @@ -12,7 +12,6 @@ import { integrationResourceArn, validatePatternSupported } from '../private/tas * * @default CONTINUE * - * @experimental */ export enum ActionOnFailure { /** @@ -34,7 +33,6 @@ export enum ActionOnFailure { /** * Properties for EmrAddStep * - * @experimental */ export interface EmrAddStepProps extends sfn.TaskStateBaseProps { /** @@ -100,7 +98,6 @@ export interface EmrAddStepProps extends sfn.TaskStateBaseProps { * * OUTPUT: the StepId * - * @experimental */ export class EmrAddStep extends sfn.TaskStateBase { private static readonly SUPPORTED_INTEGRATION_PATTERNS: sfn.IntegrationPattern[] = [ diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-cancel-step.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-cancel-step.ts index ee15fb4f44e68..cec4772436b7c 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-cancel-step.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-cancel-step.ts @@ -7,7 +7,6 @@ import { integrationResourceArn } from '../private/task-utils'; /** * Properties for EmrCancelStep * - * @experimental */ export interface EmrCancelStepProps extends sfn.TaskStateBaseProps { /** @@ -24,7 +23,6 @@ export interface EmrCancelStepProps extends sfn.TaskStateBaseProps { /** * A Step Functions Task to to cancel a Step on an EMR Cluster. * - * @experimental */ export class EmrCancelStep extends sfn.TaskStateBase { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-create-cluster.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-create-cluster.ts index 2e38d60aac150..c38bd9d8d5039 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-create-cluster.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-create-cluster.ts @@ -18,7 +18,6 @@ import { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_RunJobFlow.html * - * @experimental */ export interface EmrCreateClusterProps extends sfn.TaskStateBaseProps { /** @@ -153,7 +152,6 @@ export interface EmrCreateClusterProps extends sfn.TaskStateBaseProps { * * OUTPUT: the ClusterId. * - * @experimental */ export class EmrCreateCluster extends sfn.TaskStateBase { private static readonly SUPPORTED_INTEGRATION_PATTERNS: sfn.IntegrationPattern[] = [ @@ -364,7 +362,6 @@ export namespace EmrCreateCluster { /** * Valid valus for the Cluster ScaleDownBehavior * - * @experimental */ export enum EmrClusterScaleDownBehavior { /** @@ -374,7 +371,7 @@ export namespace EmrCreateCluster { TERMINATE_AT_INSTANCE_HOUR = 'TERMINATE_AT_INSTANCE_HOUR', /** - * Indicates that Amazon EMR blacklists and drains tasks from nodes before terminating the Amazon EC2 instances, regardless of the + * Indicates that Amazon EMR adds nodes to a deny list and drains tasks from nodes before terminating the Amazon EC2 instances, regardless of the * instance-hour boundary. */ TERMINATE_AT_TASK_COMPLETION = 'TERMINATE_AT_TASK_COMPLETION', @@ -383,7 +380,6 @@ export namespace EmrCreateCluster { /** * Instance Role Types * - * @experimental */ export enum InstanceRoleType { /** @@ -403,7 +399,6 @@ export namespace EmrCreateCluster { /** * EBS Volume Types * - * @experimental */ export enum EbsBlockDeviceVolumeType { /** @@ -426,7 +421,6 @@ export namespace EmrCreateCluster { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_VolumeSpecification.html * - * @experimental */ export interface VolumeSpecificationProperty { /** @@ -454,7 +448,6 @@ export namespace EmrCreateCluster { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_EbsBlockDeviceConfig.html * - * @experimental */ export interface EbsBlockDeviceConfigProperty { /** @@ -476,7 +469,6 @@ export namespace EmrCreateCluster { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_EbsConfiguration.html * - * @experimental */ export interface EbsConfigurationProperty { /** @@ -500,7 +492,6 @@ export namespace EmrCreateCluster { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_InstanceTypeConfig.html * - * @experimental */ export interface InstanceTypeConfigProperty { /** @@ -549,7 +540,6 @@ export namespace EmrCreateCluster { /** * Spot Timeout Actions * - * @experimental */ export enum SpotTimeoutAction { /**\ @@ -567,7 +557,6 @@ export namespace EmrCreateCluster { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_SpotProvisioningSpecification.html * - * @experimental */ export interface SpotProvisioningSpecificationProperty { /** @@ -593,7 +582,6 @@ export namespace EmrCreateCluster { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_InstanceFleetProvisioningSpecifications.html * - * @experimental */ export interface InstanceFleetProvisioningSpecificationsProperty { /** @@ -607,7 +595,6 @@ export namespace EmrCreateCluster { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_InstanceFleetConfig.html * - * @experimental */ export interface InstanceFleetConfigProperty { /** @@ -654,7 +641,6 @@ export namespace EmrCreateCluster { /** * CloudWatch Alarm Comparison Operators * - * @experimental */ export enum CloudWatchAlarmComparisonOperator { /** @@ -678,7 +664,6 @@ export namespace EmrCreateCluster { /** * CloudWatch Alarm Statistics * - * @experimental */ export enum CloudWatchAlarmStatistic { /** @@ -706,7 +691,6 @@ export namespace EmrCreateCluster { /** * CloudWatch Alarm Units * - * @experimental */ export enum CloudWatchAlarmUnit { /** @@ -826,7 +810,6 @@ export namespace EmrCreateCluster { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_MetricDimension.html * - * @experimental */ export interface MetricDimensionProperty { /** @@ -846,7 +829,6 @@ export namespace EmrCreateCluster { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_CloudWatchAlarmDefinition.html * - * @experimental */ export interface CloudWatchAlarmDefinitionProperty { /** @@ -916,7 +898,6 @@ export namespace EmrCreateCluster { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_ScalingTrigger.html * - * @experimental */ export interface ScalingTriggerProperty { /** @@ -929,7 +910,6 @@ export namespace EmrCreateCluster { /** * EC2 Instance Market * - * @experimental */ export enum InstanceMarket { /** @@ -945,7 +925,6 @@ export namespace EmrCreateCluster { /** * AutoScaling Adjustment Type * - * @experimental */ export enum ScalingAdjustmentType { /** @@ -968,7 +947,6 @@ export namespace EmrCreateCluster { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_SimpleScalingPolicyConfiguration.html * - * @experimental */ export interface SimpleScalingPolicyConfigurationProperty { /** @@ -1001,7 +979,6 @@ export namespace EmrCreateCluster { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_ScalingAction.html * - * @experimental */ export interface ScalingActionProperty { /** @@ -1023,7 +1000,6 @@ export namespace EmrCreateCluster { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_ScalingRule.html * - * @experimental */ export interface ScalingRuleProperty { /** @@ -1055,7 +1031,6 @@ export namespace EmrCreateCluster { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_ScalingConstraints.html * - * @experimental */ export interface ScalingConstraintsProperty { /** @@ -1076,7 +1051,6 @@ export namespace EmrCreateCluster { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_AutoScalingPolicy.html * - * @experimental */ export interface AutoScalingPolicyProperty { /** @@ -1096,7 +1070,6 @@ export namespace EmrCreateCluster { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_InstanceGroupConfig.html * - * @experimental */ export interface InstanceGroupConfigProperty { /** @@ -1162,7 +1135,6 @@ export namespace EmrCreateCluster { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_PlacementType.html * - * @experimental */ export interface PlacementTypeProperty { /** @@ -1189,7 +1161,6 @@ export namespace EmrCreateCluster { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_JobFlowInstancesConfig.html * - * @experimental */ export interface InstancesConfigProperty { /** @@ -1319,7 +1290,6 @@ export namespace EmrCreateCluster { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_Application.html * - * @experimental */ export interface ApplicationConfigProperty { /** @@ -1355,7 +1325,6 @@ export namespace EmrCreateCluster { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_ScriptBootstrapActionConfig.html * - * @experimental */ export interface ScriptBootstrapActionConfigProperty { /** @@ -1378,7 +1347,6 @@ export namespace EmrCreateCluster { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_BootstrapActionConfig.html * - * @experimental */ export interface BootstrapActionConfigProperty { /** @@ -1400,7 +1368,6 @@ export namespace EmrCreateCluster { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_Configuration.html * - * @experimental */ export interface ConfigurationProperty { /** @@ -1432,7 +1399,6 @@ export namespace EmrCreateCluster { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_KerberosAttributes.html * - * @experimental */ export interface KerberosAttributesProperty { /** diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-modify-instance-fleet-by-name.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-modify-instance-fleet-by-name.ts index 9c0300abef845..3fed76b790a94 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-modify-instance-fleet-by-name.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-modify-instance-fleet-by-name.ts @@ -7,7 +7,6 @@ import { integrationResourceArn } from '../private/task-utils'; /** * Properties for EmrModifyInstanceFleetByName * - * @experimental */ export interface EmrModifyInstanceFleetByNameProps extends sfn.TaskStateBaseProps { /** @@ -42,7 +41,6 @@ export interface EmrModifyInstanceFleetByNameProps extends sfn.TaskStateBaseProp /** * A Step Functions Task to to modify an InstanceFleet on an EMR Cluster. * - * @experimental */ export class EmrModifyInstanceFleetByName extends sfn.TaskStateBase { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-modify-instance-group-by-name.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-modify-instance-group-by-name.ts index a131f8b2e7f19..5b32e5efbc16a 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-modify-instance-group-by-name.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-modify-instance-group-by-name.ts @@ -9,7 +9,6 @@ import { InstanceGroupModifyConfigPropertyToJson } from './private/cluster-utils /** * Properties for EmrModifyInstanceGroupByName * - * @experimental */ export interface EmrModifyInstanceGroupByNameProps extends sfn.TaskStateBaseProps { /** @@ -35,7 +34,6 @@ export interface EmrModifyInstanceGroupByNameProps extends sfn.TaskStateBaseProp /** * A Step Functions Task to to modify an InstanceGroup on an EMR Cluster. * - * @experimental */ export class EmrModifyInstanceGroupByName extends sfn.TaskStateBase { protected readonly taskPolicies?: iam.PolicyStatement[]; @@ -81,7 +79,6 @@ export namespace EmrModifyInstanceGroupByName { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_InstanceResizePolicy.html * - * @experimental */ export interface InstanceResizePolicyProperty { /** @@ -111,7 +108,6 @@ export namespace EmrModifyInstanceGroupByName { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_ShrinkPolicy.html * - * @experimental */ export interface ShrinkPolicyProperty { /** @@ -134,7 +130,6 @@ export namespace EmrModifyInstanceGroupByName { * * @see https://docs.aws.amazon.com/emr/latest/APIReference/API_InstanceGroupModifyConfig.html * - * @experimental */ export interface InstanceGroupModifyConfigProperty { /** diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-set-cluster-termination-protection.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-set-cluster-termination-protection.ts index 78a5f305b54d2..962bf710477c0 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-set-cluster-termination-protection.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-set-cluster-termination-protection.ts @@ -7,7 +7,6 @@ import { integrationResourceArn } from '../private/task-utils'; /** * Properties for EmrSetClusterTerminationProtection * - * @experimental */ export interface EmrSetClusterTerminationProtectionProps extends sfn.TaskStateBaseProps { /** @@ -24,7 +23,6 @@ export interface EmrSetClusterTerminationProtectionProps extends sfn.TaskStateBa /** * A Step Functions Task to to set Termination Protection on an EMR Cluster. * - * @experimental */ export class EmrSetClusterTerminationProtection extends sfn.TaskStateBase { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-terminate-cluster.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-terminate-cluster.ts index 9783da1a3c9d3..04896ea40e2ff 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-terminate-cluster.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-terminate-cluster.ts @@ -7,7 +7,6 @@ import { integrationResourceArn, validatePatternSupported } from '../private/tas /** * Properties for EmrTerminateCluster * - * @experimental */ export interface EmrTerminateClusterProps extends sfn.TaskStateBaseProps { /** @@ -19,7 +18,6 @@ export interface EmrTerminateClusterProps extends sfn.TaskStateBaseProps { /** * A Step Functions Task to terminate an EMR Cluster. * - * @experimental */ export class EmrTerminateCluster extends sfn.TaskStateBase { private static readonly SUPPORTED_INTEGRATION_PATTERNS: sfn.IntegrationPattern[] = [ diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/evaluate-expression.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/evaluate-expression.ts index cf36dc806ebfb..7fb010119373b 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/evaluate-expression.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/evaluate-expression.ts @@ -7,7 +7,6 @@ import { Construct } from 'constructs'; /** * Properties for EvaluateExpression * - * @experimental */ export interface EvaluateExpressionProps extends sfn.TaskStateBaseProps { /** @@ -47,7 +46,6 @@ export interface Event { * * OUTPUT: the output of this task is the evaluated expression. * - * @experimental */ export class EvaluateExpression extends sfn.TaskStateBase { protected readonly taskMetrics?: sfn.TaskMetricsConfig; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/base-types.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/base-types.ts index 96d1a4ef38234..b9b5c20d5683f 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/base-types.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/base-types.ts @@ -10,13 +10,11 @@ import { Construct } from 'constructs'; /** * Task to train a machine learning model using Amazon SageMaker - * @experimental */ export interface ISageMakerTask extends iam.IGrantable {} /** * Specify the training algorithm and algorithm-specific metadata - * @experimental */ export interface AlgorithmSpecification { @@ -54,7 +52,6 @@ export interface AlgorithmSpecification { /** * Describes the training, validation or test dataset and the Amazon S3 location where it is stored. * - * @experimental */ export interface Channel { @@ -109,7 +106,6 @@ export interface Channel { /** * Configuration for a shuffle option for input data in a channel. * - * @experimental */ export interface ShuffleConfig { /** @@ -121,7 +117,6 @@ export interface ShuffleConfig { /** * Location of the channel data. * - * @experimental */ export interface DataSource { /** @@ -135,7 +130,6 @@ export interface DataSource { * * @see https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_S3DataSource.html * - * @experimental */ export interface S3DataSource { /** @@ -167,7 +161,6 @@ export interface S3DataSource { /** * Configures the S3 bucket where SageMaker will save the result of model training - * @experimental */ export interface OutputDataConfig { /** @@ -187,7 +180,6 @@ export interface OutputDataConfig { * Specifies a limit to how long a model training job can run. * When the job reaches the time limit, Amazon SageMaker ends the training job. * - * @experimental */ export interface StoppingCondition { /** @@ -201,7 +193,6 @@ export interface StoppingCondition { /** * Specifies the resources, ML compute instances, and ML storage volumes to deploy for model training. * - * @experimental */ export interface ResourceConfig { @@ -237,7 +228,6 @@ export interface ResourceConfig { /** * Specifies the VPC that you want your Amazon SageMaker training job to connect to. * - * @experimental */ export interface VpcConfig { /** @@ -256,7 +246,6 @@ export interface VpcConfig { /** * Specifies the metric name and regular expressions used to parse algorithm logs. * - * @experimental */ export interface MetricDefinition { @@ -274,7 +263,6 @@ export interface MetricDefinition { /** * Stores information about the location of an object in Amazon S3 * - * @experimental */ export interface S3LocationConfig { @@ -287,7 +275,6 @@ export interface S3LocationConfig { /** * Constructs `IS3Location` objects. * - * @experimental */ export abstract class S3Location { /** @@ -321,7 +308,6 @@ export abstract class S3Location { /** * Options for binding an S3 Location. * - * @experimental */ export interface S3LocationBindOptions { /** @@ -342,7 +328,6 @@ export interface S3LocationBindOptions { /** * Configuration for a using Docker image. * - * @experimental */ export interface DockerImageConfig { /** @@ -354,7 +339,6 @@ export interface DockerImageConfig { /** * Creates `IDockerImage` instances. * - * @experimental */ export abstract class DockerImage { /** @@ -409,7 +393,6 @@ export abstract class DockerImage { /** * S3 Data Type. * - * @experimental */ export enum S3DataType { /** @@ -431,7 +414,6 @@ export enum S3DataType { /** * S3 Data Distribution Type. * - * @experimental */ export enum S3DataDistributionType { /** @@ -448,7 +430,6 @@ export enum S3DataDistributionType { /** * Define the format of the input data. * - * @experimental */ export enum RecordWrapperType { /** @@ -465,7 +446,6 @@ export enum RecordWrapperType { /** * Input mode that the algorithm supports. * - * @experimental */ export enum InputMode { /** @@ -482,7 +462,6 @@ export enum InputMode { /** * Compression type of the data. * - * @experimental */ export enum CompressionType { /** @@ -503,7 +482,6 @@ export enum CompressionType { /** * Configures the timeout and maximum number of retries for processing a transform job invocation. * - * @experimental */ export interface ModelClientOptions { @@ -525,7 +503,6 @@ export interface ModelClientOptions { /** * Dataset to be transformed and the Amazon S3 location where it is stored. * - * @experimental */ export interface TransformInput { @@ -559,7 +536,6 @@ export interface TransformInput { /** * S3 location of the input data that the model can consume. * - * @experimental */ export interface TransformDataSource { @@ -572,7 +548,6 @@ export interface TransformDataSource { /** * Location of the channel data. * - * @experimental */ export interface TransformS3DataSource { @@ -592,7 +567,6 @@ export interface TransformS3DataSource { /** * S3 location where you want Amazon SageMaker to save the results from the transform job. * - * @experimental */ export interface TransformOutput { @@ -626,7 +600,6 @@ export interface TransformOutput { /** * ML compute instances for the transform job. * - * @experimental */ export interface TransformResources { @@ -652,7 +625,6 @@ export interface TransformResources { * Properties to define a ContainerDefinition * * @see https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_ContainerDefinition.html - * @experimental */ export interface ContainerDefinitionOptions { /** @@ -701,7 +673,6 @@ export interface ContainerDefinitionOptions { * Describes the container, as part of model definition. * * @see https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_ContainerDefinition.html - * @experimental */ export class ContainerDefinition implements IContainerDefinition { @@ -728,7 +699,6 @@ export class ContainerDefinition implements IContainerDefinition { * Configuration of the container used to host the model * * @see https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_ContainerDefinition.html - * @experimental */ export interface IContainerDefinition { /** @@ -752,7 +722,6 @@ export interface ContainerDefinitionConfig { /** * Specifies how many models the container hosts * - * @experimental */ export enum Mode { /** @@ -771,7 +740,6 @@ export enum Mode { * Identifies a model that you want to host and the resources to deploy for hosting it. * * @see https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_ProductionVariant.html - * @experimental */ export interface ProductionVariant { /** @@ -810,7 +778,6 @@ export interface ProductionVariant { * The generation of Elastic Inference (EI) instance * * @see https://docs.aws.amazon.com/sagemaker/latest/dg/ei.html - * @experimental */ export class AcceleratorClass { /** @@ -837,7 +804,6 @@ export class AcceleratorClass { * EI instances provide on-demand GPU computing for inference * * @see https://docs.aws.amazon.com/sagemaker/latest/dg/ei.html - * @experimental */ export class AcceleratorType { /** @@ -863,7 +829,6 @@ export class AcceleratorType { /** * Specifies the number of records to include in a mini-batch for an HTTP inference request. * - * @experimental */ export enum BatchStrategy { @@ -881,7 +846,6 @@ export enum BatchStrategy { /** * Method to use to split the transform job's data files into smaller batches. * - * @experimental */ export enum SplitType { @@ -909,7 +873,6 @@ export enum SplitType { /** * How to assemble the results of the transform job as a single S3 object. * - * @experimental */ export enum AssembleWith { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-endpoint-config.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-endpoint-config.ts index a7ff0134e1827..9d615caab886d 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-endpoint-config.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-endpoint-config.ts @@ -10,7 +10,6 @@ import { ProductionVariant } from './base-types'; * Properties for creating an Amazon SageMaker endpoint configuration * * @see https://docs.aws.amazon.com/step-functions/latest/dg/connect-sagemaker.html - * @experimental */ export interface SageMakerCreateEndpointConfigProps extends sfn.TaskStateBaseProps { /** @@ -44,7 +43,6 @@ export interface SageMakerCreateEndpointConfigProps extends sfn.TaskStateBasePro * A Step Functions Task to create a SageMaker endpoint configuration * * @see https://docs.aws.amazon.com/step-functions/latest/dg/connect-sagemaker.html - * @experimental */ export class SageMakerCreateEndpointConfig extends sfn.TaskStateBase { private static readonly SUPPORTED_INTEGRATION_PATTERNS: sfn.IntegrationPattern[] = [ diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-endpoint.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-endpoint.ts index d831a8dcbd682..6e46a7c129772 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-endpoint.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-endpoint.ts @@ -8,7 +8,6 @@ import { integrationResourceArn, validatePatternSupported } from '../private/tas * Properties for creating an Amazon SageMaker endpoint * * @see https://docs.aws.amazon.com/step-functions/latest/dg/connect-sagemaker.html - * @experimental */ export interface SageMakerCreateEndpointProps extends sfn.TaskStateBaseProps { /** @@ -31,7 +30,6 @@ export interface SageMakerCreateEndpointProps extends sfn.TaskStateBaseProps { * A Step Functions Task to create a SageMaker endpoint * * @see https://docs.aws.amazon.com/step-functions/latest/dg/connect-sagemaker.html - * @experimental */ export class SageMakerCreateEndpoint extends sfn.TaskStateBase { private static readonly SUPPORTED_INTEGRATION_PATTERNS: sfn.IntegrationPattern[] = [ diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-model.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-model.ts index ee82cc6f69818..1416c157ff69c 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-model.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-model.ts @@ -10,7 +10,6 @@ import { IContainerDefinition } from './base-types'; * Properties for creating an Amazon SageMaker model * * @see https://docs.aws.amazon.com/step-functions/latest/dg/connect-sagemaker.html - * @experimental */ export interface SageMakerCreateModelProps extends sfn.TaskStateBaseProps { /** @@ -69,7 +68,6 @@ export interface SageMakerCreateModelProps extends sfn.TaskStateBaseProps { * A Step Functions Task to create a SageMaker model * * @see https://docs.aws.amazon.com/step-functions/latest/dg/connect-sagemaker.html - * @experimental */ export class SageMakerCreateModel extends sfn.TaskStateBase implements iam.IGrantable, ec2.IConnectable { private static readonly SUPPORTED_INTEGRATION_PATTERNS: sfn.IntegrationPattern[] = [ diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-training-job.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-training-job.ts index e063378bf3eb2..1d0b41bfc76d9 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-training-job.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-training-job.ts @@ -10,7 +10,6 @@ import { renderTags } from './private/utils'; /** * Properties for creating an Amazon SageMaker training job * - * @experimental */ export interface SageMakerCreateTrainingJobProps extends sfn.TaskStateBaseProps { /** @@ -84,7 +83,6 @@ export interface SageMakerCreateTrainingJobProps extends sfn.TaskStateBaseProps /** * Class representing the SageMaker Create Training Job task. * - * @experimental */ export class SageMakerCreateTrainingJob extends sfn.TaskStateBase implements iam.IGrantable, ec2.IConnectable { private static readonly SUPPORTED_INTEGRATION_PATTERNS: sfn.IntegrationPattern[] = [ diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-transform-job.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-transform-job.ts index 4525ef489e3f2..e1b5aabfc61b6 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-transform-job.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/create-transform-job.ts @@ -10,7 +10,6 @@ import { renderTags } from './private/utils'; /** * Properties for creating an Amazon SageMaker transform job task * - * @experimental */ export interface SageMakerCreateTransformJobProps extends sfn.TaskStateBaseProps { /** @@ -94,7 +93,6 @@ export interface SageMakerCreateTransformJobProps extends sfn.TaskStateBaseProps /** * Class representing the SageMaker Create Transform Job task. * - * @experimental */ export class SageMakerCreateTransformJob extends sfn.TaskStateBase { private static readonly SUPPORTED_INTEGRATION_PATTERNS: sfn.IntegrationPattern[] = [ diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/update-endpoint.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/update-endpoint.ts index 4ff5bf4d19bb3..7d42a24c80714 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/update-endpoint.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker/update-endpoint.ts @@ -8,7 +8,6 @@ import { integrationResourceArn, validatePatternSupported } from '../private/tas * Properties for updating Amazon SageMaker endpoint * * @see https://docs.aws.amazon.com/step-functions/latest/dg/connect-sagemaker.html - * @experimental */ export interface SageMakerUpdateEndpointProps extends sfn.TaskStateBaseProps { /** @@ -25,7 +24,6 @@ export interface SageMakerUpdateEndpointProps extends sfn.TaskStateBaseProps { * A Step Functions Task to update a SageMaker endpoint * * @see https://docs.aws.amazon.com/step-functions/latest/dg/connect-sagemaker.html - * @experimental */ export class SageMakerUpdateEndpoint extends sfn.TaskStateBase { private static readonly SUPPORTED_INTEGRATION_PATTERNS: sfn.IntegrationPattern[] = [ diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json index b18cd8fc7704c..6e2e51ded665a 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json @@ -49,6 +49,12 @@ "compat": "cdk-compat", "rosetta:extract": "yarn --silent jsii-rosetta extract" }, + "awslint": { + "exclude": [ + "props-no-arn-refs:@aws-cdk/aws-stepfunctions-tasks.BatchSubmitJobProps.jobDefinitionArn", + "props-no-arn-refs:@aws-cdk/aws-stepfunctions-tasks.BatchSubmitJobProps.jobQueueArn" + ] + }, "keywords": [ "aws", "cdk", @@ -63,29 +69,30 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/aws-sns-subscriptions": "0.0.0", + "@aws-cdk/aws-glue": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", + "@aws-cdk/aws-apigatewayv2": "0.0.0", + "@aws-cdk/aws-apigatewayv2-integrations": "0.0.0", + "@aws-cdk/aws-batch": "0.0.0", + "@aws-cdk/aws-databrew": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-apigateway": "0.0.0", - "@aws-cdk/aws-apigatewayv2": "0.0.0", - "@aws-cdk/aws-apigatewayv2-integrations": "0.0.0", - "@aws-cdk/aws-batch": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-codebuild": "0.0.0", - "@aws-cdk/aws-databrew": "0.0.0", "@aws-cdk/aws-dynamodb": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-ecr": "0.0.0", "@aws-cdk/aws-ecr-assets": "0.0.0", "@aws-cdk/aws-ecs": "0.0.0", "@aws-cdk/aws-eks": "0.0.0", - "@aws-cdk/aws-glue": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", @@ -94,24 +101,19 @@ "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/aws-stepfunctions": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/aws-apigateway": "0.0.0", - "@aws-cdk/aws-apigatewayv2": "0.0.0", - "@aws-cdk/aws-apigatewayv2-integrations": "0.0.0", - "@aws-cdk/aws-batch": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-codebuild": "0.0.0", - "@aws-cdk/aws-databrew": "0.0.0", "@aws-cdk/aws-dynamodb": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-ecr": "0.0.0", "@aws-cdk/aws-ecr-assets": "0.0.0", "@aws-cdk/aws-ecs": "0.0.0", "@aws-cdk/aws-eks": "0.0.0", - "@aws-cdk/aws-glue": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", @@ -120,7 +122,7 @@ "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/aws-stepfunctions": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/apigateway/call-http-api.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/apigateway/call-http-api.test.ts index 0e7a2cf616b9a..f72272d13558e 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/apigateway/call-http-api.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/apigateway/call-http-api.test.ts @@ -11,7 +11,8 @@ describe('CallApiGatewayHttpApiEndpoint', () => { // WHEN const task = new CallApiGatewayHttpApiEndpoint(stack, 'Call', { - api: httpApi, + apiId: httpApi.apiId, + apiStack: cdk.Stack.of(httpApi), method: HttpMethod.GET, }); @@ -63,7 +64,8 @@ describe('CallApiGatewayHttpApiEndpoint', () => { // WHEN const task = new CallApiGatewayHttpApiEndpoint(stack, 'Call', { - api: httpApi, + apiId: httpApi.apiId, + apiStack: cdk.Stack.of(httpApi), method: HttpMethod.GET, integrationPattern: sfn.IntegrationPattern.WAIT_FOR_TASK_TOKEN, headers: sfn.TaskInput.fromObject({ TaskToken: sfn.JsonPath.taskToken }), @@ -121,7 +123,8 @@ describe('CallApiGatewayHttpApiEndpoint', () => { // THEN expect(() => { new CallApiGatewayHttpApiEndpoint(stack, 'Call', { - api: httpApi, + apiId: httpApi.apiId, + apiStack: cdk.Stack.of(httpApi), method: HttpMethod.GET, integrationPattern: sfn.IntegrationPattern.WAIT_FOR_TASK_TOKEN, }); @@ -136,7 +139,8 @@ describe('CallApiGatewayHttpApiEndpoint', () => { // THEN expect(() => { new CallApiGatewayHttpApiEndpoint(stack, 'Call', { - api: httpApi, + apiId: httpApi.apiId, + apiStack: cdk.Stack.of(httpApi), method: HttpMethod.GET, integrationPattern: sfn.IntegrationPattern.RUN_JOB, }); diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/apigateway/integ.call-http-api.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/apigateway/integ.call-http-api.ts index 4eb1f3b896e92..214f2e5a25ba9 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/apigateway/integ.call-http-api.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/apigateway/integ.call-http-api.ts @@ -30,7 +30,8 @@ httpApi.addRoutes({ }); const callEndpointJob = new CallApiGatewayHttpApiEndpoint(stack, 'Call APIGW', { - api: httpApi, + apiId: httpApi.apiId, + apiStack: cdk.Stack.of(httpApi), method: HttpMethod.GET, authType: AuthType.IAM_ROLE, outputPath: sfn.JsonPath.stringAt('$.ResponseBody'), diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/integ.run-batch-job.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/integ.run-batch-job.ts index ff679d770040b..c31aa18cc5fbf 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/integ.run-batch-job.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/integ.run-batch-job.ts @@ -42,9 +42,9 @@ class RunBatchStack extends cdk.Stack { const submitJob = new sfn.Task(this, 'Submit Job', { task: new tasks.RunBatchJob({ - jobDefinition: batchJobDefinition, + jobDefinitionArn: batchJobDefinition.jobDefinitionArn, jobName: 'MyJob', - jobQueue: batchQueue, + jobQueueArn: batchQueue.jobQueueArn, containerOverrides: { environment: { key: 'value' }, memory: 256, diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/integ.submit-job.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/integ.submit-job.ts index 2e8f603b9d809..93c20cc790c36 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/integ.submit-job.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/integ.submit-job.ts @@ -41,9 +41,9 @@ class RunBatchStack extends cdk.Stack { }); const submitJob = new BatchSubmitJob(this, 'Submit Job', { - jobDefinition: batchJobDefinition, + jobDefinitionArn: batchJobDefinition.jobDefinitionArn, + jobQueueArn: batchQueue.jobQueueArn, jobName: 'MyJob', - jobQueue: batchQueue, containerOverrides: { environment: { key: 'value' }, memory: cdk.Size.mebibytes(256), diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/run-batch-job.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/run-batch-job.test.ts index ce05c1021e22d..1d290e8bba8eb 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/run-batch-job.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/run-batch-job.test.ts @@ -38,9 +38,9 @@ test('Task with only the required parameters', () => { // WHEN const task = new sfn.Task(stack, 'Task', { task: new tasks.RunBatchJob({ - jobDefinition: batchJobDefinition, + jobDefinitionArn: batchJobDefinition.jobDefinitionArn, jobName: 'JobName', - jobQueue: batchJobQueue, + jobQueueArn: batchJobQueue.jobQueueArn, }), }); @@ -72,9 +72,9 @@ test('Task with all the parameters', () => { // WHEN const task = new sfn.Task(stack, 'Task', { task: new tasks.RunBatchJob({ - jobDefinition: batchJobDefinition, + jobDefinitionArn: batchJobDefinition.jobDefinitionArn, jobName: 'JobName', - jobQueue: batchJobQueue, + jobQueueArn: batchJobQueue.jobQueueArn, arraySize: 15, containerOverrides: { command: ['sudo', 'rm'], @@ -135,9 +135,9 @@ test('supports tokens', () => { // WHEN const task = new sfn.Task(stack, 'Task', { task: new tasks.RunBatchJob({ - jobDefinition: batchJobDefinition, + jobDefinitionArn: batchJobDefinition.jobDefinitionArn, + jobQueueArn: batchJobQueue.jobQueueArn, jobName: sfn.JsonPath.stringAt('$.jobName'), - jobQueue: batchJobQueue, arraySize: sfn.JsonPath.numberAt('$.arraySize'), timeout: cdk.Duration.seconds(sfn.JsonPath.numberAt('$.timeout')), attempts: sfn.JsonPath.numberAt('$.attempts'), @@ -181,9 +181,9 @@ test('Task throws if WAIT_FOR_TASK_TOKEN is supplied as service integration patt expect(() => { new sfn.Task(stack, 'Task', { task: new tasks.RunBatchJob({ - jobDefinition: batchJobDefinition, + jobDefinitionArn: batchJobDefinition.jobDefinitionArn, jobName: 'JobName', - jobQueue: batchJobQueue, + jobQueueArn: batchJobQueue.jobQueueArn, integrationPattern: sfn.ServiceIntegrationPattern.WAIT_FOR_TASK_TOKEN, }), }); @@ -196,9 +196,9 @@ test('Task throws if environment in containerOverrides contain env with name sta expect(() => { new sfn.Task(stack, 'Task', { task: new tasks.RunBatchJob({ - jobDefinition: batchJobDefinition, + jobDefinitionArn: batchJobDefinition.jobDefinitionArn, jobName: 'JobName', - jobQueue: batchJobQueue, + jobQueueArn: batchJobQueue.jobQueueArn, containerOverrides: { environment: { AWS_BATCH_MY_NAME: 'MY_VALUE' }, }, @@ -213,9 +213,9 @@ test('Task throws if arraySize is out of limits 2-10000', () => { expect(() => { new sfn.Task(stack, 'Task', { task: new tasks.RunBatchJob({ - jobDefinition: batchJobDefinition, + jobDefinitionArn: batchJobDefinition.jobDefinitionArn, jobName: 'JobName', - jobQueue: batchJobQueue, + jobQueueArn: batchJobQueue.jobQueueArn, arraySize: 1, }), }); @@ -226,9 +226,9 @@ test('Task throws if arraySize is out of limits 2-10000', () => { expect(() => { new sfn.Task(stack, 'Task', { task: new tasks.RunBatchJob({ - jobDefinition: batchJobDefinition, + jobDefinitionArn: batchJobDefinition.jobDefinitionArn, jobName: 'JobName', - jobQueue: batchJobQueue, + jobQueueArn: batchJobQueue.jobQueueArn, arraySize: 10001, }), }); @@ -241,9 +241,9 @@ test('Task throws if dependencies exceeds 20', () => { expect(() => { new sfn.Task(stack, 'Task', { task: new tasks.RunBatchJob({ - jobDefinition: batchJobDefinition, + jobDefinitionArn: batchJobDefinition.jobDefinitionArn, jobName: 'JobName', - jobQueue: batchJobQueue, + jobQueueArn: batchJobQueue.jobQueueArn, dependsOn: [...Array(21).keys()].map(i => ({ jobId: `${i}`, type: `some_type-${i}`, @@ -259,9 +259,9 @@ test('Task throws if attempts is out of limits 1-10', () => { expect(() => { new sfn.Task(stack, 'Task', { task: new tasks.RunBatchJob({ - jobDefinition: batchJobDefinition, + jobDefinitionArn: batchJobDefinition.jobDefinitionArn, jobName: 'JobName', - jobQueue: batchJobQueue, + jobQueueArn: batchJobQueue.jobQueueArn, attempts: 0, }), }); @@ -272,9 +272,9 @@ test('Task throws if attempts is out of limits 1-10', () => { expect(() => { new sfn.Task(stack, 'Task', { task: new tasks.RunBatchJob({ - jobDefinition: batchJobDefinition, + jobDefinitionArn: batchJobDefinition.jobDefinitionArn, jobName: 'JobName', - jobQueue: batchJobQueue, + jobQueueArn: batchJobQueue.jobQueueArn, attempts: 11, }), }); @@ -287,9 +287,9 @@ test('Task throws if timeout is less than 60 sec', () => { expect(() => { new sfn.Task(stack, 'Task', { task: new tasks.RunBatchJob({ - jobDefinition: batchJobDefinition, + jobDefinitionArn: batchJobDefinition.jobDefinitionArn, jobName: 'JobName', - jobQueue: batchJobQueue, + jobQueueArn: batchJobQueue.jobQueueArn, timeout: cdk.Duration.seconds(59), }), }); diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/submit-job.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/submit-job.test.ts index d9d0f1f797ee7..ade6e2983106f 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/submit-job.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/submit-job.test.ts @@ -37,9 +37,9 @@ beforeEach(() => { test('Task with only the required parameters', () => { // WHEN const task = new BatchSubmitJob(stack, 'Task', { - jobDefinition: batchJobDefinition, + jobDefinitionArn: batchJobDefinition.jobDefinitionArn, jobName: 'JobName', - jobQueue: batchJobQueue, + jobQueueArn: batchJobQueue.jobQueueArn, }); // THEN @@ -69,9 +69,9 @@ test('Task with only the required parameters', () => { test('Task with all the parameters', () => { // WHEN const task = new BatchSubmitJob(stack, 'Task', { - jobDefinition: batchJobDefinition, + jobDefinitionArn: batchJobDefinition.jobDefinitionArn, jobName: 'JobName', - jobQueue: batchJobQueue, + jobQueueArn: batchJobQueue.jobQueueArn, arraySize: 15, containerOverrides: { command: ['sudo', 'rm'], @@ -130,9 +130,9 @@ test('Task with all the parameters', () => { test('supports tokens', () => { // WHEN const task = new BatchSubmitJob(stack, 'Task', { - jobDefinition: batchJobDefinition, jobName: sfn.JsonPath.stringAt('$.jobName'), - jobQueue: batchJobQueue, + jobDefinitionArn: batchJobDefinition.jobDefinitionArn, + jobQueueArn: batchJobQueue.jobQueueArn, arraySize: sfn.JsonPath.numberAt('$.arraySize'), timeout: cdk.Duration.seconds(sfn.JsonPath.numberAt('$.timeout')), attempts: sfn.JsonPath.numberAt('$.attempts'), @@ -174,9 +174,9 @@ test('supports tokens', () => { test('supports passing task input into payload', () => { // WHEN const task = new BatchSubmitJob(stack, 'Task', { - jobDefinition: batchJobDefinition, + jobDefinitionArn: batchJobDefinition.jobDefinitionArn, + jobQueueArn: batchJobQueue.jobQueueArn, jobName: sfn.JsonPath.stringAt('$.jobName'), - jobQueue: batchJobQueue, payload: sfn.TaskInput.fromDataAt('$.foo'), }); @@ -208,9 +208,9 @@ test('supports passing task input into payload', () => { test('Task throws if WAIT_FOR_TASK_TOKEN is supplied as service integration pattern', () => { expect(() => { new BatchSubmitJob(stack, 'Task', { - jobDefinition: batchJobDefinition, + jobDefinitionArn: batchJobDefinition.jobDefinitionArn, jobName: 'JobName', - jobQueue: batchJobQueue, + jobQueueArn: batchJobQueue.jobQueueArn, integrationPattern: sfn.IntegrationPattern.WAIT_FOR_TASK_TOKEN, }); }).toThrow( @@ -221,9 +221,9 @@ test('Task throws if WAIT_FOR_TASK_TOKEN is supplied as service integration patt test('Task throws if environment in containerOverrides contain env with name starting with AWS_BATCH', () => { expect(() => { new BatchSubmitJob(stack, 'Task', { - jobDefinition: batchJobDefinition, + jobDefinitionArn: batchJobDefinition.jobDefinitionArn, jobName: 'JobName', - jobQueue: batchJobQueue, + jobQueueArn: batchJobQueue.jobQueueArn, containerOverrides: { environment: { AWS_BATCH_MY_NAME: 'MY_VALUE' }, }, @@ -236,9 +236,9 @@ test('Task throws if environment in containerOverrides contain env with name sta test('Task throws if arraySize is out of limits 2-10000', () => { expect(() => { new BatchSubmitJob(stack, 'Task', { - jobDefinition: batchJobDefinition, + jobDefinitionArn: batchJobDefinition.jobDefinitionArn, jobName: 'JobName', - jobQueue: batchJobQueue, + jobQueueArn: batchJobQueue.jobQueueArn, arraySize: 1, }); }).toThrow( @@ -247,9 +247,9 @@ test('Task throws if arraySize is out of limits 2-10000', () => { expect(() => { new BatchSubmitJob(stack, 'Task2', { - jobDefinition: batchJobDefinition, + jobDefinitionArn: batchJobDefinition.jobDefinitionArn, jobName: 'JobName', - jobQueue: batchJobQueue, + jobQueueArn: batchJobQueue.jobQueueArn, arraySize: 10001, }); }).toThrow( @@ -260,9 +260,9 @@ test('Task throws if arraySize is out of limits 2-10000', () => { test('Task throws if dependencies exceeds 20', () => { expect(() => { new BatchSubmitJob(stack, 'Task', { - jobDefinition: batchJobDefinition, + jobDefinitionArn: batchJobDefinition.jobDefinitionArn, jobName: 'JobName', - jobQueue: batchJobQueue, + jobQueueArn: batchJobQueue.jobQueueArn, dependsOn: [...Array(21).keys()].map(i => ({ jobId: `${i}`, type: `some_type-${i}`, @@ -276,9 +276,9 @@ test('Task throws if dependencies exceeds 20', () => { test('Task throws if attempts is out of limits 1-10', () => { expect(() => { new BatchSubmitJob(stack, 'Task', { - jobDefinition: batchJobDefinition, + jobDefinitionArn: batchJobDefinition.jobDefinitionArn, jobName: 'JobName', - jobQueue: batchJobQueue, + jobQueueArn: batchJobQueue.jobQueueArn, attempts: 0, }); }).toThrow( @@ -287,9 +287,9 @@ test('Task throws if attempts is out of limits 1-10', () => { expect(() => { new BatchSubmitJob(stack, 'Task2', { - jobDefinition: batchJobDefinition, + jobDefinitionArn: batchJobDefinition.jobDefinitionArn, jobName: 'JobName', - jobQueue: batchJobQueue, + jobQueueArn: batchJobQueue.jobQueueArn, attempts: 11, }); }).toThrow( @@ -300,9 +300,9 @@ test('Task throws if attempts is out of limits 1-10', () => { test('Task throws if attempt duration is less than 60 sec', () => { expect(() => { new BatchSubmitJob(stack, 'Task', { - jobDefinition: batchJobDefinition, + jobDefinitionArn: batchJobDefinition.jobDefinitionArn, jobName: 'JobName', - jobQueue: batchJobQueue, + jobQueueArn: batchJobQueue.jobQueueArn, timeout: cdk.Duration.seconds(59), }); }).toThrow( diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/databrew/integ.start-job-run.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/databrew/integ.start-job-run.ts index 689f74a678a89..9f98e9d07308b 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/databrew/integ.start-job-run.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/databrew/integ.start-job-run.ts @@ -72,9 +72,9 @@ class GlueDataBrewJobStack extends cdk.Stack { const dataset = new databrew.CfnDataset(this, 'DataBrew Dataset', { input: { - S3InputDefinition: { - Bucket: `databrew-public-datasets-${region}`, - Key: 'votes.csv', + s3InputDefinition: { + bucket: `databrew-public-datasets-${region}`, + key: 'votes.csv', }, }, name: 'dataset-1', diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/ecs-tasks.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/ecs-tasks.test.ts index c5eb0bc6ca5a5..e5654a5e752fe 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/ecs-tasks.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/ecs-tasks.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; import * as sfn from '@aws-cdk/aws-stepfunctions'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.expected.json index 97a2e05741145..c67a1adcd7dd7 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.expected.json @@ -328,7 +328,7 @@ "Type": "AWS::Lambda::Function", "Properties": { "Code": { - "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" + "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n task_arns = container_instance_task_arns(cluster, instance_arn)\n \n if task_arns:\n print('Instance ARN %s has task ARNs %s' % (instance_arn, ', '.join(task_arns)))\n\n while has_tasks(cluster, instance_arn, task_arns):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\ndef container_instance_task_arns(cluster, instance_arn):\n \"\"\"Fetch tasks for a container instance ARN.\"\"\"\n arns = ecs.list_tasks(cluster=cluster, containerInstance=instance_arn)['taskArns']\n return arns\n\ndef has_tasks(cluster, instance_arn, task_arns):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n task_count = None\n\n if task_arns:\n # Fetch details for tasks running on the container instance\n tasks = ecs.describe_tasks(cluster=cluster, tasks=task_arns)['tasks']\n if tasks:\n # Consider any non-stopped tasks as running\n task_count = sum(task['lastStatus'] != 'STOPPED' for task in tasks) + instance['pendingTasksCount']\n \n if not task_count:\n # Fallback to instance task counts if detailed task information is unavailable\n task_count = instance['runningTasksCount'] + instance['pendingTasksCount']\n \n print('Instance %s has %s tasks' % (instance_arn, task_count))\n\n return task_count > 0\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, "Role": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.expected.json index 2b574e0b9baa4..891777171b73c 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.expected.json @@ -328,7 +328,7 @@ "Type": "AWS::Lambda::Function", "Properties": { "Code": { - "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" + "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n task_arns = container_instance_task_arns(cluster, instance_arn)\n \n if task_arns:\n print('Instance ARN %s has task ARNs %s' % (instance_arn, ', '.join(task_arns)))\n\n while has_tasks(cluster, instance_arn, task_arns):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\ndef container_instance_task_arns(cluster, instance_arn):\n \"\"\"Fetch tasks for a container instance ARN.\"\"\"\n arns = ecs.list_tasks(cluster=cluster, containerInstance=instance_arn)['taskArns']\n return arns\n\ndef has_tasks(cluster, instance_arn, task_arns):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n task_count = None\n\n if task_arns:\n # Fetch details for tasks running on the container instance\n tasks = ecs.describe_tasks(cluster=cluster, tasks=task_arns)['tasks']\n if tasks:\n # Consider any non-stopped tasks as running\n task_count = sum(task['lastStatus'] != 'STOPPED' for task in tasks) + instance['pendingTasksCount']\n \n if not task_count:\n # Fallback to instance task counts if detailed task information is unavailable\n task_count = instance['runningTasksCount'] + instance['pendingTasksCount']\n \n print('Instance %s has %s tasks' % (instance_arn, task_count))\n\n return task_count > 0\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, "Role": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/run-tasks.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/run-tasks.test.ts index ff2072b6b2ebf..626d1000fde01 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/run-tasks.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/run-tasks.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; import * as sfn from '@aws-cdk/aws-stepfunctions'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.ts index 7a3f0b70c8e9d..68a048a54675d 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.ts @@ -1,3 +1,4 @@ +/// !cdk-integ pragma:ignore-assets import * as eks from '@aws-cdk/aws-eks'; import * as iam from '@aws-cdk/aws-iam'; import * as sfn from '@aws-cdk/aws-stepfunctions'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-add-step.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-add-step.test.ts index 3060184a57746..56e970d049b51 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-add-step.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-add-step.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as sfn from '@aws-cdk/aws-stepfunctions'; import * as cdk from '@aws-cdk/core'; import * as tasks from '../../lib'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-cancel-step.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-cancel-step.test.ts index f4abcfbf66fdd..9f8383e87ff1d 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-cancel-step.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-cancel-step.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as sfn from '@aws-cdk/aws-stepfunctions'; import * as cdk from '@aws-cdk/core'; import * as tasks from '../../lib'; 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 fce085651c0cf..222934c042b8d 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 @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as iam from '@aws-cdk/aws-iam'; import * as sfn from '@aws-cdk/aws-stepfunctions'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-modify-instance-fleet-by-name.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-modify-instance-fleet-by-name.test.ts index d1349bafb9e65..85bb737641440 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-modify-instance-fleet-by-name.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-modify-instance-fleet-by-name.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as sfn from '@aws-cdk/aws-stepfunctions'; import * as cdk from '@aws-cdk/core'; import * as tasks from '../../lib'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-modify-instance-group-by-name.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-modify-instance-group-by-name.test.ts index 197e92e6d526d..f2188455cd24b 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-modify-instance-group-by-name.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-modify-instance-group-by-name.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as sfn from '@aws-cdk/aws-stepfunctions'; import * as cdk from '@aws-cdk/core'; import * as tasks from '../../lib'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-set-cluster-termination-protection.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-set-cluster-termination-protection.test.ts index 4373702a617ad..e40398980ee02 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-set-cluster-termination-protection.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-set-cluster-termination-protection.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as sfn from '@aws-cdk/aws-stepfunctions'; import * as cdk from '@aws-cdk/core'; import * as tasks from '../../lib'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-terminate-cluster.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-terminate-cluster.test.ts index 3e10f073fe09b..d00983c319664 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-terminate-cluster.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-terminate-cluster.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as sfn from '@aws-cdk/aws-stepfunctions'; import * as cdk from '@aws-cdk/core'; import * as tasks from '../../lib'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/evaluate-expression.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/evaluate-expression.test.ts index 92a451b908993..f56ce0d3bce70 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/evaluate-expression.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/evaluate-expression.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as sfn from '@aws-cdk/aws-stepfunctions'; import { Stack } from '@aws-cdk/core'; import * as tasks from '../lib'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/glue/run-glue-job-task.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/glue/run-glue-job-task.test.ts index bf73289247399..47dd07fc83d9e 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/glue/run-glue-job-task.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/glue/run-glue-job-task.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as sfn from '@aws-cdk/aws-stepfunctions'; import { Duration, Stack } from '@aws-cdk/core'; import * as tasks from '../../lib'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/glue/start-job-run.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/glue/start-job-run.test.ts index 66fb849d6195f..ae3c877a0b5c4 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/glue/start-job-run.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/glue/start-job-run.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as sfn from '@aws-cdk/aws-stepfunctions'; import { Duration, Stack } from '@aws-cdk/core'; import * as tasks from '../../lib'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/invoke-activity.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/invoke-activity.test.ts index d8c6aed8b6e7a..926593e2e9d9c 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/invoke-activity.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/invoke-activity.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as sfn from '@aws-cdk/aws-stepfunctions'; import { Stack } from '@aws-cdk/core'; import * as tasks from '../lib'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/invoke-function.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/invoke-function.test.ts index eb5341281e6b2..04f86319088ce 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/invoke-function.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/invoke-function.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as lambda from '@aws-cdk/aws-lambda'; import * as sfn from '@aws-cdk/aws-stepfunctions'; import { Stack } from '@aws-cdk/core'; 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 a6b8063ad38c2..e0166427b502c 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 @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as lambda from '@aws-cdk/aws-lambda'; import * as sfn from '@aws-cdk/aws-stepfunctions'; import { Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/run-lambda-task.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/run-lambda-task.test.ts index 46538a2b41cd6..d159ad23c98f9 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/run-lambda-task.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/lambda/run-lambda-task.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as lambda from '@aws-cdk/aws-lambda'; import * as sfn from '@aws-cdk/aws-stepfunctions'; import { Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/create-endpoint-config.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/create-endpoint-config.test.ts index c59eb59eb5a83..1c61906207399 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/create-endpoint-config.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/create-endpoint-config.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as kms from '@aws-cdk/aws-kms'; import * as sfn from '@aws-cdk/aws-stepfunctions'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/create-endpoint.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/create-endpoint.test.ts index 4e7f67148b731..ee543a7fb251f 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/create-endpoint.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/create-endpoint.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as sfn from '@aws-cdk/aws-stepfunctions'; import * as cdk from '@aws-cdk/core'; import * as tasks from '../../lib'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/create-model.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/create-model.test.ts index 4a1dedeac1f21..cea5b585f83f7 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/create-model.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/create-model.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as sfn from '@aws-cdk/aws-stepfunctions'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/create-training-job.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/create-training-job.test.ts index b61ebd4173762..b99076377a701 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/create-training-job.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/create-training-job.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/create-transform-job.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/create-transform-job.test.ts index 978d5bfa4ab37..cf545b3e1defb 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/create-transform-job.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/create-transform-job.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/update-endpoint.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/update-endpoint.test.ts index edd90392970b5..ee89086763aa6 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/update-endpoint.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker/update-endpoint.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as iam from '@aws-cdk/aws-iam'; import * as sfn from '@aws-cdk/aws-stepfunctions'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/start-execution.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/start-execution.test.ts index ee6a252ab09c3..a1d5b582a62ba 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/start-execution.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/start-execution.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as sfn from '@aws-cdk/aws-stepfunctions'; import { Stack } from '@aws-cdk/core'; import * as tasks from '../lib'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/stepfunctions/invoke-activity.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/stepfunctions/invoke-activity.ts index ac2673bdaf943..fb7cc2302130b 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/stepfunctions/invoke-activity.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/stepfunctions/invoke-activity.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as sfn from '@aws-cdk/aws-stepfunctions'; import { Stack } from '@aws-cdk/core'; import { StepFunctionsInvokeActivity } from '../../lib/stepfunctions/invoke-activity'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/stepfunctions/start-execution.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/stepfunctions/start-execution.test.ts index 99228dc1491d5..87774e50d1bef 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/stepfunctions/start-execution.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/stepfunctions/start-execution.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as sfn from '@aws-cdk/aws-stepfunctions'; import { Stack } from '@aws-cdk/core'; import { StepFunctionsStartExecution } from '../../lib/stepfunctions/start-execution'; diff --git a/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts b/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts index fa97eccad71f4..d7e7a73efa3f0 100644 --- a/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts +++ b/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts @@ -1,7 +1,7 @@ import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as iam from '@aws-cdk/aws-iam'; import * as logs from '@aws-cdk/aws-logs'; -import { Arn, Duration, IResource, Resource, Stack } from '@aws-cdk/core'; +import { Arn, Duration, IResource, Resource, Stack, Token } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { StateGraph } from './state-graph'; import { StatesMetrics } from './stepfunctions-canned-metrics.generated'; @@ -379,7 +379,7 @@ export class StateMachine extends StateMachineBase { physicalName: props.stateMachineName, }); - if (props.stateMachineName != undefined) { + if (props.stateMachineName !== undefined) { this.validateStateMachineName(props.stateMachineName); } @@ -431,11 +431,14 @@ export class StateMachine extends StateMachineBase { } private validateStateMachineName(stateMachineName: string) { - if (stateMachineName.length < 1 || stateMachineName.length > 80) { - throw new Error(`State Machine name must be between 1 and 80 characters. Received: ${stateMachineName}`); - } - if (!stateMachineName.match('^[0-9a-zA-Z+!@._-]+$')) { - throw new Error(`State Machine name must match "^[0-9a-zA-Z+!@._-]+$". Received: ${stateMachineName}`); + if (!Token.isUnresolved(stateMachineName)) { + if (stateMachineName.length < 1 || stateMachineName.length > 80) { + throw new Error(`State Machine name must be between 1 and 80 characters. Received: ${stateMachineName}`); + } + + if (!stateMachineName.match(/^[a-z0-9\+\!\@\.\(\)\-\=\_\']+$/i)) { + throw new Error(`State Machine name must match "^[a-z0-9+!@.()-=_']+$/i". Received: ${stateMachineName}`); + } } } diff --git a/packages/@aws-cdk/aws-stepfunctions/lib/states/custom-state.ts b/packages/@aws-cdk/aws-stepfunctions/lib/states/custom-state.ts index eccfad6e9bcc1..20d46a14510c0 100644 --- a/packages/@aws-cdk/aws-stepfunctions/lib/states/custom-state.ts +++ b/packages/@aws-cdk/aws-stepfunctions/lib/states/custom-state.ts @@ -18,7 +18,6 @@ export interface CustomStateProps { /** * State defined by supplying Amazon States Language (ASL) in the state machine. * - * @experimental */ export class CustomState extends State implements IChainable, INextable { public readonly endStates: INextable[]; diff --git a/packages/@aws-cdk/aws-stepfunctions/package.json b/packages/@aws-cdk/aws-stepfunctions/package.json index 80035201f8b36..d1d7d13e0d730 100644 --- a/packages/@aws-cdk/aws-stepfunctions/package.json +++ b/packages/@aws-cdk/aws-stepfunctions/package.json @@ -71,11 +71,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", @@ -84,7 +85,7 @@ "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -94,7 +95,7 @@ "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-stepfunctions/test/activity.test.ts b/packages/@aws-cdk/aws-stepfunctions/test/activity.test.ts index e1aa3aa0e9c02..f2ca02a571ffc 100644 --- a/packages/@aws-cdk/aws-stepfunctions/test/activity.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions/test/activity.test.ts @@ -1,5 +1,5 @@ -import { arrayWith, objectLike } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { arrayWith, objectLike } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import * as stepfunctions from '../lib'; diff --git a/packages/@aws-cdk/aws-stepfunctions/test/condition.test.ts b/packages/@aws-cdk/aws-stepfunctions/test/condition.test.ts index 55fa5a6d2c535..6689cfcb64530 100644 --- a/packages/@aws-cdk/aws-stepfunctions/test/condition.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions/test/condition.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as stepfunctions from '../lib'; describe('Condition Variables', () => { diff --git a/packages/@aws-cdk/aws-stepfunctions/test/custom-state.test.ts b/packages/@aws-cdk/aws-stepfunctions/test/custom-state.test.ts index 9e58281059e8b..c03b716eb6248 100644 --- a/packages/@aws-cdk/aws-stepfunctions/test/custom-state.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions/test/custom-state.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import * as sfn from '../lib'; import { render } from './private/render-util'; diff --git a/packages/@aws-cdk/aws-stepfunctions/test/fail.test.ts b/packages/@aws-cdk/aws-stepfunctions/test/fail.test.ts index 4666a7a31adf1..a8e94b156466c 100644 --- a/packages/@aws-cdk/aws-stepfunctions/test/fail.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions/test/fail.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import * as stepfunctions from '../lib'; diff --git a/packages/@aws-cdk/aws-stepfunctions/test/fields.test.ts b/packages/@aws-cdk/aws-stepfunctions/test/fields.test.ts index a919912bf7c30..b9ff82b175709 100644 --- a/packages/@aws-cdk/aws-stepfunctions/test/fields.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions/test/fields.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { FieldUtils, JsonPath } from '../lib'; describe('Fields', () => { diff --git a/packages/@aws-cdk/aws-stepfunctions/test/map.test.ts b/packages/@aws-cdk/aws-stepfunctions/test/map.test.ts index 972764ea10d68..1f9ea12651d4a 100644 --- a/packages/@aws-cdk/aws-stepfunctions/test/map.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions/test/map.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import * as stepfunctions from '../lib'; diff --git a/packages/@aws-cdk/aws-stepfunctions/test/parallel.test.ts b/packages/@aws-cdk/aws-stepfunctions/test/parallel.test.ts index d5ff7999cb988..cae6bdf543e99 100644 --- a/packages/@aws-cdk/aws-stepfunctions/test/parallel.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions/test/parallel.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import * as stepfunctions from '../lib'; diff --git a/packages/@aws-cdk/aws-stepfunctions/test/pass.test.ts b/packages/@aws-cdk/aws-stepfunctions/test/pass.test.ts index 0c1b24e9a0ad6..f3cc78bb68455 100644 --- a/packages/@aws-cdk/aws-stepfunctions/test/pass.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions/test/pass.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Result } from '../lib'; describe('Pass State', () => { diff --git a/packages/@aws-cdk/aws-stepfunctions/test/state-machine-resources.test.ts b/packages/@aws-cdk/aws-stepfunctions/test/state-machine-resources.test.ts index 08bc9d1ae4a63..528b79b59dd58 100644 --- a/packages/@aws-cdk/aws-stepfunctions/test/state-machine-resources.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions/test/state-machine-resources.test.ts @@ -1,5 +1,5 @@ -import { arrayWith, objectLike, ResourcePart } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { arrayWith, objectLike, ResourcePart } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; 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 1c26947659a54..6db3dd6b476bd 100644 --- a/packages/@aws-cdk/aws-stepfunctions/test/state-machine.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions/test/state-machine.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as logs from '@aws-cdk/aws-logs'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; @@ -89,7 +89,36 @@ describe('State Machine', () => { expect(() => { createStateMachine(invalidCharactersName); - }).toThrow(`State Machine name must match "^[0-9a-zA-Z+!@._-]+$". Received: ${invalidCharactersName}`); + }).toThrow(`State Machine name must match "^[a-z0-9+!@.()-=_']+$/i". Received: ${invalidCharactersName}`); + }); + + test('State Machine with valid name', () => { + // GIVEN + const stack = new cdk.Stack(); + const newStateMachine = new stepfunctions.StateMachine(stack, 'dummyStateMachineToken', { + definition: stepfunctions.Chain.start(new stepfunctions.Pass(stack, 'dummyStateMachineTokenPass')), + }); + + // WHEN + const nameContainingToken = newStateMachine.stateMachineName + '-Name'; + const validName = 'AWS-Stepfunctions_Name.Test(@aws-cdk+)!=\'1\''; + + // THEN + expect(() => { + new stepfunctions.StateMachine(stack, 'TokenTest-StateMachine', { + stateMachineName: nameContainingToken, + definition: stepfunctions.Chain.start(new stepfunctions.Pass(stack, 'TokenTest-StateMachinePass')), + stateMachineType: stepfunctions.StateMachineType.EXPRESS, + }); + }).not.toThrow(); + + expect(() => { + new stepfunctions.StateMachine(stack, 'ValidNameTest-StateMachine', { + stateMachineName: validName, + definition: stepfunctions.Chain.start(new stepfunctions.Pass(stack, 'ValidNameTest-StateMachinePass')), + stateMachineType: stepfunctions.StateMachineType.EXPRESS, + }); + }).not.toThrow(); }); test('log configuration', () => { diff --git a/packages/@aws-cdk/aws-stepfunctions/test/states-language.test.ts b/packages/@aws-cdk/aws-stepfunctions/test/states-language.test.ts index 326bfeaf17ba1..993b6a6d27351 100644 --- a/packages/@aws-cdk/aws-stepfunctions/test/states-language.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions/test/states-language.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import * as constructs from 'constructs'; import * as stepfunctions from '../lib'; diff --git a/packages/@aws-cdk/aws-stepfunctions/test/task-base.test.ts b/packages/@aws-cdk/aws-stepfunctions/test/task-base.test.ts index c88540bb8f1e3..3a8132a1f5cb8 100644 --- a/packages/@aws-cdk/aws-stepfunctions/test/task-base.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions/test/task-base.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Metric } from '@aws-cdk/aws-cloudwatch'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-stepfunctions/test/wait.test.ts b/packages/@aws-cdk/aws-stepfunctions/test/wait.test.ts index 94c67543e2e60..350ff400a4d86 100644 --- a/packages/@aws-cdk/aws-stepfunctions/test/wait.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions/test/wait.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as cdk from '@aws-cdk/core'; import { Pass, Wait, WaitTime } from '../lib'; import { render } from './private/render-util'; diff --git a/packages/@aws-cdk/aws-synthetics/.gitignore b/packages/@aws-cdk/aws-synthetics/.gitignore index 5aa413b898780..e1dc1b360abec 100644 --- a/packages/@aws-cdk/aws-synthetics/.gitignore +++ b/packages/@aws-cdk/aws-synthetics/.gitignore @@ -16,5 +16,6 @@ coverage nyc.config.js !.eslintrc.js !jest.config.js +!test/canaries/nodejs/* junit.xml diff --git a/packages/@aws-cdk/aws-synthetics/README.md b/packages/@aws-cdk/aws-synthetics/README.md index 80a6defd34848..4c39b1430ca90 100644 --- a/packages/@aws-cdk/aws-synthetics/README.md +++ b/packages/@aws-cdk/aws-synthetics/README.md @@ -44,7 +44,7 @@ const canary = new synthetics.Canary(this, 'MyCanary', { code: synthetics.Code.fromAsset(path.join(__dirname, 'canary')), handler: 'index.handler', }), - runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_0, + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_1, }); ``` @@ -107,7 +107,7 @@ const canary = new Canary(this, 'MyCanary', { code: synthetics.Code.fromInline('/* Synthetics handler code */'), handler: 'index.handler', // must be 'index.handler' }), - runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_0, + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_1, }); // To supply the code from your local filesystem: @@ -116,7 +116,7 @@ const canary = new Canary(this, 'MyCanary', { code: synthetics.Code.fromAsset(path.join(__dirname, 'canary')), handler: 'index.handler', // must end with '.handler' }), - runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_0, + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_1, }); // To supply the code from a S3 bucket: @@ -125,7 +125,7 @@ const canary = new Canary(this, 'MyCanary', { code: synthetics.Code.fromBucket(bucket, 'canary.zip'), handler: 'index.handler', // must end with '.handler' }), - runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_0, + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_1, }); ``` diff --git a/packages/@aws-cdk/aws-synthetics/lib/canary.ts b/packages/@aws-cdk/aws-synthetics/lib/canary.ts index 72d4b311ce6e3..45687dc05cb51 100644 --- a/packages/@aws-cdk/aws-synthetics/lib/canary.ts +++ b/packages/@aws-cdk/aws-synthetics/lib/canary.ts @@ -122,6 +122,16 @@ export class Runtime { */ public static readonly SYNTHETICS_NODEJS_PUPPETEER_3_0 = new Runtime('syn-nodejs-puppeteer-3.0'); + /** + * `syn-nodejs-puppeteer-3.1` includes the following: + * - Lambda runtime Node.js 12.x + * - Puppeteer-core version 5.5.0 + * - Chromium version 88.0.4298.0 + * + * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Library_nodejs_puppeteer.html#CloudWatch_Synthetics_runtimeversion-nodejs-puppeteer-3.1 + */ + public static readonly SYNTHETICS_NODEJS_PUPPETEER_3_1 = new Runtime('syn-nodejs-puppeteer-3.1'); + /** * @param name The name of the runtime version */ diff --git a/packages/@aws-cdk/aws-synthetics/package.json b/packages/@aws-cdk/aws-synthetics/package.json index 3b15e2a0b8ffb..a62ec9b002c44 100644 --- a/packages/@aws-cdk/aws-synthetics/package.json +++ b/packages/@aws-cdk/aws-synthetics/package.json @@ -73,11 +73,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", @@ -85,7 +86,7 @@ "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", @@ -93,7 +94,7 @@ "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-synthetics/test/canary.test.ts b/packages/@aws-cdk/aws-synthetics/test/canary.test.ts index bb5e479e7f7e9..6eb5c228fec6e 100644 --- a/packages/@aws-cdk/aws-synthetics/test/canary.test.ts +++ b/packages/@aws-cdk/aws-synthetics/test/canary.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert/jest'; -import { objectLike } from '@aws-cdk/assert'; +import '@aws-cdk/assert-internal/jest'; +import { objectLike } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import * as s3 from '@aws-cdk/aws-s3'; import { App, Duration, Lazy, Stack } from '@aws-cdk/core'; @@ -44,7 +44,7 @@ test('Canary can have generated name', () => { handler: 'index.handler', code: synthetics.Code.fromInline('/* Synthetics handler code */'), }), - runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_0, + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_1, }); // THEN diff --git a/packages/@aws-cdk/aws-synthetics/test/code.test.ts b/packages/@aws-cdk/aws-synthetics/test/code.test.ts index 86e8859b2e4c5..b409653e87791 100644 --- a/packages/@aws-cdk/aws-synthetics/test/code.test.ts +++ b/packages/@aws-cdk/aws-synthetics/test/code.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as path from 'path'; import * as s3 from '@aws-cdk/aws-s3'; import { App, Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-synthetics/test/metric.test.ts b/packages/@aws-cdk/aws-synthetics/test/metric.test.ts index 6144d2d678cdb..049787b4c0cb8 100644 --- a/packages/@aws-cdk/aws-synthetics/test/metric.test.ts +++ b/packages/@aws-cdk/aws-synthetics/test/metric.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { App, Stack } from '@aws-cdk/core'; import * as synthetics from '../lib'; diff --git a/packages/@aws-cdk/aws-timestream/package.json b/packages/@aws-cdk/aws-timestream/package.json index c432583d5cbdb..6525a28e80fab 100644 --- a/packages/@aws-cdk/aws-timestream/package.json +++ b/packages/@aws-cdk/aws-timestream/package.json @@ -73,10 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-timestream/test/timestream.test.ts b/packages/@aws-cdk/aws-timestream/test/timestream.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-timestream/test/timestream.test.ts +++ b/packages/@aws-cdk/aws-timestream/test/timestream.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-transfer/package.json b/packages/@aws-cdk/aws-transfer/package.json index b70fc5929c4c0..b3dbfb66b8a0d 100644 --- a/packages/@aws-cdk/aws-transfer/package.json +++ b/packages/@aws-cdk/aws-transfer/package.json @@ -73,18 +73,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-transfer/test/transfer.test.ts b/packages/@aws-cdk/aws-transfer/test/transfer.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-transfer/test/transfer.test.ts +++ b/packages/@aws-cdk/aws-transfer/test/transfer.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-waf/package.json b/packages/@aws-cdk/aws-waf/package.json index ced3ca7dc741b..cbeab0a181cce 100644 --- a/packages/@aws-cdk/aws-waf/package.json +++ b/packages/@aws-cdk/aws-waf/package.json @@ -71,19 +71,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-waf/test/waf.test.ts b/packages/@aws-cdk/aws-waf/test/waf.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-waf/test/waf.test.ts +++ b/packages/@aws-cdk/aws-waf/test/waf.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-wafregional/package.json b/packages/@aws-cdk/aws-wafregional/package.json index 8e165fd4169f8..f2bc0f5a8151c 100644 --- a/packages/@aws-cdk/aws-wafregional/package.json +++ b/packages/@aws-cdk/aws-wafregional/package.json @@ -71,19 +71,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-wafregional/test/wafregional.test.ts b/packages/@aws-cdk/aws-wafregional/test/wafregional.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-wafregional/test/wafregional.test.ts +++ b/packages/@aws-cdk/aws-wafregional/test/wafregional.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-wafv2/package.json b/packages/@aws-cdk/aws-wafv2/package.json index 7bae0807f8209..4a14b6c046a1a 100644 --- a/packages/@aws-cdk/aws-wafv2/package.json +++ b/packages/@aws-cdk/aws-wafv2/package.json @@ -73,18 +73,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-wafv2/test/wafv2.test.ts b/packages/@aws-cdk/aws-wafv2/test/wafv2.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-wafv2/test/wafv2.test.ts +++ b/packages/@aws-cdk/aws-wafv2/test/wafv2.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/aws-workspaces/package.json b/packages/@aws-cdk/aws-workspaces/package.json index d2a3313f491dd..0faa24f1dbfa7 100644 --- a/packages/@aws-cdk/aws-workspaces/package.json +++ b/packages/@aws-cdk/aws-workspaces/package.json @@ -71,19 +71,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-workspaces/test/workspaces.test.ts b/packages/@aws-cdk/aws-workspaces/test/workspaces.test.ts index e394ef336bfb4..c4505ad966984 100644 --- a/packages/@aws-cdk/aws-workspaces/test/workspaces.test.ts +++ b/packages/@aws-cdk/aws-workspaces/test/workspaces.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import {} from '../lib'; test('No tests are specified for this package', () => { diff --git a/packages/@aws-cdk/cdk-assets-schema/package.json b/packages/@aws-cdk/cdk-assets-schema/package.json index 80be64f4b67d3..bf1bf7cec32c4 100644 --- a/packages/@aws-cdk/cdk-assets-schema/package.json +++ b/packages/@aws-cdk/cdk-assets-schema/package.json @@ -50,7 +50,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.21", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "jest": "^26.6.3", "pkglint": "0.0.0" diff --git a/packages/@aws-cdk/cfnspec/CHANGELOG.md b/packages/@aws-cdk/cfnspec/CHANGELOG.md index 861146ecf1337..4f49d0b63908e 100644 --- a/packages/@aws-cdk/cfnspec/CHANGELOG.md +++ b/packages/@aws-cdk/cfnspec/CHANGELOG.md @@ -1,3 +1,783 @@ +# CloudFormation Resource Specification v35.1.0 + +## New Resource Types + +* AWS::IoTFleetHub::Application +* AWS::IoTWireless::PartnerAccount +* AWS::IoTWireless::TaskDefinition +* AWS::NimbleStudio::LaunchProfile +* AWS::NimbleStudio::StreamingImage +* AWS::NimbleStudio::Studio +* AWS::NimbleStudio::StudioComponent +* AWS::SES::ContactList + +## Attribute Changes + +* AWS::EKS::Cluster OpenIdConnectIssuerUrl (__added__) + +## Property Changes + +* AWS::AppIntegrations::EventIntegration EventFilter.PrimitiveType (__deleted__) +* AWS::Detective::Graph Tags (__added__) +* AWS::ResourceGroups::Group Configuration (__added__) +* AWS::ResourceGroups::Group Resources (__added__) + +## Property Type Changes + +* AWS::ResourceGroups::Group.ConfigurationItem (__added__) +* AWS::ResourceGroups::Group.ConfigurationParameter (__added__) +* AWS::GroundStation::Config.DecodeConfig UnvalidatedJson (__deleted__) +* AWS::GroundStation::Config.DecodeConfig UnvalidatedJSON (__added__) +* AWS::GroundStation::Config.DemodulationConfig UnvalidatedJson (__deleted__) +* AWS::GroundStation::Config.DemodulationConfig UnvalidatedJSON (__added__) + + +# CloudFormation Resource Specification v35.0.0 + +## New Resource Types + +* AWS::AppIntegrations::EventIntegration +* AWS::AutoScaling::WarmPool +* AWS::Budgets::BudgetsAction +* AWS::CustomerProfiles::Domain +* AWS::CustomerProfiles::Integration +* AWS::CustomerProfiles::ObjectType +* AWS::EC2::EnclaveCertificateIamRoleAssociation +* AWS::GroundStation::Config +* AWS::GroundStation::DataflowEndpointGroup +* AWS::GroundStation::MissionProfile +* AWS::IVS::RecordingConfiguration +* AWS::Logs::QueryDefinition +* AWS::LookoutMetrics::Alert +* AWS::LookoutMetrics::AnomalyDetector +* AWS::QuickSight::DataSet +* AWS::QuickSight::DataSource +* AWS::Route53Resolver::FirewallDomainList +* AWS::Route53Resolver::FirewallRuleGroup +* AWS::Route53Resolver::FirewallRuleGroupAssociation + +## Attribute Changes + +* AWS::CloudFront::CloudFrontOriginAccessIdentity Id (__added__) +* AWS::FIS::ExperimentTemplate id (__deleted__) +* AWS::FIS::ExperimentTemplate Id (__added__) +* AWS::GameLift::Fleet FleetId (__added__) +* AWS::ImageBuilder::Component Name (__added__) +* AWS::ImageBuilder::ContainerRecipe Name (__added__) +* AWS::ImageBuilder::DistributionConfiguration Name (__added__) +* AWS::ImageBuilder::ImagePipeline Name (__added__) +* AWS::ImageBuilder::ImageRecipe Name (__added__) +* AWS::ImageBuilder::InfrastructureConfiguration Name (__added__) +* AWS::WAFv2::RuleGroup AvailableLabels (__added__) +* AWS::WAFv2::RuleGroup ConsumedLabels (__added__) +* AWS::WAFv2::RuleGroup LabelNamespace (__added__) +* AWS::WAFv2::WebACL LabelNamespace (__added__) + +## Property Changes + +* AWS::ApiGateway::RestApi DisableExecuteApiEndpoint (__added__) +* AWS::AppSync::GraphQLApi LambdaAuthorizerConfig (__deleted__) +* AWS::Batch::ComputeEnvironment ServiceRole.Required (__changed__) + * Old: true + * New: false +* AWS::CE::CostCategory DefaultValue (__added__) +* AWS::CloudFormation::ResourceVersion ExecutionRoleArn.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::CloudFormation::ResourceVersion LoggingConfig.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::CloudFormation::ResourceVersion SchemaHandlerPackage.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::CloudFormation::ResourceVersion TypeName.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::Config::DeliveryChannel S3KmsKeyArn (__added__) +* AWS::DMS::Endpoint ResourceIdentifier (__added__) +* AWS::DMS::ReplicationInstance ResourceIdentifier (__added__) +* AWS::DMS::ReplicationTask ResourceIdentifier (__added__) +* AWS::DataBrew::Dataset PathOptions (__added__) +* AWS::DataBrew::Dataset FormatOptions.PrimitiveType (__deleted__) +* AWS::DataBrew::Dataset FormatOptions.Type (__added__) +* AWS::DataBrew::Dataset Input.PrimitiveType (__deleted__) +* AWS::DataBrew::Dataset Input.Type (__added__) +* AWS::DynamoDB::Table KinesisStreamSpecification (__added__) +* AWS::EC2::LaunchTemplate TagSpecifications.ItemType (__changed__) + * Old: TagSpecification + * New: LaunchTemplateTagSpecification +* AWS::EFS::FileSystem BypassPolicyLockoutSafetyCheck (__added__) +* AWS::ElastiCache::CacheCluster LogDeliveryConfigurations (__added__) +* AWS::ElastiCache::ParameterGroup Tags (__added__) +* AWS::ElastiCache::ParameterGroup CacheParameterGroupFamily.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::ElastiCache::ReplicationGroup LogDeliveryConfigurations (__added__) +* AWS::ElastiCache::SecurityGroup Tags (__added__) +* AWS::ElastiCache::SubnetGroup Tags (__added__) +* AWS::ElasticBeanstalk::Environment OperationsRole (__added__) +* AWS::FIS::ExperimentTemplate actions (__deleted__) +* AWS::FIS::ExperimentTemplate description (__deleted__) +* AWS::FIS::ExperimentTemplate roleArn (__deleted__) +* AWS::FIS::ExperimentTemplate stopConditions (__deleted__) +* AWS::FIS::ExperimentTemplate tags (__deleted__) +* AWS::FIS::ExperimentTemplate targets (__deleted__) +* AWS::FIS::ExperimentTemplate Actions (__added__) +* AWS::FIS::ExperimentTemplate Description (__added__) +* AWS::FIS::ExperimentTemplate RoleArn (__added__) +* AWS::FIS::ExperimentTemplate StopConditions (__added__) +* AWS::FIS::ExperimentTemplate Tags (__added__) +* AWS::FIS::ExperimentTemplate Targets (__added__) +* AWS::GameLift::Fleet LogPaths (__deleted__) +* AWS::GameLift::Fleet ServerLaunchParameters (__deleted__) +* AWS::GameLift::Fleet ServerLaunchPath (__deleted__) +* AWS::GameLift::Fleet EC2InboundPermissions.DuplicatesAllowed (__deleted__) +* AWS::GameLift::Fleet EC2InstanceType.Required (__changed__) + * Old: true + * New: false +* AWS::GameLift::Fleet MetricGroups.DuplicatesAllowed (__deleted__) +* AWS::GameLift::Fleet Name.Required (__changed__) + * Old: true + * New: false +* AWS::GameLift::GameSessionQueue CustomEventData (__added__) +* AWS::GameLift::GameSessionQueue NotificationTarget (__added__) +* AWS::IVS::Channel RecordingConfigurationArn (__added__) +* AWS::ImageBuilder::ContainerRecipe InstanceConfiguration (__added__) +* AWS::IoT::TopicRule Tags (__added__) +* AWS::IoTEvents::DetectorModel DetectorModelDefinition.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel RoleArn.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel Tags.DuplicatesAllowed (__added__) +* AWS::IoTEvents::Input InputDefinition.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::Input Tags.DuplicatesAllowed (__added__) +* AWS::MWAA::Environment MinWorkers (__added__) +* AWS::MWAA::Environment AirflowConfigurationOptions.Type (__deleted__) +* AWS::MWAA::Environment AirflowConfigurationOptions.PrimitiveType (__added__) +* AWS::SSM::Association Parameters.ItemType (__changed__) + * Old: ParameterValues + * New: List +* AWS::SSM::Document Attachments (__added__) +* AWS::SSM::Document DocumentFormat (__added__) +* AWS::SSM::Document Requires (__added__) +* AWS::SSM::Document TargetType (__added__) +* AWS::SSM::Document VersionName (__added__) +* AWS::SSM::Document Tags.DuplicatesAllowed (__deleted__) +* AWS::WAFv2::IPSet Name.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::WAFv2::IPSet Scope.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::WAFv2::RegexPatternSet Name.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::WAFv2::RegexPatternSet Scope.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::WAFv2::RuleGroup CustomResponseBodies (__added__) +* AWS::WAFv2::RuleGroup Name.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::WAFv2::RuleGroup Scope.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::WAFv2::WebACL CustomResponseBodies (__added__) +* AWS::WAFv2::WebACL Name.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::WAFv2::WebACL Scope.UpdateType (__changed__) + * Old: Mutable + * New: Immutable + +## Property Type Changes + +* AWS::ACMPCA::Certificate.CertificatePolicyList (__removed__) +* AWS::ACMPCA::Certificate.ExtendedKeyUsageList (__removed__) +* AWS::ACMPCA::Certificate.GeneralNameList (__removed__) +* AWS::ACMPCA::Certificate.PolicyQualifierInfoList (__removed__) +* AWS::ACMPCA::CertificateAuthority.SubjectInformationAccess (__removed__) +* AWS::AppFlow::Flow.IdFieldNamesList (__removed__) +* AWS::AppSync::GraphQLApi.LambdaAuthorizerConfig (__removed__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateActionItemStartAfterList (__removed__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateTargetFilterList (__removed__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateTargetFilterValues (__removed__) +* AWS::FIS::ExperimentTemplate.ResourceArnList (__removed__) +* AWS::Kendra::DataSource.ChangeDetectingColumns (__removed__) +* AWS::Kendra::DataSource.ConfluenceAttachmentFieldMappingsList (__removed__) +* AWS::Kendra::DataSource.ConfluenceBlogFieldMappingsList (__removed__) +* AWS::Kendra::DataSource.ConfluencePageFieldMappingsList (__removed__) +* AWS::Kendra::DataSource.ConfluenceSpaceFieldMappingsList (__removed__) +* AWS::Kendra::DataSource.ConfluenceSpaceList (__removed__) +* AWS::Kendra::DataSource.DataSourceInclusionsExclusionsStrings (__removed__) +* AWS::Kendra::DataSource.DataSourceToIndexFieldMappingList (__removed__) +* AWS::Kendra::DataSource.ExcludeMimeTypesList (__removed__) +* AWS::Kendra::DataSource.ExcludeSharedDrivesList (__removed__) +* AWS::Kendra::DataSource.ExcludeUserAccountsList (__removed__) +* AWS::Kendra::DataSource.OneDriveUserList (__removed__) +* AWS::Kendra::DataSource.SalesforceChatterFeedIncludeFilterTypes (__removed__) +* AWS::Kendra::DataSource.SalesforceCustomKnowledgeArticleTypeConfigurationList (__removed__) +* AWS::Kendra::DataSource.SalesforceKnowledgeArticleStateList (__removed__) +* AWS::Kendra::DataSource.SalesforceStandardObjectConfigurationList (__removed__) +* AWS::Kendra::Index.ValueImportanceItems (__removed__) +* AWS::MWAA::Environment.AirflowConfigurationOptions (__removed__) +* AWS::SSM::Association.ParameterValues (__removed__) +* AWS::SSO::InstanceAccessControlAttributeConfiguration.AccessControlAttributeValueSourceList (__removed__) +* AWS::SageMaker::MonitoringSchedule.MonitoringInputs (__removed__) +* AWS::WAFv2::RuleGroup.AndStatementOne (__removed__) +* AWS::WAFv2::RuleGroup.AndStatementTwo (__removed__) +* AWS::WAFv2::RuleGroup.NotStatementOne (__removed__) +* AWS::WAFv2::RuleGroup.NotStatementTwo (__removed__) +* AWS::WAFv2::RuleGroup.OrStatementOne (__removed__) +* AWS::WAFv2::RuleGroup.OrStatementTwo (__removed__) +* AWS::WAFv2::RuleGroup.RateBasedStatementOne (__removed__) +* AWS::WAFv2::RuleGroup.RateBasedStatementTwo (__removed__) +* AWS::WAFv2::RuleGroup.StatementOne (__removed__) +* AWS::WAFv2::RuleGroup.StatementThree (__removed__) +* AWS::WAFv2::RuleGroup.StatementTwo (__removed__) +* AWS::WAFv2::WebACL.AndStatementOne (__removed__) +* AWS::WAFv2::WebACL.AndStatementTwo (__removed__) +* AWS::WAFv2::WebACL.NotStatementOne (__removed__) +* AWS::WAFv2::WebACL.NotStatementTwo (__removed__) +* AWS::WAFv2::WebACL.OrStatementOne (__removed__) +* AWS::WAFv2::WebACL.OrStatementTwo (__removed__) +* AWS::WAFv2::WebACL.RateBasedStatementOne (__removed__) +* AWS::WAFv2::WebACL.RateBasedStatementTwo (__removed__) +* AWS::WAFv2::WebACL.StatementOne (__removed__) +* AWS::WAFv2::WebACL.StatementThree (__removed__) +* AWS::WAFv2::WebACL.StatementTwo (__removed__) +* AWS::AppFlow::Flow.LookoutMetricsDestinationProperties (__added__) +* AWS::Batch::JobDefinition.AuthorizationConfig (__added__) +* AWS::Batch::JobDefinition.EfsVolumeConfiguration (__added__) +* AWS::DataBrew::Dataset.CsvOptions (__added__) +* AWS::DataBrew::Dataset.DataCatalogInputDefinition (__added__) +* AWS::DataBrew::Dataset.DatabaseInputDefinition (__added__) +* AWS::DataBrew::Dataset.DatasetParameter (__added__) +* AWS::DataBrew::Dataset.DatetimeOptions (__added__) +* AWS::DataBrew::Dataset.ExcelOptions (__added__) +* AWS::DataBrew::Dataset.FilesLimit (__added__) +* AWS::DataBrew::Dataset.FilterExpression (__added__) +* AWS::DataBrew::Dataset.FilterValue (__added__) +* AWS::DataBrew::Dataset.FormatOptions (__added__) +* AWS::DataBrew::Dataset.Input (__added__) +* AWS::DataBrew::Dataset.JsonOptions (__added__) +* AWS::DataBrew::Dataset.PathOptions (__added__) +* AWS::DataBrew::Dataset.PathParameter (__added__) +* AWS::DataBrew::Dataset.S3Location (__added__) +* AWS::DynamoDB::Table.KinesisStreamSpecification (__added__) +* AWS::EC2::LaunchTemplate.LaunchTemplateTagSpecification (__added__) +* AWS::ElastiCache::CacheCluster.CloudWatchLogsDestinationDetails (__added__) +* AWS::ElastiCache::CacheCluster.DestinationDetails (__added__) +* AWS::ElastiCache::CacheCluster.KinesisFirehoseDestinationDetails (__added__) +* AWS::ElastiCache::CacheCluster.LogDeliveryConfigurationRequest (__added__) +* AWS::ElastiCache::ReplicationGroup.CloudWatchLogsDestinationDetails (__added__) +* AWS::ElastiCache::ReplicationGroup.DestinationDetails (__added__) +* AWS::ElastiCache::ReplicationGroup.KinesisFirehoseDestinationDetails (__added__) +* AWS::ElastiCache::ReplicationGroup.LogDeliveryConfigurationRequest (__added__) +* AWS::ImageBuilder::ContainerRecipe.EbsInstanceBlockDeviceSpecification (__added__) +* AWS::ImageBuilder::ContainerRecipe.InstanceBlockDeviceMapping (__added__) +* AWS::ImageBuilder::ContainerRecipe.InstanceConfiguration (__added__) +* AWS::ImageBuilder::DistributionConfiguration.LaunchTemplateConfiguration (__added__) +* AWS::IoT::TopicRule.CloudwatchLogsAction (__added__) +* AWS::IoT::TopicRule.KafkaAction (__added__) +* AWS::IoT::TopicRule.TimestreamAction (__added__) +* AWS::IoT::TopicRule.TimestreamDimension (__added__) +* AWS::IoT::TopicRule.TimestreamTimestamp (__added__) +* AWS::MediaLive::Channel.ArchiveCdnSettings (__added__) +* AWS::MediaLive::Channel.ArchiveS3Settings (__added__) +* AWS::MediaLive::Channel.CaptionRectangle (__added__) +* AWS::MediaLive::Channel.FrameCaptureCdnSettings (__added__) +* AWS::MediaLive::Channel.FrameCaptureHlsSettings (__added__) +* AWS::MediaLive::Channel.FrameCaptureS3Settings (__added__) +* AWS::MediaLive::Channel.HlsS3Settings (__added__) +* AWS::MediaLive::Channel.HtmlMotionGraphicsSettings (__added__) +* AWS::MediaLive::Channel.MotionGraphicsConfiguration (__added__) +* AWS::MediaLive::Channel.MotionGraphicsSettings (__added__) +* AWS::MediaLive::Channel.VideoSelectorColorSpaceSettings (__added__) +* AWS::SSM::Document.AttachmentsSource (__added__) +* AWS::SSM::Document.DocumentRequires (__added__) +* AWS::WAFv2::RuleGroup.AndStatement (__added__) +* AWS::WAFv2::RuleGroup.CustomResponseBody (__added__) +* AWS::WAFv2::RuleGroup.JsonBody (__added__) +* AWS::WAFv2::RuleGroup.JsonMatchPattern (__added__) +* AWS::WAFv2::RuleGroup.Label (__added__) +* AWS::WAFv2::RuleGroup.LabelMatchStatement (__added__) +* AWS::WAFv2::RuleGroup.LabelSummary (__added__) +* AWS::WAFv2::RuleGroup.NotStatement (__added__) +* AWS::WAFv2::RuleGroup.OrStatement (__added__) +* AWS::WAFv2::RuleGroup.RateBasedStatement (__added__) +* AWS::WAFv2::RuleGroup.Statement (__added__) +* AWS::WAFv2::WebACL.AllowAction (__added__) +* AWS::WAFv2::WebACL.AndStatement (__added__) +* AWS::WAFv2::WebACL.BlockAction (__added__) +* AWS::WAFv2::WebACL.CountAction (__added__) +* AWS::WAFv2::WebACL.CustomHTTPHeader (__added__) +* AWS::WAFv2::WebACL.CustomRequestHandling (__added__) +* AWS::WAFv2::WebACL.CustomResponse (__added__) +* AWS::WAFv2::WebACL.CustomResponseBody (__added__) +* AWS::WAFv2::WebACL.JsonBody (__added__) +* AWS::WAFv2::WebACL.JsonMatchPattern (__added__) +* AWS::WAFv2::WebACL.Label (__added__) +* AWS::WAFv2::WebACL.LabelMatchStatement (__added__) +* AWS::WAFv2::WebACL.NotStatement (__added__) +* AWS::WAFv2::WebACL.OrStatement (__added__) +* AWS::WAFv2::WebACL.RateBasedStatement (__added__) +* AWS::WAFv2::WebACL.Statement (__added__) +* AWS::ACMPCA::Certificate.Extensions CertificatePolicies.ItemType (__added__) +* AWS::ACMPCA::Certificate.Extensions CertificatePolicies.Type (__changed__) + * Old: CertificatePolicyList + * New: List +* AWS::ACMPCA::Certificate.Extensions ExtendedKeyUsage.ItemType (__added__) +* AWS::ACMPCA::Certificate.Extensions ExtendedKeyUsage.Type (__changed__) + * Old: ExtendedKeyUsageList + * New: List +* AWS::ACMPCA::Certificate.Extensions SubjectAlternativeNames.ItemType (__added__) +* AWS::ACMPCA::Certificate.Extensions SubjectAlternativeNames.Type (__changed__) + * Old: GeneralNameList + * New: List +* AWS::ACMPCA::Certificate.PolicyInformation PolicyQualifiers.ItemType (__added__) +* AWS::ACMPCA::Certificate.PolicyInformation PolicyQualifiers.Type (__changed__) + * Old: PolicyQualifierInfoList + * New: List +* AWS::ACMPCA::CertificateAuthority.CsrExtensions SubjectInformationAccess.ItemType (__added__) +* AWS::ACMPCA::CertificateAuthority.CsrExtensions SubjectInformationAccess.Type (__changed__) + * Old: SubjectInformationAccess + * New: List +* AWS::AppFlow::Flow.DestinationConnectorProperties LookoutMetrics (__added__) +* AWS::AppFlow::Flow.SalesforceDestinationProperties IdFieldNames.PrimitiveItemType (__added__) +* AWS::AppFlow::Flow.SalesforceDestinationProperties IdFieldNames.Type (__changed__) + * Old: IdFieldNamesList + * New: List +* AWS::AppSync::GraphQLApi.AdditionalAuthenticationProvider LambdaAuthorizerConfig (__deleted__) +* AWS::Backup::BackupPlan.BackupRuleResourceType EnableContinuousBackup (__added__) +* AWS::Batch::JobDefinition.Volumes EfsVolumeConfiguration (__added__) +* AWS::CloudFormation::ResourceVersion.LoggingConfig LogGroupName.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::CloudFormation::ResourceVersion.LoggingConfig LogRoleArn.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::CloudFormation::StackSet.OperationPreferences RegionConcurrencyType (__added__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateAction actionId (__deleted__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateAction description (__deleted__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateAction parameters (__deleted__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateAction startAfter (__deleted__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateAction targets (__deleted__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateAction ActionId (__added__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateAction Description (__added__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateAction Parameters (__added__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateAction StartAfter (__added__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateAction Targets (__added__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateStopCondition source (__deleted__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateStopCondition value (__deleted__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateStopCondition Source (__added__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateStopCondition Value (__added__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateTarget filters (__deleted__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateTarget resourceArns (__deleted__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateTarget resourceTags (__deleted__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateTarget resourceType (__deleted__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateTarget selectionMode (__deleted__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateTarget Filters (__added__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateTarget ResourceArns (__added__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateTarget ResourceTags (__added__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateTarget ResourceType (__added__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateTarget SelectionMode (__added__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateTargetFilter path (__deleted__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateTargetFilter values (__deleted__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateTargetFilter Path (__added__) +* AWS::FIS::ExperimentTemplate.ExperimentTemplateTargetFilter Values (__added__) +* AWS::GameLift::Fleet.IpPermission FromPort.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-fleet-ec2inboundpermission.html#cfn-gamelift-fleet-ec2inboundpermissions-fromport + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-fleet-ippermission.html#cfn-gamelift-fleet-ippermission-fromport +* AWS::GameLift::Fleet.IpPermission IpRange.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-fleet-ec2inboundpermission.html#cfn-gamelift-fleet-ec2inboundpermissions-iprange + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-fleet-ippermission.html#cfn-gamelift-fleet-ippermission-iprange +* AWS::GameLift::Fleet.IpPermission Protocol.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-fleet-ec2inboundpermission.html#cfn-gamelift-fleet-ec2inboundpermissions-protocol + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-fleet-ippermission.html#cfn-gamelift-fleet-ippermission-protocol +* AWS::GameLift::Fleet.IpPermission ToPort.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-fleet-ec2inboundpermission.html#cfn-gamelift-fleet-ec2inboundpermissions-toport + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-fleet-ippermission.html#cfn-gamelift-fleet-ippermission-toport +* AWS::GameLift::Fleet.RuntimeConfiguration ServerProcesses.DuplicatesAllowed (__deleted__) +* AWS::ImageBuilder::DistributionConfiguration.Distribution LaunchTemplateConfigurations (__added__) +* AWS::IoT::TopicRule.Action CloudwatchLogs (__added__) +* AWS::IoT::TopicRule.Action Kafka (__added__) +* AWS::IoT::TopicRule.Action Timestream (__added__) +* AWS::IoT::TopicRule.FirehoseAction BatchMode (__added__) +* AWS::IoT::TopicRule.IotAnalyticsAction BatchMode (__added__) +* AWS::IoT::TopicRule.IotEventsAction BatchMode (__added__) +* AWS::IoTEvents::DetectorModel.AssetPropertyTimestamp TimeInSeconds.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel.AssetPropertyValue Value.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel.ClearTimer TimerName.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel.DetectorModelDefinition InitialStateName.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel.DetectorModelDefinition States.DuplicatesAllowed (__added__) +* AWS::IoTEvents::DetectorModel.DetectorModelDefinition States.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel.DynamoDB HashKeyField.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel.DynamoDB HashKeyValue.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel.DynamoDB TableName.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel.DynamoDBv2 TableName.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel.Event Actions.DuplicatesAllowed (__added__) +* AWS::IoTEvents::DetectorModel.Event EventName.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel.Firehose DeliveryStreamName.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel.IotEvents InputName.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel.IotSiteWise PropertyValue.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel.IotTopicPublish MqttTopic.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel.Lambda FunctionArn.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel.OnEnter Events.DuplicatesAllowed (__added__) +* AWS::IoTEvents::DetectorModel.OnExit Events.DuplicatesAllowed (__added__) +* AWS::IoTEvents::DetectorModel.OnInput Events.DuplicatesAllowed (__added__) +* AWS::IoTEvents::DetectorModel.OnInput TransitionEvents.DuplicatesAllowed (__added__) +* AWS::IoTEvents::DetectorModel.Payload ContentExpression.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel.Payload Type.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel.ResetTimer TimerName.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel.SetTimer TimerName.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel.SetVariable Value.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel.SetVariable VariableName.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel.Sns TargetArn.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel.Sqs QueueUrl.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel.State StateName.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel.TransitionEvent Actions.DuplicatesAllowed (__added__) +* AWS::IoTEvents::DetectorModel.TransitionEvent Condition.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel.TransitionEvent EventName.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::DetectorModel.TransitionEvent NextState.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::Input.Attribute JsonPath.Required (__changed__) + * Old: false + * New: true +* AWS::IoTEvents::Input.InputDefinition Attributes.DuplicatesAllowed (__added__) +* AWS::IoTEvents::Input.InputDefinition Attributes.Required (__changed__) + * Old: false + * New: true +* AWS::Kendra::DataSource.ColumnConfiguration ChangeDetectingColumns.PrimitiveItemType (__added__) +* AWS::Kendra::DataSource.ColumnConfiguration ChangeDetectingColumns.Type (__changed__) + * Old: ChangeDetectingColumns + * New: List +* AWS::Kendra::DataSource.ColumnConfiguration FieldMappings.ItemType (__added__) +* AWS::Kendra::DataSource.ColumnConfiguration FieldMappings.Type (__changed__) + * Old: DataSourceToIndexFieldMappingList + * New: List +* AWS::Kendra::DataSource.ConfluenceAttachmentConfiguration AttachmentFieldMappings.ItemType (__added__) +* AWS::Kendra::DataSource.ConfluenceAttachmentConfiguration AttachmentFieldMappings.Type (__changed__) + * Old: ConfluenceAttachmentFieldMappingsList + * New: List +* AWS::Kendra::DataSource.ConfluenceBlogConfiguration BlogFieldMappings.ItemType (__added__) +* AWS::Kendra::DataSource.ConfluenceBlogConfiguration BlogFieldMappings.Type (__changed__) + * Old: ConfluenceBlogFieldMappingsList + * New: List +* AWS::Kendra::DataSource.ConfluenceConfiguration ExclusionPatterns.PrimitiveItemType (__added__) +* AWS::Kendra::DataSource.ConfluenceConfiguration ExclusionPatterns.Type (__changed__) + * Old: DataSourceInclusionsExclusionsStrings + * New: List +* AWS::Kendra::DataSource.ConfluenceConfiguration InclusionPatterns.PrimitiveItemType (__added__) +* AWS::Kendra::DataSource.ConfluenceConfiguration InclusionPatterns.Type (__changed__) + * Old: DataSourceInclusionsExclusionsStrings + * New: List +* AWS::Kendra::DataSource.ConfluencePageConfiguration PageFieldMappings.ItemType (__added__) +* AWS::Kendra::DataSource.ConfluencePageConfiguration PageFieldMappings.Type (__changed__) + * Old: ConfluencePageFieldMappingsList + * New: List +* AWS::Kendra::DataSource.ConfluenceSpaceConfiguration ExcludeSpaces.PrimitiveItemType (__added__) +* AWS::Kendra::DataSource.ConfluenceSpaceConfiguration ExcludeSpaces.Type (__changed__) + * Old: ConfluenceSpaceList + * New: List +* AWS::Kendra::DataSource.ConfluenceSpaceConfiguration IncludeSpaces.PrimitiveItemType (__added__) +* AWS::Kendra::DataSource.ConfluenceSpaceConfiguration IncludeSpaces.Type (__changed__) + * Old: ConfluenceSpaceList + * New: List +* AWS::Kendra::DataSource.ConfluenceSpaceConfiguration SpaceFieldMappings.ItemType (__added__) +* AWS::Kendra::DataSource.ConfluenceSpaceConfiguration SpaceFieldMappings.Type (__changed__) + * Old: ConfluenceSpaceFieldMappingsList + * New: List +* AWS::Kendra::DataSource.GoogleDriveConfiguration ExcludeMimeTypes.PrimitiveItemType (__added__) +* AWS::Kendra::DataSource.GoogleDriveConfiguration ExcludeMimeTypes.Type (__changed__) + * Old: ExcludeMimeTypesList + * New: List +* AWS::Kendra::DataSource.GoogleDriveConfiguration ExcludeSharedDrives.PrimitiveItemType (__added__) +* AWS::Kendra::DataSource.GoogleDriveConfiguration ExcludeSharedDrives.Type (__changed__) + * Old: ExcludeSharedDrivesList + * New: List +* AWS::Kendra::DataSource.GoogleDriveConfiguration ExcludeUserAccounts.PrimitiveItemType (__added__) +* AWS::Kendra::DataSource.GoogleDriveConfiguration ExcludeUserAccounts.Type (__changed__) + * Old: ExcludeUserAccountsList + * New: List +* AWS::Kendra::DataSource.GoogleDriveConfiguration ExclusionPatterns.PrimitiveItemType (__added__) +* AWS::Kendra::DataSource.GoogleDriveConfiguration ExclusionPatterns.Type (__changed__) + * Old: DataSourceInclusionsExclusionsStrings + * New: List +* AWS::Kendra::DataSource.GoogleDriveConfiguration FieldMappings.ItemType (__added__) +* AWS::Kendra::DataSource.GoogleDriveConfiguration FieldMappings.Type (__changed__) + * Old: DataSourceToIndexFieldMappingList + * New: List +* AWS::Kendra::DataSource.GoogleDriveConfiguration InclusionPatterns.PrimitiveItemType (__added__) +* AWS::Kendra::DataSource.GoogleDriveConfiguration InclusionPatterns.Type (__changed__) + * Old: DataSourceInclusionsExclusionsStrings + * New: List +* AWS::Kendra::DataSource.OneDriveConfiguration ExclusionPatterns.PrimitiveItemType (__added__) +* AWS::Kendra::DataSource.OneDriveConfiguration ExclusionPatterns.Type (__changed__) + * Old: DataSourceInclusionsExclusionsStrings + * New: List +* AWS::Kendra::DataSource.OneDriveConfiguration FieldMappings.ItemType (__added__) +* AWS::Kendra::DataSource.OneDriveConfiguration FieldMappings.Type (__changed__) + * Old: DataSourceToIndexFieldMappingList + * New: List +* AWS::Kendra::DataSource.OneDriveConfiguration InclusionPatterns.PrimitiveItemType (__added__) +* AWS::Kendra::DataSource.OneDriveConfiguration InclusionPatterns.Type (__changed__) + * Old: DataSourceInclusionsExclusionsStrings + * New: List +* AWS::Kendra::DataSource.OneDriveUsers OneDriveUserList.PrimitiveItemType (__added__) +* AWS::Kendra::DataSource.OneDriveUsers OneDriveUserList.Type (__changed__) + * Old: OneDriveUserList + * New: List +* AWS::Kendra::DataSource.S3DataSourceConfiguration ExclusionPatterns.PrimitiveItemType (__added__) +* AWS::Kendra::DataSource.S3DataSourceConfiguration ExclusionPatterns.Type (__changed__) + * Old: DataSourceInclusionsExclusionsStrings + * New: List +* AWS::Kendra::DataSource.S3DataSourceConfiguration InclusionPatterns.PrimitiveItemType (__added__) +* AWS::Kendra::DataSource.S3DataSourceConfiguration InclusionPatterns.Type (__changed__) + * Old: DataSourceInclusionsExclusionsStrings + * New: List +* AWS::Kendra::DataSource.S3DataSourceConfiguration InclusionPrefixes.PrimitiveItemType (__added__) +* AWS::Kendra::DataSource.S3DataSourceConfiguration InclusionPrefixes.Type (__changed__) + * Old: DataSourceInclusionsExclusionsStrings + * New: List +* AWS::Kendra::DataSource.SalesforceChatterFeedConfiguration FieldMappings.ItemType (__added__) +* AWS::Kendra::DataSource.SalesforceChatterFeedConfiguration FieldMappings.Type (__changed__) + * Old: DataSourceToIndexFieldMappingList + * New: List +* AWS::Kendra::DataSource.SalesforceChatterFeedConfiguration IncludeFilterTypes.PrimitiveItemType (__added__) +* AWS::Kendra::DataSource.SalesforceChatterFeedConfiguration IncludeFilterTypes.Type (__changed__) + * Old: SalesforceChatterFeedIncludeFilterTypes + * New: List +* AWS::Kendra::DataSource.SalesforceConfiguration ExcludeAttachmentFilePatterns.PrimitiveItemType (__added__) +* AWS::Kendra::DataSource.SalesforceConfiguration ExcludeAttachmentFilePatterns.Type (__changed__) + * Old: DataSourceInclusionsExclusionsStrings + * New: List +* AWS::Kendra::DataSource.SalesforceConfiguration IncludeAttachmentFilePatterns.PrimitiveItemType (__added__) +* AWS::Kendra::DataSource.SalesforceConfiguration IncludeAttachmentFilePatterns.Type (__changed__) + * Old: DataSourceInclusionsExclusionsStrings + * New: List +* AWS::Kendra::DataSource.SalesforceConfiguration StandardObjectConfigurations.ItemType (__added__) +* AWS::Kendra::DataSource.SalesforceConfiguration StandardObjectConfigurations.Type (__changed__) + * Old: SalesforceStandardObjectConfigurationList + * New: List +* AWS::Kendra::DataSource.SalesforceCustomKnowledgeArticleTypeConfiguration FieldMappings.ItemType (__added__) +* AWS::Kendra::DataSource.SalesforceCustomKnowledgeArticleTypeConfiguration FieldMappings.Type (__changed__) + * Old: DataSourceToIndexFieldMappingList + * New: List +* AWS::Kendra::DataSource.SalesforceKnowledgeArticleConfiguration CustomKnowledgeArticleTypeConfigurations.ItemType (__added__) +* AWS::Kendra::DataSource.SalesforceKnowledgeArticleConfiguration CustomKnowledgeArticleTypeConfigurations.Type (__changed__) + * Old: SalesforceCustomKnowledgeArticleTypeConfigurationList + * New: List +* AWS::Kendra::DataSource.SalesforceKnowledgeArticleConfiguration IncludedStates.PrimitiveItemType (__added__) +* AWS::Kendra::DataSource.SalesforceKnowledgeArticleConfiguration IncludedStates.Type (__changed__) + * Old: SalesforceKnowledgeArticleStateList + * New: List +* AWS::Kendra::DataSource.SalesforceStandardKnowledgeArticleTypeConfiguration FieldMappings.ItemType (__added__) +* AWS::Kendra::DataSource.SalesforceStandardKnowledgeArticleTypeConfiguration FieldMappings.Type (__changed__) + * Old: DataSourceToIndexFieldMappingList + * New: List +* AWS::Kendra::DataSource.SalesforceStandardObjectAttachmentConfiguration FieldMappings.ItemType (__added__) +* AWS::Kendra::DataSource.SalesforceStandardObjectAttachmentConfiguration FieldMappings.Type (__changed__) + * Old: DataSourceToIndexFieldMappingList + * New: List +* AWS::Kendra::DataSource.SalesforceStandardObjectConfiguration FieldMappings.ItemType (__added__) +* AWS::Kendra::DataSource.SalesforceStandardObjectConfiguration FieldMappings.Type (__changed__) + * Old: DataSourceToIndexFieldMappingList + * New: List +* AWS::Kendra::DataSource.ServiceNowKnowledgeArticleConfiguration ExcludeAttachmentFilePatterns.PrimitiveItemType (__added__) +* AWS::Kendra::DataSource.ServiceNowKnowledgeArticleConfiguration ExcludeAttachmentFilePatterns.Type (__changed__) + * Old: DataSourceInclusionsExclusionsStrings + * New: List +* AWS::Kendra::DataSource.ServiceNowKnowledgeArticleConfiguration FieldMappings.ItemType (__added__) +* AWS::Kendra::DataSource.ServiceNowKnowledgeArticleConfiguration FieldMappings.Type (__changed__) + * Old: DataSourceToIndexFieldMappingList + * New: List +* AWS::Kendra::DataSource.ServiceNowKnowledgeArticleConfiguration IncludeAttachmentFilePatterns.PrimitiveItemType (__added__) +* AWS::Kendra::DataSource.ServiceNowKnowledgeArticleConfiguration IncludeAttachmentFilePatterns.Type (__changed__) + * Old: DataSourceInclusionsExclusionsStrings + * New: List +* AWS::Kendra::DataSource.ServiceNowServiceCatalogConfiguration ExcludeAttachmentFilePatterns.PrimitiveItemType (__added__) +* AWS::Kendra::DataSource.ServiceNowServiceCatalogConfiguration ExcludeAttachmentFilePatterns.Type (__changed__) + * Old: DataSourceInclusionsExclusionsStrings + * New: List +* AWS::Kendra::DataSource.ServiceNowServiceCatalogConfiguration FieldMappings.ItemType (__added__) +* AWS::Kendra::DataSource.ServiceNowServiceCatalogConfiguration FieldMappings.Type (__changed__) + * Old: DataSourceToIndexFieldMappingList + * New: List +* AWS::Kendra::DataSource.ServiceNowServiceCatalogConfiguration IncludeAttachmentFilePatterns.PrimitiveItemType (__added__) +* AWS::Kendra::DataSource.ServiceNowServiceCatalogConfiguration IncludeAttachmentFilePatterns.Type (__changed__) + * Old: DataSourceInclusionsExclusionsStrings + * New: List +* AWS::Kendra::DataSource.SharePointConfiguration ExclusionPatterns.PrimitiveItemType (__added__) +* AWS::Kendra::DataSource.SharePointConfiguration ExclusionPatterns.Type (__changed__) + * Old: DataSourceInclusionsExclusionsStrings + * New: List +* AWS::Kendra::DataSource.SharePointConfiguration FieldMappings.ItemType (__added__) +* AWS::Kendra::DataSource.SharePointConfiguration FieldMappings.Type (__changed__) + * Old: DataSourceToIndexFieldMappingList + * New: List +* AWS::Kendra::DataSource.SharePointConfiguration InclusionPatterns.PrimitiveItemType (__added__) +* AWS::Kendra::DataSource.SharePointConfiguration InclusionPatterns.Type (__changed__) + * Old: DataSourceInclusionsExclusionsStrings + * New: List +* AWS::Kendra::Index.Relevance ValueImportanceItems.ItemType (__added__) +* AWS::Kendra::Index.Relevance ValueImportanceItems.Type (__changed__) + * Old: ValueImportanceItems + * New: List +* AWS::MediaLive::Channel.ArchiveGroupSettings ArchiveCdnSettings (__added__) +* AWS::MediaLive::Channel.EbuTtDDestinationSettings CopyrightHolder (__added__) +* AWS::MediaLive::Channel.EncoderSettings MotionGraphicsConfiguration (__added__) +* AWS::MediaLive::Channel.FrameCaptureGroupSettings FrameCaptureCdnSettings (__added__) +* AWS::MediaLive::Channel.HlsCdnSettings HlsS3Settings (__added__) +* AWS::MediaLive::Channel.HlsSettings FrameCaptureHlsSettings (__added__) +* AWS::MediaLive::Channel.TeletextSourceSettings OutputRectangle (__added__) +* AWS::MediaLive::Channel.VideoSelector ColorSpaceSettings (__added__) +* AWS::SSO::InstanceAccessControlAttributeConfiguration.AccessControlAttributeValue Source.PrimitiveItemType (__added__) +* AWS::SSO::InstanceAccessControlAttributeConfiguration.AccessControlAttributeValue Source.Type (__changed__) + * Old: AccessControlAttributeValueSourceList + * New: List +* AWS::SageMaker::MonitoringSchedule.MonitoringJobDefinition MonitoringInputs.ItemType (__added__) +* AWS::SageMaker::MonitoringSchedule.MonitoringJobDefinition MonitoringInputs.Type (__changed__) + * Old: MonitoringInputs + * New: List +* AWS::WAFv2::RuleGroup.FieldToMatch JsonBody (__added__) +* AWS::WAFv2::RuleGroup.Rule RuleLabels (__added__) +* AWS::WAFv2::RuleGroup.Rule Statement.Type (__changed__) + * Old: StatementOne + * New: Statement +* AWS::WAFv2::WebACL.DefaultAction Allow.PrimitiveType (__deleted__) +* AWS::WAFv2::WebACL.DefaultAction Allow.Type (__added__) +* AWS::WAFv2::WebACL.DefaultAction Block.PrimitiveType (__deleted__) +* AWS::WAFv2::WebACL.DefaultAction Block.Type (__added__) +* AWS::WAFv2::WebACL.FieldToMatch JsonBody (__added__) +* AWS::WAFv2::WebACL.ManagedRuleGroupStatement ScopeDownStatement (__added__) +* AWS::WAFv2::WebACL.Rule RuleLabels (__added__) +* AWS::WAFv2::WebACL.Rule Statement.Type (__changed__) + * Old: StatementOne + * New: Statement +* AWS::WAFv2::WebACL.RuleAction Allow.PrimitiveType (__deleted__) +* AWS::WAFv2::WebACL.RuleAction Allow.Type (__added__) +* AWS::WAFv2::WebACL.RuleAction Block.PrimitiveType (__deleted__) +* AWS::WAFv2::WebACL.RuleAction Block.Type (__added__) +* AWS::WAFv2::WebACL.RuleAction Count.PrimitiveType (__deleted__) +* AWS::WAFv2::WebACL.RuleAction Count.Type (__added__) + + +# CloudFormation Resource Specification v31.1.0 + +## New Resource Types + +* AWS::FIS::ExperimentTemplate +* AWS::S3ObjectLambda::AccessPoint +* AWS::S3ObjectLambda::AccessPointPolicy + +## Attribute Changes + +* AWS::Backup::BackupSelection Id (__added__) +* AWS::RDS::DBProxy VpcId (__added__) + +## Property Changes + +* AWS::EC2::LaunchTemplate TagSpecifications.ItemType (__added__) +* AWS::EC2::LaunchTemplate TagSpecifications.Type (__changed__) + * Old: TagSpecifications + * New: List +* AWS::ServiceCatalogAppRegistry::AttributeGroup Attributes.Type (__deleted__) +* AWS::ServiceCatalogAppRegistry::AttributeGroup Attributes.PrimitiveType (__added__) +* AWS::ServiceDiscovery::Service Type (__added__) + +## Property Type Changes + +* AWS::EC2::LaunchTemplate.TagSpecifications (__removed__) +* AWS::ServiceCatalogAppRegistry::AttributeGroup.Attributes (__removed__) +* AWS::Backup::BackupSelection.BackupSelectionResourceType IamRoleArn.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::Backup::BackupSelection.BackupSelectionResourceType ListOfTags.DuplicatesAllowed (__added__) +* AWS::Backup::BackupSelection.BackupSelectionResourceType ListOfTags.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::Backup::BackupSelection.BackupSelectionResourceType Resources.DuplicatesAllowed (__added__) +* AWS::Backup::BackupSelection.BackupSelectionResourceType Resources.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::Backup::BackupSelection.BackupSelectionResourceType SelectionName.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::Backup::BackupSelection.ConditionResourceType ConditionKey.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::Backup::BackupSelection.ConditionResourceType ConditionType.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::Backup::BackupSelection.ConditionResourceType ConditionValue.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::SSM::MaintenanceWindowTarget.Targets Values.Required (__changed__) + * Old: false + * New: true +* AWS::SSM::MaintenanceWindowTask.Target Values.Required (__changed__) + * Old: false + * New: true + + # CloudFormation Resource Specification v31.0.0 ## New Resource Types diff --git a/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts b/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts index 93d20a169a12a..6689a140ec72a 100644 --- a/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts +++ b/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts @@ -176,7 +176,8 @@ async function main() { }, license: 'Apache-2.0', devDependencies: { - '@aws-cdk/assert': version, + '@types/jest': '^26.0.22', + '@aws-cdk/assert-internal': version, 'cdk-build-tools': version, 'cfn2ts': version, 'pkglint': version, @@ -259,7 +260,7 @@ async function main() { ]); await write(`test/${lowcaseModuleName}.test.ts`, [ - "import '@aws-cdk/assert/jest';", + "import '@aws-cdk/assert-internal/jest';", "import {} from '../lib';", '', "test('No tests are specified for this package', () => {", diff --git a/packages/@aws-cdk/cfnspec/cfn.version b/packages/@aws-cdk/cfnspec/cfn.version index 221a8da0b5798..4710c8eb98fcd 100644 --- a/packages/@aws-cdk/cfnspec/cfn.version +++ b/packages/@aws-cdk/cfnspec/cfn.version @@ -1 +1 @@ -31.0.0 +35.1.0 diff --git a/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json b/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json index c3d61d168d11e..43816f779cc2c 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json +++ b/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json @@ -17,18 +17,6 @@ } } }, - "AWS::ACMPCA::Certificate.CertificatePolicyList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-certificatepolicylist.html", - "Properties": { - "CertificatePolicyList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-certificatepolicylist.html#cfn-acmpca-certificate-certificatepolicylist-certificatepolicylist", - "ItemType": "PolicyInformation", - "Required": false, - "Type": "List", - "UpdateType": "Immutable" - } - } - }, "AWS::ACMPCA::Certificate.EdiPartyName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-edipartyname.html", "Properties": { @@ -63,31 +51,21 @@ } } }, - "AWS::ACMPCA::Certificate.ExtendedKeyUsageList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-extendedkeyusagelist.html", - "Properties": { - "ExtendedKeyUsageList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-extendedkeyusagelist.html#cfn-acmpca-certificate-extendedkeyusagelist-extendedkeyusagelist", - "ItemType": "ExtendedKeyUsage", - "Required": false, - "Type": "List", - "UpdateType": "Immutable" - } - } - }, "AWS::ACMPCA::Certificate.Extensions": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-extensions.html", "Properties": { "CertificatePolicies": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-extensions.html#cfn-acmpca-certificate-extensions-certificatepolicies", + "ItemType": "PolicyInformation", "Required": false, - "Type": "CertificatePolicyList", + "Type": "List", "UpdateType": "Immutable" }, "ExtendedKeyUsage": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-extensions.html#cfn-acmpca-certificate-extensions-extendedkeyusage", + "ItemType": "ExtendedKeyUsage", "Required": false, - "Type": "ExtendedKeyUsageList", + "Type": "List", "UpdateType": "Immutable" }, "KeyUsage": { @@ -98,8 +76,9 @@ }, "SubjectAlternativeNames": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-extensions.html#cfn-acmpca-certificate-extensions-subjectalternativenames", + "ItemType": "GeneralName", "Required": false, - "Type": "GeneralNameList", + "Type": "List", "UpdateType": "Immutable" } } @@ -157,18 +136,6 @@ } } }, - "AWS::ACMPCA::Certificate.GeneralNameList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-generalnamelist.html", - "Properties": { - "GeneralNameList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-generalnamelist.html#cfn-acmpca-certificate-generalnamelist-generalnamelist", - "ItemType": "GeneralName", - "Required": false, - "Type": "List", - "UpdateType": "Immutable" - } - } - }, "AWS::ACMPCA::Certificate.KeyUsage": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-keyusage.html", "Properties": { @@ -256,8 +223,9 @@ }, "PolicyQualifiers": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-policyinformation.html#cfn-acmpca-certificate-policyinformation-policyqualifiers", + "ItemType": "PolicyQualifierInfo", "Required": false, - "Type": "PolicyQualifierInfoList", + "Type": "List", "UpdateType": "Immutable" } } @@ -279,18 +247,6 @@ } } }, - "AWS::ACMPCA::Certificate.PolicyQualifierInfoList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-policyqualifierinfolist.html", - "Properties": { - "PolicyQualifierInfoList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-policyqualifierinfolist.html#cfn-acmpca-certificate-policyqualifierinfolist-policyqualifierinfolist", - "ItemType": "PolicyQualifierInfo", - "Required": false, - "Type": "List", - "UpdateType": "Immutable" - } - } - }, "AWS::ACMPCA::Certificate.Qualifier": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificate-qualifier.html", "Properties": { @@ -482,8 +438,9 @@ }, "SubjectInformationAccess": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificateauthority-csrextensions.html#cfn-acmpca-certificateauthority-csrextensions-subjectinformationaccess", + "ItemType": "AccessDescription", "Required": false, - "Type": "SubjectInformationAccess", + "Type": "List", "UpdateType": "Immutable" } } @@ -734,18 +691,6 @@ } } }, - "AWS::ACMPCA::CertificateAuthority.SubjectInformationAccess": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificateauthority-subjectinformationaccess.html", - "Properties": { - "SubjectInformationAccess": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-acmpca-certificateauthority-subjectinformationaccess.html#cfn-acmpca-certificateauthority-subjectinformationaccess-subjectinformationaccess", - "ItemType": "AccessDescription", - "Required": false, - "Type": "List", - "UpdateType": "Immutable" - } - } - }, "AWS::AccessAnalyzer::Analyzer.ArchiveRule": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-accessanalyzer-analyzer-archiverule.html", "Properties": { @@ -3307,6 +3252,12 @@ "Type": "EventBridgeDestinationProperties", "UpdateType": "Mutable" }, + "LookoutMetrics": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-destinationconnectorproperties.html#cfn-appflow-flow-destinationconnectorproperties-lookoutmetrics", + "Required": false, + "Type": "LookoutMetricsDestinationProperties", + "UpdateType": "Mutable" + }, "Redshift": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-destinationconnectorproperties.html#cfn-appflow-flow-destinationconnectorproperties-redshift", "Required": false, @@ -3424,18 +3375,6 @@ } } }, - "AWS::AppFlow::Flow.IdFieldNamesList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-idfieldnameslist.html", - "Properties": { - "IdFieldNamesList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-idfieldnameslist.html#cfn-appflow-flow-idfieldnameslist-idfieldnameslist", - "PrimitiveItemType": "String", - "Required": false, - "Type": "List", - "UpdateType": "Mutable" - } - } - }, "AWS::AppFlow::Flow.IncrementalPullConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-incrementalpullconfig.html", "Properties": { @@ -3458,6 +3397,17 @@ } } }, + "AWS::AppFlow::Flow.LookoutMetricsDestinationProperties": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-lookoutmetricsdestinationproperties.html", + "Properties": { + "Object": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-lookoutmetricsdestinationproperties.html#cfn-appflow-flow-lookoutmetricsdestinationproperties-object", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::AppFlow::Flow.MarketoSourceProperties": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-marketosourceproperties.html", "Properties": { @@ -3589,8 +3539,9 @@ }, "IdFieldNames": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-salesforcedestinationproperties.html#cfn-appflow-flow-salesforcedestinationproperties-idfieldnames", + "PrimitiveItemType": "String", "Required": false, - "Type": "IdFieldNamesList", + "Type": "List", "UpdateType": "Mutable" }, "Object": { @@ -3995,6 +3946,70 @@ } } }, + "AWS::AppIntegrations::EventIntegration.EventFilter": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appintegrations-eventintegration-eventfilter.html", + "Properties": { + "Source": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appintegrations-eventintegration-eventfilter.html#cfn-appintegrations-eventintegration-eventfilter-source", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, + "AWS::AppIntegrations::EventIntegration.EventIntegrationAssociation": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appintegrations-eventintegration-eventintegrationassociation.html", + "Properties": { + "ClientAssociationMetadata": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appintegrations-eventintegration-eventintegrationassociation.html#cfn-appintegrations-eventintegration-eventintegrationassociation-clientassociationmetadata", + "ItemType": "Metadata", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "ClientId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appintegrations-eventintegration-eventintegrationassociation.html#cfn-appintegrations-eventintegration-eventintegrationassociation-clientid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "EventBridgeRuleName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appintegrations-eventintegration-eventintegrationassociation.html#cfn-appintegrations-eventintegration-eventintegrationassociation-eventbridgerulename", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "EventIntegrationAssociationArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appintegrations-eventintegration-eventintegrationassociation.html#cfn-appintegrations-eventintegration-eventintegrationassociation-eventintegrationassociationarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "EventIntegrationAssociationId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appintegrations-eventintegration-eventintegrationassociation.html#cfn-appintegrations-eventintegration-eventintegrationassociation-eventintegrationassociationid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::AppIntegrations::EventIntegration.Metadata": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appintegrations-eventintegration-metadata.html", + "Properties": { + "Key": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appintegrations-eventintegration-metadata.html#cfn-appintegrations-eventintegration-metadata-key", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appintegrations-eventintegration-metadata.html#cfn-appintegrations-eventintegration-metadata-value", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::AppMesh::GatewayRoute.GatewayRouteSpec": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-gatewayroute-gatewayroutespec.html", "Properties": { @@ -6388,12 +6403,6 @@ "Required": true, "UpdateType": "Mutable" }, - "LambdaAuthorizerConfig": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appsync-graphqlapi-additionalauthenticationprovider.html#cfn-appsync-graphqlapi-additionalauthenticationprovider-lambdaauthorizerconfig", - "Required": false, - "Type": "LambdaAuthorizerConfig", - "UpdateType": "Mutable" - }, "OpenIDConnectConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appsync-graphqlapi-additionalauthenticationprovider.html#cfn-appsync-graphqlapi-additionalauthenticationprovider-openidconnectconfig", "Required": false, @@ -6438,29 +6447,6 @@ } } }, - "AWS::AppSync::GraphQLApi.LambdaAuthorizerConfig": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appsync-graphqlapi-lambdaauthorizerconfig.html", - "Properties": { - "AuthorizerResultTtlInSeconds": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appsync-graphqlapi-lambdaauthorizerconfig.html#cfn-appsync-graphqlapi-lambdaauthorizerconfig-authorizerresultttlinseconds", - "PrimitiveType": "Double", - "Required": false, - "UpdateType": "Mutable" - }, - "AuthorizerUri": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appsync-graphqlapi-lambdaauthorizerconfig.html#cfn-appsync-graphqlapi-lambdaauthorizerconfig-authorizeruri", - "PrimitiveType": "String", - "Required": false, - "UpdateType": "Mutable" - }, - "IdentityValidationExpression": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appsync-graphqlapi-lambdaauthorizerconfig.html#cfn-appsync-graphqlapi-lambdaauthorizerconfig-identityvalidationexpression", - "PrimitiveType": "String", - "Required": false, - "UpdateType": "Mutable" - } - } - }, "AWS::AppSync::GraphQLApi.LogConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appsync-graphqlapi-logconfig.html", "Properties": { @@ -8306,6 +8292,12 @@ "Type": "List", "UpdateType": "Mutable" }, + "EnableContinuousBackup": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-backupplan-backupruleresourcetype.html#cfn-backup-backupplan-backupruleresourcetype-enablecontinuousbackup", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, "Lifecycle": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-backupplan-backupruleresourcetype.html#cfn-backup-backupplan-backupruleresourcetype-lifecycle", "Required": false, @@ -8386,27 +8378,29 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-backupselection-backupselectionresourcetype.html#cfn-backup-backupselection-backupselectionresourcetype-iamrolearn", "PrimitiveType": "String", "Required": true, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "ListOfTags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-backupselection-backupselectionresourcetype.html#cfn-backup-backupselection-backupselectionresourcetype-listoftags", + "DuplicatesAllowed": true, "ItemType": "ConditionResourceType", "Required": false, "Type": "List", - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "Resources": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-backupselection-backupselectionresourcetype.html#cfn-backup-backupselection-backupselectionresourcetype-resources", + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": false, "Type": "List", - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "SelectionName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-backupselection-backupselectionresourcetype.html#cfn-backup-backupselection-backupselectionresourcetype-selectionname", "PrimitiveType": "String", "Required": true, - "UpdateType": "Mutable" + "UpdateType": "Immutable" } } }, @@ -8417,19 +8411,19 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-backupselection-conditionresourcetype.html#cfn-backup-backupselection-conditionresourcetype-conditionkey", "PrimitiveType": "String", "Required": true, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "ConditionType": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-backupselection-conditionresourcetype.html#cfn-backup-backupselection-conditionresourcetype-conditiontype", "PrimitiveType": "String", "Required": true, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "ConditionValue": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-backupselection-conditionresourcetype.html#cfn-backup-backupselection-conditionresourcetype-conditionvalue", "PrimitiveType": "String", "Required": true, - "UpdateType": "Mutable" + "UpdateType": "Immutable" } } }, @@ -8603,6 +8597,23 @@ } } }, + "AWS::Batch::JobDefinition.AuthorizationConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-batch-jobdefinition-authorizationconfig.html", + "Properties": { + "AccessPointId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-batch-jobdefinition-authorizationconfig.html#cfn-batch-jobdefinition-authorizationconfig-accesspointid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Iam": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-batch-jobdefinition-authorizationconfig.html#cfn-batch-jobdefinition-authorizationconfig-iam", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::Batch::JobDefinition.ContainerProperties": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-batch-jobdefinition-containerproperties.html", "Properties": { @@ -8759,6 +8770,41 @@ } } }, + "AWS::Batch::JobDefinition.EfsVolumeConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-batch-jobdefinition-efsvolumeconfiguration.html", + "Properties": { + "AuthorizationConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-batch-jobdefinition-efsvolumeconfiguration.html#cfn-batch-jobdefinition-efsvolumeconfiguration-authorizationconfig", + "Required": false, + "Type": "AuthorizationConfig", + "UpdateType": "Mutable" + }, + "FileSystemId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-batch-jobdefinition-efsvolumeconfiguration.html#cfn-batch-jobdefinition-efsvolumeconfiguration-filesystemid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "RootDirectory": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-batch-jobdefinition-efsvolumeconfiguration.html#cfn-batch-jobdefinition-efsvolumeconfiguration-rootdirectory", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "TransitEncryption": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-batch-jobdefinition-efsvolumeconfiguration.html#cfn-batch-jobdefinition-efsvolumeconfiguration-transitencryption", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "TransitEncryptionPort": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-batch-jobdefinition-efsvolumeconfiguration.html#cfn-batch-jobdefinition-efsvolumeconfiguration-transitencryptionport", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::Batch::JobDefinition.Environment": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-batch-jobdefinition-environment.html", "Properties": { @@ -9071,6 +9117,12 @@ "AWS::Batch::JobDefinition.Volumes": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-batch-jobdefinition-volumes.html", "Properties": { + "EfsVolumeConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-batch-jobdefinition-volumes.html#cfn-batch-jobdefinition-volumes-efsvolumeconfiguration", + "Required": false, + "Type": "EfsVolumeConfiguration", + "UpdateType": "Mutable" + }, "Host": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-batch-jobdefinition-volumes.html#cfn-batch-jobdefinition-volumes-host", "Required": false, @@ -9335,6 +9387,137 @@ } } }, + "AWS::Budgets::BudgetsAction.ActionThreshold": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-budgets-budgetsaction-actionthreshold.html", + "Properties": { + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-budgets-budgetsaction-actionthreshold.html#cfn-budgets-budgetsaction-actionthreshold-type", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-budgets-budgetsaction-actionthreshold.html#cfn-budgets-budgetsaction-actionthreshold-value", + "PrimitiveType": "Double", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::Budgets::BudgetsAction.Definition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-budgets-budgetsaction-definition.html", + "Properties": { + "IamActionDefinition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-budgets-budgetsaction-definition.html#cfn-budgets-budgetsaction-definition-iamactiondefinition", + "Required": false, + "Type": "IamActionDefinition", + "UpdateType": "Mutable" + }, + "ScpActionDefinition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-budgets-budgetsaction-definition.html#cfn-budgets-budgetsaction-definition-scpactiondefinition", + "Required": false, + "Type": "ScpActionDefinition", + "UpdateType": "Mutable" + }, + "SsmActionDefinition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-budgets-budgetsaction-definition.html#cfn-budgets-budgetsaction-definition-ssmactiondefinition", + "Required": false, + "Type": "SsmActionDefinition", + "UpdateType": "Mutable" + } + } + }, + "AWS::Budgets::BudgetsAction.IamActionDefinition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-budgets-budgetsaction-iamactiondefinition.html", + "Properties": { + "Groups": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-budgets-budgetsaction-iamactiondefinition.html#cfn-budgets-budgetsaction-iamactiondefinition-groups", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "PolicyArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-budgets-budgetsaction-iamactiondefinition.html#cfn-budgets-budgetsaction-iamactiondefinition-policyarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Roles": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-budgets-budgetsaction-iamactiondefinition.html#cfn-budgets-budgetsaction-iamactiondefinition-roles", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Users": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-budgets-budgetsaction-iamactiondefinition.html#cfn-budgets-budgetsaction-iamactiondefinition-users", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Budgets::BudgetsAction.ScpActionDefinition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-budgets-budgetsaction-scpactiondefinition.html", + "Properties": { + "PolicyId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-budgets-budgetsaction-scpactiondefinition.html#cfn-budgets-budgetsaction-scpactiondefinition-policyid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "TargetIds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-budgets-budgetsaction-scpactiondefinition.html#cfn-budgets-budgetsaction-scpactiondefinition-targetids", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Budgets::BudgetsAction.SsmActionDefinition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-budgets-budgetsaction-ssmactiondefinition.html", + "Properties": { + "InstanceIds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-budgets-budgetsaction-ssmactiondefinition.html#cfn-budgets-budgetsaction-ssmactiondefinition-instanceids", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "Region": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-budgets-budgetsaction-ssmactiondefinition.html#cfn-budgets-budgetsaction-ssmactiondefinition-region", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Subtype": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-budgets-budgetsaction-ssmactiondefinition.html#cfn-budgets-budgetsaction-ssmactiondefinition-subtype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::Budgets::BudgetsAction.Subscriber": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-budgets-budgetsaction-subscriber.html", + "Properties": { + "Address": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-budgets-budgetsaction-subscriber.html#cfn-budgets-budgetsaction-subscriber-address", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-budgets-budgetsaction-subscriber.html#cfn-budgets-budgetsaction-subscriber-type", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::CE::AnomalySubscription.Subscriber": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ce-anomalysubscription-subscriber.html", "Properties": { @@ -9484,13 +9667,13 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudformation-resourceversion-loggingconfig.html#cfn-cloudformation-resourceversion-loggingconfig-loggroupname", "PrimitiveType": "String", "Required": false, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "LogRoleArn": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudformation-resourceversion-loggingconfig.html#cfn-cloudformation-resourceversion-loggingconfig-logrolearn", "PrimitiveType": "String", "Required": false, - "UpdateType": "Mutable" + "UpdateType": "Immutable" } } }, @@ -9559,6 +9742,12 @@ "Required": false, "UpdateType": "Mutable" }, + "RegionConcurrencyType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudformation-stackset-operationpreferences.html#cfn-cloudformation-stackset-operationpreferences-regionconcurrencytype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "RegionOrder": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudformation-stackset-operationpreferences.html#cfn-cloudformation-stackset-operationpreferences-regionorder", "PrimitiveItemType": "String", @@ -13724,6 +13913,83 @@ } } }, + "AWS::CustomerProfiles::ObjectType.FieldMap": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-customerprofiles-objecttype-fieldmap.html", + "Properties": { + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-customerprofiles-objecttype-fieldmap.html#cfn-customerprofiles-objecttype-fieldmap-name", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ObjectTypeField": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-customerprofiles-objecttype-fieldmap.html#cfn-customerprofiles-objecttype-fieldmap-objecttypefield", + "Required": false, + "Type": "ObjectTypeField", + "UpdateType": "Mutable" + } + } + }, + "AWS::CustomerProfiles::ObjectType.KeyMap": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-customerprofiles-objecttype-keymap.html", + "Properties": { + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-customerprofiles-objecttype-keymap.html#cfn-customerprofiles-objecttype-keymap-name", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ObjectTypeKeyList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-customerprofiles-objecttype-keymap.html#cfn-customerprofiles-objecttype-keymap-objecttypekeylist", + "ItemType": "ObjectTypeKey", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::CustomerProfiles::ObjectType.ObjectTypeField": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-customerprofiles-objecttype-objecttypefield.html", + "Properties": { + "ContentType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-customerprofiles-objecttype-objecttypefield.html#cfn-customerprofiles-objecttype-objecttypefield-contenttype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Source": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-customerprofiles-objecttype-objecttypefield.html#cfn-customerprofiles-objecttype-objecttypefield-source", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Target": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-customerprofiles-objecttype-objecttypefield.html#cfn-customerprofiles-objecttype-objecttypefield-target", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::CustomerProfiles::ObjectType.ObjectTypeKey": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-customerprofiles-objecttype-objecttypekey.html", + "Properties": { + "FieldNames": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-customerprofiles-objecttype-objecttypekey.html#cfn-customerprofiles-objecttype-objecttypekey-fieldnames", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "StandardIdentifiers": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-customerprofiles-objecttype-objecttypekey.html#cfn-customerprofiles-objecttype-objecttypekey-standardidentifiers", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::DAX::Cluster.SSESpecification": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dax-cluster-ssespecification.html", "Properties": { @@ -14548,6 +14814,331 @@ } } }, + "AWS::DataBrew::Dataset.CsvOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-csvoptions.html", + "Properties": { + "Delimiter": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-csvoptions.html#cfn-databrew-dataset-csvoptions-delimiter", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "HeaderRow": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-csvoptions.html#cfn-databrew-dataset-csvoptions-headerrow", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::DataBrew::Dataset.DataCatalogInputDefinition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-datacataloginputdefinition.html", + "Properties": { + "CatalogId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-datacataloginputdefinition.html#cfn-databrew-dataset-datacataloginputdefinition-catalogid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "DatabaseName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-datacataloginputdefinition.html#cfn-databrew-dataset-datacataloginputdefinition-databasename", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "TableName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-datacataloginputdefinition.html#cfn-databrew-dataset-datacataloginputdefinition-tablename", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "TempDirectory": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-datacataloginputdefinition.html#cfn-databrew-dataset-datacataloginputdefinition-tempdirectory", + "Required": false, + "Type": "S3Location", + "UpdateType": "Mutable" + } + } + }, + "AWS::DataBrew::Dataset.DatabaseInputDefinition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-databaseinputdefinition.html", + "Properties": { + "DatabaseTableName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-databaseinputdefinition.html#cfn-databrew-dataset-databaseinputdefinition-databasetablename", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "GlueConnectionName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-databaseinputdefinition.html#cfn-databrew-dataset-databaseinputdefinition-glueconnectionname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "TempDirectory": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-databaseinputdefinition.html#cfn-databrew-dataset-databaseinputdefinition-tempdirectory", + "Required": false, + "Type": "S3Location", + "UpdateType": "Mutable" + } + } + }, + "AWS::DataBrew::Dataset.DatasetParameter": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-datasetparameter.html", + "Properties": { + "CreateColumn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-datasetparameter.html#cfn-databrew-dataset-datasetparameter-createcolumn", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "DatetimeOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-datasetparameter.html#cfn-databrew-dataset-datasetparameter-datetimeoptions", + "Required": false, + "Type": "DatetimeOptions", + "UpdateType": "Mutable" + }, + "Filter": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-datasetparameter.html#cfn-databrew-dataset-datasetparameter-filter", + "Required": false, + "Type": "FilterExpression", + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-datasetparameter.html#cfn-databrew-dataset-datasetparameter-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-datasetparameter.html#cfn-databrew-dataset-datasetparameter-type", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::DataBrew::Dataset.DatetimeOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-datetimeoptions.html", + "Properties": { + "Format": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-datetimeoptions.html#cfn-databrew-dataset-datetimeoptions-format", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "LocaleCode": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-datetimeoptions.html#cfn-databrew-dataset-datetimeoptions-localecode", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "TimezoneOffset": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-datetimeoptions.html#cfn-databrew-dataset-datetimeoptions-timezoneoffset", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::DataBrew::Dataset.ExcelOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-exceloptions.html", + "Properties": { + "HeaderRow": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-exceloptions.html#cfn-databrew-dataset-exceloptions-headerrow", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "SheetIndexes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-exceloptions.html#cfn-databrew-dataset-exceloptions-sheetindexes", + "PrimitiveItemType": "Integer", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "SheetNames": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-exceloptions.html#cfn-databrew-dataset-exceloptions-sheetnames", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::DataBrew::Dataset.FilesLimit": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-fileslimit.html", + "Properties": { + "MaxFiles": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-fileslimit.html#cfn-databrew-dataset-fileslimit-maxfiles", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + }, + "Order": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-fileslimit.html#cfn-databrew-dataset-fileslimit-order", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "OrderedBy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-fileslimit.html#cfn-databrew-dataset-fileslimit-orderedby", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::DataBrew::Dataset.FilterExpression": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-filterexpression.html", + "Properties": { + "Expression": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-filterexpression.html#cfn-databrew-dataset-filterexpression-expression", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ValuesMap": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-filterexpression.html#cfn-databrew-dataset-filterexpression-valuesmap", + "ItemType": "FilterValue", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::DataBrew::Dataset.FilterValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-filtervalue.html", + "Properties": { + "Value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-filtervalue.html#cfn-databrew-dataset-filtervalue-value", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ValueReference": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-filtervalue.html#cfn-databrew-dataset-filtervalue-valuereference", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::DataBrew::Dataset.FormatOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-formatoptions.html", + "Properties": { + "Csv": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-formatoptions.html#cfn-databrew-dataset-formatoptions-csv", + "Required": false, + "Type": "CsvOptions", + "UpdateType": "Mutable" + }, + "Excel": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-formatoptions.html#cfn-databrew-dataset-formatoptions-excel", + "Required": false, + "Type": "ExcelOptions", + "UpdateType": "Mutable" + }, + "Json": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-formatoptions.html#cfn-databrew-dataset-formatoptions-json", + "Required": false, + "Type": "JsonOptions", + "UpdateType": "Mutable" + } + } + }, + "AWS::DataBrew::Dataset.Input": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-input.html", + "Properties": { + "DataCatalogInputDefinition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-input.html#cfn-databrew-dataset-input-datacataloginputdefinition", + "Required": false, + "Type": "DataCatalogInputDefinition", + "UpdateType": "Mutable" + }, + "DatabaseInputDefinition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-input.html#cfn-databrew-dataset-input-databaseinputdefinition", + "Required": false, + "Type": "DatabaseInputDefinition", + "UpdateType": "Mutable" + }, + "S3InputDefinition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-input.html#cfn-databrew-dataset-input-s3inputdefinition", + "Required": false, + "Type": "S3Location", + "UpdateType": "Mutable" + } + } + }, + "AWS::DataBrew::Dataset.JsonOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-jsonoptions.html", + "Properties": { + "MultiLine": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-jsonoptions.html#cfn-databrew-dataset-jsonoptions-multiline", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::DataBrew::Dataset.PathOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-pathoptions.html", + "Properties": { + "FilesLimit": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-pathoptions.html#cfn-databrew-dataset-pathoptions-fileslimit", + "Required": false, + "Type": "FilesLimit", + "UpdateType": "Mutable" + }, + "LastModifiedDateCondition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-pathoptions.html#cfn-databrew-dataset-pathoptions-lastmodifieddatecondition", + "Required": false, + "Type": "FilterExpression", + "UpdateType": "Mutable" + }, + "Parameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-pathoptions.html#cfn-databrew-dataset-pathoptions-parameters", + "ItemType": "PathParameter", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::DataBrew::Dataset.PathParameter": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-pathparameter.html", + "Properties": { + "DatasetParameter": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-pathparameter.html#cfn-databrew-dataset-pathparameter-datasetparameter", + "Required": true, + "Type": "DatasetParameter", + "UpdateType": "Mutable" + }, + "PathParameterName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-pathparameter.html#cfn-databrew-dataset-pathparameter-pathparametername", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::DataBrew::Dataset.S3Location": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-s3location.html", + "Properties": { + "Bucket": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-s3location.html#cfn-databrew-dataset-s3location-bucket", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Key": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-dataset-s3location.html#cfn-databrew-dataset-s3location-key", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::DataBrew::Job.CsvOutputOptions": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-databrew-job-csvoutputoptions.html", "Properties": { @@ -15822,6 +16413,17 @@ } } }, + "AWS::DynamoDB::Table.KinesisStreamSpecification": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dynamodb-kinesisstreamspecification.html", + "Properties": { + "StreamArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dynamodb-kinesisstreamspecification.html#cfn-dynamodb-kinesisstreamspecification-streamarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::DynamoDB::Table.LocalSecondaryIndex": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dynamodb-lsi.html", "Properties": { @@ -17148,6 +17750,24 @@ } } }, + "AWS::EC2::LaunchTemplate.LaunchTemplateTagSpecification": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-launchtemplatetagspecification.html", + "Properties": { + "ResourceType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-launchtemplatetagspecification.html#cfn-ec2-launchtemplate-launchtemplatetagspecification-resourcetype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-launchtemplatetagspecification.html#cfn-ec2-launchtemplate-launchtemplatetagspecification-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::EC2::LaunchTemplate.LicenseSpecification": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-licensespecification.html", "Properties": { @@ -17414,13 +18034,6 @@ } } }, - "AWS::EC2::LaunchTemplate.TagSpecifications": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-tagspecifications.html", - "ItemType": "TagSpecification", - "Required": false, - "Type": "List", - "UpdateType": "Mutable" - }, "AWS::EC2::NetworkAclEntry.Icmp": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-networkaclentry-icmp.html", "Properties": { @@ -22033,6 +22646,74 @@ } } }, + "AWS::ElastiCache::CacheCluster.CloudWatchLogsDestinationDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-cachecluster-cloudwatchlogsdestinationdetails.html", + "Properties": { + "LogGroup": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-cachecluster-cloudwatchlogsdestinationdetails.html#cfn-elasticache-cachecluster-cloudwatchlogsdestinationdetails-loggroup", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::ElastiCache::CacheCluster.DestinationDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-cachecluster-destinationdetails.html", + "Properties": { + "CloudWatchLogsDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-cachecluster-destinationdetails.html#cfn-elasticache-cachecluster-destinationdetails-cloudwatchlogsdetails", + "Required": false, + "Type": "CloudWatchLogsDestinationDetails", + "UpdateType": "Mutable" + }, + "KinesisFirehoseDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-cachecluster-destinationdetails.html#cfn-elasticache-cachecluster-destinationdetails-kinesisfirehosedetails", + "Required": false, + "Type": "KinesisFirehoseDestinationDetails", + "UpdateType": "Mutable" + } + } + }, + "AWS::ElastiCache::CacheCluster.KinesisFirehoseDestinationDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-cachecluster-kinesisfirehosedestinationdetails.html", + "Properties": { + "DeliveryStream": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-cachecluster-kinesisfirehosedestinationdetails.html#cfn-elasticache-cachecluster-kinesisfirehosedestinationdetails-deliverystream", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::ElastiCache::CacheCluster.LogDeliveryConfigurationRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-cachecluster-logdeliveryconfigurationrequest.html", + "Properties": { + "DestinationDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-cachecluster-logdeliveryconfigurationrequest.html#cfn-elasticache-cachecluster-logdeliveryconfigurationrequest-destinationdetails", + "Required": false, + "Type": "DestinationDetails", + "UpdateType": "Mutable" + }, + "DestinationType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-cachecluster-logdeliveryconfigurationrequest.html#cfn-elasticache-cachecluster-logdeliveryconfigurationrequest-destinationtype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "LogFormat": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-cachecluster-logdeliveryconfigurationrequest.html#cfn-elasticache-cachecluster-logdeliveryconfigurationrequest-logformat", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "LogType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-cachecluster-logdeliveryconfigurationrequest.html#cfn-elasticache-cachecluster-logdeliveryconfigurationrequest-logtype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::ElastiCache::GlobalReplicationGroup.GlobalReplicationGroupMember": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-globalreplicationgroup-globalreplicationgroupmember.html", "Properties": { @@ -22100,6 +22781,74 @@ } } }, + "AWS::ElastiCache::ReplicationGroup.CloudWatchLogsDestinationDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-replicationgroup-cloudwatchlogsdestinationdetails.html", + "Properties": { + "LogGroup": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-replicationgroup-cloudwatchlogsdestinationdetails.html#cfn-elasticache-replicationgroup-cloudwatchlogsdestinationdetails-loggroup", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::ElastiCache::ReplicationGroup.DestinationDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-replicationgroup-destinationdetails.html", + "Properties": { + "CloudWatchLogsDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-replicationgroup-destinationdetails.html#cfn-elasticache-replicationgroup-destinationdetails-cloudwatchlogsdetails", + "Required": false, + "Type": "CloudWatchLogsDestinationDetails", + "UpdateType": "Mutable" + }, + "KinesisFirehoseDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-replicationgroup-destinationdetails.html#cfn-elasticache-replicationgroup-destinationdetails-kinesisfirehosedetails", + "Required": false, + "Type": "KinesisFirehoseDestinationDetails", + "UpdateType": "Mutable" + } + } + }, + "AWS::ElastiCache::ReplicationGroup.KinesisFirehoseDestinationDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-replicationgroup-kinesisfirehosedestinationdetails.html", + "Properties": { + "DeliveryStream": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-replicationgroup-kinesisfirehosedestinationdetails.html#cfn-elasticache-replicationgroup-kinesisfirehosedestinationdetails-deliverystream", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::ElastiCache::ReplicationGroup.LogDeliveryConfigurationRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-replicationgroup-logdeliveryconfigurationrequest.html", + "Properties": { + "DestinationDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-replicationgroup-logdeliveryconfigurationrequest.html#cfn-elasticache-replicationgroup-logdeliveryconfigurationrequest-destinationdetails", + "Required": false, + "Type": "DestinationDetails", + "UpdateType": "Mutable" + }, + "DestinationType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-replicationgroup-logdeliveryconfigurationrequest.html#cfn-elasticache-replicationgroup-logdeliveryconfigurationrequest-destinationtype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "LogFormat": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-replicationgroup-logdeliveryconfigurationrequest.html#cfn-elasticache-replicationgroup-logdeliveryconfigurationrequest-logformat", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "LogType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-replicationgroup-logdeliveryconfigurationrequest.html#cfn-elasticache-replicationgroup-logdeliveryconfigurationrequest-logtype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::ElastiCache::ReplicationGroup.NodeGroupConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-replicationgroup-nodegroupconfiguration.html", "Properties": { @@ -24183,6 +24932,123 @@ } } }, + "AWS::FIS::ExperimentTemplate.ExperimentTemplateAction": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplateaction.html", + "Properties": { + "ActionId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplateaction.html#cfn-fis-experimenttemplate-experimenttemplateaction-actionid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplateaction.html#cfn-fis-experimenttemplate-experimenttemplateaction-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Parameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplateaction.html#cfn-fis-experimenttemplate-experimenttemplateaction-parameters", + "Required": false, + "Type": "ExperimentTemplateActionItemParameterMap", + "UpdateType": "Mutable" + }, + "StartAfter": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplateaction.html#cfn-fis-experimenttemplate-experimenttemplateaction-startafter", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Targets": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplateaction.html#cfn-fis-experimenttemplate-experimenttemplateaction-targets", + "Required": false, + "Type": "ExperimentTemplateActionItemTargetMap", + "UpdateType": "Mutable" + } + } + }, + "AWS::FIS::ExperimentTemplate.ExperimentTemplateActionItemParameterMap": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplateactionitemparametermap.html" + }, + "AWS::FIS::ExperimentTemplate.ExperimentTemplateActionItemTargetMap": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplateactionitemtargetmap.html" + }, + "AWS::FIS::ExperimentTemplate.ExperimentTemplateStopCondition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplatestopcondition.html", + "Properties": { + "Source": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplatestopcondition.html#cfn-fis-experimenttemplate-experimenttemplatestopcondition-source", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplatestopcondition.html#cfn-fis-experimenttemplate-experimenttemplatestopcondition-value", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::FIS::ExperimentTemplate.ExperimentTemplateTarget": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplatetarget.html", + "Properties": { + "Filters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplatetarget.html#cfn-fis-experimenttemplate-experimenttemplatetarget-filters", + "ItemType": "ExperimentTemplateTargetFilter", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "ResourceArns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplatetarget.html#cfn-fis-experimenttemplate-experimenttemplatetarget-resourcearns", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "ResourceTags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplatetarget.html#cfn-fis-experimenttemplate-experimenttemplatetarget-resourcetags", + "Required": false, + "Type": "TagMap", + "UpdateType": "Mutable" + }, + "ResourceType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplatetarget.html#cfn-fis-experimenttemplate-experimenttemplatetarget-resourcetype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "SelectionMode": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplatetarget.html#cfn-fis-experimenttemplate-experimenttemplatetarget-selectionmode", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::FIS::ExperimentTemplate.ExperimentTemplateTargetFilter": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplatetargetfilter.html", + "Properties": { + "Path": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplatetargetfilter.html#cfn-fis-experimenttemplate-experimenttemplatetargetfilter-path", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Values": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplatetargetfilter.html#cfn-fis-experimenttemplate-experimenttemplatetargetfilter-values", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::FIS::ExperimentTemplate.TagMap": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-tagmap.html" + }, "AWS::FMS::Policy.IEMap": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fms-policy-iemap.html", "Properties": { @@ -24479,28 +25345,28 @@ } }, "AWS::GameLift::Fleet.IpPermission": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-fleet-ec2inboundpermission.html", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-fleet-ippermission.html", "Properties": { "FromPort": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-fleet-ec2inboundpermission.html#cfn-gamelift-fleet-ec2inboundpermissions-fromport", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-fleet-ippermission.html#cfn-gamelift-fleet-ippermission-fromport", "PrimitiveType": "Integer", "Required": true, "UpdateType": "Mutable" }, "IpRange": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-fleet-ec2inboundpermission.html#cfn-gamelift-fleet-ec2inboundpermissions-iprange", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-fleet-ippermission.html#cfn-gamelift-fleet-ippermission-iprange", "PrimitiveType": "String", "Required": true, "UpdateType": "Mutable" }, "Protocol": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-fleet-ec2inboundpermission.html#cfn-gamelift-fleet-ec2inboundpermissions-protocol", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-fleet-ippermission.html#cfn-gamelift-fleet-ippermission-protocol", "PrimitiveType": "String", "Required": true, "UpdateType": "Mutable" }, "ToPort": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-fleet-ec2inboundpermission.html#cfn-gamelift-fleet-ec2inboundpermissions-toport", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-fleet-ippermission.html#cfn-gamelift-fleet-ippermission-toport", "PrimitiveType": "Integer", "Required": true, "UpdateType": "Mutable" @@ -24541,7 +25407,6 @@ }, "ServerProcesses": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-gamelift-fleet-runtimeconfiguration.html#cfn-gamelift-fleet-runtimeconfiguration-serverprocesses", - "DuplicatesAllowed": false, "ItemType": "ServerProcess", "Required": false, "Type": "List", @@ -27587,6 +28452,390 @@ } } }, + "AWS::GroundStation::Config.AntennaDownlinkConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-antennadownlinkconfig.html", + "Properties": { + "SpectrumConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-antennadownlinkconfig.html#cfn-groundstation-config-antennadownlinkconfig-spectrumconfig", + "Required": false, + "Type": "SpectrumConfig", + "UpdateType": "Mutable" + } + } + }, + "AWS::GroundStation::Config.AntennaDownlinkDemodDecodeConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-antennadownlinkdemoddecodeconfig.html", + "Properties": { + "DecodeConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-antennadownlinkdemoddecodeconfig.html#cfn-groundstation-config-antennadownlinkdemoddecodeconfig-decodeconfig", + "Required": false, + "Type": "DecodeConfig", + "UpdateType": "Mutable" + }, + "DemodulationConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-antennadownlinkdemoddecodeconfig.html#cfn-groundstation-config-antennadownlinkdemoddecodeconfig-demodulationconfig", + "Required": false, + "Type": "DemodulationConfig", + "UpdateType": "Mutable" + }, + "SpectrumConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-antennadownlinkdemoddecodeconfig.html#cfn-groundstation-config-antennadownlinkdemoddecodeconfig-spectrumconfig", + "Required": false, + "Type": "SpectrumConfig", + "UpdateType": "Mutable" + } + } + }, + "AWS::GroundStation::Config.AntennaUplinkConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-antennauplinkconfig.html", + "Properties": { + "SpectrumConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-antennauplinkconfig.html#cfn-groundstation-config-antennauplinkconfig-spectrumconfig", + "Required": false, + "Type": "UplinkSpectrumConfig", + "UpdateType": "Mutable" + }, + "TargetEirp": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-antennauplinkconfig.html#cfn-groundstation-config-antennauplinkconfig-targeteirp", + "Required": false, + "Type": "Eirp", + "UpdateType": "Mutable" + }, + "TransmitDisabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-antennauplinkconfig.html#cfn-groundstation-config-antennauplinkconfig-transmitdisabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::GroundStation::Config.ConfigData": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-configdata.html", + "Properties": { + "AntennaDownlinkConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-configdata.html#cfn-groundstation-config-configdata-antennadownlinkconfig", + "Required": false, + "Type": "AntennaDownlinkConfig", + "UpdateType": "Mutable" + }, + "AntennaDownlinkDemodDecodeConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-configdata.html#cfn-groundstation-config-configdata-antennadownlinkdemoddecodeconfig", + "Required": false, + "Type": "AntennaDownlinkDemodDecodeConfig", + "UpdateType": "Mutable" + }, + "AntennaUplinkConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-configdata.html#cfn-groundstation-config-configdata-antennauplinkconfig", + "Required": false, + "Type": "AntennaUplinkConfig", + "UpdateType": "Mutable" + }, + "DataflowEndpointConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-configdata.html#cfn-groundstation-config-configdata-dataflowendpointconfig", + "Required": false, + "Type": "DataflowEndpointConfig", + "UpdateType": "Mutable" + }, + "S3RecordingConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-configdata.html#cfn-groundstation-config-configdata-s3recordingconfig", + "Required": false, + "Type": "S3RecordingConfig", + "UpdateType": "Mutable" + }, + "TrackingConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-configdata.html#cfn-groundstation-config-configdata-trackingconfig", + "Required": false, + "Type": "TrackingConfig", + "UpdateType": "Mutable" + }, + "UplinkEchoConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-configdata.html#cfn-groundstation-config-configdata-uplinkechoconfig", + "Required": false, + "Type": "UplinkEchoConfig", + "UpdateType": "Mutable" + } + } + }, + "AWS::GroundStation::Config.DataflowEndpointConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-dataflowendpointconfig.html", + "Properties": { + "DataflowEndpointName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-dataflowendpointconfig.html#cfn-groundstation-config-dataflowendpointconfig-dataflowendpointname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "DataflowEndpointRegion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-dataflowendpointconfig.html#cfn-groundstation-config-dataflowendpointconfig-dataflowendpointregion", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::GroundStation::Config.DecodeConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-decodeconfig.html", + "Properties": { + "UnvalidatedJSON": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-decodeconfig.html#cfn-groundstation-config-decodeconfig-unvalidatedjson", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::GroundStation::Config.DemodulationConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-demodulationconfig.html", + "Properties": { + "UnvalidatedJSON": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-demodulationconfig.html#cfn-groundstation-config-demodulationconfig-unvalidatedjson", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::GroundStation::Config.Eirp": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-eirp.html", + "Properties": { + "Units": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-eirp.html#cfn-groundstation-config-eirp-units", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-eirp.html#cfn-groundstation-config-eirp-value", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::GroundStation::Config.Frequency": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-frequency.html", + "Properties": { + "Units": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-frequency.html#cfn-groundstation-config-frequency-units", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-frequency.html#cfn-groundstation-config-frequency-value", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::GroundStation::Config.FrequencyBandwidth": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-frequencybandwidth.html", + "Properties": { + "Units": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-frequencybandwidth.html#cfn-groundstation-config-frequencybandwidth-units", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-frequencybandwidth.html#cfn-groundstation-config-frequencybandwidth-value", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::GroundStation::Config.S3RecordingConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-s3recordingconfig.html", + "Properties": { + "BucketArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-s3recordingconfig.html#cfn-groundstation-config-s3recordingconfig-bucketarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Prefix": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-s3recordingconfig.html#cfn-groundstation-config-s3recordingconfig-prefix", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-s3recordingconfig.html#cfn-groundstation-config-s3recordingconfig-rolearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::GroundStation::Config.SpectrumConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-spectrumconfig.html", + "Properties": { + "Bandwidth": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-spectrumconfig.html#cfn-groundstation-config-spectrumconfig-bandwidth", + "Required": false, + "Type": "FrequencyBandwidth", + "UpdateType": "Mutable" + }, + "CenterFrequency": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-spectrumconfig.html#cfn-groundstation-config-spectrumconfig-centerfrequency", + "Required": false, + "Type": "Frequency", + "UpdateType": "Mutable" + }, + "Polarization": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-spectrumconfig.html#cfn-groundstation-config-spectrumconfig-polarization", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::GroundStation::Config.TrackingConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-trackingconfig.html", + "Properties": { + "Autotrack": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-trackingconfig.html#cfn-groundstation-config-trackingconfig-autotrack", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::GroundStation::Config.UplinkEchoConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-uplinkechoconfig.html", + "Properties": { + "AntennaUplinkConfigArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-uplinkechoconfig.html#cfn-groundstation-config-uplinkechoconfig-antennauplinkconfigarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Enabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-uplinkechoconfig.html#cfn-groundstation-config-uplinkechoconfig-enabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::GroundStation::Config.UplinkSpectrumConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-uplinkspectrumconfig.html", + "Properties": { + "CenterFrequency": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-uplinkspectrumconfig.html#cfn-groundstation-config-uplinkspectrumconfig-centerfrequency", + "Required": false, + "Type": "Frequency", + "UpdateType": "Mutable" + }, + "Polarization": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-config-uplinkspectrumconfig.html#cfn-groundstation-config-uplinkspectrumconfig-polarization", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::GroundStation::DataflowEndpointGroup.DataflowEndpoint": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-dataflowendpointgroup-dataflowendpoint.html", + "Properties": { + "Address": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-dataflowendpointgroup-dataflowendpoint.html#cfn-groundstation-dataflowendpointgroup-dataflowendpoint-address", + "Required": false, + "Type": "SocketAddress", + "UpdateType": "Mutable" + }, + "Mtu": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-dataflowendpointgroup-dataflowendpoint.html#cfn-groundstation-dataflowendpointgroup-dataflowendpoint-mtu", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-dataflowendpointgroup-dataflowendpoint.html#cfn-groundstation-dataflowendpointgroup-dataflowendpoint-name", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::GroundStation::DataflowEndpointGroup.EndpointDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-dataflowendpointgroup-endpointdetails.html", + "Properties": { + "Endpoint": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-dataflowendpointgroup-endpointdetails.html#cfn-groundstation-dataflowendpointgroup-endpointdetails-endpoint", + "Required": false, + "Type": "DataflowEndpoint", + "UpdateType": "Mutable" + }, + "SecurityDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-dataflowendpointgroup-endpointdetails.html#cfn-groundstation-dataflowendpointgroup-endpointdetails-securitydetails", + "Required": false, + "Type": "SecurityDetails", + "UpdateType": "Mutable" + } + } + }, + "AWS::GroundStation::DataflowEndpointGroup.SecurityDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-dataflowendpointgroup-securitydetails.html", + "Properties": { + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-dataflowendpointgroup-securitydetails.html#cfn-groundstation-dataflowendpointgroup-securitydetails-rolearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SecurityGroupIds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-dataflowendpointgroup-securitydetails.html#cfn-groundstation-dataflowendpointgroup-securitydetails-securitygroupids", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "SubnetIds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-dataflowendpointgroup-securitydetails.html#cfn-groundstation-dataflowendpointgroup-securitydetails-subnetids", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::GroundStation::DataflowEndpointGroup.SocketAddress": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-dataflowendpointgroup-socketaddress.html", + "Properties": { + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-dataflowendpointgroup-socketaddress.html#cfn-groundstation-dataflowendpointgroup-socketaddress-name", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Port": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-dataflowendpointgroup-socketaddress.html#cfn-groundstation-dataflowendpointgroup-socketaddress-port", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::GroundStation::MissionProfile.DataflowEdge": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-missionprofile-dataflowedge.html", + "Properties": { + "Destination": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-missionprofile-dataflowedge.html#cfn-groundstation-missionprofile-dataflowedge-destination", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Source": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-groundstation-missionprofile-dataflowedge.html#cfn-groundstation-missionprofile-dataflowedge-source", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::GuardDuty::Detector.CFNDataSourceConfigurations": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-guardduty-detector-cfndatasourceconfigurations.html", "Properties": { @@ -27731,6 +28980,28 @@ } } }, + "AWS::IVS::RecordingConfiguration.DestinationConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ivs-recordingconfiguration-destinationconfiguration.html", + "Properties": { + "S3": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ivs-recordingconfiguration-destinationconfiguration.html#cfn-ivs-recordingconfiguration-destinationconfiguration-s3", + "Required": true, + "Type": "S3DestinationConfiguration", + "UpdateType": "Immutable" + } + } + }, + "AWS::IVS::RecordingConfiguration.S3DestinationConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ivs-recordingconfiguration-s3destinationconfiguration.html", + "Properties": { + "BucketName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ivs-recordingconfiguration-s3destinationconfiguration.html#cfn-ivs-recordingconfiguration-s3destinationconfiguration-bucketname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, "AWS::ImageBuilder::ContainerRecipe.ComponentConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-containerrecipe-componentconfiguration.html", "Properties": { @@ -27742,6 +29013,100 @@ } } }, + "AWS::ImageBuilder::ContainerRecipe.EbsInstanceBlockDeviceSpecification": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-containerrecipe-ebsinstanceblockdevicespecification.html", + "Properties": { + "DeleteOnTermination": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-containerrecipe-ebsinstanceblockdevicespecification.html#cfn-imagebuilder-containerrecipe-ebsinstanceblockdevicespecification-deleteontermination", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Immutable" + }, + "Encrypted": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-containerrecipe-ebsinstanceblockdevicespecification.html#cfn-imagebuilder-containerrecipe-ebsinstanceblockdevicespecification-encrypted", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Immutable" + }, + "Iops": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-containerrecipe-ebsinstanceblockdevicespecification.html#cfn-imagebuilder-containerrecipe-ebsinstanceblockdevicespecification-iops", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + }, + "KmsKeyId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-containerrecipe-ebsinstanceblockdevicespecification.html#cfn-imagebuilder-containerrecipe-ebsinstanceblockdevicespecification-kmskeyid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "SnapshotId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-containerrecipe-ebsinstanceblockdevicespecification.html#cfn-imagebuilder-containerrecipe-ebsinstanceblockdevicespecification-snapshotid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "VolumeSize": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-containerrecipe-ebsinstanceblockdevicespecification.html#cfn-imagebuilder-containerrecipe-ebsinstanceblockdevicespecification-volumesize", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + }, + "VolumeType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-containerrecipe-ebsinstanceblockdevicespecification.html#cfn-imagebuilder-containerrecipe-ebsinstanceblockdevicespecification-volumetype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::ImageBuilder::ContainerRecipe.InstanceBlockDeviceMapping": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-containerrecipe-instanceblockdevicemapping.html", + "Properties": { + "DeviceName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-containerrecipe-instanceblockdevicemapping.html#cfn-imagebuilder-containerrecipe-instanceblockdevicemapping-devicename", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Ebs": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-containerrecipe-instanceblockdevicemapping.html#cfn-imagebuilder-containerrecipe-instanceblockdevicemapping-ebs", + "Required": false, + "Type": "EbsInstanceBlockDeviceSpecification", + "UpdateType": "Immutable" + }, + "NoDevice": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-containerrecipe-instanceblockdevicemapping.html#cfn-imagebuilder-containerrecipe-instanceblockdevicemapping-nodevice", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "VirtualName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-containerrecipe-instanceblockdevicemapping.html#cfn-imagebuilder-containerrecipe-instanceblockdevicemapping-virtualname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::ImageBuilder::ContainerRecipe.InstanceConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-containerrecipe-instanceconfiguration.html", + "Properties": { + "BlockDeviceMappings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-containerrecipe-instanceconfiguration.html#cfn-imagebuilder-containerrecipe-instanceconfiguration-blockdevicemappings", + "ItemType": "InstanceBlockDeviceMapping", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "Image": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-containerrecipe-instanceconfiguration.html#cfn-imagebuilder-containerrecipe-instanceconfiguration-image", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, "AWS::ImageBuilder::ContainerRecipe.TargetContainerRepository": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-containerrecipe-targetcontainerrepository.html", "Properties": { @@ -27774,6 +29139,13 @@ "Required": false, "UpdateType": "Mutable" }, + "LaunchTemplateConfigurations": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-distributionconfiguration-distribution.html#cfn-imagebuilder-distributionconfiguration-distribution-launchtemplateconfigurations", + "ItemType": "LaunchTemplateConfiguration", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, "LicenseConfigurationArns": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-distributionconfiguration-distribution.html#cfn-imagebuilder-distributionconfiguration-distribution-licenseconfigurationarns", "PrimitiveItemType": "String", @@ -27789,6 +29161,29 @@ } } }, + "AWS::ImageBuilder::DistributionConfiguration.LaunchTemplateConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-distributionconfiguration-launchtemplateconfiguration.html", + "Properties": { + "AccountId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-distributionconfiguration-launchtemplateconfiguration.html#cfn-imagebuilder-distributionconfiguration-launchtemplateconfiguration-accountid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "LaunchTemplateId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-distributionconfiguration-launchtemplateconfiguration.html#cfn-imagebuilder-distributionconfiguration-launchtemplateconfiguration-launchtemplateid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SetDefaultVersion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-distributionconfiguration-launchtemplateconfiguration.html#cfn-imagebuilder-distributionconfiguration-launchtemplateconfiguration-setdefaultversion", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::ImageBuilder::Image.ImageTestsConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-image-imagetestsconfiguration.html", "Properties": { @@ -28527,6 +29922,12 @@ "Type": "CloudwatchAlarmAction", "UpdateType": "Mutable" }, + "CloudwatchLogs": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-action.html#cfn-iot-topicrule-action-cloudwatchlogs", + "Required": false, + "Type": "CloudwatchLogsAction", + "UpdateType": "Mutable" + }, "CloudwatchMetric": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-action.html#cfn-iot-topicrule-action-cloudwatchmetric", "Required": false, @@ -28581,6 +29982,12 @@ "Type": "IotSiteWiseAction", "UpdateType": "Mutable" }, + "Kafka": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-action.html#cfn-iot-topicrule-action-kafka", + "Required": false, + "Type": "KafkaAction", + "UpdateType": "Mutable" + }, "Kinesis": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-action.html#cfn-iot-topicrule-action-kinesis", "Required": false, @@ -28622,6 +30029,12 @@ "Required": false, "Type": "StepFunctionsAction", "UpdateType": "Mutable" + }, + "Timestream": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-action.html#cfn-iot-topicrule-action-timestream", + "Required": false, + "Type": "TimestreamAction", + "UpdateType": "Mutable" } } }, @@ -28723,6 +30136,23 @@ } } }, + "AWS::IoT::TopicRule.CloudwatchLogsAction": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-cloudwatchlogsaction.html", + "Properties": { + "LogGroupName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-cloudwatchlogsaction.html#cfn-iot-topicrule-cloudwatchlogsaction-loggroupname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-cloudwatchlogsaction.html#cfn-iot-topicrule-cloudwatchlogsaction-rolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::IoT::TopicRule.CloudwatchMetricAction": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-cloudwatchmetricaction.html", "Properties": { @@ -28878,6 +30308,12 @@ "AWS::IoT::TopicRule.FirehoseAction": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-firehoseaction.html", "Properties": { + "BatchMode": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-firehoseaction.html#cfn-iot-topicrule-firehoseaction-batchmode", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, "DeliveryStreamName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-firehoseaction.html#cfn-iot-topicrule-firehoseaction-deliverystreamname", "PrimitiveType": "String", @@ -28960,6 +30396,12 @@ "AWS::IoT::TopicRule.IotAnalyticsAction": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-iotanalyticsaction.html", "Properties": { + "BatchMode": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-iotanalyticsaction.html#cfn-iot-topicrule-iotanalyticsaction-batchmode", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, "ChannelName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-iotanalyticsaction.html#cfn-iot-topicrule-iotanalyticsaction-channelname", "PrimitiveType": "String", @@ -28977,6 +30419,12 @@ "AWS::IoT::TopicRule.IotEventsAction": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-ioteventsaction.html", "Properties": { + "BatchMode": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-ioteventsaction.html#cfn-iot-topicrule-ioteventsaction-batchmode", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, "InputName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-ioteventsaction.html#cfn-iot-topicrule-ioteventsaction-inputname", "PrimitiveType": "String", @@ -29016,6 +30464,42 @@ } } }, + "AWS::IoT::TopicRule.KafkaAction": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-kafkaaction.html", + "Properties": { + "ClientProperties": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-kafkaaction.html#cfn-iot-topicrule-kafkaaction-clientproperties", + "PrimitiveItemType": "String", + "Required": true, + "Type": "Map", + "UpdateType": "Mutable" + }, + "DestinationArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-kafkaaction.html#cfn-iot-topicrule-kafkaaction-destinationarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Key": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-kafkaaction.html#cfn-iot-topicrule-kafkaaction-key", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Partition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-kafkaaction.html#cfn-iot-topicrule-kafkaaction-partition", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Topic": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-kafkaaction.html#cfn-iot-topicrule-kafkaaction-topic", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::IoT::TopicRule.KinesisAction": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-kinesisaction.html", "Properties": { @@ -29242,6 +30726,76 @@ } } }, + "AWS::IoT::TopicRule.TimestreamAction": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-timestreamaction.html", + "Properties": { + "DatabaseName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-timestreamaction.html#cfn-iot-topicrule-timestreamaction-databasename", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Dimensions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-timestreamaction.html#cfn-iot-topicrule-timestreamaction-dimensions", + "ItemType": "TimestreamDimension", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-timestreamaction.html#cfn-iot-topicrule-timestreamaction-rolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "TableName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-timestreamaction.html#cfn-iot-topicrule-timestreamaction-tablename", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Timestamp": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-timestreamaction.html#cfn-iot-topicrule-timestreamaction-timestamp", + "Required": false, + "Type": "TimestreamTimestamp", + "UpdateType": "Mutable" + } + } + }, + "AWS::IoT::TopicRule.TimestreamDimension": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-timestreamdimension.html", + "Properties": { + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-timestreamdimension.html#cfn-iot-topicrule-timestreamdimension-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-timestreamdimension.html#cfn-iot-topicrule-timestreamdimension-value", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::IoT::TopicRule.TimestreamTimestamp": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-timestreamtimestamp.html", + "Properties": { + "Unit": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-timestreamtimestamp.html#cfn-iot-topicrule-timestreamtimestamp-unit", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-timestreamtimestamp.html#cfn-iot-topicrule-timestreamtimestamp-value", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::IoT::TopicRule.TopicRulePayload": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-topicrulepayload.html", "Properties": { @@ -30315,7 +31869,7 @@ "TimeInSeconds": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-assetpropertytimestamp.html#cfn-iotevents-detectormodel-assetpropertytimestamp-timeinseconds", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" } } @@ -30337,7 +31891,7 @@ }, "Value": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-assetpropertyvalue.html#cfn-iotevents-detectormodel-assetpropertyvalue-value", - "Required": false, + "Required": true, "Type": "AssetPropertyVariant", "UpdateType": "Mutable" } @@ -30378,7 +31932,7 @@ "TimerName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-cleartimer.html#cfn-iotevents-detectormodel-cleartimer-timername", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" } } @@ -30389,13 +31943,14 @@ "InitialStateName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-detectormodeldefinition.html#cfn-iotevents-detectormodel-detectormodeldefinition-initialstatename", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "States": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-detectormodeldefinition.html#cfn-iotevents-detectormodel-detectormodeldefinition-states", + "DuplicatesAllowed": true, "ItemType": "State", - "Required": false, + "Required": true, "Type": "List", "UpdateType": "Mutable" } @@ -30407,7 +31962,7 @@ "HashKeyField": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-dynamodb.html#cfn-iotevents-detectormodel-dynamodb-hashkeyfield", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "HashKeyType": { @@ -30419,7 +31974,7 @@ "HashKeyValue": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-dynamodb.html#cfn-iotevents-detectormodel-dynamodb-hashkeyvalue", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "Operation": { @@ -30461,7 +32016,7 @@ "TableName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-dynamodb.html#cfn-iotevents-detectormodel-dynamodb-tablename", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" } } @@ -30478,7 +32033,7 @@ "TableName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-dynamodbv2.html#cfn-iotevents-detectormodel-dynamodbv2-tablename", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" } } @@ -30488,6 +32043,7 @@ "Properties": { "Actions": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-event.html#cfn-iotevents-detectormodel-event-actions", + "DuplicatesAllowed": true, "ItemType": "Action", "Required": false, "Type": "List", @@ -30502,7 +32058,7 @@ "EventName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-event.html#cfn-iotevents-detectormodel-event-eventname", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" } } @@ -30513,7 +32069,7 @@ "DeliveryStreamName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-firehose.html#cfn-iotevents-detectormodel-firehose-deliverystreamname", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "Payload": { @@ -30536,7 +32092,7 @@ "InputName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-iotevents.html#cfn-iotevents-detectormodel-iotevents-inputname", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "Payload": { @@ -30576,7 +32132,7 @@ }, "PropertyValue": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-iotsitewise.html#cfn-iotevents-detectormodel-iotsitewise-propertyvalue", - "Required": false, + "Required": true, "Type": "AssetPropertyValue", "UpdateType": "Mutable" } @@ -30588,7 +32144,7 @@ "MqttTopic": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-iottopicpublish.html#cfn-iotevents-detectormodel-iottopicpublish-mqtttopic", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "Payload": { @@ -30605,7 +32161,7 @@ "FunctionArn": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-lambda.html#cfn-iotevents-detectormodel-lambda-functionarn", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "Payload": { @@ -30621,6 +32177,7 @@ "Properties": { "Events": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-onenter.html#cfn-iotevents-detectormodel-onenter-events", + "DuplicatesAllowed": true, "ItemType": "Event", "Required": false, "Type": "List", @@ -30633,6 +32190,7 @@ "Properties": { "Events": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-onexit.html#cfn-iotevents-detectormodel-onexit-events", + "DuplicatesAllowed": true, "ItemType": "Event", "Required": false, "Type": "List", @@ -30645,6 +32203,7 @@ "Properties": { "Events": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-oninput.html#cfn-iotevents-detectormodel-oninput-events", + "DuplicatesAllowed": true, "ItemType": "Event", "Required": false, "Type": "List", @@ -30652,6 +32211,7 @@ }, "TransitionEvents": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-oninput.html#cfn-iotevents-detectormodel-oninput-transitionevents", + "DuplicatesAllowed": true, "ItemType": "TransitionEvent", "Required": false, "Type": "List", @@ -30665,13 +32225,13 @@ "ContentExpression": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-payload.html#cfn-iotevents-detectormodel-payload-contentexpression", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "Type": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-payload.html#cfn-iotevents-detectormodel-payload-type", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" } } @@ -30682,7 +32242,7 @@ "TimerName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-resettimer.html#cfn-iotevents-detectormodel-resettimer-timername", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" } } @@ -30705,7 +32265,7 @@ "TimerName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-settimer.html#cfn-iotevents-detectormodel-settimer-timername", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" } } @@ -30716,13 +32276,13 @@ "Value": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-setvariable.html#cfn-iotevents-detectormodel-setvariable-value", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "VariableName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-setvariable.html#cfn-iotevents-detectormodel-setvariable-variablename", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" } } @@ -30739,7 +32299,7 @@ "TargetArn": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-sns.html#cfn-iotevents-detectormodel-sns-targetarn", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" } } @@ -30756,7 +32316,7 @@ "QueueUrl": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-sqs.html#cfn-iotevents-detectormodel-sqs-queueurl", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "UseBase64": { @@ -30791,7 +32351,7 @@ "StateName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-state.html#cfn-iotevents-detectormodel-state-statename", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" } } @@ -30801,6 +32361,7 @@ "Properties": { "Actions": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-transitionevent.html#cfn-iotevents-detectormodel-transitionevent-actions", + "DuplicatesAllowed": true, "ItemType": "Action", "Required": false, "Type": "List", @@ -30809,19 +32370,19 @@ "Condition": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-transitionevent.html#cfn-iotevents-detectormodel-transitionevent-condition", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "EventName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-transitionevent.html#cfn-iotevents-detectormodel-transitionevent-eventname", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "NextState": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-transitionevent.html#cfn-iotevents-detectormodel-transitionevent-nextstate", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" } } @@ -30832,7 +32393,7 @@ "JsonPath": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-input-attribute.html#cfn-iotevents-input-attribute-jsonpath", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" } } @@ -30842,8 +32403,9 @@ "Properties": { "Attributes": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-input-inputdefinition.html#cfn-iotevents-input-inputdefinition-attributes", + "DuplicatesAllowed": false, "ItemType": "Attribute", - "Required": false, + "Required": true, "Type": "List", "UpdateType": "Mutable" } @@ -31361,6 +32923,28 @@ } } }, + "AWS::IoTWireless::PartnerAccount.SidewalkAccountInfo": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-partneraccount-sidewalkaccountinfo.html", + "Properties": { + "AppServerPrivateKey": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-partneraccount-sidewalkaccountinfo.html#cfn-iotwireless-partneraccount-sidewalkaccountinfo-appserverprivatekey", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::IoTWireless::PartnerAccount.SidewalkUpdateAccount": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-partneraccount-sidewalkupdateaccount.html", + "Properties": { + "AppServerPrivateKey": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-partneraccount-sidewalkupdateaccount.html#cfn-iotwireless-partneraccount-sidewalkupdateaccount-appserverprivatekey", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::IoTWireless::ServiceProfile.LoRaWANServiceProfile": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-serviceprofile-lorawanserviceprofile.html", "Properties": { @@ -31480,6 +33064,98 @@ } } }, + "AWS::IoTWireless::TaskDefinition.LoRaWANGatewayVersion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-taskdefinition-lorawangatewayversion.html", + "Properties": { + "Model": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-taskdefinition-lorawangatewayversion.html#cfn-iotwireless-taskdefinition-lorawangatewayversion-model", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "PackageVersion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-taskdefinition-lorawangatewayversion.html#cfn-iotwireless-taskdefinition-lorawangatewayversion-packageversion", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Station": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-taskdefinition-lorawangatewayversion.html#cfn-iotwireless-taskdefinition-lorawangatewayversion-station", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::IoTWireless::TaskDefinition.LoRaWANUpdateGatewayTaskCreate": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-taskdefinition-lorawanupdategatewaytaskcreate.html", + "Properties": { + "CurrentVersion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-taskdefinition-lorawanupdategatewaytaskcreate.html#cfn-iotwireless-taskdefinition-lorawanupdategatewaytaskcreate-currentversion", + "Required": false, + "Type": "LoRaWANGatewayVersion", + "UpdateType": "Mutable" + }, + "SigKeyCrc": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-taskdefinition-lorawanupdategatewaytaskcreate.html#cfn-iotwireless-taskdefinition-lorawanupdategatewaytaskcreate-sigkeycrc", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "UpdateSignature": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-taskdefinition-lorawanupdategatewaytaskcreate.html#cfn-iotwireless-taskdefinition-lorawanupdategatewaytaskcreate-updatesignature", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "UpdateVersion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-taskdefinition-lorawanupdategatewaytaskcreate.html#cfn-iotwireless-taskdefinition-lorawanupdategatewaytaskcreate-updateversion", + "Required": false, + "Type": "LoRaWANGatewayVersion", + "UpdateType": "Mutable" + } + } + }, + "AWS::IoTWireless::TaskDefinition.LoRaWANUpdateGatewayTaskEntry": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-taskdefinition-lorawanupdategatewaytaskentry.html", + "Properties": { + "CurrentVersion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-taskdefinition-lorawanupdategatewaytaskentry.html#cfn-iotwireless-taskdefinition-lorawanupdategatewaytaskentry-currentversion", + "Required": false, + "Type": "LoRaWANGatewayVersion", + "UpdateType": "Mutable" + }, + "UpdateVersion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-taskdefinition-lorawanupdategatewaytaskentry.html#cfn-iotwireless-taskdefinition-lorawanupdategatewaytaskentry-updateversion", + "Required": false, + "Type": "LoRaWANGatewayVersion", + "UpdateType": "Mutable" + } + } + }, + "AWS::IoTWireless::TaskDefinition.UpdateWirelessGatewayTaskCreate": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-taskdefinition-updatewirelessgatewaytaskcreate.html", + "Properties": { + "LoRaWAN": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-taskdefinition-updatewirelessgatewaytaskcreate.html#cfn-iotwireless-taskdefinition-updatewirelessgatewaytaskcreate-lorawan", + "Required": false, + "Type": "LoRaWANUpdateGatewayTaskCreate", + "UpdateType": "Mutable" + }, + "UpdateDataRole": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-taskdefinition-updatewirelessgatewaytaskcreate.html#cfn-iotwireless-taskdefinition-updatewirelessgatewaytaskcreate-updatedatarole", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "UpdateDataSource": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-taskdefinition-updatewirelessgatewaytaskcreate.html#cfn-iotwireless-taskdefinition-updatewirelessgatewaytaskcreate-updatedatasource", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::IoTWireless::WirelessDevice.AbpV10x": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotwireless-wirelessdevice-abpv10x.html", "Properties": { @@ -31686,25 +33362,14 @@ } } }, - "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", + "PrimitiveItemType": "String", "Required": true, - "Type": "ChangeDetectingColumns", + "Type": "List", "UpdateType": "Mutable" }, "DocumentDataColumnName": { @@ -31727,8 +33392,9 @@ }, "FieldMappings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-columnconfiguration.html#cfn-kendra-datasource-columnconfiguration-fieldmappings", + "ItemType": "DataSourceToIndexFieldMapping", "Required": false, - "Type": "DataSourceToIndexFieldMappingList", + "Type": "List", "UpdateType": "Mutable" } } @@ -31738,8 +33404,9 @@ "Properties": { "AttachmentFieldMappings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-confluenceattachmentconfiguration.html#cfn-kendra-datasource-confluenceattachmentconfiguration-attachmentfieldmappings", + "ItemType": "ConfluenceAttachmentToIndexFieldMapping", "Required": false, - "Type": "ConfluenceAttachmentFieldMappingsList", + "Type": "List", "UpdateType": "Mutable" }, "CrawlAttachments": { @@ -31750,18 +33417,6 @@ } } }, - "AWS::Kendra::DataSource.ConfluenceAttachmentFieldMappingsList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-confluenceattachmentfieldmappingslist.html", - "Properties": { - "ConfluenceAttachmentFieldMappingsList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-confluenceattachmentfieldmappingslist.html#cfn-kendra-datasource-confluenceattachmentfieldmappingslist-confluenceattachmentfieldmappingslist", - "ItemType": "ConfluenceAttachmentToIndexFieldMapping", - "Required": false, - "Type": "List", - "UpdateType": "Mutable" - } - } - }, "AWS::Kendra::DataSource.ConfluenceAttachmentToIndexFieldMapping": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-confluenceattachmenttoindexfieldmapping.html", "Properties": { @@ -31790,17 +33445,6 @@ "Properties": { "BlogFieldMappings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-confluenceblogconfiguration.html#cfn-kendra-datasource-confluenceblogconfiguration-blogfieldmappings", - "Required": false, - "Type": "ConfluenceBlogFieldMappingsList", - "UpdateType": "Mutable" - } - } - }, - "AWS::Kendra::DataSource.ConfluenceBlogFieldMappingsList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-confluenceblogfieldmappingslist.html", - "Properties": { - "ConfluenceBlogFieldMappingsList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-confluenceblogfieldmappingslist.html#cfn-kendra-datasource-confluenceblogfieldmappingslist-confluenceblogfieldmappingslist", "ItemType": "ConfluenceBlogToIndexFieldMapping", "Required": false, "Type": "List", @@ -31848,14 +33492,16 @@ }, "ExclusionPatterns": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-confluenceconfiguration.html#cfn-kendra-datasource-confluenceconfiguration-exclusionpatterns", + "PrimitiveItemType": "String", "Required": false, - "Type": "DataSourceInclusionsExclusionsStrings", + "Type": "List", "UpdateType": "Mutable" }, "InclusionPatterns": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-confluenceconfiguration.html#cfn-kendra-datasource-confluenceconfiguration-inclusionpatterns", + "PrimitiveItemType": "String", "Required": false, - "Type": "DataSourceInclusionsExclusionsStrings", + "Type": "List", "UpdateType": "Mutable" }, "PageConfiguration": { @@ -31901,17 +33547,6 @@ "Properties": { "PageFieldMappings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-confluencepageconfiguration.html#cfn-kendra-datasource-confluencepageconfiguration-pagefieldmappings", - "Required": false, - "Type": "ConfluencePageFieldMappingsList", - "UpdateType": "Mutable" - } - } - }, - "AWS::Kendra::DataSource.ConfluencePageFieldMappingsList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-confluencepagefieldmappingslist.html", - "Properties": { - "ConfluencePageFieldMappingsList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-confluencepagefieldmappingslist.html#cfn-kendra-datasource-confluencepagefieldmappingslist-confluencepagefieldmappingslist", "ItemType": "ConfluencePageToIndexFieldMapping", "Required": false, "Type": "List", @@ -31959,29 +33594,20 @@ }, "ExcludeSpaces": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-confluencespaceconfiguration.html#cfn-kendra-datasource-confluencespaceconfiguration-excludespaces", + "PrimitiveItemType": "String", "Required": false, - "Type": "ConfluenceSpaceList", + "Type": "List", "UpdateType": "Mutable" }, "IncludeSpaces": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-confluencespaceconfiguration.html#cfn-kendra-datasource-confluencespaceconfiguration-includespaces", + "PrimitiveItemType": "String", "Required": false, - "Type": "ConfluenceSpaceList", + "Type": "List", "UpdateType": "Mutable" }, "SpaceFieldMappings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-confluencespaceconfiguration.html#cfn-kendra-datasource-confluencespaceconfiguration-spacefieldmappings", - "Required": false, - "Type": "ConfluenceSpaceFieldMappingsList", - "UpdateType": "Mutable" - } - } - }, - "AWS::Kendra::DataSource.ConfluenceSpaceFieldMappingsList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-confluencespacefieldmappingslist.html", - "Properties": { - "ConfluenceSpaceFieldMappingsList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-confluencespacefieldmappingslist.html#cfn-kendra-datasource-confluencespacefieldmappingslist-confluencespacefieldmappingslist", "ItemType": "ConfluenceSpaceToIndexFieldMapping", "Required": false, "Type": "List", @@ -31989,18 +33615,6 @@ } } }, - "AWS::Kendra::DataSource.ConfluenceSpaceList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-confluencespacelist.html", - "Properties": { - "ConfluenceSpaceList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-confluencespacelist.html#cfn-kendra-datasource-confluencespacelist-confluencespacelist", - "PrimitiveItemType": "String", - "Required": false, - "Type": "List", - "UpdateType": "Mutable" - } - } - }, "AWS::Kendra::DataSource.ConfluenceSpaceToIndexFieldMapping": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-confluencespacetoindexfieldmapping.html", "Properties": { @@ -32112,18 +33726,6 @@ } } }, - "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": { @@ -32147,18 +33749,6 @@ } } }, - "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": { @@ -32230,79 +33820,49 @@ } } }, - "AWS::Kendra::DataSource.ExcludeMimeTypesList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-excludemimetypeslist.html", - "Properties": { - "ExcludeMimeTypesList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-excludemimetypeslist.html#cfn-kendra-datasource-excludemimetypeslist-excludemimetypeslist", - "PrimitiveItemType": "String", - "Required": false, - "Type": "List", - "UpdateType": "Mutable" - } - } - }, - "AWS::Kendra::DataSource.ExcludeSharedDrivesList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-excludeshareddriveslist.html", - "Properties": { - "ExcludeSharedDrivesList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-excludeshareddriveslist.html#cfn-kendra-datasource-excludeshareddriveslist-excludeshareddriveslist", - "PrimitiveItemType": "String", - "Required": false, - "Type": "List", - "UpdateType": "Mutable" - } - } - }, - "AWS::Kendra::DataSource.ExcludeUserAccountsList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-excludeuseraccountslist.html", - "Properties": { - "ExcludeUserAccountsList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-excludeuseraccountslist.html#cfn-kendra-datasource-excludeuseraccountslist-excludeuseraccountslist", - "PrimitiveItemType": "String", - "Required": false, - "Type": "List", - "UpdateType": "Mutable" - } - } - }, "AWS::Kendra::DataSource.GoogleDriveConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-googledriveconfiguration.html", "Properties": { "ExcludeMimeTypes": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-googledriveconfiguration.html#cfn-kendra-datasource-googledriveconfiguration-excludemimetypes", + "PrimitiveItemType": "String", "Required": false, - "Type": "ExcludeMimeTypesList", + "Type": "List", "UpdateType": "Mutable" }, "ExcludeSharedDrives": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-googledriveconfiguration.html#cfn-kendra-datasource-googledriveconfiguration-excludeshareddrives", + "PrimitiveItemType": "String", "Required": false, - "Type": "ExcludeSharedDrivesList", + "Type": "List", "UpdateType": "Mutable" }, "ExcludeUserAccounts": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-googledriveconfiguration.html#cfn-kendra-datasource-googledriveconfiguration-excludeuseraccounts", + "PrimitiveItemType": "String", "Required": false, - "Type": "ExcludeUserAccountsList", + "Type": "List", "UpdateType": "Mutable" }, "ExclusionPatterns": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-googledriveconfiguration.html#cfn-kendra-datasource-googledriveconfiguration-exclusionpatterns", + "PrimitiveItemType": "String", "Required": false, - "Type": "DataSourceInclusionsExclusionsStrings", + "Type": "List", "UpdateType": "Mutable" }, "FieldMappings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-googledriveconfiguration.html#cfn-kendra-datasource-googledriveconfiguration-fieldmappings", + "ItemType": "DataSourceToIndexFieldMapping", "Required": false, - "Type": "DataSourceToIndexFieldMappingList", + "Type": "List", "UpdateType": "Mutable" }, "InclusionPatterns": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-googledriveconfiguration.html#cfn-kendra-datasource-googledriveconfiguration-inclusionpatterns", + "PrimitiveItemType": "String", "Required": false, - "Type": "DataSourceInclusionsExclusionsStrings", + "Type": "List", "UpdateType": "Mutable" }, "SecretArn": { @@ -32324,20 +33884,23 @@ }, "ExclusionPatterns": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-onedriveconfiguration.html#cfn-kendra-datasource-onedriveconfiguration-exclusionpatterns", + "PrimitiveItemType": "String", "Required": false, - "Type": "DataSourceInclusionsExclusionsStrings", + "Type": "List", "UpdateType": "Mutable" }, "FieldMappings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-onedriveconfiguration.html#cfn-kendra-datasource-onedriveconfiguration-fieldmappings", + "ItemType": "DataSourceToIndexFieldMapping", "Required": false, - "Type": "DataSourceToIndexFieldMappingList", + "Type": "List", "UpdateType": "Mutable" }, "InclusionPatterns": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-onedriveconfiguration.html#cfn-kendra-datasource-onedriveconfiguration-inclusionpatterns", + "PrimitiveItemType": "String", "Required": false, - "Type": "DataSourceInclusionsExclusionsStrings", + "Type": "List", "UpdateType": "Mutable" }, "OneDriveUsers": { @@ -32360,25 +33923,14 @@ } } }, - "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", + "PrimitiveItemType": "String", "Required": false, - "Type": "OneDriveUserList", + "Type": "List", "UpdateType": "Mutable" }, "OneDriveUserS3Path": { @@ -32412,20 +33964,23 @@ }, "ExclusionPatterns": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-s3datasourceconfiguration.html#cfn-kendra-datasource-s3datasourceconfiguration-exclusionpatterns", + "PrimitiveItemType": "String", "Required": false, - "Type": "DataSourceInclusionsExclusionsStrings", + "Type": "List", "UpdateType": "Mutable" }, "InclusionPatterns": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-s3datasourceconfiguration.html#cfn-kendra-datasource-s3datasourceconfiguration-inclusionpatterns", + "PrimitiveItemType": "String", "Required": false, - "Type": "DataSourceInclusionsExclusionsStrings", + "Type": "List", "UpdateType": "Mutable" }, "InclusionPrefixes": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-s3datasourceconfiguration.html#cfn-kendra-datasource-s3datasourceconfiguration-inclusionprefixes", + "PrimitiveItemType": "String", "Required": false, - "Type": "DataSourceInclusionsExclusionsStrings", + "Type": "List", "UpdateType": "Mutable" } } @@ -32464,23 +34019,13 @@ }, "FieldMappings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcechatterfeedconfiguration.html#cfn-kendra-datasource-salesforcechatterfeedconfiguration-fieldmappings", + "ItemType": "DataSourceToIndexFieldMapping", "Required": false, - "Type": "DataSourceToIndexFieldMappingList", + "Type": "List", "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", @@ -32505,14 +34050,16 @@ }, "ExcludeAttachmentFilePatterns": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforceconfiguration.html#cfn-kendra-datasource-salesforceconfiguration-excludeattachmentfilepatterns", + "PrimitiveItemType": "String", "Required": false, - "Type": "DataSourceInclusionsExclusionsStrings", + "Type": "List", "UpdateType": "Mutable" }, "IncludeAttachmentFilePatterns": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforceconfiguration.html#cfn-kendra-datasource-salesforceconfiguration-includeattachmentfilepatterns", + "PrimitiveItemType": "String", "Required": false, - "Type": "DataSourceInclusionsExclusionsStrings", + "Type": "List", "UpdateType": "Mutable" }, "KnowledgeArticleConfiguration": { @@ -32541,8 +34088,9 @@ }, "StandardObjectConfigurations": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforceconfiguration.html#cfn-kendra-datasource-salesforceconfiguration-standardobjectconfigurations", + "ItemType": "SalesforceStandardObjectConfiguration", "Required": false, - "Type": "SalesforceStandardObjectConfigurationList", + "Type": "List", "UpdateType": "Mutable" } } @@ -32564,8 +34112,9 @@ }, "FieldMappings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcecustomknowledgearticletypeconfiguration.html#cfn-kendra-datasource-salesforcecustomknowledgearticletypeconfiguration-fieldmappings", + "ItemType": "DataSourceToIndexFieldMapping", "Required": false, - "Type": "DataSourceToIndexFieldMappingList", + "Type": "List", "UpdateType": "Mutable" }, "Name": { @@ -32576,31 +34125,21 @@ } } }, - "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", + "ItemType": "SalesforceCustomKnowledgeArticleTypeConfiguration", "Required": false, - "Type": "SalesforceCustomKnowledgeArticleTypeConfigurationList", + "Type": "List", "UpdateType": "Mutable" }, "IncludedStates": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforceknowledgearticleconfiguration.html#cfn-kendra-datasource-salesforceknowledgearticleconfiguration-includedstates", + "PrimitiveItemType": "String", "Required": true, - "Type": "SalesforceKnowledgeArticleStateList", + "Type": "List", "UpdateType": "Mutable" }, "StandardKnowledgeArticleTypeConfiguration": { @@ -32611,18 +34150,6 @@ } } }, - "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": { @@ -32640,8 +34167,9 @@ }, "FieldMappings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcestandardknowledgearticletypeconfiguration.html#cfn-kendra-datasource-salesforcestandardknowledgearticletypeconfiguration-fieldmappings", + "ItemType": "DataSourceToIndexFieldMapping", "Required": false, - "Type": "DataSourceToIndexFieldMappingList", + "Type": "List", "UpdateType": "Mutable" } } @@ -32657,8 +34185,9 @@ }, "FieldMappings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcestandardobjectattachmentconfiguration.html#cfn-kendra-datasource-salesforcestandardobjectattachmentconfiguration-fieldmappings", + "ItemType": "DataSourceToIndexFieldMapping", "Required": false, - "Type": "DataSourceToIndexFieldMappingList", + "Type": "List", "UpdateType": "Mutable" } } @@ -32680,8 +34209,9 @@ }, "FieldMappings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-salesforcestandardobjectconfiguration.html#cfn-kendra-datasource-salesforcestandardobjectconfiguration-fieldmappings", + "ItemType": "DataSourceToIndexFieldMapping", "Required": false, - "Type": "DataSourceToIndexFieldMappingList", + "Type": "List", "UpdateType": "Mutable" }, "Name": { @@ -32692,18 +34222,6 @@ } } }, - "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": { @@ -32762,20 +34280,23 @@ }, "ExcludeAttachmentFilePatterns": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowknowledgearticleconfiguration.html#cfn-kendra-datasource-servicenowknowledgearticleconfiguration-excludeattachmentfilepatterns", + "PrimitiveItemType": "String", "Required": false, - "Type": "DataSourceInclusionsExclusionsStrings", + "Type": "List", "UpdateType": "Mutable" }, "FieldMappings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowknowledgearticleconfiguration.html#cfn-kendra-datasource-servicenowknowledgearticleconfiguration-fieldmappings", + "ItemType": "DataSourceToIndexFieldMapping", "Required": false, - "Type": "DataSourceToIndexFieldMappingList", + "Type": "List", "UpdateType": "Mutable" }, "IncludeAttachmentFilePatterns": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowknowledgearticleconfiguration.html#cfn-kendra-datasource-servicenowknowledgearticleconfiguration-includeattachmentfilepatterns", + "PrimitiveItemType": "String", "Required": false, - "Type": "DataSourceInclusionsExclusionsStrings", + "Type": "List", "UpdateType": "Mutable" } } @@ -32803,20 +34324,23 @@ }, "ExcludeAttachmentFilePatterns": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowservicecatalogconfiguration.html#cfn-kendra-datasource-servicenowservicecatalogconfiguration-excludeattachmentfilepatterns", + "PrimitiveItemType": "String", "Required": false, - "Type": "DataSourceInclusionsExclusionsStrings", + "Type": "List", "UpdateType": "Mutable" }, "FieldMappings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowservicecatalogconfiguration.html#cfn-kendra-datasource-servicenowservicecatalogconfiguration-fieldmappings", + "ItemType": "DataSourceToIndexFieldMapping", "Required": false, - "Type": "DataSourceToIndexFieldMappingList", + "Type": "List", "UpdateType": "Mutable" }, "IncludeAttachmentFilePatterns": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowservicecatalogconfiguration.html#cfn-kendra-datasource-servicenowservicecatalogconfiguration-includeattachmentfilepatterns", + "PrimitiveItemType": "String", "Required": false, - "Type": "DataSourceInclusionsExclusionsStrings", + "Type": "List", "UpdateType": "Mutable" } } @@ -32844,20 +34368,23 @@ }, "ExclusionPatterns": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-sharepointconfiguration.html#cfn-kendra-datasource-sharepointconfiguration-exclusionpatterns", + "PrimitiveItemType": "String", "Required": false, - "Type": "DataSourceInclusionsExclusionsStrings", + "Type": "List", "UpdateType": "Mutable" }, "FieldMappings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-sharepointconfiguration.html#cfn-kendra-datasource-sharepointconfiguration-fieldmappings", + "ItemType": "DataSourceToIndexFieldMapping", "Required": false, - "Type": "DataSourceToIndexFieldMappingList", + "Type": "List", "UpdateType": "Mutable" }, "InclusionPatterns": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-sharepointconfiguration.html#cfn-kendra-datasource-sharepointconfiguration-inclusionpatterns", + "PrimitiveItemType": "String", "Required": false, - "Type": "DataSourceInclusionsExclusionsStrings", + "Type": "List", "UpdateType": "Mutable" }, "SecretArn": { @@ -33060,8 +34587,9 @@ }, "ValueImportanceItems": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-index-relevance.html#cfn-kendra-index-relevance-valueimportanceitems", + "ItemType": "ValueImportanceItem", "Required": false, - "Type": "ValueImportanceItems", + "Type": "List", "UpdateType": "Mutable" } } @@ -33140,18 +34668,6 @@ } } }, - "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": { @@ -36022,6 +37538,402 @@ } } }, + "AWS::LookoutMetrics::AnomalyDetector.AppFlowConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-appflowconfig.html", + "Properties": { + "FlowName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-appflowconfig.html#cfn-lookoutmetrics-anomalydetector-appflowconfig-flowname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-appflowconfig.html#cfn-lookoutmetrics-anomalydetector-appflowconfig-rolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::LookoutMetrics::AnomalyDetector.CloudwatchConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-cloudwatchconfig.html", + "Properties": { + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-cloudwatchconfig.html#cfn-lookoutmetrics-anomalydetector-cloudwatchconfig-rolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::LookoutMetrics::AnomalyDetector.CsvFormatDescriptor": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-csvformatdescriptor.html", + "Properties": { + "Charset": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-csvformatdescriptor.html#cfn-lookoutmetrics-anomalydetector-csvformatdescriptor-charset", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ContainsHeader": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-csvformatdescriptor.html#cfn-lookoutmetrics-anomalydetector-csvformatdescriptor-containsheader", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "Delimiter": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-csvformatdescriptor.html#cfn-lookoutmetrics-anomalydetector-csvformatdescriptor-delimiter", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "FileCompression": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-csvformatdescriptor.html#cfn-lookoutmetrics-anomalydetector-csvformatdescriptor-filecompression", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "HeaderList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-csvformatdescriptor.html#cfn-lookoutmetrics-anomalydetector-csvformatdescriptor-headerlist", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "QuoteSymbol": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-csvformatdescriptor.html#cfn-lookoutmetrics-anomalydetector-csvformatdescriptor-quotesymbol", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::LookoutMetrics::AnomalyDetector.FileFormatDescriptor": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-fileformatdescriptor.html", + "Properties": { + "CsvFormatDescriptor": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-fileformatdescriptor.html#cfn-lookoutmetrics-anomalydetector-fileformatdescriptor-csvformatdescriptor", + "Required": false, + "Type": "CsvFormatDescriptor", + "UpdateType": "Mutable" + }, + "JsonFormatDescriptor": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-fileformatdescriptor.html#cfn-lookoutmetrics-anomalydetector-fileformatdescriptor-jsonformatdescriptor", + "Required": false, + "Type": "JsonFormatDescriptor", + "UpdateType": "Mutable" + } + } + }, + "AWS::LookoutMetrics::AnomalyDetector.JsonFormatDescriptor": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-jsonformatdescriptor.html", + "Properties": { + "Charset": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-jsonformatdescriptor.html#cfn-lookoutmetrics-anomalydetector-jsonformatdescriptor-charset", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "FileCompression": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-jsonformatdescriptor.html#cfn-lookoutmetrics-anomalydetector-jsonformatdescriptor-filecompression", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::LookoutMetrics::AnomalyDetector.Metric": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-metric.html", + "Properties": { + "AggregationFunction": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-metric.html#cfn-lookoutmetrics-anomalydetector-metric-aggregationfunction", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "MetricName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-metric.html#cfn-lookoutmetrics-anomalydetector-metric-metricname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Namespace": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-metric.html#cfn-lookoutmetrics-anomalydetector-metric-namespace", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::LookoutMetrics::AnomalyDetector.MetricSet": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-metricset.html", + "Properties": { + "DimensionList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-metricset.html#cfn-lookoutmetrics-anomalydetector-metricset-dimensionlist", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "MetricList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-metricset.html#cfn-lookoutmetrics-anomalydetector-metricset-metriclist", + "ItemType": "Metric", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "MetricSetDescription": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-metricset.html#cfn-lookoutmetrics-anomalydetector-metricset-metricsetdescription", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "MetricSetFrequency": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-metricset.html#cfn-lookoutmetrics-anomalydetector-metricset-metricsetfrequency", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "MetricSetName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-metricset.html#cfn-lookoutmetrics-anomalydetector-metricset-metricsetname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "MetricSource": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-metricset.html#cfn-lookoutmetrics-anomalydetector-metricset-metricsource", + "Required": true, + "Type": "MetricSource", + "UpdateType": "Mutable" + }, + "Offset": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-metricset.html#cfn-lookoutmetrics-anomalydetector-metricset-offset", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "TimestampColumn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-metricset.html#cfn-lookoutmetrics-anomalydetector-metricset-timestampcolumn", + "Required": false, + "Type": "TimestampColumn", + "UpdateType": "Mutable" + }, + "Timezone": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-metricset.html#cfn-lookoutmetrics-anomalydetector-metricset-timezone", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::LookoutMetrics::AnomalyDetector.MetricSource": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-metricsource.html", + "Properties": { + "AppFlowConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-metricsource.html#cfn-lookoutmetrics-anomalydetector-metricsource-appflowconfig", + "Required": false, + "Type": "AppFlowConfig", + "UpdateType": "Mutable" + }, + "CloudwatchConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-metricsource.html#cfn-lookoutmetrics-anomalydetector-metricsource-cloudwatchconfig", + "Required": false, + "Type": "CloudwatchConfig", + "UpdateType": "Mutable" + }, + "RDSSourceConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-metricsource.html#cfn-lookoutmetrics-anomalydetector-metricsource-rdssourceconfig", + "Required": false, + "Type": "RDSSourceConfig", + "UpdateType": "Mutable" + }, + "RedshiftSourceConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-metricsource.html#cfn-lookoutmetrics-anomalydetector-metricsource-redshiftsourceconfig", + "Required": false, + "Type": "RedshiftSourceConfig", + "UpdateType": "Mutable" + }, + "S3SourceConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-metricsource.html#cfn-lookoutmetrics-anomalydetector-metricsource-s3sourceconfig", + "Required": false, + "Type": "S3SourceConfig", + "UpdateType": "Mutable" + } + } + }, + "AWS::LookoutMetrics::AnomalyDetector.RDSSourceConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-rdssourceconfig.html", + "Properties": { + "DBInstanceIdentifier": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-rdssourceconfig.html#cfn-lookoutmetrics-anomalydetector-rdssourceconfig-dbinstanceidentifier", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "DatabaseHost": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-rdssourceconfig.html#cfn-lookoutmetrics-anomalydetector-rdssourceconfig-databasehost", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "DatabaseName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-rdssourceconfig.html#cfn-lookoutmetrics-anomalydetector-rdssourceconfig-databasename", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "DatabasePort": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-rdssourceconfig.html#cfn-lookoutmetrics-anomalydetector-rdssourceconfig-databaseport", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + }, + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-rdssourceconfig.html#cfn-lookoutmetrics-anomalydetector-rdssourceconfig-rolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "SecretManagerArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-rdssourceconfig.html#cfn-lookoutmetrics-anomalydetector-rdssourceconfig-secretmanagerarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "TableName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-rdssourceconfig.html#cfn-lookoutmetrics-anomalydetector-rdssourceconfig-tablename", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "VpcConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-rdssourceconfig.html#cfn-lookoutmetrics-anomalydetector-rdssourceconfig-vpcconfiguration", + "Required": true, + "Type": "VpcConfiguration", + "UpdateType": "Mutable" + } + } + }, + "AWS::LookoutMetrics::AnomalyDetector.RedshiftSourceConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-redshiftsourceconfig.html", + "Properties": { + "ClusterIdentifier": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-redshiftsourceconfig.html#cfn-lookoutmetrics-anomalydetector-redshiftsourceconfig-clusteridentifier", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "DatabaseHost": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-redshiftsourceconfig.html#cfn-lookoutmetrics-anomalydetector-redshiftsourceconfig-databasehost", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "DatabaseName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-redshiftsourceconfig.html#cfn-lookoutmetrics-anomalydetector-redshiftsourceconfig-databasename", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "DatabasePort": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-redshiftsourceconfig.html#cfn-lookoutmetrics-anomalydetector-redshiftsourceconfig-databaseport", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + }, + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-redshiftsourceconfig.html#cfn-lookoutmetrics-anomalydetector-redshiftsourceconfig-rolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "SecretManagerArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-redshiftsourceconfig.html#cfn-lookoutmetrics-anomalydetector-redshiftsourceconfig-secretmanagerarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "TableName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-redshiftsourceconfig.html#cfn-lookoutmetrics-anomalydetector-redshiftsourceconfig-tablename", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "VpcConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-redshiftsourceconfig.html#cfn-lookoutmetrics-anomalydetector-redshiftsourceconfig-vpcconfiguration", + "Required": true, + "Type": "VpcConfiguration", + "UpdateType": "Mutable" + } + } + }, + "AWS::LookoutMetrics::AnomalyDetector.S3SourceConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-s3sourceconfig.html", + "Properties": { + "FileFormatDescriptor": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-s3sourceconfig.html#cfn-lookoutmetrics-anomalydetector-s3sourceconfig-fileformatdescriptor", + "Required": true, + "Type": "FileFormatDescriptor", + "UpdateType": "Mutable" + }, + "HistoricalDataPathList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-s3sourceconfig.html#cfn-lookoutmetrics-anomalydetector-s3sourceconfig-historicaldatapathlist", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-s3sourceconfig.html#cfn-lookoutmetrics-anomalydetector-s3sourceconfig-rolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "TemplatedPathList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-s3sourceconfig.html#cfn-lookoutmetrics-anomalydetector-s3sourceconfig-templatedpathlist", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::LookoutMetrics::AnomalyDetector.TimestampColumn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-timestampcolumn.html", + "Properties": { + "ColumnFormat": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-timestampcolumn.html#cfn-lookoutmetrics-anomalydetector-timestampcolumn-columnformat", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ColumnName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-timestampcolumn.html#cfn-lookoutmetrics-anomalydetector-timestampcolumn-columnname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::LookoutMetrics::AnomalyDetector.VpcConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-vpcconfiguration.html", + "Properties": { + "SecurityGroupIdList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-vpcconfiguration.html#cfn-lookoutmetrics-anomalydetector-vpcconfiguration-securitygroupidlist", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "SubnetIdList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lookoutmetrics-anomalydetector-vpcconfiguration.html#cfn-lookoutmetrics-anomalydetector-vpcconfiguration-subnetidlist", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::MSK::Cluster.BrokerLogs": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-brokerlogs.html", "Properties": { @@ -36335,9 +38247,6 @@ } } }, - "AWS::MWAA::Environment.AirflowConfigurationOptions": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mwaa-environment-airflowconfigurationoptions.html" - }, "AWS::MWAA::Environment.LoggingConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mwaa-environment-loggingconfiguration.html", "Properties": { @@ -37082,6 +38991,17 @@ } } }, + "AWS::MediaLive::Channel.ArchiveCdnSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-archivecdnsettings.html", + "Properties": { + "ArchiveS3Settings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-archivecdnsettings.html#cfn-medialive-channel-archivecdnsettings-archives3settings", + "Required": false, + "Type": "ArchiveS3Settings", + "UpdateType": "Mutable" + } + } + }, "AWS::MediaLive::Channel.ArchiveContainerSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-archivecontainersettings.html", "Properties": { @@ -37102,6 +39022,12 @@ "AWS::MediaLive::Channel.ArchiveGroupSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-archivegroupsettings.html", "Properties": { + "ArchiveCdnSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-archivegroupsettings.html#cfn-medialive-channel-archivegroupsettings-archivecdnsettings", + "Required": false, + "Type": "ArchiveCdnSettings", + "UpdateType": "Mutable" + }, "Destination": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-archivegroupsettings.html#cfn-medialive-channel-archivegroupsettings-destination", "Required": false, @@ -37139,6 +39065,17 @@ } } }, + "AWS::MediaLive::Channel.ArchiveS3Settings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-archives3settings.html", + "Properties": { + "CannedAcl": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-archives3settings.html#cfn-medialive-channel-archives3settings-cannedacl", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::MediaLive::Channel.AribDestinationSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-aribdestinationsettings.html", "Properties": {} @@ -37789,6 +39726,35 @@ } } }, + "AWS::MediaLive::Channel.CaptionRectangle": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-captionrectangle.html", + "Properties": { + "Height": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-captionrectangle.html#cfn-medialive-channel-captionrectangle-height", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + }, + "LeftOffset": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-captionrectangle.html#cfn-medialive-channel-captionrectangle-leftoffset", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + }, + "TopOffset": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-captionrectangle.html#cfn-medialive-channel-captionrectangle-topoffset", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + }, + "Width": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-captionrectangle.html#cfn-medialive-channel-captionrectangle-width", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::MediaLive::Channel.CaptionSelector": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-captionselector.html", "Properties": { @@ -38183,6 +40149,12 @@ "AWS::MediaLive::Channel.EbuTtDDestinationSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-ebuttddestinationsettings.html", "Properties": { + "CopyrightHolder": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-ebuttddestinationsettings.html#cfn-medialive-channel-ebuttddestinationsettings-copyrightholder", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "FillLineGap": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-ebuttddestinationsettings.html#cfn-medialive-channel-ebuttddestinationsettings-filllinegap", "PrimitiveType": "String", @@ -38287,6 +40259,12 @@ "Type": "GlobalConfiguration", "UpdateType": "Mutable" }, + "MotionGraphicsConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-encodersettings.html#cfn-medialive-channel-encodersettings-motiongraphicsconfiguration", + "Required": false, + "Type": "MotionGraphicsConfiguration", + "UpdateType": "Mutable" + }, "NielsenConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-encodersettings.html#cfn-medialive-channel-encodersettings-nielsenconfiguration", "Required": false, @@ -38406,6 +40384,17 @@ } } }, + "AWS::MediaLive::Channel.FrameCaptureCdnSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-framecapturecdnsettings.html", + "Properties": { + "FrameCaptureS3Settings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-framecapturecdnsettings.html#cfn-medialive-channel-framecapturecdnsettings-framecaptures3settings", + "Required": false, + "Type": "FrameCaptureS3Settings", + "UpdateType": "Mutable" + } + } + }, "AWS::MediaLive::Channel.FrameCaptureGroupSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-framecapturegroupsettings.html", "Properties": { @@ -38414,9 +40403,19 @@ "Required": false, "Type": "OutputLocationRef", "UpdateType": "Mutable" + }, + "FrameCaptureCdnSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-framecapturegroupsettings.html#cfn-medialive-channel-framecapturegroupsettings-framecapturecdnsettings", + "Required": false, + "Type": "FrameCaptureCdnSettings", + "UpdateType": "Mutable" } } }, + "AWS::MediaLive::Channel.FrameCaptureHlsSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-framecapturehlssettings.html", + "Properties": {} + }, "AWS::MediaLive::Channel.FrameCaptureOutputSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-framecaptureoutputsettings.html", "Properties": { @@ -38428,6 +40427,17 @@ } } }, + "AWS::MediaLive::Channel.FrameCaptureS3Settings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-framecaptures3settings.html", + "Properties": { + "CannedAcl": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-framecaptures3settings.html#cfn-medialive-channel-framecaptures3settings-cannedacl", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::MediaLive::Channel.FrameCaptureSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-framecapturesettings.html", "Properties": { @@ -39104,6 +41114,12 @@ "Type": "HlsMediaStoreSettings", "UpdateType": "Mutable" }, + "HlsS3Settings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-hlscdnsettings.html#cfn-medialive-channel-hlscdnsettings-hlss3settings", + "Required": false, + "Type": "HlsS3Settings", + "UpdateType": "Mutable" + }, "HlsWebdavSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-hlscdnsettings.html#cfn-medialive-channel-hlscdnsettings-hlswebdavsettings", "Required": false, @@ -39464,6 +41480,17 @@ } } }, + "AWS::MediaLive::Channel.HlsS3Settings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-hlss3settings.html", + "Properties": { + "CannedAcl": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-hlss3settings.html#cfn-medialive-channel-hlss3settings-cannedacl", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::MediaLive::Channel.HlsSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-hlssettings.html", "Properties": { @@ -39479,6 +41506,12 @@ "Type": "Fmp4HlsSettings", "UpdateType": "Mutable" }, + "FrameCaptureHlsSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-hlssettings.html#cfn-medialive-channel-hlssettings-framecapturehlssettings", + "Required": false, + "Type": "FrameCaptureHlsSettings", + "UpdateType": "Mutable" + }, "StandardHlsSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-hlssettings.html#cfn-medialive-channel-hlssettings-standardhlssettings", "Required": false, @@ -39522,6 +41555,10 @@ } } }, + "AWS::MediaLive::Channel.HtmlMotionGraphicsSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-htmlmotiongraphicssettings.html", + "Properties": {} + }, "AWS::MediaLive::Channel.InputAttachment": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-inputattachment.html", "Properties": { @@ -40158,6 +42195,34 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-mediapackageoutputsettings.html", "Properties": {} }, + "AWS::MediaLive::Channel.MotionGraphicsConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-motiongraphicsconfiguration.html", + "Properties": { + "MotionGraphicsInsertion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-motiongraphicsconfiguration.html#cfn-medialive-channel-motiongraphicsconfiguration-motiongraphicsinsertion", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "MotionGraphicsSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-motiongraphicsconfiguration.html#cfn-medialive-channel-motiongraphicsconfiguration-motiongraphicssettings", + "Required": false, + "Type": "MotionGraphicsSettings", + "UpdateType": "Mutable" + } + } + }, + "AWS::MediaLive::Channel.MotionGraphicsSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-motiongraphicssettings.html", + "Properties": { + "HtmlMotionGraphicsSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-motiongraphicssettings.html#cfn-medialive-channel-motiongraphicssettings-htmlmotiongraphicssettings", + "Required": false, + "Type": "HtmlMotionGraphicsSettings", + "UpdateType": "Mutable" + } + } + }, "AWS::MediaLive::Channel.Mp2Settings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-mp2settings.html", "Properties": { @@ -40981,6 +43046,12 @@ "AWS::MediaLive::Channel.TeletextSourceSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-teletextsourcesettings.html", "Properties": { + "OutputRectangle": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-teletextsourcesettings.html#cfn-medialive-channel-teletextsourcesettings-outputrectangle", + "Required": false, + "Type": "CaptionRectangle", + "UpdateType": "Mutable" + }, "PageNumber": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-teletextsourcesettings.html#cfn-medialive-channel-teletextsourcesettings-pagenumber", "PrimitiveType": "String", @@ -41199,6 +43270,12 @@ "Required": false, "UpdateType": "Mutable" }, + "ColorSpaceSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-videoselector.html#cfn-medialive-channel-videoselector-colorspacesettings", + "Required": false, + "Type": "VideoSelectorColorSpaceSettings", + "UpdateType": "Mutable" + }, "ColorSpaceUsage": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-videoselector.html#cfn-medialive-channel-videoselector-colorspaceusage", "PrimitiveType": "String", @@ -41213,6 +43290,17 @@ } } }, + "AWS::MediaLive::Channel.VideoSelectorColorSpaceSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-videoselectorcolorspacesettings.html", + "Properties": { + "Hdr10Settings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-videoselectorcolorspacesettings.html#cfn-medialive-channel-videoselectorcolorspacesettings-hdr10settings", + "Required": false, + "Type": "Hdr10Settings", + "UpdateType": "Mutable" + } + } + }, "AWS::MediaLive::Channel.VideoSelectorPid": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-medialive-channel-videoselectorpid.html", "Properties": { @@ -42933,6 +45021,233 @@ } } }, + "AWS::NimbleStudio::LaunchProfile.StreamConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-launchprofile-streamconfiguration.html", + "Properties": { + "ClipboardMode": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-launchprofile-streamconfiguration.html#cfn-nimblestudio-launchprofile-streamconfiguration-clipboardmode", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Ec2InstanceTypes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-launchprofile-streamconfiguration.html#cfn-nimblestudio-launchprofile-streamconfiguration-ec2instancetypes", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "MaxSessionLengthInMinutes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-launchprofile-streamconfiguration.html#cfn-nimblestudio-launchprofile-streamconfiguration-maxsessionlengthinminutes", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + }, + "StreamingImageIds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-launchprofile-streamconfiguration.html#cfn-nimblestudio-launchprofile-streamconfiguration-streamingimageids", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::NimbleStudio::Studio.StudioEncryptionConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studio-studioencryptionconfiguration.html", + "Properties": { + "KeyArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studio-studioencryptionconfiguration.html#cfn-nimblestudio-studio-studioencryptionconfiguration-keyarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "KeyType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studio-studioencryptionconfiguration.html#cfn-nimblestudio-studio-studioencryptionconfiguration-keytype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::NimbleStudio::StudioComponent.ActiveDirectoryComputerAttribute": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-activedirectorycomputerattribute.html", + "Properties": { + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-activedirectorycomputerattribute.html#cfn-nimblestudio-studiocomponent-activedirectorycomputerattribute-name", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-activedirectorycomputerattribute.html#cfn-nimblestudio-studiocomponent-activedirectorycomputerattribute-value", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::NimbleStudio::StudioComponent.ActiveDirectoryConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-activedirectoryconfiguration.html", + "Properties": { + "ComputerAttributes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-activedirectoryconfiguration.html#cfn-nimblestudio-studiocomponent-activedirectoryconfiguration-computerattributes", + "ItemType": "ActiveDirectoryComputerAttribute", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "DirectoryId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-activedirectoryconfiguration.html#cfn-nimblestudio-studiocomponent-activedirectoryconfiguration-directoryid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "OrganizationalUnitDistinguishedName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-activedirectoryconfiguration.html#cfn-nimblestudio-studiocomponent-activedirectoryconfiguration-organizationalunitdistinguishedname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::NimbleStudio::StudioComponent.ComputeFarmConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-computefarmconfiguration.html", + "Properties": { + "ActiveDirectoryUser": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-computefarmconfiguration.html#cfn-nimblestudio-studiocomponent-computefarmconfiguration-activedirectoryuser", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Endpoint": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-computefarmconfiguration.html#cfn-nimblestudio-studiocomponent-computefarmconfiguration-endpoint", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::NimbleStudio::StudioComponent.LicenseServiceConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-licenseserviceconfiguration.html", + "Properties": { + "Endpoint": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-licenseserviceconfiguration.html#cfn-nimblestudio-studiocomponent-licenseserviceconfiguration-endpoint", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::NimbleStudio::StudioComponent.ScriptParameterKeyValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-scriptparameterkeyvalue.html", + "Properties": { + "Key": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-scriptparameterkeyvalue.html#cfn-nimblestudio-studiocomponent-scriptparameterkeyvalue-key", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-scriptparameterkeyvalue.html#cfn-nimblestudio-studiocomponent-scriptparameterkeyvalue-value", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::NimbleStudio::StudioComponent.SharedFileSystemConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-sharedfilesystemconfiguration.html", + "Properties": { + "Endpoint": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-sharedfilesystemconfiguration.html#cfn-nimblestudio-studiocomponent-sharedfilesystemconfiguration-endpoint", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "FileSystemId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-sharedfilesystemconfiguration.html#cfn-nimblestudio-studiocomponent-sharedfilesystemconfiguration-filesystemid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "LinuxMountPoint": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-sharedfilesystemconfiguration.html#cfn-nimblestudio-studiocomponent-sharedfilesystemconfiguration-linuxmountpoint", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ShareName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-sharedfilesystemconfiguration.html#cfn-nimblestudio-studiocomponent-sharedfilesystemconfiguration-sharename", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "WindowsMountDrive": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-sharedfilesystemconfiguration.html#cfn-nimblestudio-studiocomponent-sharedfilesystemconfiguration-windowsmountdrive", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::NimbleStudio::StudioComponent.StudioComponentConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-studiocomponentconfiguration.html", + "Properties": { + "ActiveDirectoryConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-studiocomponentconfiguration.html#cfn-nimblestudio-studiocomponent-studiocomponentconfiguration-activedirectoryconfiguration", + "Required": false, + "Type": "ActiveDirectoryConfiguration", + "UpdateType": "Mutable" + }, + "ComputeFarmConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-studiocomponentconfiguration.html#cfn-nimblestudio-studiocomponent-studiocomponentconfiguration-computefarmconfiguration", + "Required": false, + "Type": "ComputeFarmConfiguration", + "UpdateType": "Mutable" + }, + "LicenseServiceConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-studiocomponentconfiguration.html#cfn-nimblestudio-studiocomponent-studiocomponentconfiguration-licenseserviceconfiguration", + "Required": false, + "Type": "LicenseServiceConfiguration", + "UpdateType": "Mutable" + }, + "SharedFileSystemConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-studiocomponentconfiguration.html#cfn-nimblestudio-studiocomponent-studiocomponentconfiguration-sharedfilesystemconfiguration", + "Required": false, + "Type": "SharedFileSystemConfiguration", + "UpdateType": "Mutable" + } + } + }, + "AWS::NimbleStudio::StudioComponent.StudioComponentInitializationScript": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-studiocomponentinitializationscript.html", + "Properties": { + "LaunchProfileProtocolVersion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-studiocomponentinitializationscript.html#cfn-nimblestudio-studiocomponent-studiocomponentinitializationscript-launchprofileprotocolversion", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Platform": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-studiocomponentinitializationscript.html#cfn-nimblestudio-studiocomponent-studiocomponentinitializationscript-platform", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "RunContext": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-studiocomponentinitializationscript.html#cfn-nimblestudio-studiocomponent-studiocomponentinitializationscript-runcontext", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Script": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-nimblestudio-studiocomponent-studiocomponentinitializationscript.html#cfn-nimblestudio-studiocomponent-studiocomponentinitializationscript-script", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::OpsWorks::App.DataSource": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opsworks-app-datasource.html", "Properties": { @@ -45056,6 +47371,1144 @@ } } }, + "AWS::QuickSight::DataSet.CalculatedColumn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-calculatedcolumn.html", + "Properties": { + "ColumnId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-calculatedcolumn.html#cfn-quicksight-dataset-calculatedcolumn-columnid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ColumnName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-calculatedcolumn.html#cfn-quicksight-dataset-calculatedcolumn-columnname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Expression": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-calculatedcolumn.html#cfn-quicksight-dataset-calculatedcolumn-expression", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.CastColumnTypeOperation": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-castcolumntypeoperation.html", + "Properties": { + "ColumnName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-castcolumntypeoperation.html#cfn-quicksight-dataset-castcolumntypeoperation-columnname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Format": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-castcolumntypeoperation.html#cfn-quicksight-dataset-castcolumntypeoperation-format", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "NewColumnType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-castcolumntypeoperation.html#cfn-quicksight-dataset-castcolumntypeoperation-newcolumntype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.ColumnDescription": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-columndescription.html", + "Properties": { + "Text": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-columndescription.html#cfn-quicksight-dataset-columndescription-text", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.ColumnGroup": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-columngroup.html", + "Properties": { + "GeoSpatialColumnGroup": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-columngroup.html#cfn-quicksight-dataset-columngroup-geospatialcolumngroup", + "Required": false, + "Type": "GeoSpatialColumnGroup", + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.ColumnLevelPermissionRule": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-columnlevelpermissionrule.html", + "Properties": { + "ColumnNames": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-columnlevelpermissionrule.html#cfn-quicksight-dataset-columnlevelpermissionrule-columnnames", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Principals": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-columnlevelpermissionrule.html#cfn-quicksight-dataset-columnlevelpermissionrule-principals", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.ColumnTag": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-columntag.html", + "Properties": { + "ColumnDescription": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-columntag.html#cfn-quicksight-dataset-columntag-columndescription", + "Required": false, + "Type": "ColumnDescription", + "UpdateType": "Mutable" + }, + "ColumnGeographicRole": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-columntag.html#cfn-quicksight-dataset-columntag-columngeographicrole", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.CreateColumnsOperation": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-createcolumnsoperation.html", + "Properties": { + "Columns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-createcolumnsoperation.html#cfn-quicksight-dataset-createcolumnsoperation-columns", + "ItemType": "CalculatedColumn", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.CustomSql": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-customsql.html", + "Properties": { + "Columns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-customsql.html#cfn-quicksight-dataset-customsql-columns", + "ItemType": "InputColumn", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "DataSourceArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-customsql.html#cfn-quicksight-dataset-customsql-datasourcearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-customsql.html#cfn-quicksight-dataset-customsql-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "SqlQuery": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-customsql.html#cfn-quicksight-dataset-customsql-sqlquery", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.FieldFolder": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-fieldfolder.html", + "Properties": { + "Columns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-fieldfolder.html#cfn-quicksight-dataset-fieldfolder-columns", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-fieldfolder.html#cfn-quicksight-dataset-fieldfolder-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.FilterOperation": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-filteroperation.html", + "Properties": { + "ConditionExpression": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-filteroperation.html#cfn-quicksight-dataset-filteroperation-conditionexpression", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.GeoSpatialColumnGroup": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-geospatialcolumngroup.html", + "Properties": { + "Columns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-geospatialcolumngroup.html#cfn-quicksight-dataset-geospatialcolumngroup-columns", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "CountryCode": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-geospatialcolumngroup.html#cfn-quicksight-dataset-geospatialcolumngroup-countrycode", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-geospatialcolumngroup.html#cfn-quicksight-dataset-geospatialcolumngroup-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.IngestionWaitPolicy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-ingestionwaitpolicy.html", + "Properties": { + "IngestionWaitTimeInHours": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-ingestionwaitpolicy.html#cfn-quicksight-dataset-ingestionwaitpolicy-ingestionwaittimeinhours", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + }, + "WaitForSpiceIngestion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-ingestionwaitpolicy.html#cfn-quicksight-dataset-ingestionwaitpolicy-waitforspiceingestion", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.InputColumn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-inputcolumn.html", + "Properties": { + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-inputcolumn.html#cfn-quicksight-dataset-inputcolumn-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-inputcolumn.html#cfn-quicksight-dataset-inputcolumn-type", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.JoinInstruction": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-joininstruction.html", + "Properties": { + "LeftJoinKeyProperties": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-joininstruction.html#cfn-quicksight-dataset-joininstruction-leftjoinkeyproperties", + "Required": false, + "Type": "JoinKeyProperties", + "UpdateType": "Mutable" + }, + "LeftOperand": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-joininstruction.html#cfn-quicksight-dataset-joininstruction-leftoperand", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "OnClause": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-joininstruction.html#cfn-quicksight-dataset-joininstruction-onclause", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "RightJoinKeyProperties": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-joininstruction.html#cfn-quicksight-dataset-joininstruction-rightjoinkeyproperties", + "Required": false, + "Type": "JoinKeyProperties", + "UpdateType": "Mutable" + }, + "RightOperand": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-joininstruction.html#cfn-quicksight-dataset-joininstruction-rightoperand", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-joininstruction.html#cfn-quicksight-dataset-joininstruction-type", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.JoinKeyProperties": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-joinkeyproperties.html", + "Properties": { + "UniqueKey": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-joinkeyproperties.html#cfn-quicksight-dataset-joinkeyproperties-uniquekey", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.LogicalTable": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-logicaltable.html", + "Properties": { + "Alias": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-logicaltable.html#cfn-quicksight-dataset-logicaltable-alias", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "DataTransforms": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-logicaltable.html#cfn-quicksight-dataset-logicaltable-datatransforms", + "ItemType": "TransformOperation", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Source": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-logicaltable.html#cfn-quicksight-dataset-logicaltable-source", + "Required": true, + "Type": "LogicalTableSource", + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.LogicalTableSource": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-logicaltablesource.html", + "Properties": { + "JoinInstruction": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-logicaltablesource.html#cfn-quicksight-dataset-logicaltablesource-joininstruction", + "Required": false, + "Type": "JoinInstruction", + "UpdateType": "Mutable" + }, + "PhysicalTableId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-logicaltablesource.html#cfn-quicksight-dataset-logicaltablesource-physicaltableid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.OutputColumn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-outputcolumn.html", + "Properties": { + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-outputcolumn.html#cfn-quicksight-dataset-outputcolumn-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-outputcolumn.html#cfn-quicksight-dataset-outputcolumn-name", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-outputcolumn.html#cfn-quicksight-dataset-outputcolumn-type", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.PhysicalTable": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-physicaltable.html", + "Properties": { + "CustomSql": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-physicaltable.html#cfn-quicksight-dataset-physicaltable-customsql", + "Required": false, + "Type": "CustomSql", + "UpdateType": "Mutable" + }, + "RelationalTable": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-physicaltable.html#cfn-quicksight-dataset-physicaltable-relationaltable", + "Required": false, + "Type": "RelationalTable", + "UpdateType": "Mutable" + }, + "S3Source": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-physicaltable.html#cfn-quicksight-dataset-physicaltable-s3source", + "Required": false, + "Type": "S3Source", + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.ProjectOperation": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-projectoperation.html", + "Properties": { + "ProjectedColumns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-projectoperation.html#cfn-quicksight-dataset-projectoperation-projectedcolumns", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.RelationalTable": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-relationaltable.html", + "Properties": { + "Catalog": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-relationaltable.html#cfn-quicksight-dataset-relationaltable-catalog", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "DataSourceArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-relationaltable.html#cfn-quicksight-dataset-relationaltable-datasourcearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "InputColumns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-relationaltable.html#cfn-quicksight-dataset-relationaltable-inputcolumns", + "ItemType": "InputColumn", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-relationaltable.html#cfn-quicksight-dataset-relationaltable-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Schema": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-relationaltable.html#cfn-quicksight-dataset-relationaltable-schema", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.RenameColumnOperation": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-renamecolumnoperation.html", + "Properties": { + "ColumnName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-renamecolumnoperation.html#cfn-quicksight-dataset-renamecolumnoperation-columnname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "NewColumnName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-renamecolumnoperation.html#cfn-quicksight-dataset-renamecolumnoperation-newcolumnname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.ResourcePermission": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-resourcepermission.html", + "Properties": { + "Actions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-resourcepermission.html#cfn-quicksight-dataset-resourcepermission-actions", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "Principal": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-resourcepermission.html#cfn-quicksight-dataset-resourcepermission-principal", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.RowLevelPermissionDataSet": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-rowlevelpermissiondataset.html", + "Properties": { + "Arn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-rowlevelpermissiondataset.html#cfn-quicksight-dataset-rowlevelpermissiondataset-arn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Namespace": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-rowlevelpermissiondataset.html#cfn-quicksight-dataset-rowlevelpermissiondataset-namespace", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "PermissionPolicy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-rowlevelpermissiondataset.html#cfn-quicksight-dataset-rowlevelpermissiondataset-permissionpolicy", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.S3Source": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-s3source.html", + "Properties": { + "DataSourceArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-s3source.html#cfn-quicksight-dataset-s3source-datasourcearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "InputColumns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-s3source.html#cfn-quicksight-dataset-s3source-inputcolumns", + "ItemType": "InputColumn", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "UploadSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-s3source.html#cfn-quicksight-dataset-s3source-uploadsettings", + "Required": false, + "Type": "UploadSettings", + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.TagColumnOperation": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-tagcolumnoperation.html", + "Properties": { + "ColumnName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-tagcolumnoperation.html#cfn-quicksight-dataset-tagcolumnoperation-columnname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-tagcolumnoperation.html#cfn-quicksight-dataset-tagcolumnoperation-tags", + "ItemType": "ColumnTag", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.TransformOperation": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-transformoperation.html", + "Properties": { + "CastColumnTypeOperation": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-transformoperation.html#cfn-quicksight-dataset-transformoperation-castcolumntypeoperation", + "Required": false, + "Type": "CastColumnTypeOperation", + "UpdateType": "Mutable" + }, + "CreateColumnsOperation": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-transformoperation.html#cfn-quicksight-dataset-transformoperation-createcolumnsoperation", + "Required": false, + "Type": "CreateColumnsOperation", + "UpdateType": "Mutable" + }, + "FilterOperation": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-transformoperation.html#cfn-quicksight-dataset-transformoperation-filteroperation", + "Required": false, + "Type": "FilterOperation", + "UpdateType": "Mutable" + }, + "ProjectOperation": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-transformoperation.html#cfn-quicksight-dataset-transformoperation-projectoperation", + "Required": false, + "Type": "ProjectOperation", + "UpdateType": "Mutable" + }, + "RenameColumnOperation": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-transformoperation.html#cfn-quicksight-dataset-transformoperation-renamecolumnoperation", + "Required": false, + "Type": "RenameColumnOperation", + "UpdateType": "Mutable" + }, + "TagColumnOperation": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-transformoperation.html#cfn-quicksight-dataset-transformoperation-tagcolumnoperation", + "Required": false, + "Type": "TagColumnOperation", + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSet.UploadSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-uploadsettings.html", + "Properties": { + "ContainsHeader": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-uploadsettings.html#cfn-quicksight-dataset-uploadsettings-containsheader", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "Delimiter": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-uploadsettings.html#cfn-quicksight-dataset-uploadsettings-delimiter", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Format": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-uploadsettings.html#cfn-quicksight-dataset-uploadsettings-format", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "StartFromRow": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-uploadsettings.html#cfn-quicksight-dataset-uploadsettings-startfromrow", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + }, + "TextQualifier": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-dataset-uploadsettings.html#cfn-quicksight-dataset-uploadsettings-textqualifier", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSource.AmazonElasticsearchParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-amazonelasticsearchparameters.html", + "Properties": { + "Domain": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-amazonelasticsearchparameters.html#cfn-quicksight-datasource-amazonelasticsearchparameters-domain", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSource.AthenaParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-athenaparameters.html", + "Properties": { + "WorkGroup": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-athenaparameters.html#cfn-quicksight-datasource-athenaparameters-workgroup", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSource.AuroraParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-auroraparameters.html", + "Properties": { + "Database": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-auroraparameters.html#cfn-quicksight-datasource-auroraparameters-database", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Host": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-auroraparameters.html#cfn-quicksight-datasource-auroraparameters-host", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Port": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-auroraparameters.html#cfn-quicksight-datasource-auroraparameters-port", + "PrimitiveType": "Double", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSource.AuroraPostgreSqlParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-aurorapostgresqlparameters.html", + "Properties": { + "Database": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-aurorapostgresqlparameters.html#cfn-quicksight-datasource-aurorapostgresqlparameters-database", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Host": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-aurorapostgresqlparameters.html#cfn-quicksight-datasource-aurorapostgresqlparameters-host", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Port": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-aurorapostgresqlparameters.html#cfn-quicksight-datasource-aurorapostgresqlparameters-port", + "PrimitiveType": "Double", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSource.CredentialPair": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-credentialpair.html", + "Properties": { + "AlternateDataSourceParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-credentialpair.html#cfn-quicksight-datasource-credentialpair-alternatedatasourceparameters", + "ItemType": "DataSourceParameters", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Password": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-credentialpair.html#cfn-quicksight-datasource-credentialpair-password", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Username": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-credentialpair.html#cfn-quicksight-datasource-credentialpair-username", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSource.DataSourceCredentials": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-datasourcecredentials.html", + "Properties": { + "CopySourceArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-datasourcecredentials.html#cfn-quicksight-datasource-datasourcecredentials-copysourcearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "CredentialPair": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-datasourcecredentials.html#cfn-quicksight-datasource-datasourcecredentials-credentialpair", + "Required": false, + "Type": "CredentialPair", + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSource.DataSourceErrorInfo": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-datasourceerrorinfo.html", + "Properties": { + "Message": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-datasourceerrorinfo.html#cfn-quicksight-datasource-datasourceerrorinfo-message", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-datasourceerrorinfo.html#cfn-quicksight-datasource-datasourceerrorinfo-type", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSource.DataSourceParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-datasourceparameters.html", + "Properties": { + "AmazonElasticsearchParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-datasourceparameters.html#cfn-quicksight-datasource-datasourceparameters-amazonelasticsearchparameters", + "Required": false, + "Type": "AmazonElasticsearchParameters", + "UpdateType": "Mutable" + }, + "AthenaParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-datasourceparameters.html#cfn-quicksight-datasource-datasourceparameters-athenaparameters", + "Required": false, + "Type": "AthenaParameters", + "UpdateType": "Mutable" + }, + "AuroraParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-datasourceparameters.html#cfn-quicksight-datasource-datasourceparameters-auroraparameters", + "Required": false, + "Type": "AuroraParameters", + "UpdateType": "Mutable" + }, + "AuroraPostgreSqlParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-datasourceparameters.html#cfn-quicksight-datasource-datasourceparameters-aurorapostgresqlparameters", + "Required": false, + "Type": "AuroraPostgreSqlParameters", + "UpdateType": "Mutable" + }, + "MariaDbParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-datasourceparameters.html#cfn-quicksight-datasource-datasourceparameters-mariadbparameters", + "Required": false, + "Type": "MariaDbParameters", + "UpdateType": "Mutable" + }, + "MySqlParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-datasourceparameters.html#cfn-quicksight-datasource-datasourceparameters-mysqlparameters", + "Required": false, + "Type": "MySqlParameters", + "UpdateType": "Mutable" + }, + "OracleParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-datasourceparameters.html#cfn-quicksight-datasource-datasourceparameters-oracleparameters", + "Required": false, + "Type": "OracleParameters", + "UpdateType": "Mutable" + }, + "PostgreSqlParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-datasourceparameters.html#cfn-quicksight-datasource-datasourceparameters-postgresqlparameters", + "Required": false, + "Type": "PostgreSqlParameters", + "UpdateType": "Mutable" + }, + "PrestoParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-datasourceparameters.html#cfn-quicksight-datasource-datasourceparameters-prestoparameters", + "Required": false, + "Type": "PrestoParameters", + "UpdateType": "Mutable" + }, + "RdsParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-datasourceparameters.html#cfn-quicksight-datasource-datasourceparameters-rdsparameters", + "Required": false, + "Type": "RdsParameters", + "UpdateType": "Mutable" + }, + "RedshiftParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-datasourceparameters.html#cfn-quicksight-datasource-datasourceparameters-redshiftparameters", + "Required": false, + "Type": "RedshiftParameters", + "UpdateType": "Mutable" + }, + "S3Parameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-datasourceparameters.html#cfn-quicksight-datasource-datasourceparameters-s3parameters", + "Required": false, + "Type": "S3Parameters", + "UpdateType": "Mutable" + }, + "SnowflakeParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-datasourceparameters.html#cfn-quicksight-datasource-datasourceparameters-snowflakeparameters", + "Required": false, + "Type": "SnowflakeParameters", + "UpdateType": "Mutable" + }, + "SparkParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-datasourceparameters.html#cfn-quicksight-datasource-datasourceparameters-sparkparameters", + "Required": false, + "Type": "SparkParameters", + "UpdateType": "Mutable" + }, + "SqlServerParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-datasourceparameters.html#cfn-quicksight-datasource-datasourceparameters-sqlserverparameters", + "Required": false, + "Type": "SqlServerParameters", + "UpdateType": "Mutable" + }, + "TeradataParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-datasourceparameters.html#cfn-quicksight-datasource-datasourceparameters-teradataparameters", + "Required": false, + "Type": "TeradataParameters", + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSource.ManifestFileLocation": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-manifestfilelocation.html", + "Properties": { + "Bucket": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-manifestfilelocation.html#cfn-quicksight-datasource-manifestfilelocation-bucket", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Key": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-manifestfilelocation.html#cfn-quicksight-datasource-manifestfilelocation-key", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSource.MariaDbParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-mariadbparameters.html", + "Properties": { + "Database": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-mariadbparameters.html#cfn-quicksight-datasource-mariadbparameters-database", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Host": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-mariadbparameters.html#cfn-quicksight-datasource-mariadbparameters-host", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Port": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-mariadbparameters.html#cfn-quicksight-datasource-mariadbparameters-port", + "PrimitiveType": "Double", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSource.MySqlParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-mysqlparameters.html", + "Properties": { + "Database": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-mysqlparameters.html#cfn-quicksight-datasource-mysqlparameters-database", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Host": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-mysqlparameters.html#cfn-quicksight-datasource-mysqlparameters-host", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Port": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-mysqlparameters.html#cfn-quicksight-datasource-mysqlparameters-port", + "PrimitiveType": "Double", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSource.OracleParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-oracleparameters.html", + "Properties": { + "Database": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-oracleparameters.html#cfn-quicksight-datasource-oracleparameters-database", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Host": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-oracleparameters.html#cfn-quicksight-datasource-oracleparameters-host", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Port": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-oracleparameters.html#cfn-quicksight-datasource-oracleparameters-port", + "PrimitiveType": "Double", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSource.PostgreSqlParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-postgresqlparameters.html", + "Properties": { + "Database": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-postgresqlparameters.html#cfn-quicksight-datasource-postgresqlparameters-database", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Host": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-postgresqlparameters.html#cfn-quicksight-datasource-postgresqlparameters-host", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Port": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-postgresqlparameters.html#cfn-quicksight-datasource-postgresqlparameters-port", + "PrimitiveType": "Double", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSource.PrestoParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-prestoparameters.html", + "Properties": { + "Catalog": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-prestoparameters.html#cfn-quicksight-datasource-prestoparameters-catalog", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Host": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-prestoparameters.html#cfn-quicksight-datasource-prestoparameters-host", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Port": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-prestoparameters.html#cfn-quicksight-datasource-prestoparameters-port", + "PrimitiveType": "Double", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSource.RdsParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-rdsparameters.html", + "Properties": { + "Database": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-rdsparameters.html#cfn-quicksight-datasource-rdsparameters-database", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "InstanceId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-rdsparameters.html#cfn-quicksight-datasource-rdsparameters-instanceid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSource.RedshiftParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-redshiftparameters.html", + "Properties": { + "ClusterId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-redshiftparameters.html#cfn-quicksight-datasource-redshiftparameters-clusterid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Database": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-redshiftparameters.html#cfn-quicksight-datasource-redshiftparameters-database", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Host": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-redshiftparameters.html#cfn-quicksight-datasource-redshiftparameters-host", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Port": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-redshiftparameters.html#cfn-quicksight-datasource-redshiftparameters-port", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSource.ResourcePermission": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-resourcepermission.html", + "Properties": { + "Actions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-resourcepermission.html#cfn-quicksight-datasource-resourcepermission-actions", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "Principal": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-resourcepermission.html#cfn-quicksight-datasource-resourcepermission-principal", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSource.S3Parameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-s3parameters.html", + "Properties": { + "ManifestFileLocation": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-s3parameters.html#cfn-quicksight-datasource-s3parameters-manifestfilelocation", + "Required": true, + "Type": "ManifestFileLocation", + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSource.SnowflakeParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-snowflakeparameters.html", + "Properties": { + "Database": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-snowflakeparameters.html#cfn-quicksight-datasource-snowflakeparameters-database", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Host": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-snowflakeparameters.html#cfn-quicksight-datasource-snowflakeparameters-host", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Warehouse": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-snowflakeparameters.html#cfn-quicksight-datasource-snowflakeparameters-warehouse", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSource.SparkParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-sparkparameters.html", + "Properties": { + "Host": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-sparkparameters.html#cfn-quicksight-datasource-sparkparameters-host", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Port": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-sparkparameters.html#cfn-quicksight-datasource-sparkparameters-port", + "PrimitiveType": "Double", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSource.SqlServerParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-sqlserverparameters.html", + "Properties": { + "Database": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-sqlserverparameters.html#cfn-quicksight-datasource-sqlserverparameters-database", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Host": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-sqlserverparameters.html#cfn-quicksight-datasource-sqlserverparameters-host", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Port": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-sqlserverparameters.html#cfn-quicksight-datasource-sqlserverparameters-port", + "PrimitiveType": "Double", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSource.SslProperties": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-sslproperties.html", + "Properties": { + "DisableSsl": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-sslproperties.html#cfn-quicksight-datasource-sslproperties-disablessl", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSource.TeradataParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-teradataparameters.html", + "Properties": { + "Database": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-teradataparameters.html#cfn-quicksight-datasource-teradataparameters-database", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Host": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-teradataparameters.html#cfn-quicksight-datasource-teradataparameters-host", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Port": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-teradataparameters.html#cfn-quicksight-datasource-teradataparameters-port", + "PrimitiveType": "Double", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSource.VpcConnectionProperties": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-vpcconnectionproperties.html", + "Properties": { + "VpcConnectionArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-vpcconnectionproperties.html#cfn-quicksight-datasource-vpcconnectionproperties-vpcconnectionarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::QuickSight::Template.DataSetReference": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-template-datasetreference.html", "Properties": { @@ -45723,6 +49176,42 @@ } } }, + "AWS::ResourceGroups::Group.ConfigurationItem": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resourcegroups-group-configurationitem.html", + "Properties": { + "Parameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resourcegroups-group-configurationitem.html#cfn-resourcegroups-group-configurationitem-parameters", + "ItemType": "ConfigurationParameter", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resourcegroups-group-configurationitem.html#cfn-resourcegroups-group-configurationitem-type", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::ResourceGroups::Group.ConfigurationParameter": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resourcegroups-group-configurationparameter.html", + "Properties": { + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resourcegroups-group-configurationparameter.html#cfn-resourcegroups-group-configurationparameter-name", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Values": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resourcegroups-group-configurationparameter.html#cfn-resourcegroups-group-configurationparameter-values", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::ResourceGroups::Group.Query": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resourcegroups-group-query.html", "Properties": { @@ -46159,6 +49648,53 @@ } } }, + "AWS::Route53Resolver::FirewallRuleGroup.FirewallRule": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53resolver-firewallrulegroup-firewallrule.html", + "Properties": { + "Action": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53resolver-firewallrulegroup-firewallrule.html#cfn-route53resolver-firewallrulegroup-firewallrule-action", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "BlockOverrideDnsType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53resolver-firewallrulegroup-firewallrule.html#cfn-route53resolver-firewallrulegroup-firewallrule-blockoverridednstype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "BlockOverrideDomain": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53resolver-firewallrulegroup-firewallrule.html#cfn-route53resolver-firewallrulegroup-firewallrule-blockoverridedomain", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "BlockOverrideTtl": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53resolver-firewallrulegroup-firewallrule.html#cfn-route53resolver-firewallrulegroup-firewallrule-blockoverridettl", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "BlockResponse": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53resolver-firewallrulegroup-firewallrule.html#cfn-route53resolver-firewallrulegroup-firewallrule-blockresponse", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "FirewallDomainListId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53resolver-firewallrulegroup-firewallrule.html#cfn-route53resolver-firewallrulegroup-firewallrule-firewalldomainlistid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Priority": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53resolver-firewallrulegroup-firewallrule.html#cfn-route53resolver-firewallrulegroup-firewallrule-priority", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::Route53Resolver::ResolverEndpoint.IpAddressRequest": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53resolver-resolverendpoint-ipaddressrequest.html", "Properties": { @@ -47637,6 +51173,58 @@ } } }, + "AWS::S3ObjectLambda::AccessPoint.ObjectLambdaConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3objectlambda-accesspoint-objectlambdaconfiguration.html", + "Properties": { + "AllowedFeatures": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3objectlambda-accesspoint-objectlambdaconfiguration.html#cfn-s3objectlambda-accesspoint-objectlambdaconfiguration-allowedfeatures", + "DuplicatesAllowed": false, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "CloudWatchMetricsEnabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3objectlambda-accesspoint-objectlambdaconfiguration.html#cfn-s3objectlambda-accesspoint-objectlambdaconfiguration-cloudwatchmetricsenabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "SupportingAccessPoint": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3objectlambda-accesspoint-objectlambdaconfiguration.html#cfn-s3objectlambda-accesspoint-objectlambdaconfiguration-supportingaccesspoint", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "TransformationConfigurations": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3objectlambda-accesspoint-objectlambdaconfiguration.html#cfn-s3objectlambda-accesspoint-objectlambdaconfiguration-transformationconfigurations", + "DuplicatesAllowed": false, + "ItemType": "TransformationConfiguration", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::S3ObjectLambda::AccessPoint.TransformationConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3objectlambda-accesspoint-transformationconfiguration.html", + "Properties": { + "Actions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3objectlambda-accesspoint-transformationconfiguration.html#cfn-s3objectlambda-accesspoint-transformationconfiguration-actions", + "DuplicatesAllowed": false, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "ContentTransformation": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3objectlambda-accesspoint-transformationconfiguration.html#cfn-s3objectlambda-accesspoint-transformationconfiguration-contenttransformation", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::S3Outposts::AccessPoint.VpcConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3outposts-accesspoint-vpcconfiguration.html", "Properties": { @@ -47812,6 +51400,35 @@ } } }, + "AWS::SES::ContactList.Topic": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-contactlist-topic.html", + "Properties": { + "DefaultSubscriptionStatus": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-contactlist-topic.html#cfn-ses-contactlist-topic-defaultsubscriptionstatus", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-contactlist-topic.html#cfn-ses-contactlist-topic-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "DisplayName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-contactlist-topic.html#cfn-ses-contactlist-topic-displayname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "TopicName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-contactlist-topic.html#cfn-ses-contactlist-topic-topicname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::SES::ReceiptFilter.Filter": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ses-receiptfilter-filter.html", "Properties": { @@ -48148,18 +51765,6 @@ } } }, - "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": { @@ -48201,6 +51806,47 @@ } } }, + "AWS::SSM::Document.AttachmentsSource": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ssm-document-attachmentssource.html", + "Properties": { + "Key": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ssm-document-attachmentssource.html#cfn-ssm-document-attachmentssource-key", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ssm-document-attachmentssource.html#cfn-ssm-document-attachmentssource-name", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Values": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ssm-document-attachmentssource.html#cfn-ssm-document-attachmentssource-values", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + } + } + }, + "AWS::SSM::Document.DocumentRequires": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ssm-document-documentrequires.html", + "Properties": { + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ssm-document-documentrequires.html#cfn-ssm-document-documentrequires-name", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Version": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ssm-document-documentrequires.html#cfn-ssm-document-documentrequires-version", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, "AWS::SSM::MaintenanceWindowTarget.Targets": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ssm-maintenancewindowtarget-targets.html", "Properties": { @@ -48213,7 +51859,7 @@ "Values": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ssm-maintenancewindowtarget-targets.html#cfn-ssm-maintenancewindowtarget-targets-values", "PrimitiveItemType": "String", - "Required": false, + "Required": true, "Type": "List", "UpdateType": "Mutable" } @@ -48394,7 +52040,7 @@ "Values": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ssm-maintenancewindowtask-target.html#cfn-ssm-maintenancewindowtask-target-values", "PrimitiveItemType": "String", - "Required": false, + "Required": true, "Type": "List", "UpdateType": "Mutable" } @@ -48640,19 +52286,8 @@ "Properties": { "Source": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sso-instanceaccesscontrolattributeconfiguration-accesscontrolattributevalue.html#cfn-sso-instanceaccesscontrolattributeconfiguration-accesscontrolattributevalue-source", - "Required": true, - "Type": "AccessControlAttributeValueSourceList", - "UpdateType": "Mutable" - } - } - }, - "AWS::SSO::InstanceAccessControlAttributeConfiguration.AccessControlAttributeValueSourceList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sso-instanceaccesscontrolattributeconfiguration-accesscontrolattributevaluesourcelist.html", - "Properties": { - "AccessControlAttributeValueSourceList": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sso-instanceaccesscontrolattributeconfiguration-accesscontrolattributevaluesourcelist.html#cfn-sso-instanceaccesscontrolattributeconfiguration-accesscontrolattributevaluesourcelist-accesscontrolattributevaluesourcelist", "PrimitiveItemType": "String", - "Required": false, + "Required": true, "Type": "List", "UpdateType": "Mutable" } @@ -50614,18 +54249,6 @@ } } }, - "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": { @@ -50649,8 +54272,9 @@ }, "MonitoringInputs": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-monitoringschedule-monitoringjobdefinition.html#cfn-sagemaker-monitoringschedule-monitoringjobdefinition-monitoringinputs", + "ItemType": "MonitoringInput", "Required": true, - "Type": "MonitoringInputs", + "Type": "List", "UpdateType": "Mutable" }, "MonitoringOutputConfig": { @@ -51298,9 +54922,6 @@ } } }, - "AWS::ServiceCatalogAppRegistry::AttributeGroup.Attributes": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-servicecatalogappregistry-attributegroup-attributes.html" - }, "AWS::ServiceDiscovery::Service.DnsConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-servicediscovery-service-dnsconfig.html", "Properties": { @@ -52239,24 +55860,12 @@ } } }, - "AWS::WAFv2::RuleGroup.AndStatementOne": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-andstatementone.html", + "AWS::WAFv2::RuleGroup.AndStatement": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-andstatement.html", "Properties": { "Statements": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-andstatementone.html#cfn-wafv2-rulegroup-andstatementone-statements", - "ItemType": "StatementTwo", - "Required": true, - "Type": "List", - "UpdateType": "Mutable" - } - } - }, - "AWS::WAFv2::RuleGroup.AndStatementTwo": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-andstatementtwo.html", - "Properties": { - "Statements": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-andstatementtwo.html#cfn-wafv2-rulegroup-andstatementtwo-statements", - "ItemType": "StatementThree", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-andstatement.html#cfn-wafv2-rulegroup-andstatement-statements", + "ItemType": "Statement", "Required": true, "Type": "List", "UpdateType": "Mutable" @@ -52299,6 +55908,23 @@ } } }, + "AWS::WAFv2::RuleGroup.CustomResponseBody": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-customresponsebody.html", + "Properties": { + "Content": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-customresponsebody.html#cfn-wafv2-rulegroup-customresponsebody-content", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ContentType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-customresponsebody.html#cfn-wafv2-rulegroup-customresponsebody-contenttype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::WAFv2::RuleGroup.FieldToMatch": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-fieldtomatch.html", "Properties": { @@ -52314,6 +55940,12 @@ "Required": false, "UpdateType": "Mutable" }, + "JsonBody": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-fieldtomatch.html#cfn-wafv2-rulegroup-fieldtomatch-jsonbody", + "Required": false, + "Type": "JsonBody", + "UpdateType": "Mutable" + }, "Method": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-fieldtomatch.html#cfn-wafv2-rulegroup-fieldtomatch-method", "PrimitiveType": "Json", @@ -52421,106 +56053,134 @@ } } }, - "AWS::WAFv2::RuleGroup.NotStatementOne": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-notstatementone.html", + "AWS::WAFv2::RuleGroup.JsonBody": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-jsonbody.html", "Properties": { - "Statement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-notstatementone.html#cfn-wafv2-rulegroup-notstatementone-statement", + "InvalidFallbackBehavior": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-jsonbody.html#cfn-wafv2-rulegroup-jsonbody-invalidfallbackbehavior", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "MatchPattern": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-jsonbody.html#cfn-wafv2-rulegroup-jsonbody-matchpattern", "Required": true, - "Type": "StatementTwo", + "Type": "JsonMatchPattern", "UpdateType": "Mutable" - } - } - }, - "AWS::WAFv2::RuleGroup.NotStatementTwo": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-notstatementtwo.html", - "Properties": { - "Statement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-notstatementtwo.html#cfn-wafv2-rulegroup-notstatementtwo-statement", + }, + "MatchScope": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-jsonbody.html#cfn-wafv2-rulegroup-jsonbody-matchscope", + "PrimitiveType": "String", "Required": true, - "Type": "StatementThree", "UpdateType": "Mutable" } } }, - "AWS::WAFv2::RuleGroup.OrStatementOne": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-orstatementone.html", + "AWS::WAFv2::RuleGroup.JsonMatchPattern": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-jsonmatchpattern.html", "Properties": { - "Statements": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-orstatementone.html#cfn-wafv2-rulegroup-orstatementone-statements", - "ItemType": "StatementTwo", - "Required": true, + "All": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-jsonmatchpattern.html#cfn-wafv2-rulegroup-jsonmatchpattern-all", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Mutable" + }, + "IncludedPaths": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-jsonmatchpattern.html#cfn-wafv2-rulegroup-jsonmatchpattern-includedpaths", + "PrimitiveItemType": "String", + "Required": false, "Type": "List", "UpdateType": "Mutable" } } }, - "AWS::WAFv2::RuleGroup.OrStatementTwo": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-orstatementtwo.html", + "AWS::WAFv2::RuleGroup.Label": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-label.html", "Properties": { - "Statements": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-orstatementtwo.html#cfn-wafv2-rulegroup-orstatementtwo-statements", - "ItemType": "StatementThree", + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-label.html#cfn-wafv2-rulegroup-label-name", + "PrimitiveType": "String", "Required": true, - "Type": "List", "UpdateType": "Mutable" } } }, - "AWS::WAFv2::RuleGroup.RateBasedStatementOne": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-ratebasedstatementone.html", + "AWS::WAFv2::RuleGroup.LabelMatchStatement": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-labelmatchstatement.html", "Properties": { - "AggregateKeyType": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-ratebasedstatementone.html#cfn-wafv2-rulegroup-ratebasedstatementone-aggregatekeytype", + "Key": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-labelmatchstatement.html#cfn-wafv2-rulegroup-labelmatchstatement-key", "PrimitiveType": "String", "Required": true, "UpdateType": "Mutable" }, - "ForwardedIPConfig": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-ratebasedstatementone.html#cfn-wafv2-rulegroup-ratebasedstatementone-forwardedipconfig", + "Scope": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-labelmatchstatement.html#cfn-wafv2-rulegroup-labelmatchstatement-scope", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::WAFv2::RuleGroup.LabelSummary": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-labelsummary.html", + "Properties": { + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-labelsummary.html#cfn-wafv2-rulegroup-labelsummary-name", + "PrimitiveType": "String", "Required": false, - "Type": "ForwardedIPConfiguration", "UpdateType": "Mutable" - }, - "Limit": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-ratebasedstatementone.html#cfn-wafv2-rulegroup-ratebasedstatementone-limit", - "PrimitiveType": "Integer", + } + } + }, + "AWS::WAFv2::RuleGroup.NotStatement": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-notstatement.html", + "Properties": { + "Statement": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-notstatement.html#cfn-wafv2-rulegroup-notstatement-statement", "Required": true, + "Type": "Statement", "UpdateType": "Mutable" - }, - "ScopeDownStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-ratebasedstatementone.html#cfn-wafv2-rulegroup-ratebasedstatementone-scopedownstatement", - "Required": false, - "Type": "StatementTwo", + } + } + }, + "AWS::WAFv2::RuleGroup.OrStatement": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-orstatement.html", + "Properties": { + "Statements": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-orstatement.html#cfn-wafv2-rulegroup-orstatement-statements", + "ItemType": "Statement", + "Required": true, + "Type": "List", "UpdateType": "Mutable" } } }, - "AWS::WAFv2::RuleGroup.RateBasedStatementTwo": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-ratebasedstatementtwo.html", + "AWS::WAFv2::RuleGroup.RateBasedStatement": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-ratebasedstatement.html", "Properties": { "AggregateKeyType": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-ratebasedstatementtwo.html#cfn-wafv2-rulegroup-ratebasedstatementtwo-aggregatekeytype", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-ratebasedstatement.html#cfn-wafv2-rulegroup-ratebasedstatement-aggregatekeytype", "PrimitiveType": "String", "Required": true, "UpdateType": "Mutable" }, "ForwardedIPConfig": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-ratebasedstatementtwo.html#cfn-wafv2-rulegroup-ratebasedstatementtwo-forwardedipconfig", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-ratebasedstatement.html#cfn-wafv2-rulegroup-ratebasedstatement-forwardedipconfig", "Required": false, "Type": "ForwardedIPConfiguration", "UpdateType": "Mutable" }, "Limit": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-ratebasedstatementtwo.html#cfn-wafv2-rulegroup-ratebasedstatementtwo-limit", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-ratebasedstatement.html#cfn-wafv2-rulegroup-ratebasedstatement-limit", "PrimitiveType": "Integer", "Required": true, "UpdateType": "Mutable" }, "ScopeDownStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-ratebasedstatementtwo.html#cfn-wafv2-rulegroup-ratebasedstatementtwo-scopedownstatement", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-ratebasedstatement.html#cfn-wafv2-rulegroup-ratebasedstatement-scopedownstatement", "Required": false, - "Type": "StatementThree", + "Type": "Statement", "UpdateType": "Mutable" } } @@ -52570,10 +56230,17 @@ "Required": true, "UpdateType": "Mutable" }, + "RuleLabels": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-rule.html#cfn-wafv2-rulegroup-rule-rulelabels", + "ItemType": "Label", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, "Statement": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-rule.html#cfn-wafv2-rulegroup-rule-statement", "Required": true, - "Type": "StatementOne", + "Type": "Statement", "UpdateType": "Mutable" }, "VisibilityConfig": { @@ -52655,189 +56322,77 @@ } } }, - "AWS::WAFv2::RuleGroup.StatementOne": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementone.html", + "AWS::WAFv2::RuleGroup.Statement": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statement.html", "Properties": { "AndStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementone.html#cfn-wafv2-rulegroup-statementone-andstatement", - "Required": false, - "Type": "AndStatementOne", - "UpdateType": "Mutable" - }, - "ByteMatchStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementone.html#cfn-wafv2-rulegroup-statementone-bytematchstatement", - "Required": false, - "Type": "ByteMatchStatement", - "UpdateType": "Mutable" - }, - "GeoMatchStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementone.html#cfn-wafv2-rulegroup-statementone-geomatchstatement", - "Required": false, - "Type": "GeoMatchStatement", - "UpdateType": "Mutable" - }, - "IPSetReferenceStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementone.html#cfn-wafv2-rulegroup-statementone-ipsetreferencestatement", - "Required": false, - "Type": "IPSetReferenceStatement", - "UpdateType": "Mutable" - }, - "NotStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementone.html#cfn-wafv2-rulegroup-statementone-notstatement", - "Required": false, - "Type": "NotStatementOne", - "UpdateType": "Mutable" - }, - "OrStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementone.html#cfn-wafv2-rulegroup-statementone-orstatement", - "Required": false, - "Type": "OrStatementOne", - "UpdateType": "Mutable" - }, - "RateBasedStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementone.html#cfn-wafv2-rulegroup-statementone-ratebasedstatement", - "Required": false, - "Type": "RateBasedStatementOne", - "UpdateType": "Mutable" - }, - "RegexPatternSetReferenceStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementone.html#cfn-wafv2-rulegroup-statementone-regexpatternsetreferencestatement", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statement.html#cfn-wafv2-rulegroup-statement-andstatement", "Required": false, - "Type": "RegexPatternSetReferenceStatement", + "Type": "AndStatement", "UpdateType": "Mutable" }, - "SizeConstraintStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementone.html#cfn-wafv2-rulegroup-statementone-sizeconstraintstatement", - "Required": false, - "Type": "SizeConstraintStatement", - "UpdateType": "Mutable" - }, - "SqliMatchStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementone.html#cfn-wafv2-rulegroup-statementone-sqlimatchstatement", - "Required": false, - "Type": "SqliMatchStatement", - "UpdateType": "Mutable" - }, - "XssMatchStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementone.html#cfn-wafv2-rulegroup-statementone-xssmatchstatement", - "Required": false, - "Type": "XssMatchStatement", - "UpdateType": "Mutable" - } - } - }, - "AWS::WAFv2::RuleGroup.StatementThree": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementthree.html", - "Properties": { "ByteMatchStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementthree.html#cfn-wafv2-rulegroup-statementthree-bytematchstatement", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statement.html#cfn-wafv2-rulegroup-statement-bytematchstatement", "Required": false, "Type": "ByteMatchStatement", "UpdateType": "Mutable" }, "GeoMatchStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementthree.html#cfn-wafv2-rulegroup-statementthree-geomatchstatement", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statement.html#cfn-wafv2-rulegroup-statement-geomatchstatement", "Required": false, "Type": "GeoMatchStatement", "UpdateType": "Mutable" }, "IPSetReferenceStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementthree.html#cfn-wafv2-rulegroup-statementthree-ipsetreferencestatement", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statement.html#cfn-wafv2-rulegroup-statement-ipsetreferencestatement", "Required": false, "Type": "IPSetReferenceStatement", "UpdateType": "Mutable" }, - "RegexPatternSetReferenceStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementthree.html#cfn-wafv2-rulegroup-statementthree-regexpatternsetreferencestatement", - "Required": false, - "Type": "RegexPatternSetReferenceStatement", - "UpdateType": "Mutable" - }, - "SizeConstraintStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementthree.html#cfn-wafv2-rulegroup-statementthree-sizeconstraintstatement", - "Required": false, - "Type": "SizeConstraintStatement", - "UpdateType": "Mutable" - }, - "SqliMatchStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementthree.html#cfn-wafv2-rulegroup-statementthree-sqlimatchstatement", - "Required": false, - "Type": "SqliMatchStatement", - "UpdateType": "Mutable" - }, - "XssMatchStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementthree.html#cfn-wafv2-rulegroup-statementthree-xssmatchstatement", - "Required": false, - "Type": "XssMatchStatement", - "UpdateType": "Mutable" - } - } - }, - "AWS::WAFv2::RuleGroup.StatementTwo": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementtwo.html", - "Properties": { - "AndStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementtwo.html#cfn-wafv2-rulegroup-statementtwo-andstatement", - "Required": false, - "Type": "AndStatementTwo", - "UpdateType": "Mutable" - }, - "ByteMatchStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementtwo.html#cfn-wafv2-rulegroup-statementtwo-bytematchstatement", - "Required": false, - "Type": "ByteMatchStatement", - "UpdateType": "Mutable" - }, - "GeoMatchStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementtwo.html#cfn-wafv2-rulegroup-statementtwo-geomatchstatement", + "LabelMatchStatement": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statement.html#cfn-wafv2-rulegroup-statement-labelmatchstatement", "Required": false, - "Type": "GeoMatchStatement", - "UpdateType": "Mutable" - }, - "IPSetReferenceStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementtwo.html#cfn-wafv2-rulegroup-statementtwo-ipsetreferencestatement", - "Required": false, - "Type": "IPSetReferenceStatement", + "Type": "LabelMatchStatement", "UpdateType": "Mutable" }, "NotStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementtwo.html#cfn-wafv2-rulegroup-statementtwo-notstatement", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statement.html#cfn-wafv2-rulegroup-statement-notstatement", "Required": false, - "Type": "NotStatementTwo", + "Type": "NotStatement", "UpdateType": "Mutable" }, "OrStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementtwo.html#cfn-wafv2-rulegroup-statementtwo-orstatement", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statement.html#cfn-wafv2-rulegroup-statement-orstatement", "Required": false, - "Type": "OrStatementTwo", + "Type": "OrStatement", "UpdateType": "Mutable" }, "RateBasedStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementtwo.html#cfn-wafv2-rulegroup-statementtwo-ratebasedstatement", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statement.html#cfn-wafv2-rulegroup-statement-ratebasedstatement", "Required": false, - "Type": "RateBasedStatementTwo", + "Type": "RateBasedStatement", "UpdateType": "Mutable" }, "RegexPatternSetReferenceStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementtwo.html#cfn-wafv2-rulegroup-statementtwo-regexpatternsetreferencestatement", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statement.html#cfn-wafv2-rulegroup-statement-regexpatternsetreferencestatement", "Required": false, "Type": "RegexPatternSetReferenceStatement", "UpdateType": "Mutable" }, "SizeConstraintStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementtwo.html#cfn-wafv2-rulegroup-statementtwo-sizeconstraintstatement", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statement.html#cfn-wafv2-rulegroup-statement-sizeconstraintstatement", "Required": false, "Type": "SizeConstraintStatement", "UpdateType": "Mutable" }, "SqliMatchStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementtwo.html#cfn-wafv2-rulegroup-statementtwo-sqlimatchstatement", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statement.html#cfn-wafv2-rulegroup-statement-sqlimatchstatement", "Required": false, "Type": "SqliMatchStatement", "UpdateType": "Mutable" }, "XssMatchStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statementtwo.html#cfn-wafv2-rulegroup-statementtwo-xssmatchstatement", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-statement.html#cfn-wafv2-rulegroup-statement-xssmatchstatement", "Required": false, "Type": "XssMatchStatement", "UpdateType": "Mutable" @@ -52902,30 +56457,40 @@ } } }, - "AWS::WAFv2::WebACL.AndStatementOne": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-andstatementone.html", + "AWS::WAFv2::WebACL.AllowAction": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-allowaction.html", "Properties": { - "Statements": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-andstatementone.html#cfn-wafv2-webacl-andstatementone-statements", - "ItemType": "StatementTwo", - "Required": true, - "Type": "List", + "CustomRequestHandling": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-allowaction.html#cfn-wafv2-webacl-allowaction-customrequesthandling", + "Required": false, + "Type": "CustomRequestHandling", "UpdateType": "Mutable" } } }, - "AWS::WAFv2::WebACL.AndStatementTwo": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-andstatementtwo.html", + "AWS::WAFv2::WebACL.AndStatement": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-andstatement.html", "Properties": { "Statements": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-andstatementtwo.html#cfn-wafv2-webacl-andstatementtwo-statements", - "ItemType": "StatementThree", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-andstatement.html#cfn-wafv2-webacl-andstatement-statements", + "ItemType": "Statement", "Required": true, "Type": "List", "UpdateType": "Mutable" } } }, + "AWS::WAFv2::WebACL.BlockAction": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-blockaction.html", + "Properties": { + "CustomResponse": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-blockaction.html#cfn-wafv2-webacl-blockaction-customresponse", + "Required": false, + "Type": "CustomResponse", + "UpdateType": "Mutable" + } + } + }, "AWS::WAFv2::WebACL.ByteMatchStatement": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-bytematchstatement.html", "Properties": { @@ -52962,19 +56527,100 @@ } } }, + "AWS::WAFv2::WebACL.CountAction": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-countaction.html", + "Properties": { + "CustomRequestHandling": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-countaction.html#cfn-wafv2-webacl-countaction-customrequesthandling", + "Required": false, + "Type": "CustomRequestHandling", + "UpdateType": "Mutable" + } + } + }, + "AWS::WAFv2::WebACL.CustomHTTPHeader": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-customhttpheader.html", + "Properties": { + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-customhttpheader.html#cfn-wafv2-webacl-customhttpheader-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-customhttpheader.html#cfn-wafv2-webacl-customhttpheader-value", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::WAFv2::WebACL.CustomRequestHandling": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-customrequesthandling.html", + "Properties": { + "InsertHeaders": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-customrequesthandling.html#cfn-wafv2-webacl-customrequesthandling-insertheaders", + "ItemType": "CustomHTTPHeader", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::WAFv2::WebACL.CustomResponse": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-customresponse.html", + "Properties": { + "CustomResponseBodyKey": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-customresponse.html#cfn-wafv2-webacl-customresponse-customresponsebodykey", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ResponseCode": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-customresponse.html#cfn-wafv2-webacl-customresponse-responsecode", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + }, + "ResponseHeaders": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-customresponse.html#cfn-wafv2-webacl-customresponse-responseheaders", + "ItemType": "CustomHTTPHeader", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::WAFv2::WebACL.CustomResponseBody": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-customresponsebody.html", + "Properties": { + "Content": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-customresponsebody.html#cfn-wafv2-webacl-customresponsebody-content", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ContentType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-customresponsebody.html#cfn-wafv2-webacl-customresponsebody-contenttype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::WAFv2::WebACL.DefaultAction": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-defaultaction.html", "Properties": { "Allow": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-defaultaction.html#cfn-wafv2-webacl-defaultaction-allow", - "PrimitiveType": "Json", "Required": false, + "Type": "AllowAction", "UpdateType": "Mutable" }, "Block": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-defaultaction.html#cfn-wafv2-webacl-defaultaction-block", - "PrimitiveType": "Json", "Required": false, + "Type": "BlockAction", "UpdateType": "Mutable" } } @@ -53005,6 +56651,12 @@ "Required": false, "UpdateType": "Mutable" }, + "JsonBody": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-fieldtomatch.html#cfn-wafv2-webacl-fieldtomatch-jsonbody", + "Required": false, + "Type": "JsonBody", + "UpdateType": "Mutable" + }, "Method": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-fieldtomatch.html#cfn-wafv2-webacl-fieldtomatch-method", "PrimitiveType": "Json", @@ -53112,70 +56764,122 @@ } } }, - "AWS::WAFv2::WebACL.ManagedRuleGroupStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-managedrulegroupstatement.html", + "AWS::WAFv2::WebACL.JsonBody": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-jsonbody.html", "Properties": { - "ExcludedRules": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-managedrulegroupstatement.html#cfn-wafv2-webacl-managedrulegroupstatement-excludedrules", - "ItemType": "ExcludedRule", + "InvalidFallbackBehavior": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-jsonbody.html#cfn-wafv2-webacl-jsonbody-invalidfallbackbehavior", + "PrimitiveType": "String", "Required": false, - "Type": "List", "UpdateType": "Mutable" }, - "Name": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-managedrulegroupstatement.html#cfn-wafv2-webacl-managedrulegroupstatement-name", + "MatchPattern": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-jsonbody.html#cfn-wafv2-webacl-jsonbody-matchpattern", + "Required": true, + "Type": "JsonMatchPattern", + "UpdateType": "Mutable" + }, + "MatchScope": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-jsonbody.html#cfn-wafv2-webacl-jsonbody-matchscope", "PrimitiveType": "String", "Required": true, "UpdateType": "Mutable" + } + } + }, + "AWS::WAFv2::WebACL.JsonMatchPattern": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-jsonmatchpattern.html", + "Properties": { + "All": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-jsonmatchpattern.html#cfn-wafv2-webacl-jsonmatchpattern-all", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Mutable" }, - "VendorName": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-managedrulegroupstatement.html#cfn-wafv2-webacl-managedrulegroupstatement-vendorname", + "IncludedPaths": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-jsonmatchpattern.html#cfn-wafv2-webacl-jsonmatchpattern-includedpaths", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::WAFv2::WebACL.Label": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-label.html", + "Properties": { + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-label.html#cfn-wafv2-webacl-label-name", "PrimitiveType": "String", "Required": true, "UpdateType": "Mutable" } } }, - "AWS::WAFv2::WebACL.NotStatementOne": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-notstatementone.html", + "AWS::WAFv2::WebACL.LabelMatchStatement": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-labelmatchstatement.html", "Properties": { - "Statement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-notstatementone.html#cfn-wafv2-webacl-notstatementone-statement", + "Key": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-labelmatchstatement.html#cfn-wafv2-webacl-labelmatchstatement-key", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Scope": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-labelmatchstatement.html#cfn-wafv2-webacl-labelmatchstatement-scope", + "PrimitiveType": "String", "Required": true, - "Type": "StatementTwo", "UpdateType": "Mutable" } } }, - "AWS::WAFv2::WebACL.NotStatementTwo": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-notstatementtwo.html", + "AWS::WAFv2::WebACL.ManagedRuleGroupStatement": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-managedrulegroupstatement.html", "Properties": { - "Statement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-notstatementtwo.html#cfn-wafv2-webacl-notstatementtwo-statement", + "ExcludedRules": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-managedrulegroupstatement.html#cfn-wafv2-webacl-managedrulegroupstatement-excludedrules", + "ItemType": "ExcludedRule", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-managedrulegroupstatement.html#cfn-wafv2-webacl-managedrulegroupstatement-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ScopeDownStatement": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-managedrulegroupstatement.html#cfn-wafv2-webacl-managedrulegroupstatement-scopedownstatement", + "Required": false, + "Type": "Statement", + "UpdateType": "Mutable" + }, + "VendorName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-managedrulegroupstatement.html#cfn-wafv2-webacl-managedrulegroupstatement-vendorname", + "PrimitiveType": "String", "Required": true, - "Type": "StatementThree", "UpdateType": "Mutable" } } }, - "AWS::WAFv2::WebACL.OrStatementOne": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-orstatementone.html", + "AWS::WAFv2::WebACL.NotStatement": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-notstatement.html", "Properties": { - "Statements": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-orstatementone.html#cfn-wafv2-webacl-orstatementone-statements", - "ItemType": "StatementTwo", + "Statement": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-notstatement.html#cfn-wafv2-webacl-notstatement-statement", "Required": true, - "Type": "List", + "Type": "Statement", "UpdateType": "Mutable" } } }, - "AWS::WAFv2::WebACL.OrStatementTwo": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-orstatementtwo.html", + "AWS::WAFv2::WebACL.OrStatement": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-orstatement.html", "Properties": { "Statements": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-orstatementtwo.html#cfn-wafv2-webacl-orstatementtwo-statements", - "ItemType": "StatementThree", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-orstatement.html#cfn-wafv2-webacl-orstatement-statements", + "ItemType": "Statement", "Required": true, "Type": "List", "UpdateType": "Mutable" @@ -53199,60 +56903,31 @@ } } }, - "AWS::WAFv2::WebACL.RateBasedStatementOne": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-ratebasedstatementone.html", + "AWS::WAFv2::WebACL.RateBasedStatement": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-ratebasedstatement.html", "Properties": { "AggregateKeyType": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-ratebasedstatementone.html#cfn-wafv2-webacl-ratebasedstatementone-aggregatekeytype", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-ratebasedstatement.html#cfn-wafv2-webacl-ratebasedstatement-aggregatekeytype", "PrimitiveType": "String", "Required": true, "UpdateType": "Mutable" }, "ForwardedIPConfig": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-ratebasedstatementone.html#cfn-wafv2-webacl-ratebasedstatementone-forwardedipconfig", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-ratebasedstatement.html#cfn-wafv2-webacl-ratebasedstatement-forwardedipconfig", "Required": false, "Type": "ForwardedIPConfiguration", "UpdateType": "Mutable" }, "Limit": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-ratebasedstatementone.html#cfn-wafv2-webacl-ratebasedstatementone-limit", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-ratebasedstatement.html#cfn-wafv2-webacl-ratebasedstatement-limit", "PrimitiveType": "Integer", "Required": true, "UpdateType": "Mutable" }, "ScopeDownStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-ratebasedstatementone.html#cfn-wafv2-webacl-ratebasedstatementone-scopedownstatement", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-ratebasedstatement.html#cfn-wafv2-webacl-ratebasedstatement-scopedownstatement", "Required": false, - "Type": "StatementTwo", - "UpdateType": "Mutable" - } - } - }, - "AWS::WAFv2::WebACL.RateBasedStatementTwo": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-ratebasedstatementtwo.html", - "Properties": { - "AggregateKeyType": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-ratebasedstatementtwo.html#cfn-wafv2-webacl-ratebasedstatementtwo-aggregatekeytype", - "PrimitiveType": "String", - "Required": true, - "UpdateType": "Mutable" - }, - "ForwardedIPConfig": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-ratebasedstatementtwo.html#cfn-wafv2-webacl-ratebasedstatementtwo-forwardedipconfig", - "Required": false, - "Type": "ForwardedIPConfiguration", - "UpdateType": "Mutable" - }, - "Limit": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-ratebasedstatementtwo.html#cfn-wafv2-webacl-ratebasedstatementtwo-limit", - "PrimitiveType": "Integer", - "Required": true, - "UpdateType": "Mutable" - }, - "ScopeDownStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-ratebasedstatementtwo.html#cfn-wafv2-webacl-ratebasedstatementtwo-scopedownstatement", - "Required": false, - "Type": "StatementThree", + "Type": "Statement", "UpdateType": "Mutable" } } @@ -53308,10 +56983,17 @@ "Required": true, "UpdateType": "Mutable" }, + "RuleLabels": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-rule.html#cfn-wafv2-webacl-rule-rulelabels", + "ItemType": "Label", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, "Statement": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-rule.html#cfn-wafv2-webacl-rule-statement", "Required": true, - "Type": "StatementOne", + "Type": "Statement", "UpdateType": "Mutable" }, "VisibilityConfig": { @@ -53327,20 +57009,20 @@ "Properties": { "Allow": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-ruleaction.html#cfn-wafv2-webacl-ruleaction-allow", - "PrimitiveType": "Json", "Required": false, + "Type": "AllowAction", "UpdateType": "Mutable" }, "Block": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-ruleaction.html#cfn-wafv2-webacl-ruleaction-block", - "PrimitiveType": "Json", "Required": false, + "Type": "BlockAction", "UpdateType": "Mutable" }, "Count": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-ruleaction.html#cfn-wafv2-webacl-ruleaction-count", - "PrimitiveType": "Json", "Required": false, + "Type": "CountAction", "UpdateType": "Mutable" } } @@ -53411,225 +57093,89 @@ } } }, - "AWS::WAFv2::WebACL.StatementOne": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementone.html", + "AWS::WAFv2::WebACL.Statement": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statement.html", "Properties": { "AndStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementone.html#cfn-wafv2-webacl-statementone-andstatement", - "Required": false, - "Type": "AndStatementOne", - "UpdateType": "Mutable" - }, - "ByteMatchStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementone.html#cfn-wafv2-webacl-statementone-bytematchstatement", - "Required": false, - "Type": "ByteMatchStatement", - "UpdateType": "Mutable" - }, - "GeoMatchStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementone.html#cfn-wafv2-webacl-statementone-geomatchstatement", - "Required": false, - "Type": "GeoMatchStatement", - "UpdateType": "Mutable" - }, - "IPSetReferenceStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementone.html#cfn-wafv2-webacl-statementone-ipsetreferencestatement", - "Required": false, - "Type": "IPSetReferenceStatement", - "UpdateType": "Mutable" - }, - "ManagedRuleGroupStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementone.html#cfn-wafv2-webacl-statementone-managedrulegroupstatement", - "Required": false, - "Type": "ManagedRuleGroupStatement", - "UpdateType": "Mutable" - }, - "NotStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementone.html#cfn-wafv2-webacl-statementone-notstatement", - "Required": false, - "Type": "NotStatementOne", - "UpdateType": "Mutable" - }, - "OrStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementone.html#cfn-wafv2-webacl-statementone-orstatement", - "Required": false, - "Type": "OrStatementOne", - "UpdateType": "Mutable" - }, - "RateBasedStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementone.html#cfn-wafv2-webacl-statementone-ratebasedstatement", - "Required": false, - "Type": "RateBasedStatementOne", - "UpdateType": "Mutable" - }, - "RegexPatternSetReferenceStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementone.html#cfn-wafv2-webacl-statementone-regexpatternsetreferencestatement", - "Required": false, - "Type": "RegexPatternSetReferenceStatement", - "UpdateType": "Mutable" - }, - "RuleGroupReferenceStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementone.html#cfn-wafv2-webacl-statementone-rulegroupreferencestatement", - "Required": false, - "Type": "RuleGroupReferenceStatement", - "UpdateType": "Mutable" - }, - "SizeConstraintStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementone.html#cfn-wafv2-webacl-statementone-sizeconstraintstatement", - "Required": false, - "Type": "SizeConstraintStatement", - "UpdateType": "Mutable" - }, - "SqliMatchStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementone.html#cfn-wafv2-webacl-statementone-sqlimatchstatement", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statement.html#cfn-wafv2-webacl-statement-andstatement", "Required": false, - "Type": "SqliMatchStatement", + "Type": "AndStatement", "UpdateType": "Mutable" }, - "XssMatchStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementone.html#cfn-wafv2-webacl-statementone-xssmatchstatement", - "Required": false, - "Type": "XssMatchStatement", - "UpdateType": "Mutable" - } - } - }, - "AWS::WAFv2::WebACL.StatementThree": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementthree.html", - "Properties": { "ByteMatchStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementthree.html#cfn-wafv2-webacl-statementthree-bytematchstatement", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statement.html#cfn-wafv2-webacl-statement-bytematchstatement", "Required": false, "Type": "ByteMatchStatement", "UpdateType": "Mutable" }, "GeoMatchStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementthree.html#cfn-wafv2-webacl-statementthree-geomatchstatement", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statement.html#cfn-wafv2-webacl-statement-geomatchstatement", "Required": false, "Type": "GeoMatchStatement", "UpdateType": "Mutable" }, "IPSetReferenceStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementthree.html#cfn-wafv2-webacl-statementthree-ipsetreferencestatement", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statement.html#cfn-wafv2-webacl-statement-ipsetreferencestatement", "Required": false, "Type": "IPSetReferenceStatement", "UpdateType": "Mutable" }, - "ManagedRuleGroupStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementthree.html#cfn-wafv2-webacl-statementthree-managedrulegroupstatement", - "Required": false, - "Type": "ManagedRuleGroupStatement", - "UpdateType": "Mutable" - }, - "RegexPatternSetReferenceStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementthree.html#cfn-wafv2-webacl-statementthree-regexpatternsetreferencestatement", + "LabelMatchStatement": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statement.html#cfn-wafv2-webacl-statement-labelmatchstatement", "Required": false, - "Type": "RegexPatternSetReferenceStatement", - "UpdateType": "Mutable" - }, - "RuleGroupReferenceStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementthree.html#cfn-wafv2-webacl-statementthree-rulegroupreferencestatement", - "Required": false, - "Type": "RuleGroupReferenceStatement", - "UpdateType": "Mutable" - }, - "SizeConstraintStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementthree.html#cfn-wafv2-webacl-statementthree-sizeconstraintstatement", - "Required": false, - "Type": "SizeConstraintStatement", - "UpdateType": "Mutable" - }, - "SqliMatchStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementthree.html#cfn-wafv2-webacl-statementthree-sqlimatchstatement", - "Required": false, - "Type": "SqliMatchStatement", - "UpdateType": "Mutable" - }, - "XssMatchStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementthree.html#cfn-wafv2-webacl-statementthree-xssmatchstatement", - "Required": false, - "Type": "XssMatchStatement", - "UpdateType": "Mutable" - } - } - }, - "AWS::WAFv2::WebACL.StatementTwo": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementtwo.html", - "Properties": { - "AndStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementtwo.html#cfn-wafv2-webacl-statementtwo-andstatement", - "Required": false, - "Type": "AndStatementTwo", - "UpdateType": "Mutable" - }, - "ByteMatchStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementtwo.html#cfn-wafv2-webacl-statementtwo-bytematchstatement", - "Required": false, - "Type": "ByteMatchStatement", - "UpdateType": "Mutable" - }, - "GeoMatchStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementtwo.html#cfn-wafv2-webacl-statementtwo-geomatchstatement", - "Required": false, - "Type": "GeoMatchStatement", - "UpdateType": "Mutable" - }, - "IPSetReferenceStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementtwo.html#cfn-wafv2-webacl-statementtwo-ipsetreferencestatement", - "Required": false, - "Type": "IPSetReferenceStatement", + "Type": "LabelMatchStatement", "UpdateType": "Mutable" }, "ManagedRuleGroupStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementtwo.html#cfn-wafv2-webacl-statementtwo-managedrulegroupstatement", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statement.html#cfn-wafv2-webacl-statement-managedrulegroupstatement", "Required": false, "Type": "ManagedRuleGroupStatement", "UpdateType": "Mutable" }, "NotStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementtwo.html#cfn-wafv2-webacl-statementtwo-notstatement", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statement.html#cfn-wafv2-webacl-statement-notstatement", "Required": false, - "Type": "NotStatementTwo", + "Type": "NotStatement", "UpdateType": "Mutable" }, "OrStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementtwo.html#cfn-wafv2-webacl-statementtwo-orstatement", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statement.html#cfn-wafv2-webacl-statement-orstatement", "Required": false, - "Type": "OrStatementTwo", + "Type": "OrStatement", "UpdateType": "Mutable" }, "RateBasedStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementtwo.html#cfn-wafv2-webacl-statementtwo-ratebasedstatement", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statement.html#cfn-wafv2-webacl-statement-ratebasedstatement", "Required": false, - "Type": "RateBasedStatementTwo", + "Type": "RateBasedStatement", "UpdateType": "Mutable" }, "RegexPatternSetReferenceStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementtwo.html#cfn-wafv2-webacl-statementtwo-regexpatternsetreferencestatement", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statement.html#cfn-wafv2-webacl-statement-regexpatternsetreferencestatement", "Required": false, "Type": "RegexPatternSetReferenceStatement", "UpdateType": "Mutable" }, "RuleGroupReferenceStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementtwo.html#cfn-wafv2-webacl-statementtwo-rulegroupreferencestatement", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statement.html#cfn-wafv2-webacl-statement-rulegroupreferencestatement", "Required": false, "Type": "RuleGroupReferenceStatement", "UpdateType": "Mutable" }, "SizeConstraintStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementtwo.html#cfn-wafv2-webacl-statementtwo-sizeconstraintstatement", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statement.html#cfn-wafv2-webacl-statement-sizeconstraintstatement", "Required": false, "Type": "SizeConstraintStatement", "UpdateType": "Mutable" }, "SqliMatchStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementtwo.html#cfn-wafv2-webacl-statementtwo-sqlimatchstatement", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statement.html#cfn-wafv2-webacl-statement-sqlimatchstatement", "Required": false, "Type": "SqliMatchStatement", "UpdateType": "Mutable" }, "XssMatchStatement": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statementtwo.html#cfn-wafv2-webacl-statementtwo-xssmatchstatement", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-webacl-statement.html#cfn-wafv2-webacl-statement-xssmatchstatement", "Required": false, "Type": "XssMatchStatement", "UpdateType": "Mutable" @@ -53845,7 +57391,7 @@ } } }, - "ResourceSpecificationVersion": "31.0.0", + "ResourceSpecificationVersion": "35.1.0", "ResourceTypes": { "AWS::ACMPCA::Certificate": { "Attributes": { @@ -55119,6 +58665,12 @@ "Required": false, "UpdateType": "Mutable" }, + "DisableExecuteApiEndpoint": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-restapi.html#cfn-apigateway-restapi-disableexecuteapiendpoint", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, "EndpointConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-restapi.html#cfn-apigateway-restapi-endpointconfiguration", "Required": false, @@ -56436,6 +59988,51 @@ } } }, + "AWS::AppIntegrations::EventIntegration": { + "Attributes": { + "Associations": { + "ItemType": "EventIntegrationAssociation", + "Type": "List" + }, + "EventIntegrationArn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appintegrations-eventintegration.html", + "Properties": { + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appintegrations-eventintegration.html#cfn-appintegrations-eventintegration-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "EventBridgeBus": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appintegrations-eventintegration.html#cfn-appintegrations-eventintegration-eventbridgebus", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "EventFilter": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appintegrations-eventintegration.html#cfn-appintegrations-eventintegration-eventfilter", + "Required": true, + "Type": "EventFilter", + "UpdateType": "Immutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appintegrations-eventintegration.html#cfn-appintegrations-eventintegration-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appintegrations-eventintegration.html#cfn-appintegrations-eventintegration-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::AppMesh::GatewayRoute": { "Attributes": { "Arn": { @@ -57479,12 +61076,6 @@ "Required": true, "UpdateType": "Mutable" }, - "LambdaAuthorizerConfig": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appsync-graphqlapi.html#cfn-appsync-graphqlapi-lambdaauthorizerconfig", - "Required": false, - "Type": "LambdaAuthorizerConfig", - "UpdateType": "Mutable" - }, "LogConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appsync-graphqlapi.html#cfn-appsync-graphqlapi-logconfig", "Required": false, @@ -58504,6 +62095,35 @@ } } }, + "AWS::AutoScaling::WarmPool": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-warmpool.html", + "Properties": { + "AutoScalingGroupName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-warmpool.html#cfn-autoscaling-warmpool-autoscalinggroupname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "MaxGroupPreparedCapacity": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-warmpool.html#cfn-autoscaling-warmpool-maxgrouppreparedcapacity", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "MinSize": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-warmpool.html#cfn-autoscaling-warmpool-minsize", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "PoolState": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-warmpool.html#cfn-autoscaling-warmpool-poolstate", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::AutoScalingPlans::ScalingPlan": { "Attributes": { "ScalingPlanName": { @@ -58564,6 +62184,9 @@ "BackupPlanId": { "PrimitiveType": "String" }, + "Id": { + "PrimitiveType": "String" + }, "SelectionId": { "PrimitiveType": "String" } @@ -58646,7 +62269,7 @@ "ServiceRole": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-batch-computeenvironment.html#cfn-batch-computeenvironment-servicerole", "PrimitiveType": "String", - "Required": true, + "Required": false, "UpdateType": "Mutable" }, "State": { @@ -58789,6 +62412,65 @@ } } }, + "AWS::Budgets::BudgetsAction": { + "Attributes": { + "ActionId": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-budgets-budgetsaction.html", + "Properties": { + "ActionThreshold": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-budgets-budgetsaction.html#cfn-budgets-budgetsaction-actionthreshold", + "Required": true, + "Type": "ActionThreshold", + "UpdateType": "Mutable" + }, + "ActionType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-budgets-budgetsaction.html#cfn-budgets-budgetsaction-actiontype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "ApprovalModel": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-budgets-budgetsaction.html#cfn-budgets-budgetsaction-approvalmodel", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "BudgetName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-budgets-budgetsaction.html#cfn-budgets-budgetsaction-budgetname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Definition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-budgets-budgetsaction.html#cfn-budgets-budgetsaction-definition", + "Required": true, + "Type": "Definition", + "UpdateType": "Mutable" + }, + "ExecutionRoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-budgets-budgetsaction.html#cfn-budgets-budgetsaction-executionrolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "NotificationType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-budgets-budgetsaction.html#cfn-budgets-budgetsaction-notificationtype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Subscribers": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-budgets-budgetsaction.html#cfn-budgets-budgetsaction-subscribers", + "ItemType": "Subscriber", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::CE::AnomalyMonitor": { "Attributes": { "CreationDate": { @@ -58891,6 +62573,12 @@ }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ce-costcategory.html", "Properties": { + "DefaultValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ce-costcategory.html#cfn-ce-costcategory-defaultvalue", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "Name": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ce-costcategory.html#cfn-ce-costcategory-name", "PrimitiveType": "String", @@ -59350,25 +63038,25 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-resourceversion.html#cfn-cloudformation-resourceversion-executionrolearn", "PrimitiveType": "String", "Required": false, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "LoggingConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-resourceversion.html#cfn-cloudformation-resourceversion-loggingconfig", "Required": false, "Type": "LoggingConfig", - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "SchemaHandlerPackage": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-resourceversion.html#cfn-cloudformation-resourceversion-schemahandlerpackage", "PrimitiveType": "String", "Required": true, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "TypeName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-resourceversion.html#cfn-cloudformation-resourceversion-typename", "PrimitiveType": "String", "Required": true, - "UpdateType": "Mutable" + "UpdateType": "Immutable" } } }, @@ -59562,6 +63250,9 @@ }, "AWS::CloudFront::CloudFrontOriginAccessIdentity": { "Attributes": { + "Id": { + "PrimitiveType": "String" + }, "S3CanonicalUserId": { "PrimitiveType": "String" } @@ -61955,6 +65646,12 @@ "Required": false, "UpdateType": "Mutable" }, + "S3KmsKeyArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-config-deliverychannel.html#cfn-config-deliverychannel-s3kmskeyarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "SnsTopicARN": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-config-deliverychannel.html#cfn-config-deliverychannel-snstopicarn", "PrimitiveType": "String", @@ -62146,6 +65843,164 @@ } } }, + "AWS::CustomerProfiles::Domain": { + "Attributes": { + "CreatedAt": { + "PrimitiveType": "String" + }, + "LastUpdatedAt": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-customerprofiles-domain.html", + "Properties": { + "DeadLetterQueueUrl": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-customerprofiles-domain.html#cfn-customerprofiles-domain-deadletterqueueurl", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "DefaultEncryptionKey": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-customerprofiles-domain.html#cfn-customerprofiles-domain-defaultencryptionkey", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "DefaultExpirationDays": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-customerprofiles-domain.html#cfn-customerprofiles-domain-defaultexpirationdays", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "DomainName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-customerprofiles-domain.html#cfn-customerprofiles-domain-domainname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-customerprofiles-domain.html#cfn-customerprofiles-domain-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::CustomerProfiles::Integration": { + "Attributes": { + "CreatedAt": { + "PrimitiveType": "String" + }, + "LastUpdatedAt": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-customerprofiles-integration.html", + "Properties": { + "DomainName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-customerprofiles-integration.html#cfn-customerprofiles-integration-domainname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "ObjectTypeName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-customerprofiles-integration.html#cfn-customerprofiles-integration-objecttypename", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-customerprofiles-integration.html#cfn-customerprofiles-integration-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Uri": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-customerprofiles-integration.html#cfn-customerprofiles-integration-uri", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::CustomerProfiles::ObjectType": { + "Attributes": { + "CreatedAt": { + "PrimitiveType": "String" + }, + "LastUpdatedAt": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-customerprofiles-objecttype.html", + "Properties": { + "AllowProfileCreation": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-customerprofiles-objecttype.html#cfn-customerprofiles-objecttype-allowprofilecreation", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-customerprofiles-objecttype.html#cfn-customerprofiles-objecttype-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "DomainName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-customerprofiles-objecttype.html#cfn-customerprofiles-objecttype-domainname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "EncryptionKey": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-customerprofiles-objecttype.html#cfn-customerprofiles-objecttype-encryptionkey", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ExpirationDays": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-customerprofiles-objecttype.html#cfn-customerprofiles-objecttype-expirationdays", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "Fields": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-customerprofiles-objecttype.html#cfn-customerprofiles-objecttype-fields", + "ItemType": "FieldMap", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Keys": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-customerprofiles-objecttype.html#cfn-customerprofiles-objecttype-keys", + "ItemType": "KeyMap", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "ObjectTypeName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-customerprofiles-objecttype.html#cfn-customerprofiles-objecttype-objecttypename", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-customerprofiles-objecttype.html#cfn-customerprofiles-objecttype-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "TemplateId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-customerprofiles-objecttype.html#cfn-customerprofiles-objecttype-templateid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::DAX::Cluster": { "Attributes": { "Arn": { @@ -62490,6 +66345,12 @@ "Type": "RedshiftSettings", "UpdateType": "Mutable" }, + "ResourceIdentifier": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-resourceidentifier", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, "S3Settings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-s3settings", "Required": false, @@ -62664,6 +66525,12 @@ "Required": false, "UpdateType": "Immutable" }, + "ResourceIdentifier": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-replicationinstance.html#cfn-dms-replicationinstance-resourceidentifier", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-replicationinstance.html#cfn-dms-replicationinstance-tags", "ItemType": "Tag", @@ -62756,6 +66623,12 @@ "Required": false, "UpdateType": "Mutable" }, + "ResourceIdentifier": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-replicationtask.html#cfn-dms-replicationtask-resourceidentifier", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, "SourceEndpointArn": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-replicationtask.html#cfn-dms-replicationtask-sourceendpointarn", "PrimitiveType": "String", @@ -62800,14 +66673,14 @@ }, "FormatOptions": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-databrew-dataset.html#cfn-databrew-dataset-formatoptions", - "PrimitiveType": "Json", "Required": false, + "Type": "FormatOptions", "UpdateType": "Mutable" }, "Input": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-databrew-dataset.html#cfn-databrew-dataset-input", - "PrimitiveType": "Json", "Required": true, + "Type": "Input", "UpdateType": "Mutable" }, "Name": { @@ -62816,6 +66689,12 @@ "Required": true, "UpdateType": "Immutable" }, + "PathOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-databrew-dataset.html#cfn-databrew-dataset-pathoptions", + "Required": false, + "Type": "PathOptions", + "UpdateType": "Mutable" + }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-databrew-dataset.html#cfn-databrew-dataset-tags", "DuplicatesAllowed": true, @@ -63552,7 +67431,15 @@ } }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-detective-graph.html", - "Properties": {} + "Properties": { + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-detective-graph.html#cfn-detective-graph-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } }, "AWS::Detective::MemberInvitation": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-detective-memberinvitation.html", @@ -64040,6 +67927,12 @@ "Type": "List", "UpdateType": "Immutable" }, + "KinesisStreamSpecification": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dynamodb-table.html#cfn-dynamodb-table-kinesisstreamspecification", + "Required": false, + "Type": "KinesisStreamSpecification", + "UpdateType": "Mutable" + }, "LocalSecondaryIndexes": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dynamodb-table.html#cfn-dynamodb-table-lsi", "DuplicatesAllowed": true, @@ -64622,6 +68515,34 @@ } } }, + "AWS::EC2::EnclaveCertificateIamRoleAssociation": { + "Attributes": { + "CertificateS3BucketName": { + "PrimitiveType": "String" + }, + "CertificateS3ObjectKey": { + "PrimitiveType": "String" + }, + "EncryptionKmsKeyId": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-enclavecertificateiamroleassociation.html", + "Properties": { + "CertificateArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-enclavecertificateiamroleassociation.html#cfn-ec2-enclavecertificateiamroleassociation-certificatearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-enclavecertificateiamroleassociation.html#cfn-ec2-enclavecertificateiamroleassociation-rolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, "AWS::EC2::FlowLog": { "Attributes": { "Id": { @@ -65055,8 +68976,9 @@ }, "TagSpecifications": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-launchtemplate.html#cfn-ec2-launchtemplate-tagspecifications", + "ItemType": "LaunchTemplateTagSpecification", "Required": false, - "Type": "TagSpecifications", + "Type": "List", "UpdateType": "Mutable" } } @@ -67699,6 +71621,12 @@ "Type": "BackupPolicy", "UpdateType": "Mutable" }, + "BypassPolicyLockoutSafetyCheck": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-efs-filesystem.html#cfn-efs-filesystem-bypasspolicylockoutsafetycheck", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, "Encrypted": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-efs-filesystem.html#cfn-efs-filesystem-encrypted", "PrimitiveType": "Boolean", @@ -67853,6 +71781,9 @@ }, "Endpoint": { "PrimitiveType": "String" + }, + "OpenIdConnectIssuerUrl": { + "PrimitiveType": "String" } }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-cluster.html", @@ -68594,6 +72525,14 @@ "Required": false, "UpdateType": "Mutable" }, + "LogDeliveryConfigurations": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-cache-cluster.html#cfn-elasticache-cachecluster-logdeliveryconfigurations", + "DuplicatesAllowed": false, + "ItemType": "LogDeliveryConfigurationRequest", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, "NotificationTopicArn": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-cache-cluster.html#cfn-elasticache-cachecluster-notificationtopicarn", "PrimitiveType": "String", @@ -68754,7 +72693,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-parameter-group.html#cfn-elasticache-parametergroup-cacheparametergroupfamily", "PrimitiveType": "String", "Required": true, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "Description": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-parameter-group.html#cfn-elasticache-parametergroup-description", @@ -68769,6 +72708,14 @@ "Required": false, "Type": "Map", "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-parameter-group.html#cfn-elasticache-parametergroup-tags", + "DuplicatesAllowed": true, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" } } }, @@ -68883,6 +72830,14 @@ "Required": false, "UpdateType": "Immutable" }, + "LogDeliveryConfigurations": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticache-replicationgroup.html#cfn-elasticache-replicationgroup-logdeliveryconfigurations", + "DuplicatesAllowed": false, + "ItemType": "LogDeliveryConfigurationRequest", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, "MultiAZEnabled": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticache-replicationgroup.html#cfn-elasticache-replicationgroup-multiazenabled", "PrimitiveType": "Boolean", @@ -69031,6 +72986,14 @@ "PrimitiveType": "String", "Required": true, "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-security-group.html#cfn-elasticache-securitygroup-tags", + "DuplicatesAllowed": true, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" } } }, @@ -69079,6 +73042,14 @@ "Required": true, "Type": "List", "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-subnetgroup.html#cfn-elasticache-subnetgroup-tags", + "DuplicatesAllowed": true, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" } } }, @@ -69293,6 +73264,12 @@ "Required": false, "UpdateType": "Immutable" }, + "OperationsRole": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-beanstalk-environment.html#cfn-beanstalk-environment-operations-role", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "OptionSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-beanstalk-environment.html#cfn-beanstalk-environment-optionsettings", "DuplicatesAllowed": true, @@ -70324,6 +74301,56 @@ } } }, + "AWS::FIS::ExperimentTemplate": { + "Attributes": { + "Id": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fis-experimenttemplate.html", + "Properties": { + "Actions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fis-experimenttemplate.html#cfn-fis-experimenttemplate-actions", + "ItemType": "ExperimentTemplateAction", + "Required": false, + "Type": "Map", + "UpdateType": "Mutable" + }, + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fis-experimenttemplate.html#cfn-fis-experimenttemplate-description", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fis-experimenttemplate.html#cfn-fis-experimenttemplate-rolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "StopConditions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fis-experimenttemplate.html#cfn-fis-experimenttemplate-stopconditions", + "ItemType": "ExperimentTemplateStopCondition", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fis-experimenttemplate.html#cfn-fis-experimenttemplate-tags", + "PrimitiveItemType": "String", + "Required": true, + "Type": "Map", + "UpdateType": "Immutable" + }, + "Targets": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fis-experimenttemplate.html#cfn-fis-experimenttemplate-targets", + "ItemType": "ExperimentTemplateTarget", + "Required": true, + "Type": "Map", + "UpdateType": "Mutable" + } + } + }, "AWS::FMS::NotificationChannel": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fms-notificationchannel.html", "Properties": { @@ -70554,6 +74581,11 @@ } }, "AWS::GameLift::Fleet": { + "Attributes": { + "FleetId": { + "PrimitiveType": "String" + } + }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-fleet.html", "Properties": { "BuildId": { @@ -70582,7 +74614,6 @@ }, "EC2InboundPermissions": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-fleet.html#cfn-gamelift-fleet-ec2inboundpermissions", - "DuplicatesAllowed": false, "ItemType": "IpPermission", "Required": false, "Type": "List", @@ -70591,7 +74622,7 @@ "EC2InstanceType": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-fleet.html#cfn-gamelift-fleet-ec2instancetype", "PrimitiveType": "String", - "Required": true, + "Required": false, "UpdateType": "Immutable" }, "FleetType": { @@ -70606,14 +74637,6 @@ "Required": false, "UpdateType": "Immutable" }, - "LogPaths": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-fleet.html#cfn-gamelift-fleet-logpaths", - "DuplicatesAllowed": false, - "PrimitiveItemType": "String", - "Required": false, - "Type": "List", - "UpdateType": "Immutable" - }, "MaxSize": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-fleet.html#cfn-gamelift-fleet-maxsize", "PrimitiveType": "Integer", @@ -70622,7 +74645,6 @@ }, "MetricGroups": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-fleet.html#cfn-gamelift-fleet-metricgroups", - "DuplicatesAllowed": false, "PrimitiveItemType": "String", "Required": false, "Type": "List", @@ -70637,7 +74659,7 @@ "Name": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-fleet.html#cfn-gamelift-fleet-name", "PrimitiveType": "String", - "Required": true, + "Required": false, "UpdateType": "Mutable" }, "NewGameSessionProtectionPolicy": { @@ -70675,18 +74697,6 @@ "PrimitiveType": "String", "Required": false, "UpdateType": "Immutable" - }, - "ServerLaunchParameters": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-fleet.html#cfn-gamelift-fleet-serverlaunchparameters", - "PrimitiveType": "String", - "Required": false, - "UpdateType": "Immutable" - }, - "ServerLaunchPath": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-fleet.html#cfn-gamelift-fleet-serverlaunchpath", - "PrimitiveType": "String", - "Required": false, - "UpdateType": "Immutable" } } }, @@ -70789,6 +74799,12 @@ }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-gamesessionqueue.html", "Properties": { + "CustomEventData": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-gamesessionqueue.html#cfn-gamelift-gamesessionqueue-customeventdata", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "Destinations": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-gamesessionqueue.html#cfn-gamelift-gamesessionqueue-destinations", "ItemType": "Destination", @@ -70802,6 +74818,12 @@ "Required": true, "UpdateType": "Immutable" }, + "NotificationTarget": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-gamesessionqueue.html#cfn-gamelift-gamesessionqueue-notificationtarget", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "PlayerLatencyPolicies": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-gamelift-gamesessionqueue.html#cfn-gamelift-gamesessionqueue-playerlatencypolicies", "ItemType": "PlayerLatencyPolicy", @@ -72397,6 +76419,128 @@ } } }, + "AWS::GroundStation::Config": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "Id": { + "PrimitiveType": "String" + }, + "Type": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-groundstation-config.html", + "Properties": { + "ConfigData": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-groundstation-config.html#cfn-groundstation-config-configdata", + "Required": true, + "Type": "ConfigData", + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-groundstation-config.html#cfn-groundstation-config-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-groundstation-config.html#cfn-groundstation-config-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::GroundStation::DataflowEndpointGroup": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "Id": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-groundstation-dataflowendpointgroup.html", + "Properties": { + "EndpointDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-groundstation-dataflowendpointgroup.html#cfn-groundstation-dataflowendpointgroup-endpointdetails", + "ItemType": "EndpointDetails", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-groundstation-dataflowendpointgroup.html#cfn-groundstation-dataflowendpointgroup-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::GroundStation::MissionProfile": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "Id": { + "PrimitiveType": "String" + }, + "Region": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-groundstation-missionprofile.html", + "Properties": { + "ContactPostPassDurationSeconds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-groundstation-missionprofile.html#cfn-groundstation-missionprofile-contactpostpassdurationseconds", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "ContactPrePassDurationSeconds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-groundstation-missionprofile.html#cfn-groundstation-missionprofile-contactprepassdurationseconds", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "DataflowEdges": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-groundstation-missionprofile.html#cfn-groundstation-missionprofile-dataflowedges", + "ItemType": "DataflowEdge", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "MinimumViableContactDurationSeconds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-groundstation-missionprofile.html#cfn-groundstation-missionprofile-minimumviablecontactdurationseconds", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-groundstation-missionprofile.html#cfn-groundstation-missionprofile-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-groundstation-missionprofile.html#cfn-groundstation-missionprofile-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "TrackingConfigArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-groundstation-missionprofile.html#cfn-groundstation-missionprofile-trackingconfigarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::GuardDuty::Detector": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-guardduty-detector.html", "Properties": { @@ -73152,6 +77296,12 @@ "Required": false, "UpdateType": "Mutable" }, + "RecordingConfigurationArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ivs-channel.html#cfn-ivs-channel-recordingconfigurationarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ivs-channel.html#cfn-ivs-channel-tags", "DuplicatesAllowed": false, @@ -73201,6 +77351,39 @@ } } }, + "AWS::IVS::RecordingConfiguration": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "State": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ivs-recordingconfiguration.html", + "Properties": { + "DestinationConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ivs-recordingconfiguration.html#cfn-ivs-recordingconfiguration-destinationconfiguration", + "Required": true, + "Type": "DestinationConfiguration", + "UpdateType": "Immutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ivs-recordingconfiguration.html#cfn-ivs-recordingconfiguration-name", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ivs-recordingconfiguration.html#cfn-ivs-recordingconfiguration-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::IVS::StreamKey": { "Attributes": { "Arn": { @@ -73236,6 +77419,9 @@ "Encrypted": { "PrimitiveType": "Boolean" }, + "Name": { + "PrimitiveType": "String" + }, "Type": { "PrimitiveType": "String" } @@ -73310,6 +77496,9 @@ "Attributes": { "Arn": { "PrimitiveType": "String" + }, + "Name": { + "PrimitiveType": "String" } }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-containerrecipe.html", @@ -73351,6 +77540,13 @@ "Required": false, "UpdateType": "Mutable" }, + "InstanceConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-containerrecipe.html#cfn-imagebuilder-containerrecipe-instanceconfiguration", + "PrimitiveType": "Json", + "Required": false, + "Type": "InstanceConfiguration", + "UpdateType": "Immutable" + }, "KmsKeyId": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-containerrecipe.html#cfn-imagebuilder-containerrecipe-kmskeyid", "PrimitiveType": "String", @@ -73406,6 +77602,9 @@ "Attributes": { "Arn": { "PrimitiveType": "String" + }, + "Name": { + "PrimitiveType": "String" } }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-distributionconfiguration.html", @@ -73501,6 +77700,9 @@ "Attributes": { "Arn": { "PrimitiveType": "String" + }, + "Name": { + "PrimitiveType": "String" } }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-imagepipeline.html", @@ -73578,6 +77780,9 @@ "Attributes": { "Arn": { "PrimitiveType": "String" + }, + "Name": { + "PrimitiveType": "String" } }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-imagerecipe.html", @@ -73639,6 +77844,9 @@ "Attributes": { "Arn": { "PrimitiveType": "String" + }, + "Name": { + "PrimitiveType": "String" } }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-infrastructureconfiguration.html", @@ -74456,6 +78664,13 @@ "Required": false, "UpdateType": "Immutable" }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-topicrule.html#cfn-iot-topicrule-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, "TopicRulePayload": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-topicrule.html#cfn-iot-topicrule-topicrulepayload", "Required": true, @@ -74649,7 +78864,7 @@ "Properties": { "DetectorModelDefinition": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotevents-detectormodel.html#cfn-iotevents-detectormodel-detectormodeldefinition", - "Required": false, + "Required": true, "Type": "DetectorModelDefinition", "UpdateType": "Mutable" }, @@ -74680,11 +78895,12 @@ "RoleArn": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotevents-detectormodel.html#cfn-iotevents-detectormodel-rolearn", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotevents-detectormodel.html#cfn-iotevents-detectormodel-tags", + "DuplicatesAllowed": true, "ItemType": "Tag", "Required": false, "Type": "List", @@ -74697,7 +78913,7 @@ "Properties": { "InputDefinition": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotevents-input.html#cfn-iotevents-input-inputdefinition", - "Required": false, + "Required": true, "Type": "InputDefinition", "UpdateType": "Mutable" }, @@ -74715,6 +78931,64 @@ }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotevents-input.html#cfn-iotevents-input-tags", + "DuplicatesAllowed": true, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::IoTFleetHub::Application": { + "Attributes": { + "ApplicationArn": { + "PrimitiveType": "String" + }, + "ApplicationCreationDate": { + "PrimitiveType": "Integer" + }, + "ApplicationId": { + "PrimitiveType": "String" + }, + "ApplicationLastUpdateDate": { + "PrimitiveType": "Integer" + }, + "ApplicationState": { + "PrimitiveType": "String" + }, + "ApplicationUrl": { + "PrimitiveType": "String" + }, + "ErrorMessage": { + "PrimitiveType": "String" + }, + "SsoClientId": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotfleethub-application.html", + "Properties": { + "ApplicationDescription": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotfleethub-application.html#cfn-iotfleethub-application-applicationdescription", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ApplicationName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotfleethub-application.html#cfn-iotfleethub-application-applicationname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotfleethub-application.html#cfn-iotfleethub-application-rolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotfleethub-application.html#cfn-iotfleethub-application-tags", + "DuplicatesAllowed": false, "ItemType": "Tag", "Required": false, "Type": "List", @@ -75130,6 +79404,60 @@ } } }, + "AWS::IoTWireless::PartnerAccount": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-partneraccount.html", + "Properties": { + "AccountLinked": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-partneraccount.html#cfn-iotwireless-partneraccount-accountlinked", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "Fingerprint": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-partneraccount.html#cfn-iotwireless-partneraccount-fingerprint", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "PartnerAccountId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-partneraccount.html#cfn-iotwireless-partneraccount-partneraccountid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "PartnerType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-partneraccount.html#cfn-iotwireless-partneraccount-partnertype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Sidewalk": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-partneraccount.html#cfn-iotwireless-partneraccount-sidewalk", + "Required": false, + "Type": "SidewalkAccountInfo", + "UpdateType": "Mutable" + }, + "SidewalkUpdate": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-partneraccount.html#cfn-iotwireless-partneraccount-sidewalkupdate", + "Required": false, + "Type": "SidewalkUpdateAccount", + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-partneraccount.html#cfn-iotwireless-partneraccount-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::IoTWireless::ServiceProfile": { "Attributes": { "Arn": { @@ -75217,6 +79545,57 @@ } } }, + "AWS::IoTWireless::TaskDefinition": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "Id": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-taskdefinition.html", + "Properties": { + "AutoCreateTasks": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-taskdefinition.html#cfn-iotwireless-taskdefinition-autocreatetasks", + "PrimitiveType": "Boolean", + "Required": true, + "UpdateType": "Mutable" + }, + "LoRaWANUpdateGatewayTaskEntry": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-taskdefinition.html#cfn-iotwireless-taskdefinition-lorawanupdategatewaytaskentry", + "Required": false, + "Type": "LoRaWANUpdateGatewayTaskEntry", + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-taskdefinition.html#cfn-iotwireless-taskdefinition-name", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-taskdefinition.html#cfn-iotwireless-taskdefinition-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "TaskDefinitionType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-taskdefinition.html#cfn-iotwireless-taskdefinition-taskdefinitiontype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Update": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotwireless-taskdefinition.html#cfn-iotwireless-taskdefinition-update", + "Required": false, + "Type": "UpdateWirelessGatewayTaskCreate", + "UpdateType": "Mutable" + } + } + }, "AWS::IoTWireless::WirelessDevice": { "Attributes": { "Arn": { @@ -76742,6 +81121,35 @@ } } }, + "AWS::Logs::QueryDefinition": { + "Attributes": { + "QueryDefinitionId": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-logs-querydefinition.html", + "Properties": { + "LogGroupNames": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-logs-querydefinition.html#cfn-logs-querydefinition-loggroupnames", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-logs-querydefinition.html#cfn-logs-querydefinition-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "QueryString": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-logs-querydefinition.html#cfn-logs-querydefinition-querystring", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::Logs::SubscriptionFilter": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-logs-subscriptionfilter.html", "Properties": { @@ -76771,6 +81179,87 @@ } } }, + "AWS::LookoutMetrics::Alert": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lookoutmetrics-alert.html", + "Properties": { + "Action": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lookoutmetrics-alert.html#cfn-lookoutmetrics-alert-action", + "PrimitiveType": "Json", + "Required": true, + "UpdateType": "Immutable" + }, + "AlertDescription": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lookoutmetrics-alert.html#cfn-lookoutmetrics-alert-alertdescription", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "AlertName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lookoutmetrics-alert.html#cfn-lookoutmetrics-alert-alertname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "AlertSensitivityThreshold": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lookoutmetrics-alert.html#cfn-lookoutmetrics-alert-alertsensitivitythreshold", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Immutable" + }, + "AnomalyDetectorArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lookoutmetrics-alert.html#cfn-lookoutmetrics-alert-anomalydetectorarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, + "AWS::LookoutMetrics::AnomalyDetector": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lookoutmetrics-anomalydetector.html", + "Properties": { + "AnomalyDetectorConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lookoutmetrics-anomalydetector.html#cfn-lookoutmetrics-anomalydetector-anomalydetectorconfig", + "PrimitiveType": "Json", + "Required": true, + "UpdateType": "Mutable" + }, + "AnomalyDetectorDescription": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lookoutmetrics-anomalydetector.html#cfn-lookoutmetrics-anomalydetector-anomalydetectordescription", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "AnomalyDetectorName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lookoutmetrics-anomalydetector.html#cfn-lookoutmetrics-anomalydetector-anomalydetectorname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "KmsKeyArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lookoutmetrics-anomalydetector.html#cfn-lookoutmetrics-anomalydetector-kmskeyarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "MetricSetList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lookoutmetrics-anomalydetector.html#cfn-lookoutmetrics-anomalydetector-metricsetlist", + "ItemType": "MetricSet", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::LookoutVision::Project": { "Attributes": { "Arn": { @@ -76871,8 +81360,8 @@ "Properties": { "AirflowConfigurationOptions": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-mwaa-environment.html#cfn-mwaa-environment-airflowconfigurationoptions", + "PrimitiveType": "Json", "Required": false, - "Type": "AirflowConfigurationOptions", "UpdateType": "Mutable" }, "AirflowVersion": { @@ -76917,6 +81406,12 @@ "Required": false, "UpdateType": "Mutable" }, + "MinWorkers": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-mwaa-environment.html#cfn-mwaa-environment-minworkers", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, "Name": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-mwaa-environment.html#cfn-mwaa-environment-name", "PrimitiveType": "String", @@ -78955,6 +83450,249 @@ } } }, + "AWS::NimbleStudio::LaunchProfile": { + "Attributes": { + "LaunchProfileId": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-launchprofile.html", + "Properties": { + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-launchprofile.html#cfn-nimblestudio-launchprofile-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Ec2SubnetIds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-launchprofile.html#cfn-nimblestudio-launchprofile-ec2subnetids", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Immutable" + }, + "LaunchProfileProtocolVersions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-launchprofile.html#cfn-nimblestudio-launchprofile-launchprofileprotocolversions", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-launchprofile.html#cfn-nimblestudio-launchprofile-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "StreamConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-launchprofile.html#cfn-nimblestudio-launchprofile-streamconfiguration", + "Required": true, + "Type": "StreamConfiguration", + "UpdateType": "Mutable" + }, + "StudioComponentIds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-launchprofile.html#cfn-nimblestudio-launchprofile-studiocomponentids", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "StudioId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-launchprofile.html#cfn-nimblestudio-launchprofile-studioid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-launchprofile.html#cfn-nimblestudio-launchprofile-tags", + "PrimitiveItemType": "String", + "Required": false, + "Type": "Map", + "UpdateType": "Immutable" + } + } + }, + "AWS::NimbleStudio::StreamingImage": { + "Attributes": { + "EulaIds": { + "PrimitiveItemType": "String", + "Type": "List" + }, + "Owner": { + "PrimitiveType": "String" + }, + "Platform": { + "PrimitiveType": "String" + }, + "StreamingImageId": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-streamingimage.html", + "Properties": { + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-streamingimage.html#cfn-nimblestudio-streamingimage-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Ec2ImageId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-streamingimage.html#cfn-nimblestudio-streamingimage-ec2imageid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-streamingimage.html#cfn-nimblestudio-streamingimage-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "StudioId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-streamingimage.html#cfn-nimblestudio-streamingimage-studioid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-streamingimage.html#cfn-nimblestudio-streamingimage-tags", + "PrimitiveItemType": "String", + "Required": false, + "Type": "Map", + "UpdateType": "Immutable" + } + } + }, + "AWS::NimbleStudio::Studio": { + "Attributes": { + "HomeRegion": { + "PrimitiveType": "String" + }, + "SsoClientId": { + "PrimitiveType": "String" + }, + "StudioId": { + "PrimitiveType": "String" + }, + "StudioUrl": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-studio.html", + "Properties": { + "AdminRoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-studio.html#cfn-nimblestudio-studio-adminrolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "DisplayName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-studio.html#cfn-nimblestudio-studio-displayname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "StudioEncryptionConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-studio.html#cfn-nimblestudio-studio-studioencryptionconfiguration", + "Required": false, + "Type": "StudioEncryptionConfiguration", + "UpdateType": "Mutable" + }, + "StudioName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-studio.html#cfn-nimblestudio-studio-studioname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-studio.html#cfn-nimblestudio-studio-tags", + "PrimitiveItemType": "String", + "Required": false, + "Type": "Map", + "UpdateType": "Immutable" + }, + "UserRoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-studio.html#cfn-nimblestudio-studio-userrolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::NimbleStudio::StudioComponent": { + "Attributes": { + "StudioComponentId": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-studiocomponent.html", + "Properties": { + "Configuration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-studiocomponent.html#cfn-nimblestudio-studiocomponent-configuration", + "Required": false, + "Type": "StudioComponentConfiguration", + "UpdateType": "Mutable" + }, + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-studiocomponent.html#cfn-nimblestudio-studiocomponent-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Ec2SecurityGroupIds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-studiocomponent.html#cfn-nimblestudio-studiocomponent-ec2securitygroupids", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "InitializationScripts": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-studiocomponent.html#cfn-nimblestudio-studiocomponent-initializationscripts", + "ItemType": "StudioComponentInitializationScript", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-studiocomponent.html#cfn-nimblestudio-studiocomponent-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ScriptParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-studiocomponent.html#cfn-nimblestudio-studiocomponent-scriptparameters", + "ItemType": "ScriptParameterKeyValue", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "StudioId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-studiocomponent.html#cfn-nimblestudio-studiocomponent-studioid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Subtype": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-studiocomponent.html#cfn-nimblestudio-studiocomponent-subtype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-studiocomponent.html#cfn-nimblestudio-studiocomponent-tags", + "PrimitiveItemType": "String", + "Required": false, + "Type": "Map", + "UpdateType": "Immutable" + }, + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-nimblestudio-studiocomponent.html#cfn-nimblestudio-studiocomponent-type", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::OpsWorks::App": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opsworks-app.html", "Properties": { @@ -80898,6 +85636,208 @@ } } }, + "AWS::QuickSight::DataSet": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "ConsumedSpiceCapacityInBytes": { + "PrimitiveType": "Double" + }, + "CreatedTime": { + "PrimitiveType": "String" + }, + "LastUpdatedTime": { + "PrimitiveType": "String" + }, + "OutputColumns": { + "ItemType": "OutputColumn", + "Type": "List" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-dataset.html", + "Properties": { + "AwsAccountId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-dataset.html#cfn-quicksight-dataset-awsaccountid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "ColumnGroups": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-dataset.html#cfn-quicksight-dataset-columngroups", + "ItemType": "ColumnGroup", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "ColumnLevelPermissionRules": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-dataset.html#cfn-quicksight-dataset-columnlevelpermissionrules", + "ItemType": "ColumnLevelPermissionRule", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "DataSetId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-dataset.html#cfn-quicksight-dataset-datasetid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "FieldFolders": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-dataset.html#cfn-quicksight-dataset-fieldfolders", + "ItemType": "FieldFolder", + "Required": false, + "Type": "Map", + "UpdateType": "Mutable" + }, + "ImportMode": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-dataset.html#cfn-quicksight-dataset-importmode", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "IngestionWaitPolicy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-dataset.html#cfn-quicksight-dataset-ingestionwaitpolicy", + "Required": false, + "Type": "IngestionWaitPolicy", + "UpdateType": "Mutable" + }, + "LogicalTableMap": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-dataset.html#cfn-quicksight-dataset-logicaltablemap", + "ItemType": "LogicalTable", + "Required": false, + "Type": "Map", + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-dataset.html#cfn-quicksight-dataset-name", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Permissions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-dataset.html#cfn-quicksight-dataset-permissions", + "ItemType": "ResourcePermission", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "PhysicalTableMap": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-dataset.html#cfn-quicksight-dataset-physicaltablemap", + "ItemType": "PhysicalTable", + "Required": false, + "Type": "Map", + "UpdateType": "Mutable" + }, + "RowLevelPermissionDataSet": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-dataset.html#cfn-quicksight-dataset-rowlevelpermissiondataset", + "Required": false, + "Type": "RowLevelPermissionDataSet", + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-dataset.html#cfn-quicksight-dataset-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::QuickSight::DataSource": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "CreatedTime": { + "PrimitiveType": "String" + }, + "LastUpdatedTime": { + "PrimitiveType": "String" + }, + "Status": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-datasource.html", + "Properties": { + "AlternateDataSourceParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-datasource.html#cfn-quicksight-datasource-alternatedatasourceparameters", + "ItemType": "DataSourceParameters", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "AwsAccountId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-datasource.html#cfn-quicksight-datasource-awsaccountid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Credentials": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-datasource.html#cfn-quicksight-datasource-credentials", + "Required": false, + "Type": "DataSourceCredentials", + "UpdateType": "Mutable" + }, + "DataSourceId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-datasource.html#cfn-quicksight-datasource-datasourceid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "DataSourceParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-datasource.html#cfn-quicksight-datasource-datasourceparameters", + "Required": false, + "Type": "DataSourceParameters", + "UpdateType": "Mutable" + }, + "ErrorInfo": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-datasource.html#cfn-quicksight-datasource-errorinfo", + "Required": false, + "Type": "DataSourceErrorInfo", + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-datasource.html#cfn-quicksight-datasource-name", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Permissions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-datasource.html#cfn-quicksight-datasource-permissions", + "ItemType": "ResourcePermission", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "SslProperties": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-datasource.html#cfn-quicksight-datasource-sslproperties", + "Required": false, + "Type": "SslProperties", + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-datasource.html#cfn-quicksight-datasource-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-datasource.html#cfn-quicksight-datasource-type", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "VpcConnectionProperties": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-datasource.html#cfn-quicksight-datasource-vpcconnectionproperties", + "Required": false, + "Type": "VpcConnectionProperties", + "UpdateType": "Mutable" + } + } + }, "AWS::QuickSight::Template": { "Attributes": { "Arn": { @@ -81696,6 +86636,9 @@ }, "Endpoint": { "PrimitiveType": "String" + }, + "VpcId": { + "PrimitiveType": "String" } }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-rds-dbproxy.html", @@ -82397,6 +87340,13 @@ }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-resourcegroups-group.html", "Properties": { + "Configuration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-resourcegroups-group.html#cfn-resourcegroups-group-configuration", + "ItemType": "ConfigurationItem", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, "Description": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-resourcegroups-group.html#cfn-resourcegroups-group-description", "PrimitiveType": "String", @@ -82415,6 +87365,13 @@ "Type": "ResourceQuery", "UpdateType": "Mutable" }, + "Resources": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-resourcegroups-group.html#cfn-resourcegroups-group-resources", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-resourcegroups-group.html#cfn-resourcegroups-group-tags", "ItemType": "Tag", @@ -82856,6 +87813,196 @@ } } }, + "AWS::Route53Resolver::FirewallDomainList": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "CreationTime": { + "PrimitiveType": "String" + }, + "CreatorRequestId": { + "PrimitiveType": "String" + }, + "DomainCount": { + "PrimitiveType": "Integer" + }, + "Id": { + "PrimitiveType": "String" + }, + "ManagedOwnerName": { + "PrimitiveType": "String" + }, + "ModificationTime": { + "PrimitiveType": "String" + }, + "Status": { + "PrimitiveType": "String" + }, + "StatusMessage": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-firewalldomainlist.html", + "Properties": { + "DomainFileUrl": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-firewalldomainlist.html#cfn-route53resolver-firewalldomainlist-domainfileurl", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Domains": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-firewalldomainlist.html#cfn-route53resolver-firewalldomainlist-domains", + "DuplicatesAllowed": false, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-firewalldomainlist.html#cfn-route53resolver-firewalldomainlist-name", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-firewalldomainlist.html#cfn-route53resolver-firewalldomainlist-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Route53Resolver::FirewallRuleGroup": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "CreationTime": { + "PrimitiveType": "String" + }, + "CreatorRequestId": { + "PrimitiveType": "String" + }, + "Id": { + "PrimitiveType": "String" + }, + "ModificationTime": { + "PrimitiveType": "String" + }, + "OwnerId": { + "PrimitiveType": "String" + }, + "RuleCount": { + "PrimitiveType": "Integer" + }, + "ShareStatus": { + "PrimitiveType": "String" + }, + "Status": { + "PrimitiveType": "String" + }, + "StatusMessage": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-firewallrulegroup.html", + "Properties": { + "FirewallRules": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-firewallrulegroup.html#cfn-route53resolver-firewallrulegroup-firewallrules", + "DuplicatesAllowed": false, + "ItemType": "FirewallRule", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-firewallrulegroup.html#cfn-route53resolver-firewallrulegroup-name", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-firewallrulegroup.html#cfn-route53resolver-firewallrulegroup-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Route53Resolver::FirewallRuleGroupAssociation": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "CreationTime": { + "PrimitiveType": "String" + }, + "CreatorRequestId": { + "PrimitiveType": "String" + }, + "Id": { + "PrimitiveType": "String" + }, + "ManagedOwnerName": { + "PrimitiveType": "String" + }, + "ModificationTime": { + "PrimitiveType": "String" + }, + "Status": { + "PrimitiveType": "String" + }, + "StatusMessage": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-firewallrulegroupassociation.html", + "Properties": { + "FirewallRuleGroupId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-firewallrulegroupassociation.html#cfn-route53resolver-firewallrulegroupassociation-firewallrulegroupid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "MutationProtection": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-firewallrulegroupassociation.html#cfn-route53resolver-firewallrulegroupassociation-mutationprotection", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-firewallrulegroupassociation.html#cfn-route53resolver-firewallrulegroupassociation-name", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Priority": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-firewallrulegroupassociation.html#cfn-route53resolver-firewallrulegroupassociation-priority", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-firewallrulegroupassociation.html#cfn-route53resolver-firewallrulegroupassociation-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "VpcId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-firewallrulegroupassociation.html#cfn-route53resolver-firewallrulegroupassociation-vpcid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, "AWS::Route53Resolver::ResolverDNSSECConfig": { "Attributes": { "Id": { @@ -83346,6 +88493,48 @@ } } }, + "AWS::S3ObjectLambda::AccessPoint": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "CreationDate": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-s3objectlambda-accesspoint.html", + "Properties": { + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-s3objectlambda-accesspoint.html#cfn-s3objectlambda-accesspoint-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "ObjectLambdaConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-s3objectlambda-accesspoint.html#cfn-s3objectlambda-accesspoint-objectlambdaconfiguration", + "Required": false, + "Type": "ObjectLambdaConfiguration", + "UpdateType": "Mutable" + } + } + }, + "AWS::S3ObjectLambda::AccessPointPolicy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-s3objectlambda-accesspointpolicy.html", + "Properties": { + "ObjectLambdaAccessPoint": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-s3objectlambda-accesspointpolicy.html#cfn-s3objectlambda-accesspointpolicy-objectlambdaaccesspoint", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "PolicyDocument": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-s3objectlambda-accesspointpolicy.html#cfn-s3objectlambda-accesspointpolicy-policydocument", + "PrimitiveType": "Json", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::S3Outposts::AccessPoint": { "Attributes": { "Arn": { @@ -83517,6 +88706,37 @@ } } }, + "AWS::SES::ContactList": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ses-contactlist.html", + "Properties": { + "ContactListName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ses-contactlist.html#cfn-ses-contactlist-contactlistname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ses-contactlist.html#cfn-ses-contactlist-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ses-contactlist.html#cfn-ses-contactlist-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Topics": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ses-contactlist.html#cfn-ses-contactlist-topics", + "ItemType": "Topic", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::SES::ReceiptFilter": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ses-receiptfilter.html", "Properties": { @@ -83883,7 +89103,7 @@ }, "Parameters": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ssm-association.html#cfn-ssm-association-parameters", - "ItemType": "ParameterValues", + "ItemType": "List", "Required": false, "Type": "Map", "UpdateType": "Mutable" @@ -83918,12 +89138,25 @@ "AWS::SSM::Document": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ssm-document.html", "Properties": { + "Attachments": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ssm-document.html#cfn-ssm-document-attachments", + "ItemType": "AttachmentsSource", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, "Content": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ssm-document.html#cfn-ssm-document-content", "PrimitiveType": "Json", "Required": true, "UpdateType": "Immutable" }, + "DocumentFormat": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ssm-document.html#cfn-ssm-document-documentformat", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, "DocumentType": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ssm-document.html#cfn-ssm-document-documenttype", "PrimitiveType": "String", @@ -83936,13 +89169,31 @@ "Required": false, "UpdateType": "Immutable" }, + "Requires": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ssm-document.html#cfn-ssm-document-requires", + "ItemType": "DocumentRequires", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ssm-document.html#cfn-ssm-document-tags", - "DuplicatesAllowed": true, "ItemType": "Tag", "Required": false, "Type": "List", "UpdateType": "Mutable" + }, + "TargetType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ssm-document.html#cfn-ssm-document-targettype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "VersionName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ssm-document.html#cfn-ssm-document-versionname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" } } }, @@ -86516,8 +91767,8 @@ "Properties": { "Attributes": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-servicecatalogappregistry-attributegroup.html#cfn-servicecatalogappregistry-attributegroup-attributes", + "PrimitiveType": "Json", "Required": true, - "Type": "Attributes", "UpdateType": "Mutable" }, "Description": { @@ -86784,6 +92035,12 @@ "Required": false, "Type": "List", "UpdateType": "Mutable" + }, + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-servicediscovery-service.html#cfn-servicediscovery-service-type", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" } } }, @@ -87682,13 +92939,13 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafv2-ipset.html#cfn-wafv2-ipset-name", "PrimitiveType": "String", "Required": false, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "Scope": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafv2-ipset.html#cfn-wafv2-ipset-scope", "PrimitiveType": "String", "Required": true, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafv2-ipset.html#cfn-wafv2-ipset-tags", @@ -87720,7 +92977,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafv2-regexpatternset.html#cfn-wafv2-regexpatternset-name", "PrimitiveType": "String", "Required": false, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "RegularExpressionList": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafv2-regexpatternset.html#cfn-wafv2-regexpatternset-regularexpressionlist", @@ -87733,7 +92990,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafv2-regexpatternset.html#cfn-wafv2-regexpatternset-scope", "PrimitiveType": "String", "Required": true, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafv2-regexpatternset.html#cfn-wafv2-regexpatternset-tags", @@ -87749,8 +93006,19 @@ "Arn": { "PrimitiveType": "String" }, + "AvailableLabels": { + "ItemType": "LabelSummary", + "Type": "List" + }, + "ConsumedLabels": { + "ItemType": "LabelSummary", + "Type": "List" + }, "Id": { "PrimitiveType": "String" + }, + "LabelNamespace": { + "PrimitiveType": "String" } }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafv2-rulegroup.html", @@ -87761,6 +93029,13 @@ "Required": true, "UpdateType": "Mutable" }, + "CustomResponseBodies": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafv2-rulegroup.html#cfn-wafv2-rulegroup-customresponsebodies", + "ItemType": "CustomResponseBody", + "Required": false, + "Type": "Map", + "UpdateType": "Mutable" + }, "Description": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafv2-rulegroup.html#cfn-wafv2-rulegroup-description", "PrimitiveType": "String", @@ -87771,7 +93046,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafv2-rulegroup.html#cfn-wafv2-rulegroup-name", "PrimitiveType": "String", "Required": false, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "Rules": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafv2-rulegroup.html#cfn-wafv2-rulegroup-rules", @@ -87784,7 +93059,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafv2-rulegroup.html#cfn-wafv2-rulegroup-scope", "PrimitiveType": "String", "Required": true, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafv2-rulegroup.html#cfn-wafv2-rulegroup-tags", @@ -87811,10 +93086,20 @@ }, "Id": { "PrimitiveType": "String" + }, + "LabelNamespace": { + "PrimitiveType": "String" } }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafv2-webacl.html", "Properties": { + "CustomResponseBodies": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafv2-webacl.html#cfn-wafv2-webacl-customresponsebodies", + "ItemType": "CustomResponseBody", + "Required": false, + "Type": "Map", + "UpdateType": "Mutable" + }, "DefaultAction": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafv2-webacl.html#cfn-wafv2-webacl-defaultaction", "Required": true, @@ -87831,7 +93116,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafv2-webacl.html#cfn-wafv2-webacl-name", "PrimitiveType": "String", "Required": false, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "Rules": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafv2-webacl.html#cfn-wafv2-webacl-rules", @@ -87844,7 +93129,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafv2-webacl.html#cfn-wafv2-webacl-scope", "PrimitiveType": "String", "Required": true, - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wafv2-webacl.html#cfn-wafv2-webacl-tags", diff --git a/packages/@aws-cdk/cfnspec/spec-source/500_AWS_AppIntegrations_EventIntegration_EventFilter_patch.json b/packages/@aws-cdk/cfnspec/spec-source/500_AWS_AppIntegrations_EventIntegration_EventFilter_patch.json new file mode 100644 index 0000000000000..90cfb1ca4252f --- /dev/null +++ b/packages/@aws-cdk/cfnspec/spec-source/500_AWS_AppIntegrations_EventIntegration_EventFilter_patch.json @@ -0,0 +1,15 @@ +{ + "ResourceTypes": { + "AWS::AppIntegrations::EventIntegration": { + "patch": { + "description": "Remove incorrect PrimitiveType", + "operations": [ + { + "op": "remove", + "path": "/Properties/EventFilter/PrimitiveType" + } + ] + } + } + } +} diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/cloud-assembly/schema.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/cloud-assembly/schema.ts index 1d351364e019d..b6c9ba4ba39cd 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/lib/cloud-assembly/schema.ts +++ b/packages/@aws-cdk/cloud-assembly-schema/lib/cloud-assembly/schema.ts @@ -98,6 +98,13 @@ export interface ArtifactManifest { * @default - no properties. */ readonly properties?: ArtifactProperties; + + /** + * A string that represents this artifact. Should only be used in user interfaces. + * + * @default - no display name + */ + readonly displayName?: string; } /** diff --git a/packages/@aws-cdk/cloud-assembly-schema/package.json b/packages/@aws-cdk/cloud-assembly-schema/package.json index fdac837c6ca7a..e7c5db4003ee8 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/package.json +++ b/packages/@aws-cdk/cloud-assembly-schema/package.json @@ -58,11 +58,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.21", + "@types/jest": "^26.0.23", "@types/mock-fs": "^4.13.0", + "@types/semver": "^7.3.5", "cdk-build-tools": "0.0.0", "jest": "^26.6.3", - "mock-fs": "^4.13.0", + "mock-fs": "^4.14.0", "pkglint": "0.0.0", "typescript-json-schema": "^0.50.0" }, @@ -89,7 +90,7 @@ }, "dependencies": { "jsonschema": "^1.4.0", - "semver": "^7.3.4" + "semver": "^7.3.5" }, "awscdkio": { "announce": false diff --git a/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.schema.json b/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.schema.json index 2ed400edff3ca..38c7538f38384 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.schema.json +++ b/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.schema.json @@ -77,6 +77,10 @@ "$ref": "#/definitions/NestedCloudAssemblyProperties" } ] + }, + "displayName": { + "description": "A string that represents this artifact. Should only be used in user interfaces. (Default - no display name)", + "type": "string" } }, "required": [ diff --git a/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.version.json b/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.version.json index 193f97fba499d..1829f904a3c7a 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.version.json +++ b/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.version.json @@ -1 +1 @@ -{"version":"9.0.0"} +{"version":"10.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/cloudformation-diff/README.md b/packages/@aws-cdk/cloudformation-diff/README.md index 678bc2c9ba0d2..cc8a457769e9e 100644 --- a/packages/@aws-cdk/cloudformation-diff/README.md +++ b/packages/@aws-cdk/cloudformation-diff/README.md @@ -3,13 +3,7 @@ --- -![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. +![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge) --- diff --git a/packages/@aws-cdk/cloudformation-diff/lib/format-table.ts b/packages/@aws-cdk/cloudformation-diff/lib/format-table.ts index 372ab5d9acd8a..0799243ba954e 100644 --- a/packages/@aws-cdk/cloudformation-diff/lib/format-table.ts +++ b/packages/@aws-cdk/cloudformation-diff/lib/format-table.ts @@ -27,16 +27,15 @@ function lineBetween(rowA: string[], rowB: string[]) { return rowA[1] !== rowB[1]; } -function buildColumnConfig(widths: number[] | undefined): { [index: number]: table.TableColumns } | undefined { +function buildColumnConfig(widths: number[] | undefined): { [index: number]: table.ColumnUserConfig } | undefined { if (widths === undefined) { return undefined; } - const ret: { [index: number]: table.TableColumns } = {}; + const ret: { [index: number]: table.ColumnUserConfig } = {}; widths.forEach((width, i) => { - ret[i] = { width }; - if (width === undefined) { - delete ret[i].width; + return; } + ret[i] = { width }; }); return ret; diff --git a/packages/@aws-cdk/cloudformation-diff/package.json b/packages/@aws-cdk/cloudformation-diff/package.json index f9b2c7342a84e..1142093d6f7a4 100644 --- a/packages/@aws-cdk/cloudformation-diff/package.json +++ b/packages/@aws-cdk/cloudformation-diff/package.json @@ -26,17 +26,16 @@ "diff": "^5.0.0", "fast-deep-equal": "^3.1.3", "string-width": "^4.2.2", - "table": "^6.0.7" + "table": "^6.6.0" }, "devDependencies": { - "@types/jest": "^26.0.21", + "@types/jest": "^26.0.23", "@types/string-width": "^4.0.1", - "@types/table": "^6.0.0", "cdk-build-tools": "0.0.0", "fast-check": "^2.14.0", "jest": "^26.6.3", "pkglint": "0.0.0", - "ts-jest": "^26.5.4" + "ts-jest": "^26.5.5" }, "repository": { "url": "https://github.com/aws/aws-cdk.git", @@ -51,8 +50,8 @@ "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, - "stability": "experimental", - "maturity": "experimental", + "stability": "stable", + "maturity": "stable", "cdk-build": { "jest": true }, diff --git a/packages/@aws-cdk/cloudformation-include/NOTICE b/packages/@aws-cdk/cloudformation-include/NOTICE index 5fc3826926b5b..c84ff36099c3b 100644 --- a/packages/@aws-cdk/cloudformation-include/NOTICE +++ b/packages/@aws-cdk/cloudformation-include/NOTICE @@ -1,2 +1,23 @@ AWS Cloud Development Kit (AWS CDK) Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +------------------------------------------------------------------------------- + +The AWS CDK includes the following third-party software/licensing: + +** yaml - https://www.npmjs.com/package/yaml +Copyright 2018 Eemeli Aro + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. + +---------------- diff --git a/packages/@aws-cdk/cloudformation-include/lib/file-utils.ts b/packages/@aws-cdk/cloudformation-include/lib/file-utils.ts index 2eb24e7013d93..4207068a29f33 100644 --- a/packages/@aws-cdk/cloudformation-include/lib/file-utils.ts +++ b/packages/@aws-cdk/cloudformation-include/lib/file-utils.ts @@ -1,5 +1,5 @@ import * as fs from 'fs'; -import * as yaml_cfn from '@aws-cdk/yaml-cfn'; +import * as yaml_cfn from './private/yaml-cfn'; export function readJsonSync(filePath: string): any { const fileContents = fs.readFileSync(filePath); diff --git a/packages/@aws-cdk/cloudformation-include/lib/private/yaml-cfn.ts b/packages/@aws-cdk/cloudformation-include/lib/private/yaml-cfn.ts new file mode 100644 index 0000000000000..5a191e92234e5 --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/lib/private/yaml-cfn.ts @@ -0,0 +1,60 @@ +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): yaml_types.Schema.CustomTag { + return { + identify(value: any) { return typeof value === 'string'; }, + tag: `!${intrinsicName}`, + resolve: (_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', 'GetAtt', +].map(name => makeTagForCfnIntrinsic(name, true)).concat( + makeTagForCfnIntrinsic('Ref', false), + makeTagForCfnIntrinsic('Condition', false), +); + +function parseYamlStrWithCfnTags(text: string): any { + return yaml.parse(text, { + customTags: shortForms, + schema: 'core', + }); +} + diff --git a/packages/@aws-cdk/cloudformation-include/package.json b/packages/@aws-cdk/cloudformation-include/package.json index c913b93bcdf41..2a68f7c70654f 100644 --- a/packages/@aws-cdk/cloudformation-include/package.json +++ b/packages/@aws-cdk/cloudformation-include/package.json @@ -74,6 +74,7 @@ "@aws-cdk/aws-apigatewayv2": "0.0.0", "@aws-cdk/aws-appconfig": "0.0.0", "@aws-cdk/aws-appflow": "0.0.0", + "@aws-cdk/aws-appintegrations": "0.0.0", "@aws-cdk/aws-applicationautoscaling": "0.0.0", "@aws-cdk/aws-applicationinsights": "0.0.0", "@aws-cdk/aws-appmesh": "0.0.0", @@ -106,6 +107,7 @@ "@aws-cdk/aws-codestarnotifications": "0.0.0", "@aws-cdk/aws-cognito": "0.0.0", "@aws-cdk/aws-config": "0.0.0", + "@aws-cdk/aws-customerprofiles": "0.0.0", "@aws-cdk/aws-databrew": "0.0.0", "@aws-cdk/aws-datapipeline": "0.0.0", "@aws-cdk/aws-datasync": "0.0.0", @@ -131,6 +133,7 @@ "@aws-cdk/aws-emrcontainers": "0.0.0", "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-eventschemas": "0.0.0", + "@aws-cdk/aws-fis": "0.0.0", "@aws-cdk/aws-fms": "0.0.0", "@aws-cdk/aws-fsx": "0.0.0", "@aws-cdk/aws-gamelift": "0.0.0", @@ -138,6 +141,7 @@ "@aws-cdk/aws-glue": "0.0.0", "@aws-cdk/aws-greengrass": "0.0.0", "@aws-cdk/aws-greengrassv2": "0.0.0", + "@aws-cdk/aws-groundstation": "0.0.0", "@aws-cdk/aws-guardduty": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-imagebuilder": "0.0.0", @@ -146,6 +150,7 @@ "@aws-cdk/aws-iot1click": "0.0.0", "@aws-cdk/aws-iotanalytics": "0.0.0", "@aws-cdk/aws-iotevents": "0.0.0", + "@aws-cdk/aws-iotfleethub": "0.0.0", "@aws-cdk/aws-iotsitewise": "0.0.0", "@aws-cdk/aws-iotthingsgraph": "0.0.0", "@aws-cdk/aws-iotwireless": "0.0.0", @@ -159,6 +164,7 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-licensemanager": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", + "@aws-cdk/aws-lookoutmetrics": "0.0.0", "@aws-cdk/aws-lookoutvision": "0.0.0", "@aws-cdk/aws-macie": "0.0.0", "@aws-cdk/aws-managedblockchain": "0.0.0", @@ -172,6 +178,7 @@ "@aws-cdk/aws-neptune": "0.0.0", "@aws-cdk/aws-networkfirewall": "0.0.0", "@aws-cdk/aws-networkmanager": "0.0.0", + "@aws-cdk/aws-nimblestudio": "0.0.0", "@aws-cdk/aws-opsworks": "0.0.0", "@aws-cdk/aws-opsworkscm": "0.0.0", "@aws-cdk/aws-pinpoint": "0.0.0", @@ -186,6 +193,7 @@ "@aws-cdk/aws-route53": "0.0.0", "@aws-cdk/aws-route53resolver": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", + "@aws-cdk/aws-s3objectlambda": "0.0.0", "@aws-cdk/aws-s3outposts": "0.0.0", "@aws-cdk/aws-sagemaker": "0.0.0", "@aws-cdk/aws-sam": "0.0.0", @@ -210,8 +218,8 @@ "@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.2.0" + "constructs": "^3.3.69", + "yaml": "1.10.2" }, "peerDependencies": { "@aws-cdk/alexa-ask": "0.0.0", @@ -223,6 +231,7 @@ "@aws-cdk/aws-apigatewayv2": "0.0.0", "@aws-cdk/aws-appconfig": "0.0.0", "@aws-cdk/aws-appflow": "0.0.0", + "@aws-cdk/aws-appintegrations": "0.0.0", "@aws-cdk/aws-applicationautoscaling": "0.0.0", "@aws-cdk/aws-applicationinsights": "0.0.0", "@aws-cdk/aws-appmesh": "0.0.0", @@ -255,6 +264,7 @@ "@aws-cdk/aws-codestarnotifications": "0.0.0", "@aws-cdk/aws-cognito": "0.0.0", "@aws-cdk/aws-config": "0.0.0", + "@aws-cdk/aws-customerprofiles": "0.0.0", "@aws-cdk/aws-databrew": "0.0.0", "@aws-cdk/aws-datapipeline": "0.0.0", "@aws-cdk/aws-datasync": "0.0.0", @@ -280,6 +290,7 @@ "@aws-cdk/aws-emrcontainers": "0.0.0", "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-eventschemas": "0.0.0", + "@aws-cdk/aws-fis": "0.0.0", "@aws-cdk/aws-fms": "0.0.0", "@aws-cdk/aws-fsx": "0.0.0", "@aws-cdk/aws-gamelift": "0.0.0", @@ -287,6 +298,7 @@ "@aws-cdk/aws-glue": "0.0.0", "@aws-cdk/aws-greengrass": "0.0.0", "@aws-cdk/aws-greengrassv2": "0.0.0", + "@aws-cdk/aws-groundstation": "0.0.0", "@aws-cdk/aws-guardduty": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-imagebuilder": "0.0.0", @@ -295,6 +307,7 @@ "@aws-cdk/aws-iot1click": "0.0.0", "@aws-cdk/aws-iotanalytics": "0.0.0", "@aws-cdk/aws-iotevents": "0.0.0", + "@aws-cdk/aws-iotfleethub": "0.0.0", "@aws-cdk/aws-iotsitewise": "0.0.0", "@aws-cdk/aws-iotthingsgraph": "0.0.0", "@aws-cdk/aws-iotwireless": "0.0.0", @@ -308,6 +321,7 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-licensemanager": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", + "@aws-cdk/aws-lookoutmetrics": "0.0.0", "@aws-cdk/aws-lookoutvision": "0.0.0", "@aws-cdk/aws-macie": "0.0.0", "@aws-cdk/aws-managedblockchain": "0.0.0", @@ -321,6 +335,7 @@ "@aws-cdk/aws-neptune": "0.0.0", "@aws-cdk/aws-networkfirewall": "0.0.0", "@aws-cdk/aws-networkmanager": "0.0.0", + "@aws-cdk/aws-nimblestudio": "0.0.0", "@aws-cdk/aws-opsworks": "0.0.0", "@aws-cdk/aws-opsworkscm": "0.0.0", "@aws-cdk/aws-pinpoint": "0.0.0", @@ -335,6 +350,7 @@ "@aws-cdk/aws-route53": "0.0.0", "@aws-cdk/aws-route53resolver": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", + "@aws-cdk/aws-s3objectlambda": "0.0.0", "@aws-cdk/aws-s3outposts": "0.0.0", "@aws-cdk/aws-sagemaker": "0.0.0", "@aws-cdk/aws-sam": "0.0.0", @@ -359,18 +375,20 @@ "@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.2.0" + "constructs": "^3.3.69" }, "devDependencies": { - "@aws-cdk/assert": "0.0.0", - "@types/jest": "^26.0.21", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "jest": "^26.6.3", "pkglint": "0.0.0", - "ts-jest": "^26.5.4" + "ts-jest": "^26.5.5", + "@aws-cdk/assert-internal": "0.0.0" }, + "bundledDependencies": [ + "yaml" + ], "keywords": [ "aws", "cdk", @@ -396,6 +414,7 @@ "awscdkio": { "announce": false }, + "nozem": false, "publishConfig": { "tag": "latest" } 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 a81f01f03fabb..326b80a3585f8 100644 --- a/packages/@aws-cdk/cloudformation-include/test/invalid-templates.test.ts +++ b/packages/@aws-cdk/cloudformation-include/test/invalid-templates.test.ts @@ -1,6 +1,6 @@ import * as path from 'path'; -import { SynthUtils } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { SynthUtils } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as core from '@aws-cdk/core'; import * as constructs from 'constructs'; import * as inc from '../lib'; 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 0e9dcadc5ce60..1a0d9763280ca 100644 --- a/packages/@aws-cdk/cloudformation-include/test/nested-stacks.test.ts +++ b/packages/@aws-cdk/cloudformation-include/test/nested-stacks.test.ts @@ -1,6 +1,6 @@ import * as path from 'path'; -import { ABSENT, ResourcePart } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { ABSENT, ResourcePart } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as s3 from '@aws-cdk/aws-s3'; import * as core from '@aws-cdk/core'; import * as inc from '../lib'; diff --git a/packages/@aws-cdk/cloudformation-include/test/serverless-transform.test.ts b/packages/@aws-cdk/cloudformation-include/test/serverless-transform.test.ts index 54f5b28b7fed3..853869ec1dd24 100644 --- a/packages/@aws-cdk/cloudformation-include/test/serverless-transform.test.ts +++ b/packages/@aws-cdk/cloudformation-include/test/serverless-transform.test.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as core from '@aws-cdk/core'; import * as constructs from 'constructs'; import * as inc from '../lib'; diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/fn-sub-map-empty.json b/packages/@aws-cdk/cloudformation-include/test/test-templates/fn-sub-map-empty.json new file mode 100644 index 0000000000000..07def731df41f --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/fn-sub-map-empty.json @@ -0,0 +1,12 @@ +{ + "Resources": { + "Bucket": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketName": { + "Fn::Sub": ["my-bucket", {}] + } + } + } + } +} diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/yaml/json-in-fn-sub.yaml b/packages/@aws-cdk/cloudformation-include/test/test-templates/yaml/json-in-fn-sub.yaml new file mode 100644 index 0000000000000..111490f99c9db --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/yaml/json-in-fn-sub.yaml @@ -0,0 +1,26 @@ +AWSTemplateFormatVersion: 2010-09-09 +Parameters: + Stage: + Type: String +Resources: + Dashboard: + Type: AWS::CloudWatch::Dashboard + Properties: + DashboardName: !Sub ${Stage}-Dashboard + DashboardBody: !Sub | + { + "widgets": [ + { + "type": "text", + "properties": { + "markdown": "${Stage} ${Stage}" + } + }, + { + "type": "text", + "properties": { + "markdown": "${Stage} ${Stage}" + } + } + ] + } diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/yaml/year-month-date-as-strings.yaml b/packages/@aws-cdk/cloudformation-include/test/test-templates/yaml/year-month-date-as-strings.yaml new file mode 100644 index 0000000000000..f25f363879810 --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/yaml/year-month-date-as-strings.yaml @@ -0,0 +1,14 @@ +AWSTemplateFormatVersion: 2010-09-09 +Resources: + Role: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Principal: + Service: + - ec2.amazonaws.com + Action: + - sts:AssumeRole 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 3d8b51098d293..0741b7f9d23df 100644 --- a/packages/@aws-cdk/cloudformation-include/test/valid-templates.test.ts +++ b/packages/@aws-cdk/cloudformation-include/test/valid-templates.test.ts @@ -1,6 +1,6 @@ import * as path from 'path'; -import { ResourcePart } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { ResourcePart } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/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'; @@ -273,6 +273,14 @@ describe('CDK Include', () => { ); }); + test('preserves an empty map passed to Fn::Sub', () => { + includeTestTemplate(stack, 'fn-sub-map-empty.json'); + + expect(stack).toMatchTemplate( + loadTestFileToJsObject('fn-sub-map-empty.json'), + ); + }); + test('can ingest a template with Fn::Sub shadowing a logical ID from the template and output it unchanged', () => { includeTestTemplate(stack, 'fn-sub-shadow.json'); @@ -326,6 +334,44 @@ describe('CDK Include', () => { ); }); + test('when a parameter in an Fn::Sub expression is substituted with a deploy-time value, it adds a new key to the Fn::Sub map', () => { + const parameter = new core.CfnParameter(stack, 'AnotherParam'); + includeTestTemplate(stack, 'fn-sub-parameters.json', { + parameters: { + 'MyParam': `it's_a_${parameter.valueAsString}_concatenation`, + }, + }); + + expect(stack).toMatchTemplate({ + "Parameters": { + "AnotherParam": { + "Type": "String", + }, + }, + "Resources": { + "Bucket": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketName": { + "Fn::Sub": [ + "${MyParam}", + { + "MyParam": { + "Fn::Join": ["", [ + "it's_a_", + { "Ref": "AnotherParam" }, + "_concatenation", + ]], + }, + }, + ], + }, + }, + }, + }, + }); + }); + test('can ingest a template with a Ref expression for an array value, and output it unchanged', () => { includeTestTemplate(stack, 'ref-array-property.json'); diff --git a/packages/@aws-cdk/cloudformation-include/test/yaml-templates.test.ts b/packages/@aws-cdk/cloudformation-include/test/yaml-templates.test.ts index 5faf8bd1a5e1c..06beafcdeb62c 100644 --- a/packages/@aws-cdk/cloudformation-include/test/yaml-templates.test.ts +++ b/packages/@aws-cdk/cloudformation-include/test/yaml-templates.test.ts @@ -1,5 +1,6 @@ import * as path from 'path'; -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; +import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as core from '@aws-cdk/core'; import * as constructs from 'constructs'; import * as inc from '../lib'; @@ -23,6 +24,33 @@ describe('CDK Include', () => { ); }); + test('can ingest a template with year-month-date parsed as string instead of Date', () => { + includeTestTemplate(stack, 'year-month-date-as-strings.yaml'); + + expect(stack).toMatchTemplate({ + "AWSTemplateFormatVersion": "2010-09-09", + "Resources": { + "Role": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Service": ["ec2.amazonaws.com"], + }, + "Action": ["sts:AssumeRole"], + }, + ], + }, + }, + }, + }, + }); + }); + test('can ingest a template with the short form Base64 function', () => { includeTestTemplate(stack, 'short-form-base64.yaml'); @@ -370,7 +398,7 @@ describe('CDK Include', () => { ); }); - test('can ingest a YAML tempalte with Fn::Sub in string form and output it unchanged', () => { + test('can ingest a YAML template with Fn::Sub in string form and output it unchanged', () => { includeTestTemplate(stack, 'short-form-fnsub-string.yaml'); expect(stack).toMatchTemplate( @@ -378,7 +406,7 @@ describe('CDK Include', () => { ); }); - test('can ingest a YAML tmeplate with Fn::Sub in map form and output it unchanged', () => { + test('can ingest a YAML template with Fn::Sub in map form and output it unchanged', () => { includeTestTemplate(stack, 'short-form-sub-map.yaml'); expect(stack).toMatchTemplate( @@ -386,16 +414,43 @@ describe('CDK Include', () => { ); }); - test('the parser throws an error on a YAML tmeplate with short form import value that uses short form sub', () => { + test('can correctly substitute values inside a string containing JSON passed to Fn::Sub', () => { + const cfnInclude = includeTestTemplate(stack, 'json-in-fn-sub.yaml', { + Stage: 'test', + }); + + const dashboard = cfnInclude.getResource('Dashboard') as cloudwatch.CfnDashboard; + // we need to resolve the Fn::Sub expression to get to its argument + const resolvedDashboardBody = stack.resolve(dashboard.dashboardBody)['Fn::Sub']; + expect(JSON.parse(resolvedDashboardBody)).toStrictEqual({ + "widgets": [ + { + "type": "text", + "properties": { + "markdown": "test test", + }, + }, + { + "type": "text", + "properties": { + "markdown": "test test", + }, + }, + ], + }); + }); + + test('the parser throws an error on a YAML template with short form import value that uses short form sub', () => { expect(() => { includeTestTemplate(stack, 'invalid/short-form-import-sub.yaml'); }).toThrow(/A node can have at most one tag/); }); }); -function includeTestTemplate(scope: constructs.Construct, testTemplate: string): inc.CfnInclude { +function includeTestTemplate(scope: constructs.Construct, testTemplate: string, parameters?: { [key: string]: string }): inc.CfnInclude { return new inc.CfnInclude(scope, 'MyScope', { templateFile: _testTemplateFilePath(testTemplate), + parameters, }); } diff --git a/packages/@aws-cdk/core/README.md b/packages/@aws-cdk/core/README.md index bb519f066af55..44fdda5893019 100644 --- a/packages/@aws-cdk/core/README.md +++ b/packages/@aws-cdk/core/README.md @@ -19,6 +19,8 @@ Guide](https://docs.aws.amazon.com/cdk/latest/guide/home.html) for information of most of the capabilities of this library. The rest of this README will only cover topics not already covered in the Developer Guide. + + ## Stacks and Stages A `Stack` is the smallest physical unit of deployment, and maps directly onto @@ -911,3 +913,5 @@ When deploying to AWS CloudFormation, it needs to keep in check the amount of re It's possible to synthesize the project with more Resources than the allowed (or even reduce the number of Resources). Set the context key `@aws-cdk/core:stackResourceLimit` with the proper value, being 0 for disable the limit of resources. + + diff --git a/packages/@aws-cdk/core/lib/arn.ts b/packages/@aws-cdk/core/lib/arn.ts index 1ffcc2da2b33c..fe6b5b12b934b 100644 --- a/packages/@aws-cdk/core/lib/arn.ts +++ b/packages/@aws-cdk/core/lib/arn.ts @@ -286,31 +286,39 @@ function parseToken(arnToken: string, sep: string = '/', hasName: boolean = true * Validate that a string is either unparseable or looks mostly like an ARN */ function parseArnShape(arn: string): 'token' | string[] { - const components = arn.split(':'); - const looksLikeArn = arn.startsWith('arn:') && components.length >= 6; + // assume anything that starts with 'arn:' is an ARN, + // so we can report better errors + const looksLikeArn = arn.startsWith('arn:'); if (!looksLikeArn) { - if (Token.isUnresolved(arn)) { return 'token'; } - throw new Error(`ARNs must start with "arn:" and have at least 6 components: ${arn}`); + if (Token.isUnresolved(arn)) { + return 'token'; + } else { + throw new Error(`ARNs must start with "arn:" and have at least 6 components: ${arn}`); + } } // If the ARN merely contains Tokens, but otherwise *looks* mostly like an ARN, - // it's a string of the form 'arn:${partition}:service:${region}:${account}:abc/xyz'. + // it's a string of the form 'arn:${partition}:service:${region}:${account}:resource/xyz'. // Parse fields out to the best of our ability. // Tokens won't contain ":", so this won't break them. + const components = arn.split(':'); - const [/* arn */, partition, service, /* region */ , /* account */ , resource] = components; + // const [/* arn */, partition, service, /* region */ , /* account */ , resource] = components; + const partition = components.length > 1 ? components[1] : undefined; if (!partition) { - throw new Error('The `partition` component (2nd component) is required: ' + arn); + throw new Error('The `partition` component (2nd component) of an ARN is required: ' + arn); } + const service = components.length > 2 ? components[2] : undefined; if (!service) { - throw new Error('The `service` component (3rd component) is required: ' + arn); + throw new Error('The `service` component (3rd component) of an ARN is required: ' + arn); } + const resource = components.length > 5 ? components[5] : undefined; if (!resource) { - throw new Error('The `resource` component (6th component) is required: ' + arn); + throw new Error('The `resource` component (6th component) of an ARN is required: ' + arn); } // Region can be missing in global ARNs (such as used by IAM) @@ -318,4 +326,4 @@ function parseArnShape(arn: string): 'token' | string[] { // Account can be missing in some ARN types (such as used for S3 buckets) return components; -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/core/lib/asset-staging.ts b/packages/@aws-cdk/core/lib/asset-staging.ts index 6a34bd9b4b1ac..09820293b63ec 100644 --- a/packages/@aws-cdk/core/lib/asset-staging.ts +++ b/packages/@aws-cdk/core/lib/asset-staging.ts @@ -75,13 +75,11 @@ export interface AssetStagingProps extends FingerprintOptions, AssetOptions { export class AssetStaging extends CoreConstruct { /** * The directory inside the bundling container into which the asset sources will be mounted. - * @experimental */ public static readonly BUNDLING_INPUT_DIR = '/asset-input'; /** * The directory inside the bundling container into which the bundled output should be written. - * @experimental */ public static readonly BUNDLING_OUTPUT_DIR = '/asset-output'; diff --git a/packages/@aws-cdk/core/lib/assets.ts b/packages/@aws-cdk/core/lib/assets.ts index 72cba9719e784..d9bd02d4d91a9 100644 --- a/packages/@aws-cdk/core/lib/assets.ts +++ b/packages/@aws-cdk/core/lib/assets.ts @@ -53,7 +53,7 @@ export interface AssetOptions { * @default - uploaded as-is to S3 if the asset is a regular file or a .zip file, * archived into a .zip file and uploaded to S3 otherwise * - * @experimental + * */ readonly bundling?: BundlingOptions; } diff --git a/packages/@aws-cdk/core/lib/bundling.ts b/packages/@aws-cdk/core/lib/bundling.ts index e3c1458aa0ab9..24af4f1b3139f 100644 --- a/packages/@aws-cdk/core/lib/bundling.ts +++ b/packages/@aws-cdk/core/lib/bundling.ts @@ -6,13 +6,12 @@ import { FileSystem } from './fs'; /** * Bundling options * - * @experimental */ export interface BundlingOptions { /** * The Docker image where the command will run. */ - readonly image: BundlingDockerImage; + readonly image: DockerImage; /** * The entrypoint to run in the Docker container. @@ -77,7 +76,6 @@ export interface BundlingOptions { * * @default - bundling will only be performed in a Docker container * - * @experimental */ readonly local?: ILocalBundling; @@ -86,7 +84,6 @@ export interface BundlingOptions { * * @default BundlingOutput.AUTO_DISCOVER * - * @experimental */ readonly outputType?: BundlingOutput; } @@ -94,7 +91,6 @@ export interface BundlingOptions { /** * The type of output that a bundling operation is producing. * - * @experimental */ export enum BundlingOutput { /** @@ -120,7 +116,6 @@ export enum BundlingOutput { /** * Local bundling * - * @experimental */ export interface ILocalBundling { /** @@ -146,7 +141,7 @@ export class BundlingDockerImage { * @param image the image name */ public static fromRegistry(image: string) { - return new BundlingDockerImage(image); + return new DockerImage(image); } /** @@ -157,34 +152,8 @@ export class BundlingDockerImage { * * @deprecated use DockerImage.fromBuild() */ - public static fromAsset(path: string, options: DockerBuildOptions = {}) { - const buildArgs = options.buildArgs || {}; - - if (options.file && isAbsolute(options.file)) { - throw new Error(`"file" must be relative to the docker build directory. Got ${options.file}`); - } - - // Image tag derived from path and build options - const input = JSON.stringify({ path, ...options }); - const tagHash = crypto.createHash('sha256').update(input).digest('hex'); - const tag = `cdk-${tagHash}`; - - const dockerArgs: string[] = [ - 'build', '-t', tag, - ...(options.file ? ['-f', join(path, options.file)] : []), - ...flatten(Object.entries(buildArgs).map(([k, v]) => ['--build-arg', `${k}=${v}`])), - path, - ]; - - dockerExec(dockerArgs); - - // Fingerprints the directory containing the Dockerfile we're building and - // differentiates the fingerprint based on build arguments. We do this so - // we can provide a stable image hash. Otherwise, the image ID will be - // different every time the Docker layer cache is cleared, due primarily to - // timestamps. - const hash = FileSystem.fingerprint(path, { extraHash: JSON.stringify(options) }); - return new BundlingDockerImage(tag, hash); + public static fromAsset(path: string, options: DockerBuildOptions = {}): BundlingDockerImage { + return DockerImage.fromBuild(path, options); } /** @param image The Docker image */ @@ -276,7 +245,76 @@ export class DockerImage extends BundlingDockerImage { * @param options Docker build options */ public static fromBuild(path: string, options: DockerBuildOptions = {}) { - return BundlingDockerImage.fromAsset(path, options); + const buildArgs = options.buildArgs || {}; + + if (options.file && isAbsolute(options.file)) { + throw new Error(`"file" must be relative to the docker build directory. Got ${options.file}`); + } + + // Image tag derived from path and build options + const input = JSON.stringify({ path, ...options }); + const tagHash = crypto.createHash('sha256').update(input).digest('hex'); + const tag = `cdk-${tagHash}`; + + const dockerArgs: string[] = [ + 'build', '-t', tag, + ...(options.file ? ['-f', join(path, options.file)] : []), + ...flatten(Object.entries(buildArgs).map(([k, v]) => ['--build-arg', `${k}=${v}`])), + path, + ]; + + dockerExec(dockerArgs); + + // Fingerprints the directory containing the Dockerfile we're building and + // differentiates the fingerprint based on build arguments. We do this so + // we can provide a stable image hash. Otherwise, the image ID will be + // different every time the Docker layer cache is cleared, due primarily to + // timestamps. + const hash = FileSystem.fingerprint(path, { extraHash: JSON.stringify(options) }); + return new DockerImage(tag, hash); + } + + /** + * Reference an image on DockerHub or another online registry. + * + * @param image the image name + */ + public static fromRegistry(image: string) { + return new DockerImage(image); + } + + /** @param image The Docker image */ + constructor(public readonly image: string, _imageHash?: string) { + super(image, _imageHash); + } + + /** + * Provides a stable representation of this image for JSON serialization. + * + * @return The overridden image name if set or image hash name in that order + */ + public toJSON() { + return super.toJSON(); + } + + /** + * Runs a Docker image + */ + public run(options: DockerRunOptions = {}) { + return super.run(options); + } + + /** + * Copies a file or directory out of the Docker image to the local filesystem. + * + * If `outputPath` is omitted the destination path is a temporary directory. + * + * @param imagePath the path in the Docker image + * @param outputPath the destination path for the copy operation + * @returns the destination path + */ + public cp(imagePath: string, outputPath?: string): string { + return super.cp(imagePath, outputPath); } } diff --git a/packages/@aws-cdk/core/lib/cfn-parse.ts b/packages/@aws-cdk/core/lib/cfn-parse.ts index 8f5d820584d98..e57bf28e785f3 100644 --- a/packages/@aws-cdk/core/lib/cfn-parse.ts +++ b/packages/@aws-cdk/core/lib/cfn-parse.ts @@ -79,7 +79,6 @@ export class FromCloudFormationPropertyObject> ext * (to not make it part of the public API), * it is directly referenced in the generated L1 code. * - * @experimental */ export class FromCloudFormation { // nothing to for any but return it @@ -340,7 +339,6 @@ export interface ParseCfnOptions { * it is directly referenced in the generated L1 code, * so any renames of it need to be reflected in cfn2ts/codegen.ts as well. * - * @experimental */ export class CfnParser { private readonly options: ParseCfnOptions; @@ -648,7 +646,7 @@ export class CfnParser { map = value[1]; } - return Fn.sub(this.parseFnSubString(fnSubString, map), map); + return this.parseFnSubString(fnSubString, map); } case 'Condition': { // a reference to a Condition from another Condition @@ -682,48 +680,78 @@ export class CfnParser { : undefined; } - private parseFnSubString(value: string, map: { [key: string]: any } = {}): string { - const leftBrace = value.indexOf('${'); - const rightBrace = value.indexOf('}') + 1; - // don't include left and right braces when searching for the target of the reference - if (leftBrace === -1 || leftBrace >= rightBrace) { - return value; - } - - const leftHalf = value.substring(0, leftBrace); - const rightHalf = value.substring(rightBrace); - const refTarget = value.substring(leftBrace + 2, rightBrace - 1).trim(); - if (refTarget[0] === '!') { - return value.substring(0, rightBrace) + this.parseFnSubString(rightHalf, map); - } - - // lookup in map - if (refTarget in map) { - return leftHalf + '${' + refTarget + '}' + this.parseFnSubString(rightHalf, map); - } - - // since it's not in the map, check if it's a pseudo parameter - const specialRef = this.specialCaseSubRefs(refTarget); - if (specialRef !== undefined) { - return leftHalf + specialRef + this.parseFnSubString(rightHalf, map); - } + private parseFnSubString(templateString: string, expressionMap: { [key: string]: any } | undefined): string { + const map = expressionMap ?? {}; + const self = this; + return Fn.sub(go(templateString), Object.keys(map).length === 0 ? expressionMap : map); + + function go(value: string): string { + const leftBrace = value.indexOf('${'); + if (leftBrace === -1) { + return value; + } + // search for the closing brace to the right of the opening '${' + // (in theory, there could be other braces in the string, + // for example if it represents a JSON object) + const rightBrace = value.indexOf('}', leftBrace); + if (rightBrace === -1) { + return value; + } + + const leftHalf = value.substring(0, leftBrace); + const rightHalf = value.substring(rightBrace + 1); + // don't include left and right braces when searching for the target of the reference + const refTarget = value.substring(leftBrace + 2, rightBrace).trim(); + if (refTarget[0] === '!') { + return value.substring(0, rightBrace + 1) + go(rightHalf); + } + + // lookup in map + if (refTarget in map) { + return leftHalf + '${' + refTarget + '}' + go(rightHalf); + } + + // since it's not in the map, check if it's a pseudo-parameter + // (or a value to be substituted for a Parameter, provided by the customer) + const specialRef = self.specialCaseSubRefs(refTarget); + if (specialRef !== undefined) { + if (Token.isUnresolved(specialRef)) { + // specialRef can only be a Token if the value passed by the customer + // for substituting a Parameter was a Token. + // This is actually bad here, + // because the Token can potentially be something that doesn't render + // well inside an Fn::Sub template string, like a { Ref } object. + // To handle this case, + // instead of substituting the Parameter directly with the token in the template string, + // add a new entry to the Fn::Sub map, + // with key refTarget, and the token as the value. + // This is safe, because this sort of shadowing is legal in CloudFormation, + // and also because we're certain the Fn::Sub map doesn't contain an entry for refTarget + // (as we check that condition in the code right above this). + map[refTarget] = specialRef; + return leftHalf + '${' + refTarget + '}' + go(rightHalf); + } else { + return leftHalf + specialRef + go(rightHalf); + } + } - const dotIndex = refTarget.indexOf('.'); - const isRef = dotIndex === -1; - if (isRef) { - const refElement = this.finder.findRefTarget(refTarget); - if (!refElement) { - throw new Error(`Element referenced in Fn::Sub expression with logical ID: '${refTarget}' was not found in the template`); - } - return leftHalf + CfnReference.for(refElement, 'Ref', ReferenceRendering.FN_SUB).toString() + this.parseFnSubString(rightHalf, map); - } else { - const targetId = refTarget.substring(0, dotIndex); - const refResource = this.finder.findResource(targetId); - if (!refResource) { - throw new Error(`Resource referenced in Fn::Sub expression with logical ID: '${targetId}' was not found in the template`); - } - const attribute = refTarget.substring(dotIndex + 1); - return leftHalf + CfnReference.for(refResource, attribute, ReferenceRendering.FN_SUB).toString() + this.parseFnSubString(rightHalf, map); + const dotIndex = refTarget.indexOf('.'); + const isRef = dotIndex === -1; + if (isRef) { + const refElement = self.finder.findRefTarget(refTarget); + if (!refElement) { + throw new Error(`Element referenced in Fn::Sub expression with logical ID: '${refTarget}' was not found in the template`); + } + return leftHalf + CfnReference.for(refElement, 'Ref', ReferenceRendering.FN_SUB).toString() + go(rightHalf); + } else { + const targetId = refTarget.substring(0, dotIndex); + const refResource = self.finder.findResource(targetId); + if (!refResource) { + throw new Error(`Resource referenced in Fn::Sub expression with logical ID: '${targetId}' was not found in the template`); + } + const attribute = refTarget.substring(dotIndex + 1); + return leftHalf + CfnReference.for(refResource, attribute, ReferenceRendering.FN_SUB).toString() + go(rightHalf); + } } } diff --git a/packages/@aws-cdk/core/lib/construct-compat.ts b/packages/@aws-cdk/core/lib/construct-compat.ts index ac7873a837dde..d468ce234c4f3 100644 --- a/packages/@aws-cdk/core/lib/construct-compat.ts +++ b/packages/@aws-cdk/core/lib/construct-compat.ts @@ -412,11 +412,17 @@ export class ConstructNode { return this._actualNode.tryGetContext(key); } + /** + * DEPRECATED + * @deprecated use `metadataEntry` + */ + public get metadata() { return this._actualNode.metadata as cxapi.MetadataEntry[]; } + /** * An immutable array of metadata objects associated with this construct. * This can be used, for example, to implement support for deprecation notices, source mapping, etc. */ - public get metadata() { return this._actualNode.metadata as cxapi.MetadataEntry[]; } + public get metadataEntry() { return this._actualNode.metadata; } /** * Adds a metadata entry to this construct. @@ -516,7 +522,6 @@ export class ConstructNode { * Remove the child with the given name, if present. * * @returns Whether a child with the given name was deleted. - * @experimental */ public tryRemoveChild(childName: string): boolean { return this._actualNode.tryRemoveChild(childName); } } diff --git a/packages/@aws-cdk/core/lib/context-provider.ts b/packages/@aws-cdk/core/lib/context-provider.ts index d0ebaa34705ab..1eb210623558f 100644 --- a/packages/@aws-cdk/core/lib/context-provider.ts +++ b/packages/@aws-cdk/core/lib/context-provider.ts @@ -6,7 +6,6 @@ import { Stack } from './stack'; import { Token } from './token'; /** - * @experimental */ export interface GetContextKeyOptions { /** @@ -21,7 +20,6 @@ export interface GetContextKeyOptions { } /** - * @experimental */ export interface GetContextValueOptions extends GetContextKeyOptions { /** @@ -33,7 +31,6 @@ export interface GetContextValueOptions extends GetContextKeyOptions { } /** - * @experimental */ export interface GetContextKeyResult { readonly key: string; @@ -41,7 +38,6 @@ export interface GetContextKeyResult { } /** - * @experimental */ export interface GetContextValueResult { readonly value?: any; @@ -56,7 +52,6 @@ export interface GetContextValueResult { * * ContextProvider needs access to a Construct to hook into the context mechanism. * - * @experimental */ export class ContextProvider { /** diff --git a/packages/@aws-cdk/core/lib/custom-resource-provider/custom-resource-provider.ts b/packages/@aws-cdk/core/lib/custom-resource-provider/custom-resource-provider.ts index c7f3776339907..06f257fa18ff3 100644 --- a/packages/@aws-cdk/core/lib/custom-resource-provider/custom-resource-provider.ts +++ b/packages/@aws-cdk/core/lib/custom-resource-provider/custom-resource-provider.ts @@ -19,7 +19,6 @@ import { Construct as CoreConstruct } from '../construct-compat'; /** * Initialization properties for `CustomResourceProvider`. * - * @experimental */ export interface CustomResourceProviderProps { /** @@ -79,7 +78,6 @@ export interface CustomResourceProviderProps { /** * The lambda runtime to use for the resource provider. This also indicates * which language is used for the handler. - * @experimental */ export enum CustomResourceProviderRuntime { /** @@ -103,7 +101,6 @@ export enum CustomResourceProviderRuntime { /** * An AWS-Lambda backed custom resource provider. * - * @experimental */ export class CustomResourceProvider extends CoreConstruct { /** diff --git a/packages/@aws-cdk/core/lib/dependency.ts b/packages/@aws-cdk/core/lib/dependency.ts index 382d5acae0a61..781a1ef281bed 100644 --- a/packages/@aws-cdk/core/lib/dependency.ts +++ b/packages/@aws-cdk/core/lib/dependency.ts @@ -21,7 +21,6 @@ export interface IDependable { * This class can be used when a set of constructs which are disjoint in the * construct tree needs to be combined to be used as a single dependable. * - * @experimental */ export class ConcreteDependable implements IDependable { private readonly _dependencyRoots = new Array(); @@ -66,7 +65,6 @@ const DEPENDABLE_SYMBOL = Symbol.for('@aws-cdk/core.DependableTrait'); * } * DependableTrait.implement(construct, new TraitImplementation()); * - * @experimental */ export abstract class DependableTrait { /** diff --git a/packages/@aws-cdk/core/lib/fs/options.ts b/packages/@aws-cdk/core/lib/fs/options.ts index 3ea836a24e831..baf73bd7ffd30 100644 --- a/packages/@aws-cdk/core/lib/fs/options.ts +++ b/packages/@aws-cdk/core/lib/fs/options.ts @@ -56,19 +56,9 @@ export enum IgnoreMode { * context flag is set. */ DOCKER = 'docker' -}; - -/** - * Obtains applied when copying directories into the staging location. - */ -export interface CopyOptions { - /** - * A strategy for how to handle symlinks. - * - * @default SymlinkFollowMode.NEVER - */ - readonly follow?: SymlinkFollowMode; +} +interface FileOptions { /** * Glob patterns to exclude from the copy. * @@ -85,9 +75,30 @@ export interface CopyOptions { } /** - * Options related to calculating source hash. + * Options applied when copying directories + */ +export interface CopyOptions extends FileOptions { + /** + * A strategy for how to handle symlinks. + * + * @default SymlinkFollowMode.NEVER + */ + readonly follow?: SymlinkFollowMode; +} + +/** + * Options applied when copying directories into the staging location. */ -export interface FingerprintOptions extends CopyOptions { +export interface FileCopyOptions extends FileOptions { + /** + * A strategy for how to handle symlinks. + * + * @default SymlinkFollowMode.NEVER + */ + readonly followSymlinks?: SymlinkFollowMode; +} + +interface ExtraHashOptions { /** * Extra information to encode into the fingerprint (e.g. build instructions * and other inputs) @@ -96,3 +107,15 @@ export interface FingerprintOptions extends CopyOptions { */ readonly extraHash?: string; } + +/** + * Options related to calculating source hash. + */ +export interface FingerprintOptions extends CopyOptions, ExtraHashOptions { +} + +/** + * Options related to calculating source hash. + */ +export interface FileFingerprintOptions extends FileCopyOptions, ExtraHashOptions { +} diff --git a/packages/@aws-cdk/core/lib/nested-stack.ts b/packages/@aws-cdk/core/lib/nested-stack.ts index 648211aab22f0..fd8c47f6a0731 100644 --- a/packages/@aws-cdk/core/lib/nested-stack.ts +++ b/packages/@aws-cdk/core/lib/nested-stack.ts @@ -23,7 +23,6 @@ const NESTED_STACK_SYMBOL = Symbol.for('@aws-cdk/core.NestedStack'); /** * Initialization props for the `NestedStack` construct. * - * @experimental */ export interface NestedStackProps { /** @@ -90,7 +89,6 @@ export interface NestedStackProps { * nested stack will automatically be translated to stack parameters and * outputs. * - * @experimental */ export class NestedStack extends Stack { diff --git a/packages/@aws-cdk/core/lib/private/cloudformation-lang.ts b/packages/@aws-cdk/core/lib/private/cloudformation-lang.ts index c2be580474426..049ceb207f92f 100644 --- a/packages/@aws-cdk/core/lib/private/cloudformation-lang.ts +++ b/packages/@aws-cdk/core/lib/private/cloudformation-lang.ts @@ -233,7 +233,15 @@ function tokenAwareStringify(root: any, space: number, ctx: IResolveContext) { // // Therefore, if we encounter lists we need to defer to a custom resource to handle // them properly at deploy time. - pushIntrinsic(CfnUtils.stringify(Stack.of(ctx.scope), `CdkJsonStringify${stringifyCounter++}`, intrinsic)); + const stack = Stack.of(ctx.scope); + + // Because this will be called twice (once during `prepare`, once during `resolve`), + // we need to make sure to be idempotent, so use a cache. + const stringifyResponse = stringifyCache.obtain(stack, JSON.stringify(intrinsic), () => + CfnUtils.stringify(stack, `CdkJsonStringify${stringifyCounter++}`, intrinsic), + ); + + pushIntrinsic(stringifyResponse); return; case ResolutionTypeHint.NUMBER: @@ -418,4 +426,28 @@ function quoteString(s: string) { return s.substring(1, s.length - 1); } -let stringifyCounter = 1; \ No newline at end of file +let stringifyCounter = 1; + +/** + * A cache scoped to object instances, that's maintained externally to the object instances + */ +class ScopedCache { + private cache = new WeakMap>(); + + public obtain(object: O, key: K, init: () => V): V { + let kvMap = this.cache.get(object); + if (!kvMap) { + kvMap = new Map(); + this.cache.set(object, kvMap); + } + + let ret = kvMap.get(key); + if (ret === undefined) { + ret = init(); + kvMap.set(key, ret); + } + return ret; + } +} + +const stringifyCache = new ScopedCache(); \ No newline at end of file diff --git a/packages/@aws-cdk/core/lib/private/intrinsic.ts b/packages/@aws-cdk/core/lib/private/intrinsic.ts index 88cbe6ee02af7..cb814a6363594 100644 --- a/packages/@aws-cdk/core/lib/private/intrinsic.ts +++ b/packages/@aws-cdk/core/lib/private/intrinsic.ts @@ -5,7 +5,6 @@ import { Token } from '../token'; /** * Customization properties for an Intrinsic token * - * @experimental */ export interface IntrinsicProps { /** @@ -24,7 +23,6 @@ export interface IntrinsicProps { * * This class will disappear in a future release and should not be used. * - * @experimental */ export class Intrinsic implements IResolvable { /** diff --git a/packages/@aws-cdk/core/lib/private/runtime-info.ts b/packages/@aws-cdk/core/lib/private/runtime-info.ts index da4fbdcbe99d8..e92bbc1c986c9 100644 --- a/packages/@aws-cdk/core/lib/private/runtime-info.ts +++ b/packages/@aws-cdk/core/lib/private/runtime-info.ts @@ -88,5 +88,11 @@ function getJsiiAgentVersion() { jsiiAgent = `node.js/${process.version}`; } + // Sanitize the agent to remove characters which might mess with the downstream + // prefix encoding & decoding. In particular the .NET jsii agent takes a form like: + // DotNet/5.0.3/.NETCoreApp,Version=v3.1/1.0.0.0 + // The `,` in the above messes with the prefix decoding when reporting the analytics. + jsiiAgent = jsiiAgent.replace(/[^a-z0-9.-/=_]/gi, '-'); + return jsiiAgent; } diff --git a/packages/@aws-cdk/core/lib/private/synthesis.ts b/packages/@aws-cdk/core/lib/private/synthesis.ts index 737f11367e13f..c8a54267823a8 100644 --- a/packages/@aws-cdk/core/lib/private/synthesis.ts +++ b/packages/@aws-cdk/core/lib/private/synthesis.ts @@ -131,7 +131,7 @@ function injectMetadataResources(root: IConstruct) { visit(root, 'post', construct => { if (!Stack.isStack(construct) || !construct._versionReportingEnabled) { return; } - // Because of https://github.com/aws/aws-cdk/blob/master/packages/@aws-cdk/assert/lib/synth-utils.ts#L74 + // Because of https://github.com/aws/aws-cdk/blob/master/packages/assert-internal/lib/synth-utils.ts#L74 // synthesize() may be called more than once on a stack in unit tests, and the below would break // if we execute it a second time. Guard against the constructs already existing. const CDKMetadata = 'CDKMetadata'; @@ -205,7 +205,6 @@ function visit(root: IConstruct, order: 'pre' | 'post', cb: (x: IProtectedConstr /** * Interface which provides access to special methods of Construct * - * @experimental */ interface IProtectedConstructMethods extends IConstruct { /** diff --git a/packages/@aws-cdk/core/lib/private/tree-metadata.ts b/packages/@aws-cdk/core/lib/private/tree-metadata.ts index 97fe514bb4d87..8421fd3933aea 100644 --- a/packages/@aws-cdk/core/lib/private/tree-metadata.ts +++ b/packages/@aws-cdk/core/lib/private/tree-metadata.ts @@ -15,7 +15,6 @@ const FILE_PATH = 'tree.json'; * This generates, as part of synthesis, a file containing the construct tree and the metadata for each node in the tree. * The output is in a tree format so as to preserve the construct hierarchy. * - * @experimental */ export class TreeMetadata extends Construct { constructor(scope: Construct) { diff --git a/packages/@aws-cdk/core/lib/resolvable.ts b/packages/@aws-cdk/core/lib/resolvable.ts index 9004cd111bb33..bde3d670c5419 100644 --- a/packages/@aws-cdk/core/lib/resolvable.ts +++ b/packages/@aws-cdk/core/lib/resolvable.ts @@ -105,7 +105,6 @@ export interface ITokenResolver { * * Interface so it could potentially be exposed over jsii. * - * @experimental */ export interface IFragmentConcatenator { /** @@ -130,7 +129,6 @@ export class StringConcat implements IFragmentConcatenator { /** * Default resolver implementation * - * @experimental */ export class DefaultTokenResolver implements ITokenResolver { constructor(private readonly concat: IFragmentConcatenator) { diff --git a/packages/@aws-cdk/core/lib/resource.ts b/packages/@aws-cdk/core/lib/resource.ts index a828f0d6cec98..65fcacd55bf25 100644 --- a/packages/@aws-cdk/core/lib/resource.ts +++ b/packages/@aws-cdk/core/lib/resource.ts @@ -90,6 +90,18 @@ export interface ResourceProps { * @default - the resource is in the same region as the stack it belongs to */ readonly region?: string; + + /** + * ARN to deduce region and account from + * + * The ARN is parsed and the account and region are taken from the ARN. + * This should be used for imported resources. + * + * Cannot be supplied together with either `account` or `region`. + * + * @default - take environment from `account`, `region` parameters, or use Stack environment. + */ + readonly environmentFromArn?: string; } /** @@ -116,7 +128,6 @@ export abstract class Resource extends CoreConstruct implements IResource { * - a concrete name generated automatically during synthesis, in * cross-environment scenarios. * - * @experimental */ protected readonly physicalName: string; @@ -126,12 +137,18 @@ export abstract class Resource extends CoreConstruct implements IResource { constructor(scope: Construct, id: string, props: ResourceProps = {}) { super(scope, id); + if ((props.account !== undefined || props.region !== undefined) && props.environmentFromArn !== undefined) { + throw new Error(`Supply at most one of 'account'/'region' (${props.account}/${props.region}) and 'environmentFromArn' (${props.environmentFromArn})`); + } + Object.defineProperty(this, RESOURCE_SYMBOL, { value: true }); this.stack = Stack.of(this); + + const parsedArn = props.environmentFromArn ? this.stack.parseArn(props.environmentFromArn) : undefined; this.env = { - account: props.account ?? this.stack.account, - region: props.region ?? this.stack.region, + account: props.account ?? parsedArn?.account ?? this.stack.account, + region: props.region ?? parsedArn?.region ?? this.stack.region, }; let physicalName = props.physicalName; @@ -211,7 +228,6 @@ export abstract class Resource extends CoreConstruct implements IResource { * * @param nameAttr The CFN attribute which resolves to the resource's name. * Commonly this is the resource's `ref`. - * @experimental */ protected getResourceNameAttribute(nameAttr: string) { return mimicReference(nameAttr, { @@ -244,7 +260,6 @@ export abstract class Resource extends CoreConstruct implements IResource { * reference `this.physicalName` somewhere within the ARN in order for * cross-environment references to work. * - * @experimental */ protected getResourceArnAttribute(arnAttr: string, arnComponents: ArnComponents) { return mimicReference(arnAttr, { diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/_shared.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/_shared.ts index 233490968b31d..c5d88c9e76686 100644 --- a/packages/@aws-cdk/core/lib/stack-synthesizers/_shared.ts +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/_shared.ts @@ -57,6 +57,7 @@ export function addStackArtifactToAssembly( properties, dependencies: deps.length > 0 ? deps : undefined, metadata: Object.keys(meta).length > 0 ? meta : undefined, + displayName: stack.node.path, }); } diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts index 2527bca98c9d6..c902e3326d44b 100644 --- a/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts @@ -547,7 +547,7 @@ function stackLocationOrInstrinsics(stack: Stack) { * so we encode this rule into the template in a way that CloudFormation will check it. */ function addBootstrapVersionRule(stack: Stack, requiredVersion: number, qualifier: string) { - // Because of https://github.com/aws/aws-cdk/blob/master/packages/@aws-cdk/assert/lib/synth-utils.ts#L74 + // Because of https://github.com/aws/aws-cdk/blob/master/packages/assert-internal/lib/synth-utils.ts#L74 // synthesize() may be called more than once on a stack in unit tests, and the below would break // if we execute it a second time. Guard against the constructs already existing. if (stack.node.tryFindChild('BootstrapVersion')) { return; } diff --git a/packages/@aws-cdk/core/lib/stack.ts b/packages/@aws-cdk/core/lib/stack.ts index 2284ddedc203f..e256f73231714 100644 --- a/packages/@aws-cdk/core/lib/stack.ts +++ b/packages/@aws-cdk/core/lib/stack.ts @@ -273,7 +273,6 @@ export class Stack extends CoreConstruct implements ITaggable { * If this is a nested stack, this represents its `AWS::CloudFormation::Stack` * resource. `undefined` for top-level (non-nested) stacks. * - * @experimental */ public readonly nestedStackResource?: CfnResource; @@ -293,7 +292,6 @@ export class Stack extends CoreConstruct implements ITaggable { /** * Synthesis method for this stack * - * @experimental */ public readonly synthesizer: IStackSynthesizer; @@ -424,6 +422,17 @@ export class Stack extends CoreConstruct implements ITaggable { return CloudFormationLang.toJSON(obj, space).toString(); } + /** + * DEPRECATED + * @deprecated use `reportMissingContextKey()` + */ + public reportMissingContext(report: cxapi.MissingContext) { + if (!Object.values(cxschema.ContextProvider).includes(report.provider as cxschema.ContextProvider)) { + throw new Error(`Unknown context provider requested in: ${JSON.stringify(report)}`); + } + this.reportMissingContextKey(report as cxschema.MissingContext); + } + /** * Indicate that a context key was expected * @@ -432,11 +441,8 @@ export class Stack extends CoreConstruct implements ITaggable { * * @param report The set of parameters needed to obtain the context */ - public reportMissingContext(report: cxapi.MissingContext) { - if (!Object.values(cxschema.ContextProvider).includes(report.provider as cxschema.ContextProvider)) { - throw new Error(`Unknown context provider requested in: ${JSON.stringify(report)}`); - } - this._missingContext.push(report as cxschema.MissingContext); + public reportMissingContextKey(report: cxschema.MissingContext) { + this._missingContext.push(report); } /** diff --git a/packages/@aws-cdk/core/lib/stage.ts b/packages/@aws-cdk/core/lib/stage.ts index fd93f4251bf7f..ba0fc21d4248d 100644 --- a/packages/@aws-cdk/core/lib/stage.ts +++ b/packages/@aws-cdk/core/lib/stage.ts @@ -75,7 +75,6 @@ export class Stage extends CoreConstruct { * Return the stage this construct is contained with, if available. If called * on a nested stage, returns its parent. * - * @experimental */ public static of(construct: IConstruct): Stage | undefined { return Node.of(construct).scopes.reverse().slice(1).find(Stage.isStage); @@ -84,7 +83,6 @@ export class Stage extends CoreConstruct { /** * Test whether the given construct is a stage. * - * @experimental */ public static isStage(x: any ): x is Stage { return x !== null && typeof(x) === 'object' && STAGE_SYMBOL in x; @@ -93,21 +91,18 @@ export class Stage extends CoreConstruct { /** * The default region for all resources defined within this stage. * - * @experimental */ public readonly region?: string; /** * The default account for all resources defined within this stage. * - * @experimental */ public readonly account?: string; /** * The cloud assembly builder that is being used for this App * - * @experimental * @internal */ public readonly _assemblyBuilder: cxapi.CloudAssemblyBuilder; @@ -116,14 +111,12 @@ export class Stage extends CoreConstruct { * The name of the stage. Based on names of the parent stages separated by * hypens. * - * @experimental */ public readonly stageName: string; /** * The parent stage or `undefined` if this is the app. * * - * @experimental */ public readonly parentStage?: Stage; @@ -170,7 +163,6 @@ export class Stage extends CoreConstruct { * * Derived from the construct path. * - * @experimental */ public get artifactId() { if (!this.node.path) { return ''; } diff --git a/packages/@aws-cdk/core/package.json b/packages/@aws-cdk/core/package.json index d1a10d8ac8fd2..af2e803a1f7f8 100644 --- a/packages/@aws-cdk/core/package.json +++ b/packages/@aws-cdk/core/package.json @@ -174,9 +174,12 @@ }, "license": "Apache-2.0", "devDependencies": { + "@types/aws-lambda": "^8.10.76", + "@types/fs-extra": "^8.1.1", + "@types/jest": "^26.0.23", "@types/lodash": "^4.14.168", - "@types/minimatch": "^3.0.3", - "@types/node": "^10.17.55", + "@types/minimatch": "^3.0.4", + "@types/node": "^10.17.59", "@types/sinon": "^9.0.11", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -185,14 +188,14 @@ "nodeunit-shim": "0.0.0", "pkglint": "0.0.0", "sinon": "^9.2.4", - "ts-mock-imports": "^1.3.3" + "ts-mock-imports": "^1.3.4" }, "dependencies": { "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/region-info": "0.0.0", "@balena/dockerignore": "^1.0.2", - "constructs": "^3.2.0", + "constructs": "^3.3.69", "fs-extra": "^9.1.0", "ignore": "^5.1.8", "minimatch": "^3.0.4" @@ -208,7 +211,7 @@ "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/region-info": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" @@ -217,6 +220,9 @@ "awscdkio": { "announce": false }, + "nozem": { + "ostools": ["rm", "tar", "grep", "xargs", "head", "cut", "touch", "diff", "echo", "gzip"] + }, "maturity": "stable", "publishConfig": { "tag": "latest" diff --git a/packages/@aws-cdk/core/test/arn.test.ts b/packages/@aws-cdk/core/test/arn.test.ts index b4b135fff94e6..febbcc407c2b7 100644 --- a/packages/@aws-cdk/core/test/arn.test.ts +++ b/packages/@aws-cdk/core/test/arn.test.ts @@ -110,19 +110,19 @@ nodeunitShim({ 'if the ARN doesnt have enough components'(test: Test) { const stack = new Stack(); - test.throws(() => stack.parseArn('arn:is:too:short'), /ARNs must.*have at least 6 components.*arn:is:too:short/); + test.throws(() => stack.parseArn('arn:is:too:short'), /The `resource` component \(6th component\) of an ARN is required/); test.done(); }, 'if "service" is not specified'(test: Test) { const stack = new Stack(); - test.throws(() => stack.parseArn('arn:aws::4:5:6'), /The `service` component \(3rd component\) is required/); + test.throws(() => stack.parseArn('arn:aws::4:5:6'), /The `service` component \(3rd component\) of an ARN is required/); test.done(); }, 'if "resource" is not specified'(test: Test) { const stack = new Stack(); - test.throws(() => stack.parseArn('arn:aws:service:::'), /The `resource` component \(6th component\) is required/); + test.throws(() => stack.parseArn('arn:aws:service:::'), /The `resource` component \(6th component\) of an ARN is required/); test.done(); }, }, diff --git a/packages/@aws-cdk/core/test/bundling.test.ts b/packages/@aws-cdk/core/test/bundling.test.ts index 99548030c011a..97b9d5969c2b3 100644 --- a/packages/@aws-cdk/core/test/bundling.test.ts +++ b/packages/@aws-cdk/core/test/bundling.test.ts @@ -60,7 +60,7 @@ nodeunitShim({ const fingerprintStub = sinon.stub(FileSystem, 'fingerprint'); fingerprintStub.callsFake(() => imageHash); - const image = BundlingDockerImage.fromAsset('docker-path', { + const image = DockerImage.fromBuild('docker-path', { buildArgs: { TEST_ARG: 'cdk-test', }, @@ -139,7 +139,7 @@ nodeunitShim({ const fingerprintStub = sinon.stub(FileSystem, 'fingerprint'); fingerprintStub.callsFake(() => imageHash); - const image = BundlingDockerImage.fromAsset('docker-path'); + const image = DockerImage.fromBuild('docker-path'); const tagHash = crypto.createHash('sha256').update(JSON.stringify({ path: 'docker-path', @@ -173,6 +173,25 @@ nodeunitShim({ test.done(); }, + 'fromAsset'(test: Test) { + sinon.stub(child_process, 'spawnSync').returns({ + status: 0, + stderr: Buffer.from('stderr'), + stdout: Buffer.from('sha256:1234567890abcdef'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + + const imagePath = path.join(__dirname, 'fs/fixtures/test1'); + const image = BundlingDockerImage.fromAsset(imagePath, { + file: 'my-dockerfile', + }); + test.ok(image); + test.ok(image.image); + test.done(); + }, + 'custom entrypoint is passed through to docker exec'(test: Test) { const spawnSyncStub = sinon.stub(child_process, 'spawnSync').returns({ status: 0, diff --git a/packages/@aws-cdk/core/test/cloudformation-json.test.ts b/packages/@aws-cdk/core/test/cloudformation-json.test.ts index e9a0957a86269..977795fc35d9d 100644 --- a/packages/@aws-cdk/core/test/cloudformation-json.test.ts +++ b/packages/@aws-cdk/core/test/cloudformation-json.test.ts @@ -1,4 +1,4 @@ -import { App, Aws, CfnOutput, Fn, IPostProcessor, IResolvable, IResolveContext, Lazy, Stack, Token } from '../lib'; +import { App, Aws, CfnOutput, CfnResource, Fn, IPostProcessor, IResolvable, IResolveContext, Lazy, Stack, Token } from '../lib'; import { Intrinsic } from '../lib/private/intrinsic'; import { evaluateCFN } from './evaluate-cfn'; @@ -102,10 +102,22 @@ describe('tokens that return literals', () => { const someList = Token.asList(new Intrinsic({ Ref: 'Thing' })); // WHEN - expect(stack.resolve(stack.toJsonString({ someList }))).toEqual({ + new CfnResource(stack, 'Resource', { + type: 'AWS::Banana', + properties: { + someJson: stack.toJsonString({ someList }), + }, + }); + + const asm = app.synth(); + const template = asm.getStackByName(stack.stackName).template; + const stringifyLogicalId = Object.keys(template.Resources).filter(id => id.startsWith('CdkJsonStringify'))[0]; + expect(stringifyLogicalId).toBeDefined(); + + expect(template.Resources.Resource.Properties.someJson).toEqual({ 'Fn::Join': ['', [ '{"someList":', - { 'Fn::GetAtt': [expect.stringContaining('CdkJsonStringify'), 'Value'] }, + { 'Fn::GetAtt': [stringifyLogicalId, 'Value'] }, '}', ]], }); diff --git a/packages/@aws-cdk/core/test/fs/fs-ignore.test.ts b/packages/@aws-cdk/core/test/fs/fs-ignore.test.ts index 19cf979a650b5..a24dab6afdc05 100644 --- a/packages/@aws-cdk/core/test/fs/fs-ignore.test.ts +++ b/packages/@aws-cdk/core/test/fs/fs-ignore.test.ts @@ -31,7 +31,7 @@ describe('GlobIgnoreStrategy', () => { expect(strategyPermits(strategy, permits)).toEqual(permits); }); - test('does not exclude whitelisted files', () => { + test('does not exclude allow listed files', () => { const strategy = IgnoreStrategy.glob('/tmp', ['*.ignored', '!important.*']); const permits = [ '/tmp/some/important.ignored', @@ -79,7 +79,7 @@ describe('GitIgnoreStrategy', () => { expect(strategyPermits(strategy, permits)).toEqual(permits); }); - test('does not exclude whitelisted files', () => { + test('does not exclude allow listed files', () => { const strategy = IgnoreStrategy.git('/tmp', ['*.ignored', '!important.*']); const permits = [ '/tmp/some/important.ignored', @@ -114,7 +114,7 @@ describe('DockerIgnoreStrategy', () => { expect(strategyPermits(strategy, permits)).toEqual(permits); }); - test('does not exclude whitelisted files', () => { + test('does not exclude allow listed files', () => { const strategy = IgnoreStrategy.docker('/tmp', ['*.ignored', '!important.*']); const permits = [ '/tmp/some/important.ignored', diff --git a/packages/@aws-cdk/core/test/resource.test.ts b/packages/@aws-cdk/core/test/resource.test.ts index b883d11f8d752..aa8fbe74575fc 100644 --- a/packages/@aws-cdk/core/test/resource.test.ts +++ b/packages/@aws-cdk/core/test/resource.test.ts @@ -3,7 +3,7 @@ import { nodeunitShim, Test } from 'nodeunit-shim'; import { App, App as Root, CfnCondition, CfnDeletionPolicy, CfnResource, Construct, - Fn, RemovalPolicy, Stack, + Fn, RemovalPolicy, Resource, Stack, } from '../lib'; import { synthesize } from '../lib/private/synthesis'; import { toCloudFormation } from './util'; @@ -818,6 +818,19 @@ nodeunitShim({ }, }); +test('Resource can get account and Region from ARN', () => { + const stack = new Stack(); + + // WHEN + const resource = new TestResource(stack, 'Resource', { + environmentFromArn: 'arn:partition:service:region:account:relative-id', + }); + + // THEN + expect(resource.env.account).toEqual('account'); + expect(resource.env.region).toEqual('region'); +}); + interface CounterProps { Count: number; } @@ -887,3 +900,8 @@ class CustomizableResource extends CfnResource { return cleanProps; } } + +/** + * Because Resource is abstract + */ +class TestResource extends Resource {} \ No newline at end of file diff --git a/packages/@aws-cdk/core/test/runtime-info.test.ts b/packages/@aws-cdk/core/test/runtime-info.test.ts index 421c504036e33..b637bb2ba9b50 100644 --- a/packages/@aws-cdk/core/test/runtime-info.test.ts +++ b/packages/@aws-cdk/core/test/runtime-info.test.ts @@ -84,6 +84,16 @@ describeTscSafe('constructInfoForStack', () => { expect(jsiiInfo?.version).toMatch(/node.js/); }); + test('sanitizes jsii runtime info to remove unwanted characters', () => { + process.env.JSII_AGENT = 'DotNet/5.0.3/.NETCore^App,Version=v3.1!/1.0.0_0'; + const constructInfos = constructInfoFromStack(stack); + const jsiiInfo = constructInfos.find(i => i.fqn === 'jsii-runtime.Runtime'); + + expect(jsiiInfo?.version).toEqual('DotNet/5.0.3/.NETCore-App-Version=v3.1-/1.0.0_0'); + + delete process.env.JSII_AGENT; + }); + test('returns info for constructs added to the stack', () => { new TestConstruct(stack, 'TestConstruct'); diff --git a/packages/@aws-cdk/core/test/stack.test.ts b/packages/@aws-cdk/core/test/stack.test.ts index 849ad10369147..11a4a01796031 100644 --- a/packages/@aws-cdk/core/test/stack.test.ts +++ b/packages/@aws-cdk/core/test/stack.test.ts @@ -489,7 +489,7 @@ describe('stack', () => { test('cross stack references and dependencies work within child stacks (non-nested)', () => { // GIVEN - const app = new App(); + const app = new App({ context: { '@aws-cdk/core:stackRelativeExports': true } }); const parent = new Stack(app, 'Parent'); const child1 = new Stack(parent, 'Child1'); const child2 = new Stack(parent, 'Child2'); @@ -520,7 +520,7 @@ describe('stack', () => { Outputs: { ExportsOutputRefResourceA461B4EF9: { Value: { Ref: 'ResourceA' }, - Export: { Name: 'ParentChild18FAEF419:Child1ExportsOutputRefResourceA7BF20B37' }, + Export: { Name: 'ParentChild18FAEF419:ExportsOutputRefResourceA461B4EF9' }, }, }, }); @@ -529,7 +529,7 @@ describe('stack', () => { Resource1: { Type: 'R2', Properties: { - RefToResource1: { 'Fn::ImportValue': 'ParentChild18FAEF419:Child1ExportsOutputRefResourceA7BF20B37' }, + RefToResource1: { 'Fn::ImportValue': 'ParentChild18FAEF419:ExportsOutputRefResourceA461B4EF9' }, }, }, }, @@ -541,7 +541,7 @@ describe('stack', () => { test('automatic cross-stack references and manual exports look the same', () => { // GIVEN: automatic - const appA = new App(); + const appA = new App({ context: { '@aws-cdk/core:stackRelativeExports': true } }); const producerA = new Stack(appA, 'Producer'); const consumerA = new Stack(appA, 'Consumer'); const resourceA = new CfnResource(producerA, 'Resource', { type: 'AWS::Resource' }); @@ -704,7 +704,7 @@ describe('stack', () => { test('cross-stack reference (parent stack references substack)', () => { // GIVEN - const app = new App(); + const app = new App({ context: { '@aws-cdk/core:stackRelativeExports': true } }); const parentStack = new Stack(app, 'parent'); const childStack = new Stack(parentStack, 'child'); @@ -724,7 +724,7 @@ describe('stack', () => { MyParentResource: { Type: 'Resource::Parent', Properties: { - ParentProp: { 'Fn::ImportValue': 'parentchild13F9359B:childExportsOutputFnGetAttMyChildResourceAttributeOfChildResource420052FC' }, + ParentProp: { 'Fn::ImportValue': 'parentchild13F9359B:ExportsOutputFnGetAttMyChildResourceAttributeOfChildResource52813264' }, }, }, }, @@ -735,7 +735,7 @@ describe('stack', () => { Outputs: { ExportsOutputFnGetAttMyChildResourceAttributeOfChildResource52813264: { Value: { 'Fn::GetAtt': ['MyChildResource', 'AttributeOfChildResource'] }, - Export: { Name: 'parentchild13F9359B:childExportsOutputFnGetAttMyChildResourceAttributeOfChildResource420052FC' }, + Export: { Name: 'parentchild13F9359B:ExportsOutputFnGetAttMyChildResourceAttributeOfChildResource52813264' }, }, }, }); @@ -1181,4 +1181,4 @@ class StackWithPostProcessor extends Stack { return template; } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/core/test/synthesis.test.ts b/packages/@aws-cdk/core/test/synthesis.test.ts index 8b5200c1dfb72..77c8c306ef81f 100644 --- a/packages/@aws-cdk/core/test/synthesis.test.ts +++ b/packages/@aws-cdk/core/test/synthesis.test.ts @@ -105,6 +105,7 @@ nodeunitShim({ type: 'aws:cloudformation:stack', environment: 'aws://unknown-account/unknown-region', properties: { templateFile: 'one-stack.template.json' }, + displayName: 'one-stack', }, }, }); diff --git a/packages/@aws-cdk/custom-resources/README.md b/packages/@aws-cdk/custom-resources/README.md index 0be6398f162c0..327ed2a62c0dd 100644 --- a/packages/@aws-cdk/custom-resources/README.md +++ b/packages/@aws-cdk/custom-resources/README.md @@ -472,6 +472,29 @@ const getParameter = new AwsCustomResource(this, 'GetParameter', { getParameter.getResponseField('Parameter.Value') ``` +#### Associate a PrivateHostedZone with VPC shared from another account + +```ts +const getParameter = new AwsCustomResource(this, 'AssociateVPCWithHostedZone', { + onCreate: { + assumedRoleArn: 'arn:aws:iam::OTHERACCOUNT:role/CrossAccount/ManageHostedZoneConnections', + service: 'Route53', + action: 'associateVPCWithHostedZone', + parameters: { + HostedZoneId: 'hz-123', + VPC: { + VPCId: 'vpc-123', + VPCRegion: 'region-for-vpc' + } + }, + physicalResourceId: PhysicalResourceId.of('${vpcStack.SharedVpc.VpcId}-${vpcStack.Region}-${PrivateHostedZone.HostedZoneId}') + }, + //Will ignore any resource and use the assumedRoleArn as resource and 'sts:AssumeRole' for service:action + policy: AwsCustomResourcePolicy.fromSdkCalls({resources: AwsCustomResourcePolicy.ANY_RESOURCE}) +}); + +``` + --- This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. 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 bc86cea1c9d43..dd16c15a4646d 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 @@ -130,6 +130,17 @@ export interface AwsSdkCall { * @default - return all data */ readonly outputPath?: string; + + /** + * Used for running the SDK calls in underlying lambda with a different role + * Can be used primarily for cross-account requests to for example connect + * hostedzone with a shared vpc + * + * Example for Route53 / associateVPCWithHostedZone + * + * @default - run without assuming role + */ + readonly assumedRoleArn?: string; } /** @@ -355,12 +366,18 @@ export class AwsCustomResource extends CoreConstruct implements iam.IGrantable { } else { // Derive statements from AWS SDK calls for (const call of [props.onCreate, props.onUpdate, props.onDelete]) { - if (call) { + if (call && call.assumedRoleArn == null) { const statement = new iam.PolicyStatement({ actions: [awsSdkToIamAction(call.service, call.action)], resources: props.policy.resources, }); statements.push(statement); + } else if (call && call.assumedRoleArn != null) { + const statement = new iam.PolicyStatement({ + actions: ['sts:AssumeRole'], + resources: [call.assumedRoleArn], + }); + statements.push(statement); } } } 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 5fafd6db214e2..56d485e83d4fa 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 @@ -115,6 +115,22 @@ export async function handler(event: AWSLambda.CloudFormationCustomResourceEvent const call: AwsSdkCall | undefined = event.ResourceProperties[event.RequestType]; if (call) { + + if (call.assumedRoleArn) { + + const timestamp = (new Date()).getTime(); + + const params = { + RoleArn: call.assumedRoleArn, + RoleSessionName: `${physicalResourceId}-${timestamp}`, + }; + + AWS.config.credentials = new AWS.ChainableTemporaryCredentials({ + params: params, + }); + + } + const awsService = new (AWS as any)[call.service]({ apiVersion: call.apiVersion, region: call.region, diff --git a/packages/@aws-cdk/custom-resources/package.json b/packages/@aws-cdk/custom-resources/package.json index 6c3c3d4f2d0b5..c93d01bc53e7e 100644 --- a/packages/@aws-cdk/custom-resources/package.json +++ b/packages/@aws-cdk/custom-resources/package.json @@ -71,11 +71,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "@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.72", + "@types/aws-lambda": "^8.10.76", "@types/fs-extra": "^8.1.1", "@types/sinon": "^9.0.11", "aws-sdk": "^2.848.0", @@ -86,7 +86,8 @@ "fs-extra": "^9.1.0", "nock": "^13.0.11", "pkglint": "0.0.0", - "sinon": "^9.2.4" + "sinon": "^9.2.4", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-cloudformation": "0.0.0", @@ -96,7 +97,7 @@ "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -107,7 +108,7 @@ "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" @@ -121,6 +122,9 @@ "awscdkio": { "announce": false }, + "nozem": { + "ostools": ["rm", "cp"] + }, "maturity": "stable", "publishConfig": { "tag": "latest" 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 086ef301ea41c..f072c0f926875 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 @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as iam from '@aws-cdk/aws-iam'; import * as logs from '@aws-cdk/aws-logs'; import * as cdk from '@aws-cdk/core'; @@ -711,4 +711,35 @@ test('tokens can be used as dictionary keys', () => { ], }, }); +}); + +test('assumedRoleArn adds statement for sts:assumeRole', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new AwsCustomResource(stack, 'AwsSdk', { + onCreate: { + assumedRoleArn: 'roleArn', + service: 'service', + action: 'action', + physicalResourceId: PhysicalResourceId.of('id'), + }, + policy: AwsCustomResourcePolicy.fromSdkCalls({ resources: AwsCustomResourcePolicy.ANY_RESOURCE }), + }); + + // THEN + + expect(stack).toHaveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: 'sts:AssumeRole', + Effect: 'Allow', + Resource: 'roleArn', + }, + ], + Version: '2012-10-17', + }, + }); }); \ No newline at end of file diff --git a/packages/@aws-cdk/custom-resources/test/provider-framework/provider.test.ts b/packages/@aws-cdk/custom-resources/test/provider-framework/provider.test.ts index b60ef1a602431..3b8ba5de5ada9 100644 --- a/packages/@aws-cdk/custom-resources/test/provider-framework/provider.test.ts +++ b/packages/@aws-cdk/custom-resources/test/provider-framework/provider.test.ts @@ -6,7 +6,7 @@ import { Duration, Stack } from '@aws-cdk/core'; import * as cr from '../../lib'; import * as util from '../../lib/provider-framework/util'; -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; test('security groups are applied to all framework functions', () => { diff --git a/packages/@aws-cdk/custom-resources/test/provider-framework/waiter-state-machine.test.ts b/packages/@aws-cdk/custom-resources/test/provider-framework/waiter-state-machine.test.ts index cd6182d5e70ef..acaaeb3a73ef6 100644 --- a/packages/@aws-cdk/custom-resources/test/provider-framework/waiter-state-machine.test.ts +++ b/packages/@aws-cdk/custom-resources/test/provider-framework/waiter-state-machine.test.ts @@ -1,4 +1,4 @@ -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import { Code, Function as lambdaFn, Runtime } from '@aws-cdk/aws-lambda'; import { Duration, Stack } from '@aws-cdk/core'; import { WaiterStateMachine } from '../../lib/provider-framework/waiter-state-machine'; diff --git a/packages/@aws-cdk/cx-api/README.md b/packages/@aws-cdk/cx-api/README.md index e0983d9d8e092..49dee59c9dd85 100644 --- a/packages/@aws-cdk/cx-api/README.md +++ b/packages/@aws-cdk/cx-api/README.md @@ -3,13 +3,7 @@ --- -![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. +![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge) --- diff --git a/packages/@aws-cdk/cx-api/lib/cloud-artifact.ts b/packages/@aws-cdk/cx-api/lib/cloud-artifact.ts index 5a57b9f36c1eb..7f4e5a899983a 100644 --- a/packages/@aws-cdk/cx-api/lib/cloud-artifact.ts +++ b/packages/@aws-cdk/cx-api/lib/cloud-artifact.ts @@ -142,6 +142,15 @@ export class CloudArtifact { return messages; } + + /** + * An identifier that shows where this artifact is located in the tree + * of nested assemblies, based on their manifests. Defaults to the normal + * id. Should only be used in user interfaces. + */ + public get hierarchicalId(): string { + return this.manifest.displayName ?? this.id; + } } // needs to be defined at the end to avoid a cyclic dependency diff --git a/packages/@aws-cdk/cx-api/lib/cloud-assembly.ts b/packages/@aws-cdk/cx-api/lib/cloud-assembly.ts index 53fafe3d37049..400981cea7054 100644 --- a/packages/@aws-cdk/cx-api/lib/cloud-assembly.ts +++ b/packages/@aws-cdk/cx-api/lib/cloud-assembly.ts @@ -49,7 +49,7 @@ export class CloudAssembly { constructor(directory: string) { this.directory = directory; - this.manifest = cxschema.Manifest.load(path.join(directory, MANIFEST_FILE)); + this.manifest = cxschema.Manifest.loadAssemblyManifest(path.join(directory, MANIFEST_FILE)); this.version = this.manifest.version; this.artifacts = this.renderArtifacts(); this.runtime = this.manifest.runtime || { libraries: { } }; @@ -108,7 +108,8 @@ export class CloudAssembly { * @returns a `CloudFormationStackArtifact` object. */ public getStackArtifact(artifactId: string): CloudFormationStackArtifact { - const artifact = this.tryGetArtifact(artifactId); + const artifact = this.tryGetArtifactRecursively(artifactId); + if (!artifact) { throw new Error(`Unable to find artifact with id "${artifactId}"`); } @@ -120,6 +121,27 @@ export class CloudAssembly { return artifact; } + private tryGetArtifactRecursively(artifactId: string): CloudArtifact | undefined { + return this.stacksRecursively.find(a => a.id === artifactId); + } + + /** + * Returns all the stacks, including the ones in nested assemblies + */ + public get stacksRecursively(): CloudFormationStackArtifact[] { + function search(stackArtifacts: CloudFormationStackArtifact[], assemblies: CloudAssembly[]): CloudFormationStackArtifact[] { + if (assemblies.length === 0) { + return stackArtifacts; + } + + const [head, ...tail] = assemblies; + const nestedAssemblies = head.nestedAssemblies.map(asm => asm.nestedAssembly); + return search(stackArtifacts.concat(head.stacks), tail.concat(nestedAssemblies)); + }; + + return search([], [this]); + } + /** * Returns a nested assembly artifact. * @@ -303,7 +325,7 @@ export class CloudAssemblyBuilder { manifest = filterUndefined(manifest); const manifestFilePath = path.join(this.outdir, MANIFEST_FILE); - cxschema.Manifest.save(manifest, manifestFilePath); + cxschema.Manifest.saveAssemblyManifest(manifest, manifestFilePath); // "backwards compatibility": in order for the old CLI to tell the user they // need a new version, we'll emit the legacy manifest with only "version". diff --git a/packages/@aws-cdk/cx-api/lib/features.ts b/packages/@aws-cdk/cx-api/lib/features.ts index 162ec0de9d7f4..a2525fafa71c0 100644 --- a/packages/@aws-cdk/cx-api/lib/features.ts +++ b/packages/@aws-cdk/cx-api/lib/features.ts @@ -104,6 +104,43 @@ export const S3_GRANT_WRITE_WITHOUT_ACL = '@aws-cdk/aws-s3:grantWriteWithoutAcl' */ export const ECS_REMOVE_DEFAULT_DESIRED_COUNT = '@aws-cdk/aws-ecs-patterns:removeDefaultDesiredCount'; +/** + * ServerlessCluster.clusterIdentifier currently can has uppercase letters, + * and ServerlessCluster pass it through to CfnDBCluster.dbClusterIdentifier. + * The identifier is saved as lowercase string in AWS and is resolved as original string in CloudFormation. + * + * If this flag is not set, original value that one set to ServerlessCluster.clusterIdentifier + * is passed to CfnDBCluster.dbClusterIdentifier. + * If this flag is true, ServerlessCluster.clusterIdentifier is converted into a string containing + * only lowercase characters by the `toLowerCase` function and passed to CfnDBCluster.dbClusterIdentifier. + * + * This feature flag make correct the ServerlessCluster.clusterArn when + * clusterIdentifier contains a Upper case letters. + */ +export const RDS_LOWERCASE_DB_IDENTIFIER = '@aws-cdk/aws-rds:lowercaseDbIdentifier'; + +/** + * The UsagePlanKey resource connects an ApiKey with a UsagePlan. API Gateway does not allow more than one UsagePlanKey + * for any given UsagePlan and ApiKey combination. For this reason, CloudFormation cannot replace this resource without + * either the UsagePlan or ApiKey changing. + * + * The feature addition to support multiple UsagePlanKey resources - 142bd0e2 - recognized this and attempted to keep + * existing UsagePlanKey logical ids unchanged. + * However, this intentionally caused the logical id of the UsagePlanKey to be sensitive to order. That is, when + * the 'first' UsagePlanKey resource is removed, the logical id of the 'second' assumes what was originally the 'first', + * which again is disallowed. + * + * In effect, there is no way to get out of this mess in a backwards compatible way, while supporting existing stacks. + * This flag changes the logical id layout of UsagePlanKey to not be sensitive to order. + */ +export const APIGATEWAY_USAGEPLANKEY_ORDERINSENSITIVE_ID = '@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId'; + +/** + * Enable this feature flag to have elastic file systems encrypted at rest by default. + * + * Encryption can also be configured explicitly using the `encrypted` property. + */ +export const EFS_DEFAULT_ENCRYPTION_AT_REST = '@aws-cdk/aws-efs:defaultEncryptionAtRest'; /** * This map includes context keys and values for feature flags that enable * capabilities "from the future", which we could not introduce as the default @@ -118,6 +155,7 @@ export const ECS_REMOVE_DEFAULT_DESIRED_COUNT = '@aws-cdk/aws-ecs-patterns:remov * Tests must cover the default (disabled) case and the future (enabled) case. */ export const FUTURE_FLAGS: { [key: string]: any } = { + [APIGATEWAY_USAGEPLANKEY_ORDERINSENSITIVE_ID]: true, [ENABLE_STACK_NAME_DUPLICATES_CONTEXT]: 'true', [ENABLE_DIFF_NO_FAIL_CONTEXT]: 'true', [STACK_RELATIVE_EXPORTS_CONTEXT]: 'true', @@ -126,6 +164,8 @@ export const FUTURE_FLAGS: { [key: string]: any } = { [KMS_DEFAULT_KEY_POLICIES]: true, [S3_GRANT_WRITE_WITHOUT_ACL]: true, [ECS_REMOVE_DEFAULT_DESIRED_COUNT]: true, + [RDS_LOWERCASE_DB_IDENTIFIER]: true, + [EFS_DEFAULT_ENCRYPTION_AT_REST]: true, // We will advertise this flag when the feature is complete // [NEW_STYLE_STACK_SYNTHESIS_CONTEXT]: 'true', @@ -143,6 +183,7 @@ export const FUTURE_FLAGS_EXPIRED: string[] = [ * explicitly configured. */ const FUTURE_FLAGS_DEFAULTS: { [key: string]: boolean } = { + [APIGATEWAY_USAGEPLANKEY_ORDERINSENSITIVE_ID]: false, [ENABLE_STACK_NAME_DUPLICATES_CONTEXT]: false, [ENABLE_DIFF_NO_FAIL_CONTEXT]: false, [STACK_RELATIVE_EXPORTS_CONTEXT]: false, @@ -152,6 +193,8 @@ const FUTURE_FLAGS_DEFAULTS: { [key: string]: boolean } = { [KMS_DEFAULT_KEY_POLICIES]: false, [S3_GRANT_WRITE_WITHOUT_ACL]: false, [ECS_REMOVE_DEFAULT_DESIRED_COUNT]: false, + [RDS_LOWERCASE_DB_IDENTIFIER]: false, + [EFS_DEFAULT_ENCRYPTION_AT_REST]: false, }; export function futureFlagDefault(flag: string): boolean { diff --git a/packages/@aws-cdk/cx-api/package.json b/packages/@aws-cdk/cx-api/package.json index 5e5ce913f629c..e362a20ae0650 100644 --- a/packages/@aws-cdk/cx-api/package.json +++ b/packages/@aws-cdk/cx-api/package.json @@ -57,19 +57,19 @@ }, "dependencies": { "@aws-cdk/cloud-assembly-schema": "0.0.0", - "semver": "^7.3.4" + "semver": "^7.3.5" }, "peerDependencies": { "@aws-cdk/cloud-assembly-schema": "0.0.0" }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.21", + "@types/jest": "^26.0.23", "@types/mock-fs": "^4.13.0", - "@types/semver": "^7.3.4", + "@types/semver": "^7.3.5", "cdk-build-tools": "0.0.0", "jest": "^26.6.3", - "mock-fs": "^4.13.0", + "mock-fs": "^4.14.0", "pkglint": "0.0.0" }, "repository": { @@ -88,8 +88,8 @@ "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, - "stability": "experimental", - "maturity": "experimental", + "stability": "stable", + "maturity": "stable", "awslint": { "exclude": [ "props-default-doc:@aws-cdk/cx-api.MetadataEntry.data", diff --git a/packages/@aws-cdk/cx-api/test/cloud-assembly.test.ts b/packages/@aws-cdk/cx-api/test/cloud-assembly.test.ts index 6f477be5185ea..ddd7538308ec3 100644 --- a/packages/@aws-cdk/cx-api/test/cloud-assembly.test.ts +++ b/packages/@aws-cdk/cx-api/test/cloud-assembly.test.ts @@ -151,3 +151,14 @@ test('can read assembly with asset manifest', () => { expect(assembly.stacks).toHaveLength(1); expect(assembly.artifacts).toHaveLength(2); }); + +test('getStackArtifact retrieves a stack by artifact id from a nested assembly', () => { + const assembly = new CloudAssembly(path.join(FIXTURES, 'nested-assemblies')); + + expect(assembly.getStackArtifact('topLevelStack').stackName).toEqual('topLevelStack'); + expect(assembly.getStackArtifact('stack1').stackName).toEqual('first-stack'); + expect(assembly.getStackArtifact('stack2').stackName).toEqual('second-stack'); + expect(assembly.getStackArtifact('topLevelStack').id).toEqual('topLevelStack'); + expect(assembly.getStackArtifact('stack1').id).toEqual('stack1'); + expect(assembly.getStackArtifact('stack2').id).toEqual('stack2'); +}); diff --git a/packages/@aws-cdk/cx-api/test/fixtures/nested-assemblies/manifest.json b/packages/@aws-cdk/cx-api/test/fixtures/nested-assemblies/manifest.json new file mode 100644 index 0000000000000..b79e280d6a1fb --- /dev/null +++ b/packages/@aws-cdk/cx-api/test/fixtures/nested-assemblies/manifest.json @@ -0,0 +1,21 @@ +{ + "version": "0.0.0", + "artifacts": { + "subassembly": { + "type": "cdk:cloud-assembly", + "properties": { + "directoryName": "subassembly", + "displayName": "subassembly" + } + }, + "topLevelStack": { + "type": "aws:cloudformation:stack", + "environment": "aws://111111111111/us-east-1", + "properties": { + "templateFile": "topLevelStack.template.json", + "stackName": "topLevelStack" + }, + "displayName": "topLevelStack" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/cx-api/test/fixtures/nested-assemblies/subassembly/manifest.json b/packages/@aws-cdk/cx-api/test/fixtures/nested-assemblies/subassembly/manifest.json new file mode 100644 index 0000000000000..703e640daea91 --- /dev/null +++ b/packages/@aws-cdk/cx-api/test/fixtures/nested-assemblies/subassembly/manifest.json @@ -0,0 +1,20 @@ +{ + "version": "0.0.0", + "artifacts": { + "subsubassembly": { + "type": "cdk:cloud-assembly", + "properties": { + "directoryName": "subsubassembly", + "displayName": "subsubassembly" + } + }, + "stack1": { + "type": "aws:cloudformation:stack", + "environment": "aws://37736633/us-region-1", + "properties": { + "templateFile": "template.json", + "stackName": "first-stack" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/cx-api/test/fixtures/nested-assemblies/subassembly/subsubassembly/manifest.json b/packages/@aws-cdk/cx-api/test/fixtures/nested-assemblies/subassembly/subsubassembly/manifest.json new file mode 100644 index 0000000000000..4166babad9831 --- /dev/null +++ b/packages/@aws-cdk/cx-api/test/fixtures/nested-assemblies/subassembly/subsubassembly/manifest.json @@ -0,0 +1,13 @@ +{ + "version": "0.0.0", + "artifacts": { + "stack2": { + "type": "aws:cloudformation:stack", + "environment": "aws://37736633/us-region-1", + "properties": { + "templateFile": "template.2.json", + "stackName": "second-stack" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/cx-api/test/fixtures/nested-assemblies/subassembly/subsubassembly/template.2.json b/packages/@aws-cdk/cx-api/test/fixtures/nested-assemblies/subassembly/subsubassembly/template.2.json new file mode 100644 index 0000000000000..284fd64cffc21 --- /dev/null +++ b/packages/@aws-cdk/cx-api/test/fixtures/nested-assemblies/subassembly/subsubassembly/template.2.json @@ -0,0 +1,7 @@ +{ + "Resources": { + "MyBucket": { + "Type": "AWS::S3::Bucket" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/cx-api/test/fixtures/nested-assemblies/subassembly/template.json b/packages/@aws-cdk/cx-api/test/fixtures/nested-assemblies/subassembly/template.json new file mode 100644 index 0000000000000..284fd64cffc21 --- /dev/null +++ b/packages/@aws-cdk/cx-api/test/fixtures/nested-assemblies/subassembly/template.json @@ -0,0 +1,7 @@ +{ + "Resources": { + "MyBucket": { + "Type": "AWS::S3::Bucket" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/cx-api/test/fixtures/nested-assemblies/topLevelStack.template.json b/packages/@aws-cdk/cx-api/test/fixtures/nested-assemblies/topLevelStack.template.json new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/@aws-cdk/cx-api/test/stack-artifact.test.ts b/packages/@aws-cdk/cx-api/test/stack-artifact.test.ts index 1f4591f00177a..baba32bb7b573 100644 --- a/packages/@aws-cdk/cx-api/test/stack-artifact.test.ts +++ b/packages/@aws-cdk/cx-api/test/stack-artifact.test.ts @@ -130,3 +130,30 @@ test('read tags from stack metadata', () => { // THEN expect(assembly.getStackByName('Stack').tags).toEqual({ foo: 'bar' }); }); + +test('user friendly id is the assembly display name', () => { + // GIVEN + builder.addArtifact('Stack', { + ...stackBase, + displayName: 'some/path/to/the/stack', + }); + + // WHEN + const assembly = builder.buildAssembly(); + + // THEN + expect(assembly.getStackByName('Stack').hierarchicalId).toEqual('some/path/to/the/stack'); +}); + +test('user friendly id is the id itself if no display name is given', () => { + // GIVEN + builder.addArtifact('Stack', { + ...stackBase, + }); + + // WHEN + const assembly = builder.buildAssembly(); + + // THEN + expect(assembly.getStackByName('Stack').hierarchicalId).toEqual('Stack'); +}); diff --git a/packages/@aws-cdk/example-construct-library/package.json b/packages/@aws-cdk/example-construct-library/package.json index 762b080eff94a..0f05299af14d6 100644 --- a/packages/@aws-cdk/example-construct-library/package.json +++ b/packages/@aws-cdk/example-construct-library/package.json @@ -64,11 +64,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", @@ -77,7 +78,7 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { @@ -87,7 +88,7 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/example-construct-library/test/example-resource.test.ts b/packages/@aws-cdk/example-construct-library/test/example-resource.test.ts index e9f56d52769a6..8145feddb307d 100644 --- a/packages/@aws-cdk/example-construct-library/test/example-resource.test.ts +++ b/packages/@aws-cdk/example-construct-library/test/example-resource.test.ts @@ -5,9 +5,9 @@ */ // import the various CDK assertion helpers -import { ABSENT, ResourcePart } from '@aws-cdk/assert'; +import { ABSENT, ResourcePart } from '@aws-cdk/assert-internal'; // always import our Jest-specific helpers -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; diff --git a/packages/@aws-cdk/lambda-layer-awscli/README.md b/packages/@aws-cdk/lambda-layer-awscli/README.md index ae6460fae09d3..baad6362f5e21 100644 --- a/packages/@aws-cdk/lambda-layer-awscli/README.md +++ b/packages/@aws-cdk/lambda-layer-awscli/README.md @@ -3,13 +3,7 @@ --- -![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. +![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge) --- diff --git a/packages/@aws-cdk/lambda-layer-awscli/package.json b/packages/@aws-cdk/lambda-layer-awscli/package.json index 115f686f9e414..4474e0c74a1bb 100644 --- a/packages/@aws-cdk/lambda-layer-awscli/package.json +++ b/packages/@aws-cdk/lambda-layer-awscli/package.json @@ -64,28 +64,29 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, - "stability": "experimental", - "maturity": "experimental", + "stability": "stable", + "maturity": "stable", "awscdkio": { "announce": false }, @@ -101,6 +102,9 @@ "ubergen": { "exclude": false }, + "nozem": { + "ostools": ["dirname", "docker"] + }, "publishConfig": { "tag": "latest" } diff --git a/packages/@aws-cdk/lambda-layer-awscli/test/awscli-layer.test.ts b/packages/@aws-cdk/lambda-layer-awscli/test/awscli-layer.test.ts index 923d4f3ceaf64..2a5c4b7d80043 100644 --- a/packages/@aws-cdk/lambda-layer-awscli/test/awscli-layer.test.ts +++ b/packages/@aws-cdk/lambda-layer-awscli/test/awscli-layer.test.ts @@ -1,6 +1,6 @@ import { Stack } from '@aws-cdk/core'; import { AwsCliLayer } from '../lib'; -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; test('synthesized to a layer version', () => { //GIVEN diff --git a/packages/@aws-cdk/lambda-layer-kubectl/README.md b/packages/@aws-cdk/lambda-layer-kubectl/README.md index d2c0343807369..3782174b1aa72 100644 --- a/packages/@aws-cdk/lambda-layer-kubectl/README.md +++ b/packages/@aws-cdk/lambda-layer-kubectl/README.md @@ -3,19 +3,12 @@ --- -![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. +![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge) --- - This module exports a single class called `KubectlLayer` which is a `lambda.Layer` that bundles the [`kubectl`](https://kubernetes.io/docs/reference/kubectl/kubectl/) and the [`helm`](https://helm.sh/) command line. > - Helm Version: 1.20.0 diff --git a/packages/@aws-cdk/lambda-layer-kubectl/package.json b/packages/@aws-cdk/lambda-layer-kubectl/package.json index 9ba2b10e89d47..d3d03e9569dfd 100644 --- a/packages/@aws-cdk/lambda-layer-kubectl/package.json +++ b/packages/@aws-cdk/lambda-layer-kubectl/package.json @@ -64,11 +64,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "pkglint": { "attribution": [ @@ -79,19 +80,19 @@ "dependencies": { "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, - "stability": "experimental", - "maturity": "experimental", + "stability": "stable", + "maturity": "stable", "awscdkio": { "announce": false }, @@ -104,6 +105,9 @@ "AWSLINT_BASE_CONSTRUCT": true } }, + "nozem": { + "ostools": ["dirname", "docker"] + }, "ubergen": { "exclude": false }, diff --git a/packages/@aws-cdk/lambda-layer-kubectl/test/kubectl-layer.test.ts b/packages/@aws-cdk/lambda-layer-kubectl/test/kubectl-layer.test.ts index d73303dd5e32d..c7591af7b3c2b 100644 --- a/packages/@aws-cdk/lambda-layer-kubectl/test/kubectl-layer.test.ts +++ b/packages/@aws-cdk/lambda-layer-kubectl/test/kubectl-layer.test.ts @@ -1,6 +1,6 @@ import { Stack } from '@aws-cdk/core'; import { KubectlLayer } from '../lib'; -import '@aws-cdk/assert/jest'; +import '@aws-cdk/assert-internal/jest'; test('synthesized to a layer version', () => { //GIVEN diff --git a/packages/@aws-cdk/pipelines/README.md b/packages/@aws-cdk/pipelines/README.md index 5413b38fa0d16..6097c87c16426 100644 --- a/packages/@aws-cdk/pipelines/README.md +++ b/packages/@aws-cdk/pipelines/README.md @@ -749,6 +749,18 @@ ID: ...) The stack failed its previous deployment, and is in a non-retryable state. Go into the CloudFormation console, delete the stack, and retry the deployment. +### Cannot find module 'xxxx' or its corresponding type declarations + +You may see this if you are using TypeScript or other NPM-based languages, +when using NPM 7 on your workstation (where you generate `package-lock.json`) +and NPM 6 on the CodeBuild image used for synthesizing. + +It looks like NPM 7 has started writing less information to `package-lock.json`, +leading NPM 6 reading that same file to not install all required packages anymore. + +Make sure you are using the same NPM version everywhere, either downgrade your +workstation's version or upgrade the CodeBuild version. + ## Current Limitations Limitations that we are aware of and will address: 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 10b1bccbab965..50c7705cc4528 100644 --- a/packages/@aws-cdk/pipelines/lib/actions/publish-assets-action.ts +++ b/packages/@aws-cdk/pipelines/lib/actions/publish-assets-action.ts @@ -105,7 +105,7 @@ export class PublishAssetsAction extends CoreConstruct implements codepipeline.I const project = new codebuild.PipelineProject(this, 'Default', { projectName: this.props.projectName, environment: { - buildImage: codebuild.LinuxBuildImage.STANDARD_4_0, + buildImage: codebuild.LinuxBuildImage.STANDARD_5_0, privileged: (props.assetType === AssetType.DOCKER_IMAGE) ? true : undefined, }, vpc: props.vpc, diff --git a/packages/@aws-cdk/pipelines/lib/actions/update-pipeline-action.ts b/packages/@aws-cdk/pipelines/lib/actions/update-pipeline-action.ts index 20dce58246c27..0d77f616e7cf9 100644 --- a/packages/@aws-cdk/pipelines/lib/actions/update-pipeline-action.ts +++ b/packages/@aws-cdk/pipelines/lib/actions/update-pipeline-action.ts @@ -58,7 +58,7 @@ export class UpdatePipelineAction extends CoreConstruct implements codepipeline. const selfMutationProject = new codebuild.PipelineProject(this, 'SelfMutation', { projectName: props.projectName, - environment: { buildImage: codebuild.LinuxBuildImage.STANDARD_4_0 }, + environment: { buildImage: codebuild.LinuxBuildImage.STANDARD_5_0 }, buildSpec: codebuild.BuildSpec.fromObject({ version: '0.2', phases: { 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 415f49f703e26..eec90185b9744 100644 --- a/packages/@aws-cdk/pipelines/lib/synths/simple-synth-action.ts +++ b/packages/@aws-cdk/pipelines/lib/synths/simple-synth-action.ts @@ -7,10 +7,11 @@ 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 { Stack } from '@aws-cdk/core'; -import { cloudAssemblyBuildSpecDir } from '../private/construct-internals'; import { toPosixPath } from '../private/fs'; import { copyEnvironmentVariables, filterEmpty } from './_util'; +const DEFAULT_OUTPUT_DIR = 'cdk.out'; + // keep this import separate from other imports to reduce chance for merge conflicts with v2-main // eslint-disable-next-line no-duplicate-imports, import/order import { Construct } from '@aws-cdk/core'; @@ -62,7 +63,7 @@ export interface SimpleSynthOptions { /** * Build environment to use for CodeBuild job * - * @default BuildEnvironment.LinuxBuildImage.STANDARD_4_0 + * @default BuildEnvironment.LinuxBuildImage.STANDARD_5_0 */ readonly environment?: codebuild.BuildEnvironment; @@ -320,7 +321,7 @@ export class SimpleSynthAction implements codepipeline.IAction, iam.IGrantable { artifacts: renderArtifacts(this), }); - const environment = { buildImage: codebuild.LinuxBuildImage.STANDARD_4_0, ...this.props.environment }; + const environment = { buildImage: codebuild.LinuxBuildImage.STANDARD_5_0, ...this.props.environment }; const environmentVariables = { ...copyEnvironmentVariables(...this.props.copyEnvironmentVariables || []), @@ -378,7 +379,7 @@ export class SimpleSynthAction implements codepipeline.IAction, iam.IGrantable { // using secondary artifacts or not. const cloudAsmArtifactSpec = { - 'base-directory': toPosixPath(path.join(self.props.subdirectory ?? '.', cloudAssemblyBuildSpecDir(scope))), + 'base-directory': toPosixPath(path.join(self.props.subdirectory ?? '.', DEFAULT_OUTPUT_DIR)), 'files': '**/*', }; 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 59f64555a76b5..436f099d3c67d 100644 --- a/packages/@aws-cdk/pipelines/lib/validation/shell-script-action.ts +++ b/packages/@aws-cdk/pipelines/lib/validation/shell-script-action.ts @@ -61,7 +61,7 @@ export interface ShellScriptActionProps { /** * The CodeBuild environment where scripts are executed. * - * @default LinuxBuildImage.STANDARD_4_0 + * @default LinuxBuildImage.STANDARD_5_0 */ readonly environment?: codebuild.BuildEnvironment @@ -195,7 +195,7 @@ export class ShellScriptAction implements codepipeline.IAction, iam.IGrantable { } this._project = new codebuild.PipelineProject(scope, 'Project', { - environment: this.props.environment || { buildImage: codebuild.LinuxBuildImage.STANDARD_4_0 }, + environment: this.props.environment || { buildImage: codebuild.LinuxBuildImage.STANDARD_5_0 }, vpc: this.props.vpc, securityGroups: this.props.securityGroups, subnetSelection: this.props.subnetSelection, diff --git a/packages/@aws-cdk/pipelines/package.json b/packages/@aws-cdk/pipelines/package.json index 8717570fc8f1d..5f9824d49d92f 100644 --- a/packages/@aws-cdk/pipelines/package.json +++ b/packages/@aws-cdk/pipelines/package.json @@ -30,17 +30,18 @@ "organization": true }, "devDependencies": { - "@aws-cdk/assert": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-ecr": "0.0.0", - "@aws-cdk/aws-ecr-assets": "0.0.0" + "@aws-cdk/aws-ecr-assets": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "peerDependencies": { - "constructs": "^3.2.0", + "constructs": "^3.3.69", "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-codebuild": "0.0.0", "@aws-cdk/aws-codepipeline": "0.0.0", @@ -53,7 +54,7 @@ "@aws-cdk/cx-api": "0.0.0" }, "dependencies": { - "constructs": "^3.2.0", + "constructs": "^3.3.69", "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-codebuild": "0.0.0", "@aws-cdk/aws-codepipeline": "0.0.0", diff --git a/packages/@aws-cdk/pipelines/test/build-role-policy-statements.test.ts b/packages/@aws-cdk/pipelines/test/build-role-policy-statements.test.ts index 298e8ccbb4e79..4fe019d34a005 100644 --- a/packages/@aws-cdk/pipelines/test/build-role-policy-statements.test.ts +++ b/packages/@aws-cdk/pipelines/test/build-role-policy-statements.test.ts @@ -1,5 +1,5 @@ -import { arrayWith, deepObjectLike } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { arrayWith, deepObjectLike } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import { PolicyStatement } from '@aws-cdk/aws-iam'; import { Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/pipelines/test/builds.test.ts b/packages/@aws-cdk/pipelines/test/builds.test.ts index f0b18e1e36442..5f91472b458f1 100644 --- a/packages/@aws-cdk/pipelines/test/builds.test.ts +++ b/packages/@aws-cdk/pipelines/test/builds.test.ts @@ -1,5 +1,5 @@ -import { arrayWith, deepObjectLike, encodedJson, objectLike, Capture } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { arrayWith, deepObjectLike, encodedJson, objectLike, Capture } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/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'; @@ -43,7 +43,7 @@ test('SimpleSynthAction takes arrays of commands', () => { // THEN expect(pipelineStack).toHaveResourceLike('AWS::CodeBuild::Project', { Environment: { - Image: 'aws/codebuild/standard:4.0', + Image: 'aws/codebuild/standard:5.0', }, Source: { BuildSpec: encodedJson(deepObjectLike({ @@ -80,12 +80,12 @@ test.each([['npm'], ['yarn']])('%s build automatically determines artifact base- // THEN expect(pipelineStack).toHaveResourceLike('AWS::CodeBuild::Project', { Environment: { - Image: 'aws/codebuild/standard:4.0', + Image: 'aws/codebuild/standard:5.0', }, Source: { BuildSpec: encodedJson(deepObjectLike({ artifacts: { - 'base-directory': 'testcdk.out', + 'base-directory': 'cdk.out', }, })), }, @@ -107,7 +107,7 @@ test.each([['npm'], ['yarn']])('%s build respects subdirectory', (npmYarn) => { // THEN expect(pipelineStack).toHaveResourceLike('AWS::CodeBuild::Project', { Environment: { - Image: 'aws/codebuild/standard:4.0', + Image: 'aws/codebuild/standard:5.0', }, Source: { BuildSpec: encodedJson(deepObjectLike({ @@ -117,7 +117,7 @@ test.each([['npm'], ['yarn']])('%s build respects subdirectory', (npmYarn) => { }, }, artifacts: { - 'base-directory': 'subdir/testcdk.out', + 'base-directory': 'subdir/cdk.out', }, })), }, @@ -135,7 +135,7 @@ test.each([['npm'], ['yarn']])('%s assumes no build step by default', (npmYarn) // THEN expect(pipelineStack).toHaveResourceLike('AWS::CodeBuild::Project', { Environment: { - Image: 'aws/codebuild/standard:4.0', + Image: 'aws/codebuild/standard:5.0', }, Source: { BuildSpec: encodedJson(deepObjectLike({ @@ -259,7 +259,7 @@ test.each([['npm'], ['yarn']])('%s can have its install command overridden', (np // THEN expect(pipelineStack).toHaveResourceLike('AWS::CodeBuild::Project', { Environment: { - Image: 'aws/codebuild/standard:4.0', + Image: 'aws/codebuild/standard:5.0', }, Source: { BuildSpec: encodedJson(deepObjectLike({ @@ -294,14 +294,14 @@ test('Standard (NPM) synth can output additional artifacts', () => { // THEN expect(pipelineStack).toHaveResourceLike('AWS::CodeBuild::Project', { Environment: { - Image: 'aws/codebuild/standard:4.0', + Image: 'aws/codebuild/standard:5.0', }, Source: { BuildSpec: encodedJson(deepObjectLike({ artifacts: { 'secondary-artifacts': { CloudAsm: { - 'base-directory': 'testcdk.out', + 'base-directory': 'cdk.out', 'files': '**/*', }, IntegTest: { diff --git a/packages/@aws-cdk/pipelines/test/cross-environment-infra.test.ts b/packages/@aws-cdk/pipelines/test/cross-environment-infra.test.ts index f9b100802036c..c9dcd17b567b3 100644 --- a/packages/@aws-cdk/pipelines/test/cross-environment-infra.test.ts +++ b/packages/@aws-cdk/pipelines/test/cross-environment-infra.test.ts @@ -1,5 +1,5 @@ -import { arrayWith, objectLike, stringLike } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { arrayWith, objectLike, stringLike } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import { Stack, Stage, StageProps } from '@aws-cdk/core'; import { Construct } from 'constructs'; import * as cdkp from '../lib'; diff --git a/packages/@aws-cdk/pipelines/test/existing-pipeline.test.ts b/packages/@aws-cdk/pipelines/test/existing-pipeline.test.ts index 1c280ec2fe1a6..170d2b25c3de1 100644 --- a/packages/@aws-cdk/pipelines/test/existing-pipeline.test.ts +++ b/packages/@aws-cdk/pipelines/test/existing-pipeline.test.ts @@ -1,5 +1,5 @@ -import { objectLike } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { objectLike } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as cp from '@aws-cdk/aws-codepipeline'; import { Stack } from '@aws-cdk/core'; import * as cdkp from '../lib'; diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-assets.expected.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-assets.expected.json index 248e3b79911c9..871d741989ca3 100644 --- a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-assets.expected.json +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-assets.expected.json @@ -293,7 +293,7 @@ "ProjectName": { "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" }, - "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"ea30b07764cb215963f4b0c292b5a06993fc3dd94621fbdc1c618e0f1e0dae10\"}]" + "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"a0d828d64c88aa603631eb7a08bc4748769f45d4b84d1b550cc85f41e49dc87e\"}]" }, "InputArtifacts": [ { @@ -765,7 +765,7 @@ }, "Environment": { "ComputeType": "BUILD_GENERAL1_SMALL", - "Image": "aws/codebuild/standard:4.0", + "Image": "aws/codebuild/standard:5.0", "ImagePullCredentialsType": "CODEBUILD", "PrivilegedMode": false, "Type": "LINUX_CONTAINER" @@ -777,7 +777,7 @@ ] }, "Source": { - "BuildSpec": "{\n \"version\": \"0.2\",\n \"phases\": {\n \"pre_build\": {\n \"commands\": [\n \"npm ci\"\n ]\n },\n \"build\": {\n \"commands\": [\n \"npx cdk synth\"\n ]\n }\n },\n \"artifacts\": {\n \"secondary-artifacts\": {\n \"CloudAsm\": {\n \"base-directory\": \"cdk-integ.out\",\n \"files\": \"**/*\"\n },\n \"IntegTests\": {\n \"base-directory\": \"test\",\n \"files\": \"**/*\"\n }\n }\n }\n}", + "BuildSpec": "{\n \"version\": \"0.2\",\n \"phases\": {\n \"pre_build\": {\n \"commands\": [\n \"npm ci\"\n ]\n },\n \"build\": {\n \"commands\": [\n \"npx cdk synth\"\n ]\n }\n },\n \"artifacts\": {\n \"secondary-artifacts\": {\n \"CloudAsm\": {\n \"base-directory\": \"cdk.out\",\n \"files\": \"**/*\"\n },\n \"IntegTests\": {\n \"base-directory\": \"test\",\n \"files\": \"**/*\"\n }\n }\n }\n}", "Type": "CODEPIPELINE" }, "EncryptionKey": { @@ -1071,7 +1071,7 @@ }, "Environment": { "ComputeType": "BUILD_GENERAL1_SMALL", - "Image": "aws/codebuild/standard:4.0", + "Image": "aws/codebuild/standard:5.0", "ImagePullCredentialsType": "CODEBUILD", "PrivilegedMode": false, "Type": "LINUX_CONTAINER" @@ -1278,7 +1278,7 @@ }, "Environment": { "ComputeType": "BUILD_GENERAL1_SMALL", - "Image": "aws/codebuild/standard:4.0", + "Image": "aws/codebuild/standard:5.0", "ImagePullCredentialsType": "CODEBUILD", "PrivilegedMode": false, "Type": "LINUX_CONTAINER" @@ -1453,7 +1453,7 @@ }, "Environment": { "ComputeType": "BUILD_GENERAL1_SMALL", - "Image": "aws/codebuild/standard:4.0", + "Image": "aws/codebuild/standard:5.0", "ImagePullCredentialsType": "CODEBUILD", "PrivilegedMode": false, "Type": "LINUX_CONTAINER" @@ -1484,7 +1484,7 @@ }, "Environment": { "ComputeType": "BUILD_GENERAL1_SMALL", - "Image": "aws/codebuild/standard:4.0", + "Image": "aws/codebuild/standard:5.0", "ImagePullCredentialsType": "CODEBUILD", "PrivilegedMode": false, "Type": "LINUX_CONTAINER" diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline.expected.json b/packages/@aws-cdk/pipelines/test/integ.pipeline.expected.json index 5d1569fbadc84..68e86fd208660 100644 --- a/packages/@aws-cdk/pipelines/test/integ.pipeline.expected.json +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline.expected.json @@ -283,7 +283,7 @@ "ProjectName": { "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" }, - "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"ea30b07764cb215963f4b0c292b5a06993fc3dd94621fbdc1c618e0f1e0dae10\"}]" + "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"a0d828d64c88aa603631eb7a08bc4748769f45d4b84d1b550cc85f41e49dc87e\"}]" }, "InputArtifacts": [ { @@ -698,7 +698,7 @@ }, "Environment": { "ComputeType": "BUILD_GENERAL1_SMALL", - "Image": "aws/codebuild/standard:4.0", + "Image": "aws/codebuild/standard:5.0", "ImagePullCredentialsType": "CODEBUILD", "PrivilegedMode": false, "Type": "LINUX_CONTAINER" @@ -710,7 +710,7 @@ ] }, "Source": { - "BuildSpec": "{\n \"version\": \"0.2\",\n \"phases\": {\n \"pre_build\": {\n \"commands\": [\n \"npm ci\"\n ]\n },\n \"build\": {\n \"commands\": [\n \"npx cdk synth\"\n ]\n }\n },\n \"artifacts\": {\n \"secondary-artifacts\": {\n \"CloudAsm\": {\n \"base-directory\": \"cdk-integ.out\",\n \"files\": \"**/*\"\n },\n \"IntegTests\": {\n \"base-directory\": \"test\",\n \"files\": \"**/*\"\n }\n }\n }\n}", + "BuildSpec": "{\n \"version\": \"0.2\",\n \"phases\": {\n \"pre_build\": {\n \"commands\": [\n \"npm ci\"\n ]\n },\n \"build\": {\n \"commands\": [\n \"npx cdk synth\"\n ]\n }\n },\n \"artifacts\": {\n \"secondary-artifacts\": {\n \"CloudAsm\": {\n \"base-directory\": \"cdk.out\",\n \"files\": \"**/*\"\n },\n \"IntegTests\": {\n \"base-directory\": \"test\",\n \"files\": \"**/*\"\n }\n }\n }\n}", "Type": "CODEPIPELINE" }, "EncryptionKey": { @@ -1004,7 +1004,7 @@ }, "Environment": { "ComputeType": "BUILD_GENERAL1_SMALL", - "Image": "aws/codebuild/standard:4.0", + "Image": "aws/codebuild/standard:5.0", "ImagePullCredentialsType": "CODEBUILD", "PrivilegedMode": false, "Type": "LINUX_CONTAINER" @@ -1211,7 +1211,7 @@ }, "Environment": { "ComputeType": "BUILD_GENERAL1_SMALL", - "Image": "aws/codebuild/standard:4.0", + "Image": "aws/codebuild/standard:5.0", "ImagePullCredentialsType": "CODEBUILD", "PrivilegedMode": false, "Type": "LINUX_CONTAINER" diff --git a/packages/@aws-cdk/pipelines/test/pipeline-assets.test.ts b/packages/@aws-cdk/pipelines/test/pipeline-assets.test.ts index 01b1d815bea17..ec89b621d6443 100644 --- a/packages/@aws-cdk/pipelines/test/pipeline-assets.test.ts +++ b/packages/@aws-cdk/pipelines/test/pipeline-assets.test.ts @@ -1,6 +1,6 @@ import * as path from 'path'; -import { arrayWith, deepObjectLike, encodedJson, notMatching, objectLike, stringLike } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { arrayWith, deepObjectLike, encodedJson, notMatching, objectLike, stringLike } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as cp from '@aws-cdk/aws-codepipeline'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecr_assets from '@aws-cdk/aws-ecr-assets'; @@ -151,7 +151,7 @@ describe('basic pipeline', () => { // THEN expect(pipelineStack).toHaveResourceLike('AWS::CodeBuild::Project', { Environment: { - Image: 'aws/codebuild/standard:4.0', + Image: 'aws/codebuild/standard:5.0', }, Source: { BuildSpec: encodedJson(deepObjectLike({ @@ -219,7 +219,7 @@ describe('basic pipeline', () => { }, Environment: objectLike({ PrivilegedMode: false, - Image: 'aws/codebuild/standard:4.0', + Image: 'aws/codebuild/standard:5.0', }), }); @@ -250,7 +250,7 @@ describe('basic pipeline', () => { })), }, Environment: objectLike({ - Image: 'aws/codebuild/standard:4.0', + Image: 'aws/codebuild/standard:5.0', PrivilegedMode: true, }), }); @@ -276,7 +276,7 @@ describe('basic pipeline', () => { // THEN expect(stack2).toHaveResourceLike('AWS::CodeBuild::Project', { Environment: { - Image: 'aws/codebuild/standard:4.0', + Image: 'aws/codebuild/standard:5.0', }, Source: { BuildSpec: encodedJson(deepObjectLike({ diff --git a/packages/@aws-cdk/pipelines/test/pipeline.test.ts b/packages/@aws-cdk/pipelines/test/pipeline.test.ts index 003aacf021d47..5069e9c6d542e 100644 --- a/packages/@aws-cdk/pipelines/test/pipeline.test.ts +++ b/packages/@aws-cdk/pipelines/test/pipeline.test.ts @@ -9,8 +9,8 @@ import { notMatching, objectLike, stringLike, -} from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +} from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as cp from '@aws-cdk/aws-codepipeline'; import * as cpa from '@aws-cdk/aws-codepipeline-actions'; import { Stack, Stage, StageProps, SecretValue, Tags } from '@aws-cdk/core'; @@ -301,7 +301,7 @@ test('pipeline has self-mutation stage', () => { expect(pipelineStack).toHaveResourceLike('AWS::CodeBuild::Project', { Environment: { - Image: 'aws/codebuild/standard:4.0', + Image: 'aws/codebuild/standard:5.0', }, Source: { BuildSpec: encodedJson(deepObjectLike({ @@ -327,7 +327,7 @@ test('selfmutation stage correctly identifies nested assembly of pipeline stack' // THEN expect(stackTemplate(nestedPipelineStack)).toHaveResourceLike('AWS::CodeBuild::Project', { Environment: { - Image: 'aws/codebuild/standard:4.0', + Image: 'aws/codebuild/standard:5.0', }, Source: { BuildSpec: encodedJson(deepObjectLike({ diff --git a/packages/@aws-cdk/pipelines/test/stack-ordering.test.ts b/packages/@aws-cdk/pipelines/test/stack-ordering.test.ts index c7b2fc98f4f20..4f3fa3c0b77b9 100644 --- a/packages/@aws-cdk/pipelines/test/stack-ordering.test.ts +++ b/packages/@aws-cdk/pipelines/test/stack-ordering.test.ts @@ -1,5 +1,5 @@ -import { arrayWith, objectLike } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { arrayWith, objectLike } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import { App, Stack, Stage, StageProps } from '@aws-cdk/core'; import { Construct } from 'constructs'; import * as cdkp from '../lib'; diff --git a/packages/@aws-cdk/pipelines/test/testmatchers.ts b/packages/@aws-cdk/pipelines/test/testmatchers.ts index c412993d4b51d..90b31fb133fd4 100644 --- a/packages/@aws-cdk/pipelines/test/testmatchers.ts +++ b/packages/@aws-cdk/pipelines/test/testmatchers.ts @@ -1,4 +1,4 @@ -import { annotateMatcher, InspectionFailure, matcherFrom, PropertyMatcher } from '@aws-cdk/assert'; +import { annotateMatcher, InspectionFailure, matcherFrom, PropertyMatcher } from '@aws-cdk/assert-internal'; /** * Sort an array (of Actions) by their RunOrder field before applying a matcher. diff --git a/packages/@aws-cdk/pipelines/test/validation.test.ts b/packages/@aws-cdk/pipelines/test/validation.test.ts index 8cfe55d558b34..c78903612714e 100644 --- a/packages/@aws-cdk/pipelines/test/validation.test.ts +++ b/packages/@aws-cdk/pipelines/test/validation.test.ts @@ -1,5 +1,5 @@ -import { anything, arrayWith, deepObjectLike, encodedJson, objectLike } from '@aws-cdk/assert'; -import '@aws-cdk/assert/jest'; +import { anything, arrayWith, deepObjectLike, encodedJson, objectLike } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as ec2 from '@aws-cdk/aws-ec2'; @@ -81,7 +81,7 @@ test('can use stack outputs as validation inputs', () => { expect(pipelineStack).toHaveResourceLike('AWS::CodeBuild::Project', { Environment: { - Image: 'aws/codebuild/standard:4.0', + Image: 'aws/codebuild/standard:5.0', }, Source: { BuildSpec: encodedJson(deepObjectLike({ @@ -122,7 +122,7 @@ test('can use additional files from source', () => { }); expect(pipelineStack).toHaveResourceLike('AWS::CodeBuild::Project', { Environment: { - Image: 'aws/codebuild/standard:4.0', + Image: 'aws/codebuild/standard:5.0', }, Source: { BuildSpec: encodedJson(deepObjectLike({ @@ -161,7 +161,7 @@ test('can use additional files from build', () => { }); expect(pipelineStack).toHaveResourceLike('AWS::CodeBuild::Project', { Environment: { - Image: 'aws/codebuild/standard:4.0', + Image: 'aws/codebuild/standard:5.0', }, Source: { BuildSpec: encodedJson(deepObjectLike({ @@ -250,7 +250,7 @@ test('run ShellScriptAction in a VPC', () => { }); expect(pipelineStack).toHaveResourceLike('AWS::CodeBuild::Project', { Environment: { - Image: 'aws/codebuild/standard:4.0', + Image: 'aws/codebuild/standard:5.0', }, VpcConfig: { SecurityGroupIds: [ diff --git a/packages/@aws-cdk/region-info/README.md b/packages/@aws-cdk/region-info/README.md index 07119849babb4..0f1186318ee49 100644 --- a/packages/@aws-cdk/region-info/README.md +++ b/packages/@aws-cdk/region-info/README.md @@ -3,13 +3,7 @@ --- -![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. +![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge) --- diff --git a/packages/@aws-cdk/region-info/package.json b/packages/@aws-cdk/region-info/package.json index fe5a7e1acf1ec..47daf4d1d60fa 100644 --- a/packages/@aws-cdk/region-info/package.json +++ b/packages/@aws-cdk/region-info/package.json @@ -55,6 +55,7 @@ "license": "Apache-2.0", "devDependencies": { "@types/fs-extra": "^8.1.1", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "fs-extra": "^9.1.0", "pkglint": "0.0.0" @@ -72,8 +73,8 @@ "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, - "stability": "experimental", - "maturity": "experimental", + "stability": "stable", + "maturity": "stable", "awslint": { "exclude": [ "docs-public-apis:@aws-cdk/region-info.Fact.regions", @@ -81,6 +82,9 @@ "docs-public-apis:@aws-cdk/region-info.RegionInfo.name" ] }, + "nozem": { + "ostools": ["bash"] + }, "awscdkio": { "announce": false }, diff --git a/packages/@aws-cdk/yaml-cfn/README.md b/packages/@aws-cdk/yaml-cfn/README.md index 5045163f84ce6..7090b6001111c 100644 --- a/packages/@aws-cdk/yaml-cfn/README.md +++ b/packages/@aws-cdk/yaml-cfn/README.md @@ -3,13 +3,9 @@ --- -![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge) +![Deprecated](https://img.shields.io/badge/deprecated-critical.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 API may emit warnings. Backward compatibility is not guaranteed. --- diff --git a/packages/@aws-cdk/yaml-cfn/lib/yaml.ts b/packages/@aws-cdk/yaml-cfn/lib/yaml.ts index eca37db0ed048..e46c8f8d6bf72 100644 --- a/packages/@aws-cdk/yaml-cfn/lib/yaml.ts +++ b/packages/@aws-cdk/yaml-cfn/lib/yaml.ts @@ -54,6 +54,6 @@ const shortForms: yaml_types.Schema.CustomTag[] = [ function parseYamlStrWithCfnTags(text: string): any { return yaml.parse(text, { customTags: shortForms, - schema: 'yaml-1.1', + schema: 'core', }); } diff --git a/packages/@aws-cdk/yaml-cfn/package.json b/packages/@aws-cdk/yaml-cfn/package.json index 7fc68d44a23af..4bb5660823884 100644 --- a/packages/@aws-cdk/yaml-cfn/package.json +++ b/packages/@aws-cdk/yaml-cfn/package.json @@ -1,5 +1,6 @@ { "name": "@aws-cdk/yaml-cfn", + "deprecated": "This module is no longer supported and will be removed in a future release.", "version": "0.0.0", "description": "Utilities for handling CloudFormation-flavored YAML", "main": "lib/index.js", @@ -66,12 +67,12 @@ "yaml": "1.10.2" }, "devDependencies": { - "@aws-cdk/assert": "0.0.0", - "@types/jest": "^26.0.21", + "@types/jest": "^26.0.23", "@types/yaml": "^1.9.7", "cdk-build-tools": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0" }, "bundledDependencies": [ "yaml" @@ -82,8 +83,8 @@ "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, - "stability": "experimental", - "maturity": "experimental", + "stability": "deprecated", + "maturity": "deprecated", "awscdkio": { "announce": false }, diff --git a/packages/@aws-cdk/yaml-cfn/test/deserialization.test.ts b/packages/@aws-cdk/yaml-cfn/test/deserialization.test.ts new file mode 100644 index 0000000000000..3d790ea9d60e6 --- /dev/null +++ b/packages/@aws-cdk/yaml-cfn/test/deserialization.test.ts @@ -0,0 +1,34 @@ +import '@aws-cdk/assert-internal/jest'; +import * as yaml_cfn from '../lib'; + +test('Unquoted year-month-day is treated as a string, not a Date', () => { + const value = yaml_cfn.deserialize('Key: 2020-12-31'); + + expect(value).toEqual({ + Key: '2020-12-31', + }); +}); + +test("Unquoted 'No' is treated as a string, not a boolean", () => { + const value = yaml_cfn.deserialize('Key: No'); + + expect(value).toEqual({ + Key: 'No', + }); +}); + +test("Short-form 'Ref' is deserialized correctly", () => { + const value = yaml_cfn.deserialize('!Ref Resource'); + + expect(value).toEqual({ + Ref: 'Resource', + }); +}); + +test("Short-form 'Fn::GetAtt' is deserialized correctly", () => { + const value = yaml_cfn.deserialize('!GetAtt Resource.Attribute'); + + expect(value).toEqual({ + 'Fn::GetAtt': 'Resource.Attribute', + }); +}); diff --git a/packages/@aws-cdk/yaml-cfn/test/serialization.test.ts b/packages/@aws-cdk/yaml-cfn/test/serialization.test.ts new file mode 100644 index 0000000000000..3237f16f986b4 --- /dev/null +++ b/packages/@aws-cdk/yaml-cfn/test/serialization.test.ts @@ -0,0 +1,8 @@ +import '@aws-cdk/assert-internal/jest'; +import * as yaml_cfn from '../lib'; + +test('An object with a single string value is serialized as a simple string', () => { + const value = yaml_cfn.serialize({ key: 'some string' }); + + expect(value).toEqual('key: some string\n'); +}); diff --git a/packages/@monocdk-experiment/assert/clone.sh b/packages/@monocdk-experiment/assert/clone.sh index 9cf4731c69f64..983cae5d5a9c0 100755 --- a/packages/@monocdk-experiment/assert/clone.sh +++ b/packages/@monocdk-experiment/assert/clone.sh @@ -3,7 +3,7 @@ scriptdir=$(cd $(dirname $0) && pwd) cd $scriptdir set -euo pipefail -src="../../@aws-cdk/assert" +src="../../@aws-cdk/assert-internal" rsync -av $src/lib/ lib/ rsync -av $src/test/ test/ diff --git a/packages/@monocdk-experiment/assert/package.json b/packages/@monocdk-experiment/assert/package.json index a0f33eba501ac..a8676b333fc16 100644 --- a/packages/@monocdk-experiment/assert/package.json +++ b/packages/@monocdk-experiment/assert/package.json @@ -9,7 +9,7 @@ "watch": "cdk-watch", "lint": "cdk-lint", "test": "cdk-test", - "pkglint": "pkglint -f", + "pkglint": "true", "package": "cdk-package", "build+test+package": "yarn build+test && yarn package", "build+test": "yarn build && yarn test" @@ -34,20 +34,20 @@ "license": "Apache-2.0", "devDependencies": { "@monocdk-experiment/rewrite-imports": "0.0.0", - "@types/jest": "^26.0.21", - "@types/node": "^10.17.55", + "@types/jest": "^26.0.23", + "@types/node": "^10.17.59", "cdk-build-tools": "0.0.0", - "constructs": "^3.2.0", + "constructs": "^3.3.69", "jest": "^26.6.3", "monocdk": "0.0.0", "pkglint": "0.0.0", - "ts-jest": "^26.5.4" + "ts-jest": "^26.5.5" }, "dependencies": { "@aws-cdk/cloudformation-diff": "0.0.0" }, "peerDependencies": { - "constructs": "^3.2.0", + "constructs": "^3.3.69", "jest": "^26.6.3", "monocdk": "^0.0.0" }, diff --git a/packages/@monocdk-experiment/rewrite-imports/package.json b/packages/@monocdk-experiment/rewrite-imports/package.json index 6c8a2788e1f53..966a486b7c730 100644 --- a/packages/@monocdk-experiment/rewrite-imports/package.json +++ b/packages/@monocdk-experiment/rewrite-imports/package.json @@ -37,8 +37,8 @@ }, "devDependencies": { "@types/glob": "^7.1.3", - "@types/jest": "^26.0.21", - "@types/node": "^10.17.55", + "@types/jest": "^26.0.23", + "@types/node": "^10.17.59", "cdk-build-tools": "0.0.0", "pkglint": "0.0.0" }, diff --git a/packages/aws-cdk-lib/README.md b/packages/aws-cdk-lib/README.md index d7b2d367ad94b..445346a4a90bc 100644 --- a/packages/aws-cdk-lib/README.md +++ b/packages/aws-cdk-lib/README.md @@ -30,10 +30,10 @@ According to the kind of project you are developing: You can use a classic import to get access to each service namespaces: ```ts -import { core, aws_s3 as s3 } from 'aws-cdk-lib'; +import { Stack, App, aws_s3 as s3 } from 'aws-cdk-lib'; -const app = new core.App(); -const stack = new core.Stack(app, 'TestStack'); +const app = new App(); +const stack = new Stack(app, 'TestStack'); new s3.Bucket(stack, 'TestBucket'); ``` @@ -51,3 +51,900 @@ const stack = new Stack(app, 'TestStack'); new Bucket(stack, 'TestBucket'); ``` + + + +## Stacks and Stages + +A `Stack` is the smallest physical unit of deployment, and maps directly onto +a CloudFormation Stack. You define a Stack by defining a subclass of `Stack` +-- let's call it `MyStack` -- and instantiating the constructs that make up +your application in `MyStack`'s constructor. You then instantiate this stack +one or more times to define different instances of your application. For example, +you can instantiate it once using few and cheap EC2 instances for testing, +and once again using more and bigger EC2 instances for production. + +When your application grows, you may decide that it makes more sense to split it +out across multiple `Stack` classes. This can happen for a number of reasons: + +- You could be starting to reach the maximum number of resources allowed in a single + stack (this is currently 500). +- You could decide you want to separate out stateful resources and stateless resources + into separate stacks, so that it becomes easy to tear down and recreate the stacks + that don't have stateful resources. +- There could be a single stack with resources (like a VPC) that are shared + between multiple instances of other stacks containing your applications. + +As soon as your conceptual application starts to encompass multiple stacks, +it is convenient to wrap them in another construct that represents your +logical application. You can then treat that new unit the same way you used +to be able to treat a single stack: by instantiating it multiple times +for different instances of your application. + +You can define a custom subclass of `Construct`, holding one or more +`Stack`s, to represent a single logical instance of your application. + +As a final note: `Stack`s are not a unit of reuse. They describe physical +deployment layouts, and as such are best left to application builders to +organize their deployments with. If you want to vend a reusable construct, +define it as a subclasses of `Construct`: the consumers of your construct +will decide where to place it in their own stacks. + +## Nested Stacks + +[Nested stacks](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-nested-stacks.html) are stacks created as part of other stacks. You create a nested stack within another stack by using the `NestedStack` construct. + +As your infrastructure grows, common patterns can emerge in which you declare the same components in multiple templates. You can separate out these common components and create dedicated templates for them. Then use the resource in your template to reference other templates, creating nested stacks. + +For example, assume that you have a load balancer configuration that you use for most of your stacks. Instead of copying and pasting the same configurations into your templates, you can create a dedicated template for the load balancer. Then, you just use the resource to reference that template from within other templates. + +The following example will define a single top-level stack that contains two nested stacks: each one with a single Amazon S3 bucket: + +```ts +class MyNestedStack extends cfn.NestedStack { + constructor(scope: Construct, id: string, props?: cfn.NestedStackProps) { + super(scope, id, props); + + new s3.Bucket(this, 'NestedBucket'); + } +} + +class MyParentStack extends Stack { + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + + new MyNestedStack(this, 'Nested1'); + new MyNestedStack(this, 'Nested2'); + } +} +``` + +Resources references across nested/parent boundaries (even with multiple levels of nesting) will be wired by the AWS CDK +through CloudFormation parameters and outputs. When a resource from a parent stack is referenced by a nested stack, +a CloudFormation parameter will automatically be added to the nested stack and assigned from the parent; when a resource +from a nested stack is referenced by a parent stack, a CloudFormation output will be automatically be added to the +nested stack and referenced using `Fn::GetAtt "Outputs.Xxx"` from the parent. + +Nested stacks also support the use of Docker image and file assets. + +## Accessing resources in a different stack + +You can access resources in a different stack, as long as they are in the +same account and AWS Region. The following example defines the stack `stack1`, +which defines an Amazon S3 bucket. Then it defines a second stack, `stack2`, +which takes the bucket from stack1 as a constructor property. + +```ts +const prod = { account: '123456789012', region: 'us-east-1' }; + +const stack1 = new StackThatProvidesABucket(app, 'Stack1' , { env: prod }); + +// stack2 will take a property { bucket: IBucket } +const stack2 = new StackThatExpectsABucket(app, 'Stack2', { + bucket: stack1.bucket, + env: prod +}); +``` + +If the AWS CDK determines that the resource is in the same account and +Region, but in a different stack, it automatically synthesizes AWS +CloudFormation +[Exports](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-stack-exports.html) +in the producing stack and an +[Fn::ImportValue](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-importvalue.html) +in the consuming stack to transfer that information from one stack to the +other. + +### Removing automatic cross-stack references + +The automatic references created by CDK when you use resources across stacks +are convenient, but may block your deployments if you want to remove the +resources that are referenced in this way. You will see an error like: + +```text +Export Stack1:ExportsOutputFnGetAtt-****** cannot be deleted as it is in use by Stack1 +``` + +Let's say there is a Bucket in the `stack1`, and the `stack2` references its +`bucket.bucketName`. You now want to remove the bucket and run into the error above. + +It's not safe to remove `stack1.bucket` while `stack2` is still using it, so +unblocking yourself from this is a two-step process. This is how it works: + +DEPLOYMENT 1: break the relationship + +- Make sure `stack2` no longer references `bucket.bucketName` (maybe the consumer + stack now uses its own bucket, or it writes to an AWS DynamoDB table, or maybe you just + remove the Lambda Function altogether). +- In the `stack1` class, call `this.exportValue(this.bucket.bucketName)`. This + will make sure the CloudFormation Export continues to exist while the relationship + between the two stacks is being broken. +- Deploy (this will effectively only change the `stack2`, but it's safe to deploy both). + +DEPLOYMENT 2: remove the resource + +- You are now free to remove the `bucket` resource from `stack1`. +- Don't forget to remove the `exportValue()` call as well. +- Deploy again (this time only the `stack1` will be changed -- the bucket will be deleted). + +## Durations + +To make specifications of time intervals unambiguous, a single class called +`Duration` is used throughout the AWS Construct Library by all constructs +that that take a time interval as a parameter (be it for a timeout, a +rate, or something else). + +An instance of Duration is constructed by using one of the static factory +methods on it: + +```ts +Duration.seconds(300) // 5 minutes +Duration.minutes(5) // 5 minutes +Duration.hours(1) // 1 hour +Duration.days(7) // 7 days +Duration.parse('PT5M') // 5 minutes +``` + +## Size (Digital Information Quantity) + +To make specification of digital storage quantities unambiguous, a class called +`Size` is available. + +An instance of `Size` is initialized through one of its static factory methods: + +```ts +Size.kibibytes(200) // 200 KiB +Size.mebibytes(5) // 5 MiB +Size.gibibytes(40) // 40 GiB +Size.tebibytes(200) // 200 TiB +Size.pebibytes(3) // 3 PiB +``` + +Instances of `Size` created with one of the units can be converted into others. +By default, conversion to a higher unit will fail if the conversion does not produce +a whole number. This can be overridden by unsetting `integral` property. + +```ts +Size.mebibytes(2).toKibibytes() // yields 2048 +Size.kibibytes(2050).toMebibytes({ rounding: SizeRoundingBehavior.FLOOR }) // yields 2 +``` + +## Secrets + +To help avoid accidental storage of secrets as plain text, we use the `SecretValue` type to +represent secrets. Any construct that takes a value that should be a secret (such as +a password or an access key) will take a parameter of type `SecretValue`. + +The best practice is to store secrets in AWS Secrets Manager and reference them using `SecretValue.secretsManager`: + +```ts +const secret = SecretValue.secretsManager('secretId', { + jsonField: 'password', // optional: key of a JSON field to retrieve (defaults to all content), + versionId: 'id', // optional: id of the version (default AWSCURRENT) + versionStage: 'stage', // optional: version stage name (default AWSCURRENT) +}); +``` + +Using AWS Secrets Manager is the recommended way to reference secrets in a CDK app. +`SecretValue` also supports the following secret sources: + + - `SecretValue.plainText(secret)`: stores the secret as plain text in your app and the resulting template (not recommended). + - `SecretValue.ssmSecure(param, version)`: refers to a secret stored as a SecureString in the SSM Parameter Store. + - `SecretValue.cfnParameter(param)`: refers to a secret passed through a CloudFormation parameter (must have `NoEcho: true`). + - `SecretValue.cfnDynamicReference(dynref)`: refers to a secret described by a CloudFormation dynamic reference (used by `ssmSecure` and `secretsManager`). + +## ARN manipulation + +Sometimes you will need to put together or pick apart Amazon Resource Names +(ARNs). The functions `stack.formatArn()` and `stack.parseArn()` exist for +this purpose. + +`formatArn()` can be used to build an ARN from components. It will automatically +use the region and account of the stack you're calling it on: + +```ts +// Builds "arn::lambda:::function:MyFunction" +stack.formatArn({ + service: 'lambda', + resource: 'function', + sep: ':', + resourceName: 'MyFunction' +}); +``` + +`parseArn()` can be used to get a single component from an ARN. `parseArn()` +will correctly deal with both literal ARNs and deploy-time values (tokens), +but in case of a deploy-time value be aware that the result will be another +deploy-time value which cannot be inspected in the CDK application. + +```ts +// Extracts the function name out of an AWS Lambda Function ARN +const arnComponents = stack.parseArn(arn, ':'); +const functionName = arnComponents.resourceName; +``` + +Note that depending on the service, the resource separator can be either +`:` or `/`, and the resource name can be either the 6th or 7th +component in the ARN. When using these functions, you will need to know +the format of the ARN you are dealing with. + +For an exhaustive list of ARN formats used in AWS, see [AWS ARNs and +Namespaces](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) +in the AWS General Reference. + +## Dependencies + +### Construct Dependencies + +Sometimes AWS resources depend on other resources, and the creation of one +resource must be completed before the next one can be started. + +In general, CloudFormation will correctly infer the dependency relationship +between resources based on the property values that are used. In the cases where +it doesn't, the AWS Construct Library will add the dependency relationship for +you. + +If you need to add an ordering dependency that is not automatically inferred, +you do so by adding a dependency relationship using +`constructA.node.addDependency(constructB)`. This will add a dependency +relationship between all resources in the scope of `constructA` and all +resources in the scope of `constructB`. + +If you want a single object to represent a set of constructs that are not +necessarily in the same scope, you can use a `ConcreteDependable`. The +following creates a single object that represents a dependency on two +constructs, `constructB` and `constructC`: + +```ts +// Declare the dependable object +const bAndC = new ConcreteDependable(); +bAndC.add(constructB); +bAndC.add(constructC); + +// Take the dependency +constructA.node.addDependency(bAndC); +``` + +### Stack Dependencies + +Two different stack instances can have a dependency on one another. This +happens when an resource from one stack is referenced in another stack. In +that case, CDK records the cross-stack referencing of resources, +automatically produces the right CloudFormation primitives, and adds a +dependency between the two stacks. You can also manually add a dependency +between two stacks by using the `stackA.addDependency(stackB)` method. + +A stack dependency has the following implications: + +- Cyclic dependencies are not allowed, so if `stackA` is using resources from + `stackB`, the reverse is not possible anymore. +- Stacks with dependencies between them are treated specially by the CDK + toolkit: + - If `stackA` depends on `stackB`, running `cdk deploy stackA` will also + automatically deploy `stackB`. + - `stackB`'s deployment will be performed *before* `stackA`'s deployment. + +## Custom Resources + +Custom Resources are CloudFormation resources that are implemented by arbitrary +user code. They can do arbitrary lookups or modifications during a +CloudFormation deployment. + +To define a custom resource, use the `CustomResource` construct: + +```ts +new CustomResource(this, 'MyMagicalResource', { + resourceType: 'Custom::MyCustomResource', // must start with 'Custom::' + + // the resource properties + properties: { + Property1: 'foo', + Property2: 'bar' + }, + + // the ARN of the provider (SNS/Lambda) which handles + // CREATE, UPDATE or DELETE events for this resource type + // see next section for details + serviceToken: 'ARN' +}); +``` + +### Custom Resource Providers + +Custom resources are backed by a **custom resource provider** which can be +implemented in one of the following ways. The following table compares the +various provider types (ordered from low-level to high-level): + +| Provider | Compute Type | Error Handling | Submit to CloudFormation | Max Timeout | Language | Footprint | +|----------------------------------------------------------------------|:------------:|:--------------:|:------------------------:|:---------------:|:--------:|:---------:| +| [sns.Topic](#amazon-sns-topic) | Self-managed | Manual | Manual | Unlimited | Any | Depends | +| [lambda.Function](#aws-lambda-function) | AWS Lambda | Manual | Manual | 15min | Any | Small | +| [core.CustomResourceProvider](#the-corecustomresourceprovider-class) | Lambda | Auto | Auto | 15min | Node.js | Small | +| [custom-resources.Provider](#the-custom-resource-provider-framework) | Lambda | Auto | Auto | Unlimited Async | Any | Large | + +Legend: + +- **Compute type**: which type of compute can is used to execute the handler. +- **Error Handling**: whether errors thrown by handler code are automatically + trapped and a FAILED response is submitted to CloudFormation. If this is + "Manual", developers must take care of trapping errors. Otherwise, events + could cause stacks to hang. +- **Submit to CloudFormation**: whether the framework takes care of submitting + SUCCESS/FAILED responses to CloudFormation through the event's response URL. +- **Max Timeout**: maximum allows/possible timeout. +- **Language**: which programming languages can be used to implement handlers. +- **Footprint**: how many resources are used by the provider framework itself. + +**A NOTE ABOUT SINGLETONS** + +When defining resources for a custom resource provider, you will likely want to +define them as a *stack singleton* so that only a single instance of the +provider is created in your stack and which is used by all custom resources of +that type. + +Here is a basic pattern for defining stack singletons in the CDK. The following +examples ensures that only a single SNS topic is defined: + +```ts +function getOrCreate(scope: Construct): sns.Topic { + const stack = Stack.of(scope); + const uniqueid = 'GloballyUniqueIdForSingleton'; // For example, a UUID from `uuidgen` + return stack.node.tryFindChild(uniqueid) as sns.Topic ?? new sns.Topic(stack, uniqueid); +} +``` + +#### Amazon SNS Topic + +Every time a resource event occurs (CREATE/UPDATE/DELETE), an SNS notification +is sent to the SNS topic. Users must process these notifications (e.g. through a +fleet of worker hosts) and submit success/failure responses to the +CloudFormation service. + +Set `serviceToken` to `topic.topicArn` in order to use this provider: + +```ts +const topic = new sns.Topic(this, 'MyProvider'); + +new CustomResource(this, 'MyResource', { + serviceToken: topic.topicArn +}); +``` + +#### AWS Lambda Function + +An AWS lambda function is called *directly* by CloudFormation for all resource +events. The handler must take care of explicitly submitting a success/failure +response to the CloudFormation service and handle various error cases. + +Set `serviceToken` to `lambda.functionArn` to use this provider: + +```ts +const fn = new lambda.Function(this, 'MyProvider', functionProps); + +new CustomResource(this, 'MyResource', { + serviceToken: fn.functionArn, +}); +``` + +#### The `core.CustomResourceProvider` class + +The class [`@aws-cdk/core.CustomResourceProvider`] offers a basic low-level +framework designed to implement simple and slim custom resource providers. It +currently only supports Node.js-based user handlers, and it does not have +support for asynchronous waiting (handler cannot exceed the 15min lambda +timeout). + +[`@aws-cdk/core.CustomResourceProvider`]: https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_core.CustomResourceProvider.html + +The provider has a built-in singleton method which uses the resource type as a +stack-unique identifier and returns the service token: + +```ts +const serviceToken = CustomResourceProvider.getOrCreate(this, 'Custom::MyCustomResourceType', { + codeDirectory: `${__dirname}/my-handler`, + runtime: CustomResourceProviderRuntime.NODEJS_12_X, + description: "Lambda function created by the custom resource provider", +}); + +new CustomResource(this, 'MyResource', { + resourceType: 'Custom::MyCustomResourceType', + serviceToken: serviceToken +}); +``` + +The directory (`my-handler` in the above example) must include an `index.js` file. It cannot import +external dependencies or files outside this directory. It must export an async +function named `handler`. This function accepts the CloudFormation resource +event object and returns an object with the following structure: + +```js +exports.handler = async function(event) { + const id = event.PhysicalResourceId; // only for "Update" and "Delete" + const props = event.ResourceProperties; + const oldProps = event.OldResourceProperties; // only for "Update"s + + switch (event.RequestType) { + case "Create": + // ... + + case "Update": + // ... + + // if an error is thrown, a FAILED response will be submitted to CFN + throw new Error('Failed!'); + + case "Delete": + // ... + } + + return { + // (optional) the value resolved from `resource.ref` + // defaults to "event.PhysicalResourceId" or "event.RequestId" + PhysicalResourceId: "REF", + + // (optional) calling `resource.getAtt("Att1")` on the custom resource in the CDK app + // will return the value "BAR". + Data: { + Att1: "BAR", + Att2: "BAZ" + }, + + // (optional) user-visible message + Reason: "User-visible message", + + // (optional) hides values from the console + NoEcho: true + }; +} +``` + +Here is an complete example of a custom resource that summarizes two numbers: + +`sum-handler/index.js`: + +```js +exports.handler = async (e) => { + return { + Data: { + Result: e.ResourceProperties.lhs + e.ResourceProperties.rhs, + }, + }; +}; +``` + +`sum.ts`: + +```ts nofixture +import { + Construct, + CustomResource, + CustomResourceProvider, + CustomResourceProviderRuntime, + Token, +} from '@aws-cdk/core'; + +export interface SumProps { + readonly lhs: number; + readonly rhs: number; +} + +export class Sum extends Construct { + public readonly result: number; + + constructor(scope: Construct, id: string, props: SumProps) { + super(scope, id); + + const resourceType = 'Custom::Sum'; + const serviceToken = CustomResourceProvider.getOrCreate(this, resourceType, { + codeDirectory: `${__dirname}/sum-handler`, + runtime: CustomResourceProviderRuntime.NODEJS_12_X, + }); + + const resource = new CustomResource(this, 'Resource', { + resourceType: resourceType, + serviceToken: serviceToken, + properties: { + lhs: props.lhs, + rhs: props.rhs + } + }); + + this.result = Token.asNumber(resource.getAtt('Result')); + } +} +``` + +Usage will look like this: + +```ts fixture=README-custom-resource-provider +const sum = new Sum(this, 'MySum', { lhs: 40, rhs: 2 }); +new CfnOutput(this, 'Result', { value: Token.asString(sum.result) }); +``` + +To access the ARN of the provider's AWS Lambda function role, use the `getOrCreateProvider()` +built-in singleton method: + +```ts +const provider = CustomResourceProvider.getOrCreateProvider(this, 'Custom::MyCustomResourceType', { + codeDirectory: `${__dirname}/my-handler`, + runtime: CustomResourceProviderRuntime.NODEJS_12_X, +}); + +const roleArn = provider.roleArn; +``` + +This role ARN can then be used in resource-based IAM policies. + +#### The Custom Resource Provider Framework + +The [`@aws-cdk/custom-resources`] module includes an advanced framework for +implementing custom resource providers. + +[`@aws-cdk/custom-resources`]: https://docs.aws.amazon.com/cdk/api/latest/docs/custom-resources-readme.html + +Handlers are implemented as AWS Lambda functions, which means that they can be +implemented in any Lambda-supported runtime. Furthermore, this provider has an +asynchronous mode, which means that users can provide an `isComplete` lambda +function which is called periodically until the operation is complete. This +allows implementing providers that can take up to two hours to stabilize. + +Set `serviceToken` to `provider.serviceToken` to use this type of provider: + +```ts +const provider = new customresources.Provider(this, 'MyProvider', { + onEventHandler, + isCompleteHandler, // optional async waiter +}); + +new CustomResource(this, 'MyResource', { + serviceToken: provider.serviceToken +}); +``` + +See the [documentation](https://docs.aws.amazon.com/cdk/api/latest/docs/custom-resources-readme.html) for more details. + +## AWS CloudFormation features + +A CDK stack synthesizes to an AWS CloudFormation Template. This section +explains how this module allows users to access low-level CloudFormation +features when needed. + +### Stack Outputs + +CloudFormation [stack outputs][cfn-stack-output] and exports are created using +the `CfnOutput` class: + +```ts +new CfnOutput(this, 'OutputName', { + value: myBucket.bucketName, + description: 'The name of an S3 bucket', // Optional + exportName: 'TheAwesomeBucket', // Registers a CloudFormation export named "TheAwesomeBucket" +}); +``` + +[cfn-stack-output]: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html + +### Parameters + +CloudFormation templates support the use of [Parameters][cfn-parameters] to +customize a template. They enable CloudFormation users to input custom values to +a template each time a stack is created or updated. While the CDK design +philosophy favors using build-time parameterization, users may need to use +CloudFormation in a number of cases (for example, when migrating an existing +stack to the AWS CDK). + +Template parameters can be added to a stack by using the `CfnParameter` class: + +```ts +new CfnParameter(this, 'MyParameter', { + type: 'Number', + default: 1337, + // See the API reference for more configuration props +}); +``` + +The value of parameters can then be obtained using one of the `value` methods. +As parameters are only resolved at deployment time, the values obtained are +placeholder tokens for the real value (`Token.isUnresolved()` would return `true` +for those): + +```ts +const param = new CfnParameter(this, 'ParameterName', { /* config */ }); + +// If the parameter is a String +param.valueAsString; + +// If the parameter is a Number +param.valueAsNumber; + +// If the parameter is a List +param.valueAsList; +``` + +[cfn-parameters]: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html + +### Pseudo Parameters + +CloudFormation supports a number of [pseudo parameters][cfn-pseudo-params], +which resolve to useful values at deployment time. CloudFormation pseudo +parameters can be obtained from static members of the `Aws` class. + +It is generally recommended to access pseudo parameters from the scope's `stack` +instead, which guarantees the values produced are qualifying the designated +stack, which is essential in cases where resources are shared cross-stack: + +```ts +// "this" is the current construct +const stack = Stack.of(this); + +stack.account; // Returns the AWS::AccountId for this stack (or the literal value if known) +stack.region; // Returns the AWS::Region for this stack (or the literal value if known) +stack.partition; +``` + +[cfn-pseudo-params]: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/pseudo-parameter-reference.html + +### Resource Options + +CloudFormation resources can also specify [resource +attributes][cfn-resource-attributes]. The `CfnResource` class allows +accessing those through the `cfnOptions` property: + +```ts +const rawBucket = new s3.CfnBucket(this, 'Bucket', { /* ... */ }); +// -or- +const rawBucketAlt = myBucket.node.defaultChild as s3.CfnBucket; + +// then +rawBucket.cfnOptions.condition = new CfnCondition(this, 'EnableBucket', { /* ... */ }); +rawBucket.cfnOptions.metadata = { + metadataKey: 'MetadataValue', +}; +``` + +Resource dependencies (the `DependsOn` attribute) is modified using the +`cfnResource.addDependsOn` method: + +```ts +const resourceA = new CfnResource(this, 'ResourceA', resourceProps); +const resourceB = new CfnResource(this, 'ResourceB', resourceProps); + +resourceB.addDependsOn(resourceA); +``` + +[cfn-resource-attributes]: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-product-attribute-reference.html + +### Intrinsic Functions and Condition Expressions + +CloudFormation supports [intrinsic functions][cfn-intrinsics]. These functions +can be accessed from the `Fn` class, which provides type-safe methods for each +intrinsic function as well as condition expressions: + +```ts +// To use Fn::Base64 +Fn.base64('SGVsbG8gQ0RLIQo='); + +// To compose condition expressions: +const environmentParameter = new CfnParameter(this, 'Environment'); +Fn.conditionAnd( + // The "Environment" CloudFormation template parameter evaluates to "Production" + Fn.conditionEquals('Production', environmentParameter), + // The AWS::Region pseudo-parameter value is NOT equal to "us-east-1" + Fn.conditionNot(Fn.conditionEquals('us-east-1', Aws.REGION)), +); +``` + +When working with deploy-time values (those for which `Token.isUnresolved` +returns `true`), idiomatic conditionals from the programming language cannot be +used (the value will not be known until deployment time). When conditional logic +needs to be expressed with un-resolved values, it is necessary to use +CloudFormation conditions by means of the `CfnCondition` class: + +```ts +const environmentParameter = new CfnParameter(this, 'Environment'); +const isProd = new CfnCondition(this, 'IsProduction', { + expression: Fn.conditionEquals('Production', environmentParameter), +}); + +// Configuration value that is a different string based on IsProduction +const stage = Fn.conditionIf(isProd.logicalId, 'Beta', 'Prod').toString(); + +// Make Bucket creation condition to IsProduction by accessing +// and overriding the CloudFormation resource +const bucket = new s3.Bucket(this, 'Bucket'); +const cfnBucket = myBucket.node.defaultChild as s3.CfnBucket; +cfnBucket.cfnOptions.condition = isProd; +``` + +[cfn-intrinsics]: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html + +### Mappings + +CloudFormation [mappings][cfn-mappings] are created and queried using the +`CfnMappings` class: + +```ts +const regionTable = new CfnMapping(this, 'RegionTable', { + mapping: { + regionName: { + 'us-east-1': 'US East (N. Virginia)', + 'us-east-2': 'US East (Ohio)', + // ... + }, + // ... + } +}); + +regionTable.findInMap('regionName', Aws.REGION); +``` + +This will yield the following template: + +```yaml +Mappings: + RegionTable: + regionName: + us-east-1: US East (N. Virginia) + us-east-2: US East (Ohio) +``` + +[cfn-mappings]: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/mappings-section-structure.html + +### Dynamic References + +CloudFormation supports [dynamically resolving][cfn-dynamic-references] values +for SSM parameters (including secure strings) and Secrets Manager. Encoding such +references is done using the `CfnDynamicReference` class: + +```ts +new CfnDynamicReference( + CfnDynamicReferenceService.SECRETS_MANAGER, + 'secret-id:secret-string:json-key:version-stage:version-id', +); +``` + +[cfn-dynamic-references]: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html + +### Template Options & Transform + +CloudFormation templates support a number of options, including which Macros or +[Transforms][cfn-transform] to use when deploying the stack. Those can be +configured using the `stack.templateOptions` property: + +```ts +const stack = new Stack(app, 'StackName'); + +stack.templateOptions.description = 'This will appear in the AWS console'; +stack.templateOptions.transforms = ['AWS::Serverless-2016-10-31']; +stack.templateOptions.metadata = { + metadataKey: 'MetadataValue', +}; +``` + +[cfn-transform]: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/transform-section-structure.html + +### Emitting Raw Resources + +The `CfnResource` class allows emitting arbitrary entries in the +[Resources][cfn-resources] section of the CloudFormation template. + +```ts +new CfnResource(this, 'ResourceId', { + type: 'AWS::S3::Bucket', + properties: { + BucketName: 'bucket-name' + }, +}); +``` + +As for any other resource, the logical ID in the CloudFormation template will be +generated by the AWS CDK, but the type and properties will be copied verbatim in +the synthesized template. + +[cfn-resources]: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html + +### Including raw CloudFormation template fragments + +When migrating a CloudFormation stack to the AWS CDK, it can be useful to +include fragments of an existing template verbatim in the synthesized template. +This can be achieved using the `CfnInclude` class. + +```ts +new CfnInclude(this, 'ID', { + template: { + Resources: { + Bucket: { + Type: 'AWS::S3::Bucket', + Properties: { + BucketName: 'my-shiny-bucket' + } + } + } + }, +}); +``` + +### Termination Protection + +You can prevent a stack from being accidentally deleted by enabling termination +protection on the stack. If a user attempts to delete a stack with termination +protection enabled, the deletion fails and the stack--including its status--remains +unchanged. Enabling or disabling termination protection on a stack sets it for any +nested stacks belonging to that stack as well. You can enable termination protection +on a stack by setting the `terminationProtection` prop to `true`. + +```ts +const stack = new Stack(app, 'StackName', { + terminationProtection: true, +}); +``` + +By default, termination protection is disabled. + +### CfnJson + +`CfnJson` allows you to postpone the resolution of a JSON blob from +deployment-time. This is useful in cases where the CloudFormation JSON template +cannot express a certain value. + +A common example is to use `CfnJson` in order to render a JSON map which needs +to use intrinsic functions in keys. Since JSON map keys must be strings, it is +impossible to use intrinsics in keys and `CfnJson` can help. + +The following example defines an IAM role which can only be assumed by +principals that are tagged with a specific tag. + +```ts +const tagParam = new CfnParameter(this, 'TagName'); + +const stringEquals = new CfnJson(this, 'ConditionJson', { + value: { + [`aws:PrincipalTag/${tagParam.valueAsString}`]: true, + }, +}); + +const principal = new iam.AccountRootPrincipal().withConditions({ + StringEquals: stringEquals, +}); + +new iam.Role(this, 'MyRole', { assumedBy: principal }); +``` + +**Explanation**: since in this example we pass the tag name through a parameter, it +can only be resolved during deployment. The resolved value can be represented in +the template through a `{ "Ref": "TagName" }`. However, since we want to use +this value inside a [`aws:PrincipalTag/TAG-NAME`](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html#condition-keys-principaltag) +IAM operator, we need it in the *key* of a `StringEquals` condition. JSON keys +*must be* strings, so to circumvent this limitation, we use `CfnJson` +to "delay" the rendition of this template section to deploy-time. This means +that the value of `StringEquals` in the template will be `{ "Fn::GetAtt": [ "ConditionJson", "Value" ] }`, and will only "expand" to the operator we synthesized during deployment. + +### Stack Resource Limit + +When deploying to AWS CloudFormation, it needs to keep in check the amount of resources being added inside a Stack. Currently it's possible to check the limits in the [AWS CloudFormation quotas](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cloudformation-limits.html) page. + +It's possible to synthesize the project with more Resources than the allowed (or even reduce the number of Resources). + +Set the context key `@aws-cdk/core:stackResourceLimit` with the proper value, being 0 for disable the limit of resources. + + \ No newline at end of file diff --git a/packages/aws-cdk-lib/package.json b/packages/aws-cdk-lib/package.json index 3f4b9857b9231..ecc5f73614f4b 100644 --- a/packages/aws-cdk-lib/package.json +++ b/packages/aws-cdk-lib/package.json @@ -33,7 +33,14 @@ "cdk-build": { "eslint": { "disable": true - } + }, + "stripDeprecated": true, + "post": [ + "node ./scripts/verify-readme-import-rewrites.js" + ] + }, + "cdk-package": { + "post": "node ./scripts/verify-stripped-exp.js" }, "pkglint": { "exclude": [ @@ -52,20 +59,22 @@ "dotnet": { "namespace": "Amazon.CDK", "packageId": "Amazon.CDK.Lib", - "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png", - "versionSuffix": "-devpreview" + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png" }, "java": { - "package": "software.amazon.awscdk.core", + "package": "software.amazon.awscdk", "maven": { "groupId": "software.amazon.awscdk", - "artifactId": "aws-cdk-lib", - "versionSuffix": ".DEVPREVIEW" + "artifactId": "aws-cdk-lib" } }, "python": { "distName": "aws-cdk-lib", "module": "aws_cdk" + }, + "go": { + "moduleName": "github.com/aws/aws-cdk-go", + "packageName": "awscdk" } }, "projectReferences": false @@ -95,7 +104,7 @@ "jsonschema": "^1.4.0", "minimatch": "^3.0.4", "punycode": "^2.1.1", - "semver": "^7.3.4", + "semver": "^7.3.5", "yaml": "1.10.2" }, "devDependencies": { @@ -112,6 +121,7 @@ "@aws-cdk/aws-apigatewayv2-integrations": "0.0.0", "@aws-cdk/aws-appconfig": "0.0.0", "@aws-cdk/aws-appflow": "0.0.0", + "@aws-cdk/aws-appintegrations": "0.0.0", "@aws-cdk/aws-applicationautoscaling": "0.0.0", "@aws-cdk/aws-applicationinsights": "0.0.0", "@aws-cdk/aws-appmesh": "0.0.0", @@ -150,6 +160,7 @@ "@aws-cdk/aws-codestarnotifications": "0.0.0", "@aws-cdk/aws-cognito": "0.0.0", "@aws-cdk/aws-config": "0.0.0", + "@aws-cdk/aws-customerprofiles": "0.0.0", "@aws-cdk/aws-databrew": "0.0.0", "@aws-cdk/aws-datapipeline": "0.0.0", "@aws-cdk/aws-datasync": "0.0.0", @@ -181,13 +192,16 @@ "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-events-targets": "0.0.0", "@aws-cdk/aws-eventschemas": "0.0.0", + "@aws-cdk/aws-fis": "0.0.0", "@aws-cdk/aws-fms": "0.0.0", "@aws-cdk/aws-fsx": "0.0.0", "@aws-cdk/aws-gamelift": "0.0.0", "@aws-cdk/aws-globalaccelerator": "0.0.0", + "@aws-cdk/aws-globalaccelerator-endpoints": "0.0.0", "@aws-cdk/aws-glue": "0.0.0", "@aws-cdk/aws-greengrass": "0.0.0", "@aws-cdk/aws-greengrassv2": "0.0.0", + "@aws-cdk/aws-groundstation": "0.0.0", "@aws-cdk/aws-guardduty": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-imagebuilder": "0.0.0", @@ -196,6 +210,7 @@ "@aws-cdk/aws-iot1click": "0.0.0", "@aws-cdk/aws-iotanalytics": "0.0.0", "@aws-cdk/aws-iotevents": "0.0.0", + "@aws-cdk/aws-iotfleethub": "0.0.0", "@aws-cdk/aws-iotsitewise": "0.0.0", "@aws-cdk/aws-iotthingsgraph": "0.0.0", "@aws-cdk/aws-iotwireless": "0.0.0", @@ -211,10 +226,12 @@ "@aws-cdk/aws-lambda-destinations": "0.0.0", "@aws-cdk/aws-lambda-event-sources": "0.0.0", "@aws-cdk/aws-lambda-nodejs": "0.0.0", + "@aws-cdk/aws-lambda-go": "0.0.0", "@aws-cdk/aws-lambda-python": "0.0.0", "@aws-cdk/aws-licensemanager": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-logs-destinations": "0.0.0", + "@aws-cdk/aws-lookoutmetrics": "0.0.0", "@aws-cdk/aws-lookoutvision": "0.0.0", "@aws-cdk/aws-macie": "0.0.0", "@aws-cdk/aws-managedblockchain": "0.0.0", @@ -228,6 +245,7 @@ "@aws-cdk/aws-neptune": "0.0.0", "@aws-cdk/aws-networkfirewall": "0.0.0", "@aws-cdk/aws-networkmanager": "0.0.0", + "@aws-cdk/aws-nimblestudio": "0.0.0", "@aws-cdk/aws-opsworks": "0.0.0", "@aws-cdk/aws-opsworkscm": "0.0.0", "@aws-cdk/aws-pinpoint": "0.0.0", @@ -247,6 +265,7 @@ "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/aws-s3-deployment": "0.0.0", "@aws-cdk/aws-s3-notifications": "0.0.0", + "@aws-cdk/aws-s3objectlambda": "0.0.0", "@aws-cdk/aws-s3outposts": "0.0.0", "@aws-cdk/aws-sagemaker": "0.0.0", "@aws-cdk/aws-sam": "0.0.0", @@ -282,11 +301,10 @@ "@aws-cdk/lambda-layer-kubectl": "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.55", + "@types/node": "^10.17.59", "cdk-build-tools": "0.0.0", - "constructs": "^3.2.0", + "constructs": "^3.3.69", "fs-extra": "^9.1.0", "pkglint": "0.0.0", "ts-node": "^9.1.1", @@ -294,7 +312,7 @@ "ubergen": "0.0.0" }, "peerDependencies": { - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "engines": { @@ -304,10 +322,12 @@ "aws", "cdk" ], + "nozem": false, "awscdkio": { "announce": false }, "ubergen": { - "exclude": true + "exclude": true, + "excludeExperimentalModules": true } } diff --git a/packages/aws-cdk-lib/scripts/verify-readme-import-rewrites.ts b/packages/aws-cdk-lib/scripts/verify-readme-import-rewrites.ts new file mode 100644 index 0000000000000..a31f721c05dfc --- /dev/null +++ b/packages/aws-cdk-lib/scripts/verify-readme-import-rewrites.ts @@ -0,0 +1,49 @@ +/** + * This script verifies the behavior of the `rewriteReadmeImports` method in `ubergen`, + * which rewrites '@aws-cdk/...' imports to 'aws-cdk-lib' imports in the package READMEs. + * Any verification based on expected state of the live READMEs is going to be somewhat fragile, + * but this is the most certain way to be notified if either the tool is broken or the READMEs + * have been explicitly changed to no longer reference their import statements. + * + * The script looks at a few modules with known different import formats and verifies that the + * expected rewritten import is present in the generated .jsii manifest. + */ + +import * as path from 'path'; +import * as fs from 'fs-extra'; + +const jsiiManifestPath = path.resolve(process.cwd(), '.jsii'); +if (!fs.existsSync(jsiiManifestPath)) { + throw new Error(`No .jsii manifest file found at: ${jsiiManifestPath}`); +} + +const jsiiManifest = JSON.parse(fs.readFileSync(jsiiManifestPath, { encoding: 'utf-8' })); + +// Expected import statements chosen from the individual module READMEs to have a breadth of styles and syntax. +// If this test fails because one of the below import statements is invalid, +// please update to have a new, comparable example. +// This is admittedly a bit fragile; if this test breaks a lot, we should reconsider validation methodology. +// Count of times this test has been broken by README updates so far (please increment as necessary! :D): 0 +const EXPECTED_SUBMODULE_IMPORTS = { + // import * as origins from '@aws-cdk/aws-cloudfront-origins'; + 'aws-cdk-lib.aws_cloudfront_origins': "import { aws_cloudfront_origins as origins } from 'aws-cdk-lib';", + // import * as cw from "@aws-cdk/aws-cloudwatch"; + 'aws-cdk-lib.aws_cloudwatch_actions': "import { aws_cloudwatch as cw } from 'aws-cdk-lib';", + // import { PhysicalName } from '@aws-cdk/core'; + 'aws-cdk-lib.aws_codepipeline_actions': "import { PhysicalName } from 'aws-cdk-lib';", + // import { Rule, Schedule } from '@aws-cdk/aws-events'; + 'aws-cdk-lib.aws_events': "import { Rule, Schedule } from 'aws-cdk-lib/aws-events';", + // import * as cdk from '@aws-cdk/core'; + 'aws-cdk-lib.aws_stepfunctions': "import * as cdk from 'aws-cdk-lib';", +}; + +Object.entries(EXPECTED_SUBMODULE_IMPORTS).forEach(([submodule, importStatement]) => { + const submoduleReadme = jsiiManifest.submodules[submodule]?.readme?.markdown; + if (!submoduleReadme) { + throw new Error(`jsii manifest for submodule ${submodule} not found`); + } else if (!submoduleReadme.includes(importStatement)) { + const errorMessage = `Expected to find import statement in ${submodule} README: ${importStatement}\n` + + 'This may mean the README has changed and this test needs to be updated, or the uberGen rewriteReadmeImports method is broken.'; + throw new Error(errorMessage); + } +}); diff --git a/packages/aws-cdk-lib/scripts/verify-stripped-exp.ts b/packages/aws-cdk-lib/scripts/verify-stripped-exp.ts new file mode 100644 index 0000000000000..10e3da07b7f4d --- /dev/null +++ b/packages/aws-cdk-lib/scripts/verify-stripped-exp.ts @@ -0,0 +1,158 @@ +// +------------------------------------------------------------------------------------------------ +// | this script is executed post packaging to verify that experimental modules in aws-cdk-lib includes **only** L1 autogenerated files. +// | The purpose is to avoid publishing L2 of experimental modules with aws-cdk-lib +// | +import { spawnSync } from 'child_process'; +import * as console from 'console'; +import * as os from 'os'; +import * as path from 'path'; +import * as fs from 'fs-extra'; + +async function main(tempDir: string) { + console.log('🧐 Verifying all experimental modules includes only L1s files...'); + const cwd = process.cwd(); + const awsCdkModulesRepoPath = path.join(findWorkspacePath(), 'packages', '@aws-cdk'); + // eslint-disable-next-line @typescript-eslint/no-require-imports + const version = require('./../package.json').version; + const tarFullPath = path.join(cwd, 'dist', 'js', `aws-cdk-lib@${version}.jsii.tgz`); + + const invalidCfnModules = new Map>(); + const invalidModules = new Array(); + + // install the tarball in a temp directory + console.log(`installing aws-cdk-lib from dist/js into ${tempDir}`); + exec('npm', ['install', '--prefix', tempDir, tarFullPath]); + const installedAwsCdkLibPath = path.join(tempDir, 'node_modules', 'aws-cdk-lib', 'lib'); + + for (const module of fs.readdirSync(awsCdkModulesRepoPath)) { + // eslint-disable-next-line @typescript-eslint/no-require-imports + const pkgJson = require(path.join(awsCdkModulesRepoPath, module, 'package.json')); + if (pkgJson.stability !== 'experimental') { + continue; + } + if (pkgJson['cdk-build'].cloudformation) { + // if a cfn module, verify only the allowed files exists + const files = await listAllFiles(path.join(installedAwsCdkLibPath, module)); + const invalidFiles = new Array(); + files.forEach(file => { + if (!isAllowedFile(file)) { + invalidFiles.push(file); + } + }); + if (invalidFiles.length > 0) { + invalidCfnModules.set(module, invalidFiles); + } + } else { + // not a cfn module, verify it was entirely removed + if (fs.existsSync(path.join(installedAwsCdkLibPath, module))) { + invalidModules.push(module); + } + } + } + + if (invalidCfnModules.size > 0 || invalidModules.length > 0) { + if (invalidCfnModules.size > 0 ) { + console.log('cfn module with invalid files:'); + for (let [module, files] of invalidCfnModules.entries()) { + console.log(`${module}:`); + files.forEach(file => console.log(`\t ${file}`)); + } + } + console.log('---------------------------------------------'); + if (invalidModules.length > 0) { + console.log('non-cfn experimental modules:'); + invalidModules.forEach(m => console.log(`\t ${m}`)); + } + throw new Error('Verification Error'); + } +} + +const tempDir = fs.mkdtempSync(os.tmpdir()); + +main(tempDir).then( + () => { + fs.removeSync(tempDir); + console.log('✅ All experimental modules includes only L1s files!'); + process.exit(0); + }, + (err) => { + process.stderr.write(`${err}\n`); + process.stderr.write(`❌ Verification failed, Some experimental modules includes non L1 files, see details above. Inspect working directory: '${tempDir}'`); + process.exit(1); + }, +); + + +/** + * Spawn sync with error handling + */ +function exec(cmd: string, args: string[]) { + const proc = spawnSync(cmd, args); + + if (proc.error) { + throw proc.error; + } + + if (proc.status !== 0) { + if (proc.stdout || proc.stderr) { + throw new Error(`${cmd} exited with status ${proc.status}; stdout: ${proc.stdout?.toString().trim()}\n\n\nstderr: ${proc.stderr?.toString().trim()}`); + } + throw new Error(`${cmd} exited with status ${proc.status}`); + } + + return proc; +} + +const GENERATED_SUFFIX_REGEX = new RegExp(/generated\.(js|d\.ts)$/); +const ALLOWED_FILES = ['.jsiirc.json', 'index.ts', 'index.js', 'index.d.ts']; + +/** + * Recursively collect all files in dir + */ +async function listAllFiles(dir: string) { + const ret = new Array(); + + async function recurse(part: string) { + const files = await fs.readdir(part); + for (const file of files) { + const fullPath = path.join(part, file); + if ((await fs.stat(fullPath)).isDirectory()) { + await recurse(fullPath); + } else { + ret.push(file); + } + } + } + await recurse(dir); + return ret; +} + +/** + * Find the workspace root path. Walk up the directory tree until you find lerna.json + */ +function findWorkspacePath() { + + return _findRootPath(process.cwd()); + + function _findRootPath(part: string): string { + if (part === path.resolve(part, '..')) { + throw new Error('couldn\'t find a \'lerna.json\' file when walking up the directory tree, are you in a aws-cdk project?'); + } + + if (fs.existsSync(path.resolve(part, 'lerna.json'))) { + return part; + } + return _findRootPath(path.resolve(part, '..')); + } +} + +/** + * @param file + * @returns true if the file allowed in an L1 only modules, otherwise false + */ +function isAllowedFile(file: string) { + if (GENERATED_SUFFIX_REGEX.test(file)) { + return true; + } + return ALLOWED_FILES.includes(file); +} \ No newline at end of file diff --git a/packages/aws-cdk-migration/.eslintrc.js b/packages/aws-cdk-migration/.eslintrc.js new file mode 100644 index 0000000000000..61dd8dd001f63 --- /dev/null +++ b/packages/aws-cdk-migration/.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-migration/.gitignore b/packages/aws-cdk-migration/.gitignore new file mode 100644 index 0000000000000..6b33b2cabe8ed --- /dev/null +++ b/packages/aws-cdk-migration/.gitignore @@ -0,0 +1,15 @@ +node_modules +*.js +*.d.ts + +dist +.LAST_PACKAGE +.LAST_BUILD +*.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-migration/.no-packagejson-validator b/packages/aws-cdk-migration/.no-packagejson-validator new file mode 100644 index 0000000000000..171d30544e368 --- /dev/null +++ b/packages/aws-cdk-migration/.no-packagejson-validator @@ -0,0 +1 @@ +disable pkglint diff --git a/packages/aws-cdk-migration/.npmignore b/packages/aws-cdk-migration/.npmignore new file mode 100644 index 0000000000000..4a2955c9ce9f9 --- /dev/null +++ b/packages/aws-cdk-migration/.npmignore @@ -0,0 +1,17 @@ + +dist +.LAST_PACKAGE +*.tsbuildinfo +tsconfig.json +.LAST_BUILD +*.snk + +*.ts +!*.d.ts +.eslintrc.js +jest.config.js + +# exclude cdk artifacts +**/cdk.out +junit.xml +test/ \ No newline at end of file diff --git a/packages/aws-cdk-migration/LICENSE b/packages/aws-cdk-migration/LICENSE new file mode 100644 index 0000000000000..28e4bdcec77ec --- /dev/null +++ b/packages/aws-cdk-migration/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-2021 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-migration/NOTICE b/packages/aws-cdk-migration/NOTICE new file mode 100644 index 0000000000000..5fc3826926b5b --- /dev/null +++ b/packages/aws-cdk-migration/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/aws-cdk-migration/README.md b/packages/aws-cdk-migration/README.md new file mode 100644 index 0000000000000..ba37d609c28db --- /dev/null +++ b/packages/aws-cdk-migration/README.md @@ -0,0 +1,11 @@ +# aws-cdk-migration + +Migrate TypeScript `import` statements from modular CDK (i.e. `@aws-cdk/aws-s3`) to aws-cdk-lib (i.e. `aws-cdk-lib`); + +Usage: + +```shell +$ npx -p aws-cdk-migration rewrite-imports-v2 lib/**/*.ts +``` + +NOTE: `node_modules` and `*.d.ts` files are ignored. diff --git a/packages/aws-cdk-migration/bin/rewrite-imports-v2 b/packages/aws-cdk-migration/bin/rewrite-imports-v2 new file mode 100755 index 0000000000000..59071f9ed501a --- /dev/null +++ b/packages/aws-cdk-migration/bin/rewrite-imports-v2 @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require('./rewrite-imports-v2.js'); diff --git a/packages/aws-cdk-migration/bin/rewrite-imports-v2.ts b/packages/aws-cdk-migration/bin/rewrite-imports-v2.ts new file mode 100644 index 0000000000000..42dd59f43ad43 --- /dev/null +++ b/packages/aws-cdk-migration/bin/rewrite-imports-v2.ts @@ -0,0 +1,37 @@ +/* eslint-disable no-console */ +import * as fs from 'fs'; +import { promisify } from 'util'; +import * as _glob from 'glob'; + +import { rewriteImports } from '../lib/rewrite'; + +const glob = promisify(_glob); + +async function main() { + if (!process.argv[2]) { + console.error('usage: rewrite-imports **/*.ts'); + return; + } + + const ignore = [ + '**/*.d.ts', + 'node_modules/**', + ]; + + const args = process.argv.slice(2); + for (const arg of args) { + const files = await glob(arg, { ignore, matchBase: true }); + for (const file of files) { + const input = await fs.promises.readFile(file, { encoding: 'utf8' }); + const output = rewriteImports(input, file); + if (output.trim() !== input.trim()) { + await fs.promises.writeFile(file, output); + } + } + } +} + +main().catch(e => { + console.error(e.stack); + process.exit(1); +}); diff --git a/packages/aws-cdk-migration/jest.config.js b/packages/aws-cdk-migration/jest.config.js new file mode 100644 index 0000000000000..ac8c47076506a --- /dev/null +++ b/packages/aws-cdk-migration/jest.config.js @@ -0,0 +1,10 @@ +const baseConfig = require('cdk-build-tools/config/jest.config'); +module.exports = { + ...baseConfig, + coverageThreshold: { + global: { + statements: 75, + branches: 65, + }, + }, +}; diff --git a/packages/aws-cdk-migration/lib/rewrite.ts b/packages/aws-cdk-migration/lib/rewrite.ts new file mode 100644 index 0000000000000..f25ae7b6735f2 --- /dev/null +++ b/packages/aws-cdk-migration/lib/rewrite.ts @@ -0,0 +1,114 @@ +import * as ts from 'typescript'; + +/** + * Re-writes "hyper-modular" CDK imports (most packages in `@aws-cdk/*`) to the + * relevant "mono" CDK import path. The re-writing will only modify the imported + * library path, presrving the existing quote style, etc... + * + * Syntax errors in the source file being processed may cause some import + * statements to not be re-written. + * + * Supported import statement forms are: + * - `import * as lib from '@aws-cdk/lib';` + * - `import { Type } from '@aws-cdk/lib';` + * - `import '@aws-cdk/lib';` + * - `import lib = require('@aws-cdk/lib');` + * - `import { Type } = require('@aws-cdk/lib'); + * - `require('@aws-cdk/lib'); + * + * @param sourceText the source code where imports should be re-written. + * @param fileName a customized file name to provide the TypeScript processor. + * + * @returns the updated source code. + */ +export function rewriteImports(sourceText: string, fileName: string = 'index.ts'): string { + const sourceFile = ts.createSourceFile(fileName, sourceText, ts.ScriptTarget.ES2018); + + const replacements = new Array<{ original: ts.Node, updatedLocation: string }>(); + + const visitor = (node: T): ts.VisitResult => { + const moduleSpecifier = getModuleSpecifier(node); + const newTarget = moduleSpecifier && updatedLocationOf(moduleSpecifier.text); + + if (moduleSpecifier != null && newTarget != null) { + replacements.push({ original: moduleSpecifier, updatedLocation: newTarget }); + } + + return node; + }; + + sourceFile.statements.forEach(node => ts.visitNode(node, visitor)); + + let updatedSourceText = sourceText; + // Applying replacements in reverse order, so node positions remain valid. + for (const replacement of replacements.sort(({ original: l }, { original: r }) => r.getStart(sourceFile) - l.getStart(sourceFile))) { + const prefix = updatedSourceText.substring(0, replacement.original.getStart(sourceFile) + 1); + const suffix = updatedSourceText.substring(replacement.original.getEnd() - 1); + + updatedSourceText = prefix + replacement.updatedLocation + suffix; + } + + return updatedSourceText; + + function getModuleSpecifier(node: ts.Node): ts.StringLiteral | undefined { + if (ts.isImportDeclaration(node)) { + // import style + const moduleSpecifier = node.moduleSpecifier; + if (ts.isStringLiteral(moduleSpecifier)) { + // import from 'location'; + // import * as name from 'location'; + return moduleSpecifier; + } else if (ts.isBinaryExpression(moduleSpecifier) && ts.isCallExpression(moduleSpecifier.right)) { + // import { Type } = require('location'); + return getModuleSpecifier(moduleSpecifier.right); + } + } else if ( + ts.isImportEqualsDeclaration(node) + && ts.isExternalModuleReference(node.moduleReference) + && ts.isStringLiteral(node.moduleReference.expression) + ) { + // import name = require('location'); + return node.moduleReference.expression; + } else if ( + (ts.isCallExpression(node)) + && ts.isIdentifier(node.expression) + && node.expression.escapedText === 'require' + && node.arguments.length === 1 + ) { + // require('location'); + const argument = node.arguments[0]; + if (ts.isStringLiteral(argument)) { + return argument; + } + } else if (ts.isExpressionStatement(node) && ts.isCallExpression(node.expression)) { + // require('location'); // This is an alternate AST version of it + return getModuleSpecifier(node.expression); + } + return undefined; + } +} + +const EXEMPTIONS = new Set([ + '@aws-cdk/cloudformation-diff', +]); + +function updatedLocationOf(modulePath: string): string | undefined { + if (!modulePath.startsWith('@aws-cdk/') || EXEMPTIONS.has(modulePath)) { + return undefined; + } + + if (modulePath === '@aws-cdk/core') { + return 'aws-cdk-lib'; + } + + // These 2 are unchanged + if (modulePath === '@aws-cdk/assert') { + return '@aws-cdk/assert'; + } + + if (modulePath === '@aws-cdk/assert/jest') { + return '@aws-cdk/assert/jest'; + } + + return `aws-cdk-lib/${modulePath.substring(9)}`; +} diff --git a/packages/aws-cdk-migration/package.json b/packages/aws-cdk-migration/package.json new file mode 100644 index 0000000000000..88869e06c699e --- /dev/null +++ b/packages/aws-cdk-migration/package.json @@ -0,0 +1,58 @@ +{ + "name": "aws-cdk-migration", + "version": "0.0.0", + "description": "Rewrites typescript 'import' statements from @aws-cdk/xxx to aws-cdk-lib", + "bin": { + "rewrite-imports-v2": "bin/rewrite-imports-v2" + }, + "main": "lib/rewrite.js", + "types": "lib/rewrite.d.ts", + "scripts": { + "build": "cdk-build", + "watch": "cdk-watch", + "test": "cdk-test", + "lint": "cdk-lint", + "pkglint": "pkglint -f", + "package": "cdk-package", + "build+test+package": "yarn build+test && yarn package", + "build+test": "yarn build && yarn test" + }, + "cdk-build": { + "jest": true + }, + "keywords": [ + "aws", + "cdk", + "awscdk" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "dependencies": { + "glob": "^7.1.6", + "typescript": "~3.9.9" + }, + "devDependencies": { + "@types/glob": "^7.1.3", + "@types/jest": "^26.0.23", + "@types/node": "^10.17.59", + "cdk-build-tools": "0.0.0", + "pkglint": "0.0.0" + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/aws-cdk-migration" + }, + "homepage": "https://github.com/aws/aws-cdk", + "stability": "experimental", + "engines": { + "node": ">= 10.13.0 <13 || >=13.7.0" + }, + "publishConfig": { + "tag": "latest" + } +} diff --git a/packages/aws-cdk-migration/test/rewrite.test.ts b/packages/aws-cdk-migration/test/rewrite.test.ts new file mode 100644 index 0000000000000..f9ff8b247d6ce --- /dev/null +++ b/packages/aws-cdk-migration/test/rewrite.test.ts @@ -0,0 +1,91 @@ +import { rewriteImports } from '../lib/rewrite'; + +describe(rewriteImports, () => { + test('correctly rewrites naked "import"', () => { + const output = rewriteImports(` + // something before + import '@aws-cdk/aws-s3/hello'; + // something after + + console.log('Look! I did something!');`, 'subhect.ts'); + + expect(output).toBe(` + // something before + import 'aws-cdk-lib/aws-s3/hello'; + // something after + + console.log('Look! I did something!');`); + }); + + test('correctly rewrites naked "require"', () => { + const output = rewriteImports(` + // something before + require('@aws-cdk/aws-s3/hello'); + // something after + + console.log('Look! I did something!');`, 'subhect.ts'); + + expect(output).toBe(` + // something before + require('aws-cdk-lib/aws-s3/hello'); + // something after + + console.log('Look! I did something!');`); + }); + + test('correctly rewrites "import from"', () => { + const output = rewriteImports(` + // something before + import * as s3 from '@aws-cdk/aws-s3'; + import * as cfndiff from '@aws-cdk/cloudformation-diff'; + import { Construct } from "@aws-cdk/core"; + // something after + + console.log('Look! I did something!');`, 'subject.ts'); + + expect(output).toBe(` + // something before + import * as s3 from 'aws-cdk-lib/aws-s3'; + import * as cfndiff from '@aws-cdk/cloudformation-diff'; + import { Construct } from "aws-cdk-lib"; + // something after + + console.log('Look! I did something!');`); + }); + + test('correctly rewrites "import = require"', () => { + const output = rewriteImports(` + // something before + import s3 = require('@aws-cdk/aws-s3'); + import cfndiff = require('@aws-cdk/cloudformation-diff'); + import { Construct } = require("@aws-cdk/core"); + // something after + + console.log('Look! I did something!');`, 'subject.ts'); + + expect(output).toBe(` + // something before + import s3 = require('aws-cdk-lib/aws-s3'); + import cfndiff = require('@aws-cdk/cloudformation-diff'); + import { Construct } = require("aws-cdk-lib"); + // something after + + console.log('Look! I did something!');`); + }); + + test('does not rewrite @aws-cdk/assert', () => { + const output = rewriteImports(` + // something before + import '@aws-cdk/assert/jest'; + // something after + + console.log('Look! I did something!');`, 'subhect.ts'); + + expect(output).toBe(` + // something before + import '@aws-cdk/assert/jest'; + // something after + + console.log('Look! I did something!');`); + }); +}); diff --git a/packages/aws-cdk-migration/tsconfig.json b/packages/aws-cdk-migration/tsconfig.json new file mode 100644 index 0000000000000..644a2975f7200 --- /dev/null +++ b/packages/aws-cdk-migration/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "ES2018", + "module": "commonjs", + "lib": ["es2018", "dom"], + "strict": true, + "alwaysStrict": true, + "declaration": true, + "inlineSourceMap": true, + "inlineSources": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "resolveJsonModule": true, + "composite": true, + "incremental": true + }, + "include": [ + "**/*.ts", + "**/*.d.ts" + ], + "exclude": [ + "node_modules" + ] +} + diff --git a/packages/aws-cdk/README.md b/packages/aws-cdk/README.md index 41dd4c75fbe2a..ece1ff5450081 100644 --- a/packages/aws-cdk/README.md +++ b/packages/aws-cdk/README.md @@ -158,9 +158,9 @@ and always deploy the stack. You can have multiple stacks in a cdk app. An example can be found in [how to create multiple stacks](https://docs.aws.amazon.com/cdk/latest/guide/stack_how_to_create_multiple_stacks.html). -In order to deploy them, you can list the stacks you want to deploy. +In order to deploy them, you can list the stacks you want to deploy. If your application contains pipeline stacks, the `cdk list` command will show stack names as paths, showing where they are in the pipeline hierarchy (e.g., `PipelineStack`, `PipelineStack/Prod`, `PipelineStack/Prod/MyService` etc). -If you want to deploy all of them, you can use the flag `--all` or the wildcard `*` to deploy all stacks in an app. +If you want to deploy all of them, you can use the flag `--all` or the wildcard `*` to deploy all stacks in an app. Please note that, if you have a hierarchy of stacks as described above, `--all` and `*` will only match the stacks on the top level. If you want to match all the stacks in the hierarchy, use `**`. You can also combine these patterns. For example, if you want to deploy all stacks in the `Prod` stage, you can use `cdk deploy PipelineStack/Prod/**`. #### Parameters diff --git a/packages/aws-cdk/bin/cdk.ts b/packages/aws-cdk/bin/cdk.ts index 9dc3a71799457..a9d5c8e0d9f0b 100644 --- a/packages/aws-cdk/bin/cdk.ts +++ b/packages/aws-cdk/bin/cdk.ts @@ -4,11 +4,12 @@ import * as cxapi from '@aws-cdk/cx-api'; import * as colors from 'colors/safe'; import * as yargs from 'yargs'; -import { ToolkitInfo, BootstrapSource, Bootstrapper } from '../lib'; import { SdkProvider } from '../lib/api/aws-auth'; +import { BootstrapSource, Bootstrapper } from '../lib/api/bootstrap'; import { CloudFormationDeployments } from '../lib/api/cloudformation-deployments'; import { CloudExecutable } from '../lib/api/cxapp/cloud-executable'; import { execProgram } from '../lib/api/cxapp/exec'; +import { ToolkitInfo } from '../lib/api/toolkit-info'; import { StackActivityProgress } from '../lib/api/util/cloudformation/stack-activity-monitor'; import { CdkToolkit } from '../lib/cdk-toolkit'; import { RequireApproval } from '../lib/diff'; @@ -256,24 +257,7 @@ async function initCommandLine() { }); case 'bootstrap': - // Use new bootstrapping if it's requested via environment variable, or if - // new style stack synthesis has been configured in `cdk.json`. - // - // In code it's optimistically called "default" bootstrapping but that is in - // anticipation of flipping the switch, in user messaging we still call it - // "new" bootstrapping. - let source: BootstrapSource = { source: 'legacy' }; - const newStyleStackSynthesis = isFeatureEnabled(configuration, cxapi.NEW_STYLE_STACK_SYNTHESIS_CONTEXT); - if (args.template) { - print(`Using bootstrapping template from ${args.template}`); - source = { source: 'custom', templateFile: args.template }; - } else if (process.env.CDK_NEW_BOOTSTRAP) { - print('CDK_NEW_BOOTSTRAP set, using new-style bootstrapping'); - source = { source: 'default' }; - } else if (newStyleStackSynthesis) { - print(`'${cxapi.NEW_STYLE_STACK_SYNTHESIS_CONTEXT}' context set, using new-style bootstrapping`); - source = { source: 'default' }; - } + const source: BootstrapSource = determineBootsrapVersion(args, configuration); const bootstrapper = new Bootstrapper(source); @@ -361,6 +345,48 @@ async function initCommandLine() { } } +/** + * Determine which version of bootstrapping + * (legacy, or "new") should be used. + */ +function determineBootsrapVersion(args: { template?: string }, configuration: Configuration): BootstrapSource { + const isV1 = version.DISPLAY_VERSION.startsWith('1.'); + return isV1 ? determineV1BootstrapSource(args, configuration) : determineV2BootstrapSource(args); +} + +function determineV1BootstrapSource(args: { template?: string }, configuration: Configuration): BootstrapSource { + let source: BootstrapSource; + if (args.template) { + print(`Using bootstrapping template from ${args.template}`); + source = { source: 'custom', templateFile: args.template }; + } else if (process.env.CDK_NEW_BOOTSTRAP) { + print('CDK_NEW_BOOTSTRAP set, using new-style bootstrapping'); + source = { source: 'default' }; + } else if (isFeatureEnabled(configuration, cxapi.NEW_STYLE_STACK_SYNTHESIS_CONTEXT)) { + print(`'${cxapi.NEW_STYLE_STACK_SYNTHESIS_CONTEXT}' context set, using new-style bootstrapping`); + source = { source: 'default' }; + } else { + // in V1, the "legacy" bootstrapping is the default + source = { source: 'legacy' }; + } + return source; +} + +function determineV2BootstrapSource(args: { template?: string }): BootstrapSource { + let source: BootstrapSource; + if (args.template) { + print(`Using bootstrapping template from ${args.template}`); + source = { source: 'custom', templateFile: args.template }; + } else if (process.env.CDK_LEGACY_BOOTSTRAP) { + print('CDK_LEGACY_BOOTSTRAP set, using legacy-style bootstrapping'); + source = { source: 'legacy' }; + } else { + // in V2, the "new" bootstrapping is the default + source = { source: 'default' }; + } + return source; +} + function isFeatureEnabled(configuration: Configuration, featureFlag: string) { return configuration.context.get(featureFlag) ?? cxapi.futureFlagDefault(featureFlag); } diff --git a/packages/aws-cdk/lib/api/aws-auth/credentials.ts b/packages/aws-cdk/lib/api/aws-auth/credentials.ts index 00f75ba57908c..8643f3d76eac3 100644 --- a/packages/aws-cdk/lib/api/aws-auth/credentials.ts +++ b/packages/aws-cdk/lib/api/aws-auth/credentials.ts @@ -6,7 +6,6 @@ export enum Mode { } /** - * @experimental */ export interface CredentialProviderSource { name: string; diff --git a/packages/aws-cdk/lib/api/aws-auth/sdk.ts b/packages/aws-cdk/lib/api/aws-auth/sdk.ts index 891ced65451b8..d5787a258275d 100644 --- a/packages/aws-cdk/lib/api/aws-auth/sdk.ts +++ b/packages/aws-cdk/lib/api/aws-auth/sdk.ts @@ -5,7 +5,6 @@ import { cached } from '../../util/functions'; import { AccountAccessKeyCache } from './account-cache'; import { Account } from './sdk-provider'; -/** @experimental */ export interface ISDK { /** * The region this SDK has been instantiated for diff --git a/packages/aws-cdk/lib/api/bootstrap/bootstrap-environment.ts b/packages/aws-cdk/lib/api/bootstrap/bootstrap-environment.ts index a5443517ad984..5350524b0dae3 100644 --- a/packages/aws-cdk/lib/api/bootstrap/bootstrap-environment.ts +++ b/packages/aws-cdk/lib/api/bootstrap/bootstrap-environment.ts @@ -40,7 +40,6 @@ export class Bootstrapper { /** * Deploy legacy bootstrap stack * - * @experimental */ private async legacyBootstrap(environment: cxapi.Environment, sdkProvider: SdkProvider, options: BootstrapEnvironmentOptions = {}): Promise { const params = options.parameters ?? {}; @@ -68,7 +67,6 @@ export class Bootstrapper { /** * Deploy CI/CD-ready bootstrap stack from template * - * @experimental */ private async modernBootstrap( environment: cxapi.Environment, diff --git a/packages/aws-cdk/lib/api/bootstrap/bootstrap-props.ts b/packages/aws-cdk/lib/api/bootstrap/bootstrap-props.ts index 010e5603f1400..dd36739d4381d 100644 --- a/packages/aws-cdk/lib/api/bootstrap/bootstrap-props.ts +++ b/packages/aws-cdk/lib/api/bootstrap/bootstrap-props.ts @@ -1,14 +1,9 @@ import { Tag } from '../../cdk-toolkit'; -/** @experimental */ export const BUCKET_NAME_OUTPUT = 'BucketName'; -/** @experimental */ export const REPOSITORY_NAME_OUTPUT = 'RepositoryName'; -/** @experimental */ export const BUCKET_DOMAIN_NAME_OUTPUT = 'BucketDomainName'; -/** @experimental */ export const BOOTSTRAP_VERSION_OUTPUT = 'BootstrapVersion'; -/** @experimental */ export const BOOTSTRAP_VERSION_RESOURCE = 'CdkBootstrapVersion'; /** diff --git a/packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts b/packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts index fb96c549f7fc7..59fa022ac145c 100644 --- a/packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts +++ b/packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts @@ -1,7 +1,9 @@ import * as cxapi from '@aws-cdk/cx-api'; import * as colors from 'colors/safe'; import * as minimatch from 'minimatch'; +import * as semver from 'semver'; import { error, print, warning } from '../../logging'; +import { versionNumber } from '../../version'; export enum DefaultSelection { /** @@ -16,7 +18,13 @@ export enum DefaultSelection { OnlySingle = 'single', /** - * If no selectors are provided, returns all stacks in the app. + * Returns all stacks in the main (top level) assembly only. + */ + MainAssembly = 'main', + + /** + * If no selectors are provided, returns all stacks in the app, + * including stacks inside nested assemblies. */ AllStacks = 'all', } @@ -71,20 +79,24 @@ export class CloudAssembly { selectors = selectors.filter(s => s != null); // filter null/undefined selectors = [...new Set(selectors)]; // make them unique - const stacks = this.assembly.stacks; + const asm = this.assembly; + const stacks = semver.major(asm.version) < 10 ? asm.stacks : asm.stacksRecursively; if (stacks.length === 0) { throw new Error('This app contains no stacks'); } if (selectors.length === 0) { + const topLevelStacks = this.assembly.stacks; switch (options.defaultBehavior) { + case DefaultSelection.MainAssembly: + return new StackCollection(this, topLevelStacks); case DefaultSelection.AllStacks: return new StackCollection(this, stacks); case DefaultSelection.None: return new StackCollection(this, []); case DefaultSelection.OnlySingle: - if (stacks.length === 1) { - return new StackCollection(this, stacks); + if (topLevelStacks.length === 1) { + return new StackCollection(this, topLevelStacks); } else { throw new Error('Since this app includes more than a single stack, specify which stacks to use (wildcards are supported) or specify `--all`\n' + `Stacks: ${stacks.map(x => x.id).join(' ')}`); @@ -96,7 +108,7 @@ export class CloudAssembly { const allStacks = new Map(); for (const stack of stacks) { - allStacks.set(stack.id, stack); + allStacks.set(stack.hierarchicalId, stack); } // For every selector argument, pick stacks from the list. @@ -105,8 +117,14 @@ export class CloudAssembly { let found = false; for (const stack of stacks) { - if (minimatch(stack.id, pattern) && !selectedStacks.has(stack.id)) { - selectedStacks.set(stack.id, stack); + const hierarchicalId = stack.hierarchicalId; + if (minimatch(hierarchicalId, pattern) && !selectedStacks.has(hierarchicalId)) { + selectedStacks.set(hierarchicalId, stack); + found = true; + } else if (minimatch(stack.id, pattern) && !selectedStacks.has(hierarchicalId) && semver.major(versionNumber()) < 2) { + warning('Selecting stack by identifier "%s". This identifier is deprecated and will be removed in v2. Please use "%s" instead.', colors.bold(stack.id), colors.bold(stack.hierarchicalId)); + warning('Run "cdk ls" to see a list of all stack identifiers'); + selectedStacks.set(hierarchicalId, stack); found = true; } } @@ -127,7 +145,7 @@ export class CloudAssembly { } // Filter original array because it is in the right order - const selectedList = stacks.filter(s => selectedStacks.has(s.id)); + const selectedList = stacks.filter(s => selectedStacks.has(s.hierarchicalId)); return new StackCollection(this, selectedList); } @@ -282,7 +300,7 @@ function includeUpstreamStacks( for (const stack of selectedStacks.values()) { // Select an additional stack if it's not selected yet and a dependency of a selected stack (and exists, obviously) - for (const dependencyId of stack.dependencies.map(x => x.id)) { + for (const dependencyId of stack.dependencies.map(x => x.manifest.displayName ?? x.id)) { if (!selectedStacks.has(dependencyId) && allStacks.has(dependencyId)) { added.push(dependencyId); selectedStacks.set(dependencyId, allStacks.get(dependencyId)!); diff --git a/packages/aws-cdk/lib/api/deploy-stack.ts b/packages/aws-cdk/lib/api/deploy-stack.ts index 177df82d4fcbf..df811e39587be 100644 --- a/packages/aws-cdk/lib/api/deploy-stack.ts +++ b/packages/aws-cdk/lib/api/deploy-stack.ts @@ -32,7 +32,6 @@ type TemplateBodyParameter = { TemplateURL?: string }; -/** @experimental */ export interface DeployStackResult { readonly noOp: boolean; readonly outputs: { [name: string]: string }; @@ -40,7 +39,6 @@ export interface DeployStackResult { readonly stackArtifact: cxapi.CloudFormationStackArtifact; } -/** @experimental */ export interface DeployStackOptions { /** * The stack to be deployed @@ -181,7 +179,6 @@ export interface DeployStackOptions { const LARGE_TEMPLATE_SIZE_KB = 50; -/** @experimental */ export async function deployStack(options: DeployStackOptions): Promise { const stackArtifact = options.stack; @@ -366,7 +363,6 @@ async function makeBodyParameter( return { TemplateURL: templateURL }; } -/** @experimental */ export interface DestroyStackOptions { /** * The stack to be destroyed @@ -379,7 +375,6 @@ export interface DestroyStackOptions { quiet?: boolean; } -/** @experimental */ export async function destroyStack(options: DestroyStackOptions) { const deployName = options.deployName || options.stack.stackName; const cfn = options.sdk.cloudFormation(); diff --git a/packages/aws-cdk/lib/api/toolkit-info.ts b/packages/aws-cdk/lib/api/toolkit-info.ts index 014a08c670619..5cd62fb402313 100644 --- a/packages/aws-cdk/lib/api/toolkit-info.ts +++ b/packages/aws-cdk/lib/api/toolkit-info.ts @@ -34,14 +34,12 @@ const BOOTSTRAP_TEMPLATE_VERSION_INTRODUCING_GETPARAMETER = 5; * * Called "ToolkitInfo" for historical reasons. * - * @experimental */ export abstract class ToolkitInfo { public static determineName(overrideName?: string) { return overrideName ?? DEFAULT_TOOLKIT_STACK_NAME; } - /** @experimental */ public static async lookup(environment: cxapi.Environment, sdk: ISDK, stackName: string | undefined): Promise { const cfn = sdk.cloudFormation(); const stack = await stabilizeStack(cfn, stackName ?? DEFAULT_TOOLKIT_STACK_NAME); @@ -185,7 +183,6 @@ class ExistingToolkitInfo extends ToolkitInfo { /** * Prepare an ECR repository for uploading to using Docker * - * @experimental */ public async prepareEcrRepository(repositoryName: string): Promise { if (!this.sdk) { @@ -292,12 +289,10 @@ class BootstrapStackNotFoundInfo extends ToolkitInfo { } } -/** @experimental */ export interface EcrRepositoryInfo { repositoryUri: string; } -/** @experimental */ export interface EcrCredentials { username: string; password: string; diff --git a/packages/aws-cdk/lib/cdk-toolkit.ts b/packages/aws-cdk/lib/cdk-toolkit.ts index 5491a3d221e24..d7011d743ffaf 100644 --- a/packages/aws-cdk/lib/cdk-toolkit.ts +++ b/packages/aws-cdk/lib/cdk-toolkit.ts @@ -240,7 +240,7 @@ export class CdkToolkit { if (!options.force) { // eslint-disable-next-line max-len - const confirmed = await promptly.confirm(`Are you sure you want to delete: ${colors.blue(stacks.stackArtifacts.map(s => s.id).join(', '))} (y/n)?`); + const confirmed = await promptly.confirm(`Are you sure you want to delete: ${colors.blue(stacks.stackArtifacts.map(s => s.hierarchicalId).join(', '))} (y/n)?`); if (!confirmed) { return; } @@ -281,7 +281,7 @@ export class CdkToolkit { // just print stack IDs for (const stack of stacks.stackArtifacts) { - data(stack.id); + data(stack.hierarchicalId); } return 0; // exit-code @@ -394,14 +394,15 @@ export class CdkToolkit { private async selectStacksForDiff(stackNames: string[], exclusively?: boolean) { const assembly = await this.assembly(); - const stacks = await assembly.selectStacks(stackNames, { - extend: exclusively ? ExtendedStackSelection.None : ExtendedStackSelection.Upstream, - defaultBehavior: DefaultSelection.AllStacks, - }); - await this.validateStacks(stacks); + const idsToValidate = process.env.STACKS_TO_VALIDATE ? process.env.STACKS_TO_VALIDATE.split(';') : stackNames; + const stacksToValidate = await this.selectStacksForList(idsToValidate); + await this.validateStacks(stacksToValidate); - return stacks; + return assembly.selectStacks(stackNames, { + extend: exclusively ? ExtendedStackSelection.None : ExtendedStackSelection.Upstream, + defaultBehavior: DefaultSelection.MainAssembly, + }); } private async selectStacksForDestroy(stackNames: string[], exclusively?: boolean) { diff --git a/packages/aws-cdk/lib/init-templates/LICENSE b/packages/aws-cdk/lib/init-templates/LICENSE new file mode 100644 index 0000000000000..a2f04c7c3bdc9 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/LICENSE @@ -0,0 +1,16 @@ +MIT No Attribution + +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this +software and associated documentation files (the "Software"), to deal in the Software +without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/aws-cdk/lib/init-templates/v1/app/csharp/src/%name.PascalCased%/Program.template.cs b/packages/aws-cdk/lib/init-templates/v1/app/csharp/src/%name.PascalCased%/Program.template.cs index a2ce1b67fdd53..ec6a50b8bdc00 100644 --- a/packages/aws-cdk/lib/init-templates/v1/app/csharp/src/%name.PascalCased%/Program.template.cs +++ b/packages/aws-cdk/lib/init-templates/v1/app/csharp/src/%name.PascalCased%/Program.template.cs @@ -10,7 +10,35 @@ sealed class Program public static void Main(string[] args) { var app = new App(); - new %name.PascalCased%Stack(app, "%name.PascalCased%Stack"); + new %name.PascalCased%Stack(app, "%name.PascalCased%Stack", new StackProps + { + // If you don't specify 'env', this stack will be environment-agnostic. + // Account/Region-dependent features and context lookups will not work, + // but a single synthesized template can be deployed anywhere. + + // Uncomment the next block to specialize this stack for the AWS Account + // and Region that are implied by the current CLI configuration. + /* + Env = new Amazon.CDK.Environment + { + Account = System.Environment.GetEnvironmentVariable("CDK_DEFAULT_ACCOUNT"), + Region = System.Environment.GetEnvironmentVariable("CDK_DEFAULT_REGION"), + } + */ + + // Uncomment the next block if you know exactly what Account and Region you + // want to deploy the stack to. + /* + Env = new Amazon.CDK.Environment + { + Account = "123456789012", + Region = "us-east-1", + } + */ + + // For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html + }); + app.Synth(); } } diff --git a/packages/aws-cdk/lib/init-templates/v1/app/go/%name%.template.go b/packages/aws-cdk/lib/init-templates/v1/app/go/%name%.template.go new file mode 100644 index 0000000000000..24a2b0e90b616 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v1/app/go/%name%.template.go @@ -0,0 +1,68 @@ +package main + +import ( + "github.com/aws/aws-cdk-go/awscdk" + "github.com/aws/aws-cdk-go/awscdk/awssns" + "github.com/aws/constructs-go/constructs/v3" + "github.com/aws/jsii-runtime-go" +) + +type %name.PascalCased%StackProps struct { + awscdk.StackProps +} + +func New%name.PascalCased%Stack(scope constructs.Construct, id string, props *%name.PascalCased%StackProps) awscdk.Stack { + var sprops awscdk.StackProps + if props != nil { + sprops = props.StackProps + } + stack := awscdk.NewStack(scope, &id, &sprops) + + // The code that defines your stack goes here + + // as an example, here's how you would define an AWS SNS topic: + awssns.NewTopic(stack, jsii.String("MyTopic"), &awssns.TopicProps{ + DisplayName: jsii.String("MyCoolTopic"), + }) + + return stack +} + +func main() { + app := awscdk.NewApp(nil) + + New%name.PascalCased%Stack(app, "%name.PascalCased%Stack", &%name.PascalCased%StackProps{ + awscdk.StackProps{ + Env: env(), + }, + }) + + app.Synth(nil) +} + +// env determines the AWS environment (account+region) in which our stack is to +// be deployed. For more information see: https://docs.aws.amazon.com/cdk/latest/guide/environments.html +func env() *awscdk.Environment { + // If unspecified, this stack will be "environment-agnostic". + // Account/Region-dependent features and context lookups will not work, but a + // single synthesized template can be deployed anywhere. + //--------------------------------------------------------------------------- + return nil + + // Uncomment if you know exactly what account and region you want to deploy + // the stack to. This is the recommendation for production stacks. + //--------------------------------------------------------------------------- + // return &awscdk.Environment{ + // Account: jsii.String("123456789012"), + // Region: jsii.String("us-east-1"), + // } + + // Uncomment to specialize this stack for the AWS Account and Region that are + // implied by the current CLI configuration. This is recommended for dev + // stacks. + //--------------------------------------------------------------------------- + // return &awscdk.Environment{ + // Account: jsii.String(os.Getenv("CDK_DEFAULT_ACCOUNT")), + // Region: jsii.String(os.Getenv("CDK_DEFAULT_REGION")), + // } +} diff --git a/packages/aws-cdk/lib/init-templates/v1/app/go/%name%_test.template.go b/packages/aws-cdk/lib/init-templates/v1/app/go/%name%_test.template.go new file mode 100644 index 0000000000000..c0534249b6282 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v1/app/go/%name%_test.template.go @@ -0,0 +1,28 @@ +package main + +import ( + "encoding/json" + "testing" + + "github.com/aws/aws-cdk-go/awscdk" + "github.com/stretchr/testify/assert" + "github.com/tidwall/gjson" +) + +func Test%name.PascalCased%Stack(t *testing.T) { + // GIVEN + app := awscdk.NewApp(nil) + + // WHEN + stack := New%name.PascalCased%Stack(app, "MyStack", nil) + + // THEN + bytes, err := json.Marshal(app.Synth(nil).GetStackArtifact(stack.ArtifactId()).Template()) + if err != nil { + t.Error(err) + } + + template := gjson.ParseBytes(bytes) + displayName := template.Get("Resources.MyTopic86869434.Properties.DisplayName").String() + assert.Equal(t, "MyCoolTopic", displayName) +} diff --git a/packages/aws-cdk/lib/init-templates/v1/app/go/.template.gitignore b/packages/aws-cdk/lib/init-templates/v1/app/go/.template.gitignore new file mode 100644 index 0000000000000..92fe1ec34b4b6 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v1/app/go/.template.gitignore @@ -0,0 +1,19 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# go.sum should be committed +!go.sum + +# CDK asset staging directory +.cdk.staging +cdk.out diff --git a/packages/aws-cdk/lib/init-templates/v1/app/go/README.md b/packages/aws-cdk/lib/init-templates/v1/app/go/README.md new file mode 100644 index 0000000000000..9b8d4b29f26e3 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v1/app/go/README.md @@ -0,0 +1,14 @@ +# Welcome to your CDK Go project! + +This is a blank project for Go development with CDK. + +**NOTICE**: Go support is still in Developer Preview. This implies that APIs may +change while we address early feedback from the community. We would love to hear +about your experience through GitHub issues. + +## Useful commands + + * `cdk deploy` deploy this stack to your default AWS account/region + * `cdk diff` compare deployed stack with current state + * `cdk synth` emits the synthesized CloudFormation template + * `go test` run unit tests diff --git a/packages/aws-cdk/lib/init-templates/v1/app/go/cdk.template.json b/packages/aws-cdk/lib/init-templates/v1/app/go/cdk.template.json new file mode 100644 index 0000000000000..ad88cd7ef75f3 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v1/app/go/cdk.template.json @@ -0,0 +1,3 @@ +{ + "app": "go mod download && go run %name%.go" +} \ No newline at end of file diff --git a/packages/aws-cdk/lib/init-templates/v1/app/go/go.template.mod b/packages/aws-cdk/lib/init-templates/v1/app/go/go.template.mod new file mode 100644 index 0000000000000..a1dcb391c1614 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v1/app/go/go.template.mod @@ -0,0 +1,13 @@ +module %name% + +go 1.16 + +require ( + github.com/aws/aws-cdk-go/awscdk v%cdk-version%-devpreview + github.com/aws/constructs-go/constructs/v3 v3.3.71 + github.com/aws/jsii-runtime-go v1.26.0 + + // for testing + github.com/tidwall/gjson v1.7.4 + github.com/stretchr/testify v1.7.0 +) diff --git a/packages/aws-cdk/lib/init-templates/v1/app/java/src/main/java/com/myorg/%name.PascalCased%App.template.java b/packages/aws-cdk/lib/init-templates/v1/app/java/src/main/java/com/myorg/%name.PascalCased%App.template.java index 93b1690e7cfe3..f3eb72f9dfe0c 100644 --- a/packages/aws-cdk/lib/init-templates/v1/app/java/src/main/java/com/myorg/%name.PascalCased%App.template.java +++ b/packages/aws-cdk/lib/init-templates/v1/app/java/src/main/java/com/myorg/%name.PascalCased%App.template.java @@ -1,6 +1,8 @@ package com.myorg; import software.amazon.awscdk.core.App; +import software.amazon.awscdk.core.Environment; +import software.amazon.awscdk.core.StackProps; import java.util.Arrays; @@ -8,7 +10,31 @@ public class %name.PascalCased%App { public static void main(final String[] args) { App app = new App(); - new %name.PascalCased%Stack(app, "%name.PascalCased%Stack"); + new %name.PascalCased%Stack(app, "%name.PascalCased%Stack", StackProps.builder() + // If you don't specify 'env', this stack will be environment-agnostic. + // Account/Region-dependent features and context lookups will not work, + // but a single synthesized template can be deployed anywhere. + + // Uncomment the next block to specialize this stack for the AWS Account + // and Region that are implied by the current CLI configuration. + /* + .env(Environment.builder() + .account(System.getenv("CDK_DEFAULT_ACCOUNT")) + .region(System.getenv("CDK_DEFAULT_REGION")) + .build()) + */ + + // Uncomment the next block if you know exactly what Account and Region you + // want to deploy the stack to. + /* + .env(Environment.builder() + .account("123456789012") + .region("us-east-1") + .build()) + */ + + // For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html + .build()); app.synth(); } diff --git a/packages/aws-cdk/lib/init-templates/v1/app/java/src/test/java/com/myorg/%name.PascalCased%Test.template.java b/packages/aws-cdk/lib/init-templates/v1/app/java/src/test/java/com/myorg/%name.PascalCased%Test.template.java index 85fe60307e7c3..9494caf63d628 100644 --- a/packages/aws-cdk/lib/init-templates/v1/app/java/src/test/java/com/myorg/%name.PascalCased%Test.template.java +++ b/packages/aws-cdk/lib/init-templates/v1/app/java/src/test/java/com/myorg/%name.PascalCased%Test.template.java @@ -19,10 +19,10 @@ public void testStack() throws IOException { App app = new App(); %name.PascalCased%Stack stack = new %name.PascalCased%Stack(app, "test"); - // synthesize the stack to a CloudFormation template and compare against - // a checked-in JSON file. + // synthesize the stack to a CloudFormation template JsonNode actual = JSON.valueToTree(app.synth().getStackArtifact(stack.getArtifactId()).getTemplate()); - assertThat(new ObjectMapper().createObjectNode()).isEqualTo(actual); + // Update once resources have been added to the stack + assertThat(actual.get("Resources")).isNull(); } } diff --git a/packages/aws-cdk/lib/init-templates/v1/app/javascript/bin/%name%.template.js b/packages/aws-cdk/lib/init-templates/v1/app/javascript/bin/%name%.template.js index 7ef6ca7df55c0..1a99b7e2c55ec 100644 --- a/packages/aws-cdk/lib/init-templates/v1/app/javascript/bin/%name%.template.js +++ b/packages/aws-cdk/lib/init-templates/v1/app/javascript/bin/%name%.template.js @@ -4,4 +4,18 @@ const cdk = require('@aws-cdk/core'); const { %name.PascalCased%Stack } = require('../lib/%name%-stack'); const app = new cdk.App(); -new %name.PascalCased%Stack(app, '%name.PascalCased%Stack'); +new %name.PascalCased%Stack(app, '%name.PascalCased%Stack', { + /* If you don't specify 'env', this stack will be environment-agnostic. + * Account/Region-dependent features and context lookups will not work, + * but a single synthesized template can be deployed anywhere. */ + + /* Uncomment the next line to specialize this stack for the AWS Account + * and Region that are implied by the current CLI configuration. */ + // env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION }, + + /* Uncomment the next line if you know exactly what Account and Region you + * want to deploy the stack to. */ + // env: { account: '123456789012', region: 'us-east-1' }, + + /* For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html */ +}); \ No newline at end of file diff --git a/packages/aws-cdk/lib/init-templates/v1/app/python/app.template.py b/packages/aws-cdk/lib/init-templates/v1/app/python/app.template.py index bf6da5f40868f..a63ab8ac2e62e 100644 --- a/packages/aws-cdk/lib/init-templates/v1/app/python/app.template.py +++ b/packages/aws-cdk/lib/init-templates/v1/app/python/app.template.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +import os from aws_cdk import core as cdk @@ -12,6 +13,22 @@ app = core.App() -%name.PascalCased%Stack(app, "%name.PascalCased%Stack") +%name.PascalCased%Stack(app, "%name.PascalCased%Stack", + # If you don't specify 'env', this stack will be environment-agnostic. + # Account/Region-dependent features and context lookups will not work, + # but a single synthesized template can be deployed anywhere. + + # Uncomment the next line to specialize this stack for the AWS Account + # and Region that are implied by the current CLI configuration. + + #env=core.Environment(account=os.getenv('CDK_DEFAULT_ACCOUNT'), region=os.getenv('CDK_DEFAULT_REGION')), + + # Uncomment the next line if you know exactly what Account and Region you + # want to deploy the stack to. */ + + #env=core.Environment(account='123456789012', region='us-east-1'), + + # For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html + ) app.synth() diff --git a/packages/aws-cdk/lib/init-templates/v1/app/python/setup.template.py b/packages/aws-cdk/lib/init-templates/v1/app/python/setup.template.py index 3303427f63d0e..113bf29e54755 100644 --- a/packages/aws-cdk/lib/init-templates/v1/app/python/setup.template.py +++ b/packages/aws-cdk/lib/init-templates/v1/app/python/setup.template.py @@ -29,8 +29,6 @@ "Intended Audience :: Developers", - "License :: OSI Approved :: Apache Software License", - "Programming Language :: JavaScript", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.6", diff --git a/packages/aws-cdk/lib/init-templates/v1/app/typescript/bin/%name%.template.ts b/packages/aws-cdk/lib/init-templates/v1/app/typescript/bin/%name%.template.ts index 57c0a9a41db06..9479fc651f175 100644 --- a/packages/aws-cdk/lib/init-templates/v1/app/typescript/bin/%name%.template.ts +++ b/packages/aws-cdk/lib/init-templates/v1/app/typescript/bin/%name%.template.ts @@ -4,4 +4,18 @@ import * as cdk from '@aws-cdk/core'; import { %name.PascalCased%Stack } from '../lib/%name%-stack'; const app = new cdk.App(); -new %name.PascalCased%Stack(app, '%name.PascalCased%Stack'); +new %name.PascalCased%Stack(app, '%name.PascalCased%Stack', { + /* If you don't specify 'env', this stack will be environment-agnostic. + * Account/Region-dependent features and context lookups will not work, + * but a single synthesized template can be deployed anywhere. */ + + /* Uncomment the next line to specialize this stack for the AWS Account + * and Region that are implied by the current CLI configuration. */ + // env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION }, + + /* Uncomment the next line if you know exactly what Account and Region you + * want to deploy the stack to. */ + // env: { account: '123456789012', region: 'us-east-1' }, + + /* For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html */ +}); diff --git a/packages/aws-cdk/lib/init-templates/v1/lib/typescript/test/%name%.test.template.ts b/packages/aws-cdk/lib/init-templates/v1/lib/typescript/test/%name%.test.template.ts index 7dbd310b088f7..0b49cb3cc99d1 100644 --- a/packages/aws-cdk/lib/init-templates/v1/lib/typescript/test/%name%.test.template.ts +++ b/packages/aws-cdk/lib/init-templates/v1/lib/typescript/test/%name%.test.template.ts @@ -3,7 +3,7 @@ import * as cdk from '@aws-cdk/core'; import * as %name.PascalCased% from '../lib/index'; /* - * Example test + * Example test */ test('SNS Topic Created', () => { const app = new cdk.App(); diff --git a/packages/aws-cdk/lib/init-templates/v1/sample-app/python/setup.template.py b/packages/aws-cdk/lib/init-templates/v1/sample-app/python/setup.template.py index 9e9b137c1014c..d79611021c860 100644 --- a/packages/aws-cdk/lib/init-templates/v1/sample-app/python/setup.template.py +++ b/packages/aws-cdk/lib/init-templates/v1/sample-app/python/setup.template.py @@ -34,8 +34,6 @@ "Intended Audience :: Developers", - "License :: OSI Approved :: Apache Software License", - "Programming Language :: JavaScript", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.6", diff --git a/packages/aws-cdk/lib/init-templates/v2/app/csharp/src/%name.PascalCased%/%name.PascalCased%Stack.template.cs b/packages/aws-cdk/lib/init-templates/v2/app/csharp/src/%name.PascalCased%/%name.PascalCased%Stack.template.cs index 998db3c5335cd..2e8c5e654324a 100644 --- a/packages/aws-cdk/lib/init-templates/v2/app/csharp/src/%name.PascalCased%/%name.PascalCased%Stack.template.cs +++ b/packages/aws-cdk/lib/init-templates/v2/app/csharp/src/%name.PascalCased%/%name.PascalCased%Stack.template.cs @@ -1,4 +1,5 @@ -using Amazon.CDK.Lib; +using Amazon.CDK; +using Constructs; namespace %name.PascalCased% { diff --git a/packages/aws-cdk/lib/init-templates/v2/app/csharp/src/%name.PascalCased%/Program.template.cs b/packages/aws-cdk/lib/init-templates/v2/app/csharp/src/%name.PascalCased%/Program.template.cs index 93f1e27a57523..0a35f06be9217 100644 --- a/packages/aws-cdk/lib/init-templates/v2/app/csharp/src/%name.PascalCased%/Program.template.cs +++ b/packages/aws-cdk/lib/init-templates/v2/app/csharp/src/%name.PascalCased%/Program.template.cs @@ -1,4 +1,4 @@ -using Amazon.CDK.Lib; +using Amazon.CDK; using System; using System.Collections.Generic; using System.Linq; @@ -10,7 +10,34 @@ sealed class Program public static void Main(string[] args) { var app = new App(); - new %name.PascalCased%Stack(app, "%name.PascalCased%Stack"); + new %name.PascalCased%Stack(app, "%name.PascalCased%Stack", new StackProps + { + // If you don't specify 'env', this stack will be environment-agnostic. + // Account/Region-dependent features and context lookups will not work, + // but a single synthesized template can be deployed anywhere. + + // Uncomment the next block to specialize this stack for the AWS Account + // and Region that are implied by the current CLI configuration. + /* + Env = new Amazon.CDK.Environment + { + Account = System.Environment.GetEnvironmentVariable("CDK_DEFAULT_ACCOUNT"), + Region = System.Environment.GetEnvironmentVariable("CDK_DEFAULT_REGION"), + } + */ + + // Uncomment the next block if you know exactly what Account and Region you + // want to deploy the stack to. + /* + Env = new Amazon.CDK.Environment + { + Account = "123456789012", + Region = "us-east-1", + } + */ + + // For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html + }); app.Synth(); } } diff --git a/packages/aws-cdk/lib/init-templates/v2/app/fsharp/src/%name.PascalCased%/%name.PascalCased%Stack.template.fs b/packages/aws-cdk/lib/init-templates/v2/app/fsharp/src/%name.PascalCased%/%name.PascalCased%Stack.template.fs index 40f90dc43d77e..5e4d9ef94e748 100644 --- a/packages/aws-cdk/lib/init-templates/v2/app/fsharp/src/%name.PascalCased%/%name.PascalCased%Stack.template.fs +++ b/packages/aws-cdk/lib/init-templates/v2/app/fsharp/src/%name.PascalCased%/%name.PascalCased%Stack.template.fs @@ -1,6 +1,6 @@ namespace %name.PascalCased% -open Amazon.CDK.Lib +open Amazon.CDK type %name.PascalCased%Stack(scope, id, props) as this = inherit Stack(scope, id, props) diff --git a/packages/aws-cdk/lib/init-templates/v2/app/fsharp/src/%name.PascalCased%/Program.template.fs b/packages/aws-cdk/lib/init-templates/v2/app/fsharp/src/%name.PascalCased%/Program.template.fs index 4b28d1e03ba9a..dc618af3fbbf1 100644 --- a/packages/aws-cdk/lib/init-templates/v2/app/fsharp/src/%name.PascalCased%/Program.template.fs +++ b/packages/aws-cdk/lib/init-templates/v2/app/fsharp/src/%name.PascalCased%/Program.template.fs @@ -1,4 +1,4 @@ -open Amazon.CDK.Lib +open Amazon.CDK open %name.PascalCased% [] diff --git a/packages/aws-cdk/lib/init-templates/v2/app/java/pom.template.xml b/packages/aws-cdk/lib/init-templates/v2/app/java/pom.template.xml index 5defab0b3a0b6..922c04ccb0943 100644 --- a/packages/aws-cdk/lib/init-templates/v2/app/java/pom.template.xml +++ b/packages/aws-cdk/lib/init-templates/v2/app/java/pom.template.xml @@ -40,7 +40,7 @@ software.amazon.awscdk - lib + aws-cdk-lib ${cdk.version} diff --git a/packages/aws-cdk/lib/init-templates/v2/app/java/src/main/java/com/myorg/%name.PascalCased%App.template.java b/packages/aws-cdk/lib/init-templates/v2/app/java/src/main/java/com/myorg/%name.PascalCased%App.template.java index 2574c970d3992..6499cbc9d2870 100644 --- a/packages/aws-cdk/lib/init-templates/v2/app/java/src/main/java/com/myorg/%name.PascalCased%App.template.java +++ b/packages/aws-cdk/lib/init-templates/v2/app/java/src/main/java/com/myorg/%name.PascalCased%App.template.java @@ -1,6 +1,8 @@ package com.myorg; -import software.amazon.awscdk.lib.App; +import software.amazon.awscdk.App; +import software.amazon.awscdk.Environment; +import software.amazon.awscdk.StackProps; import java.util.Arrays; @@ -8,8 +10,33 @@ public class %name.PascalCased%App { public static void main(final String[] args) { App app = new App(); - new %name.PascalCased%Stack(app, "%name.PascalCased%Stack"); + new %name.PascalCased%Stack(app, "%name.PascalCased%Stack", StackProps.builder() + // If you don't specify 'env', this stack will be environment-agnostic. + // Account/Region-dependent features and context lookups will not work, + // but a single synthesized template can be deployed anywhere. + + // Uncomment the next block to specialize this stack for the AWS Account + // and Region that are implied by the current CLI configuration. + /* + .env(Environment.builder() + .account(System.getenv("CDK_DEFAULT_ACCOUNT")) + .region(System.getenv("CDK_DEFAULT_REGION")) + .build()) + */ + + // Uncomment the next block if you know exactly what Account and Region you + // want to deploy the stack to. + /* + .env(Environment.builder() + .account("123456789012") + .region("us-east-1") + .build()) + */ + + // For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html + .build()); app.synth(); } } + diff --git a/packages/aws-cdk/lib/init-templates/v2/app/javascript/bin/%name%.template.js b/packages/aws-cdk/lib/init-templates/v2/app/javascript/bin/%name%.template.js index 637cb35435106..46f0d3cbcc860 100644 --- a/packages/aws-cdk/lib/init-templates/v2/app/javascript/bin/%name%.template.js +++ b/packages/aws-cdk/lib/init-templates/v2/app/javascript/bin/%name%.template.js @@ -4,4 +4,18 @@ const cdk = require('aws-cdk-lib'); const { %name.PascalCased%Stack } = require('../lib/%name%-stack'); const app = new cdk.App(); -new %name.PascalCased%Stack(app, '%name.PascalCased%Stack'); +new %name.PascalCased%Stack(app, '%name.PascalCased%Stack', { + /* If you don't specify 'env', this stack will be environment-agnostic. + * Account/Region-dependent features and context lookups will not work, + * but a single synthesized template can be deployed anywhere. */ + + /* Uncomment the next line to specialize this stack for the AWS Account + * and Region that are implied by the current CLI configuration. */ + // env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION }, + + /* Uncomment the next line if you know exactly what Account and Region you + * want to deploy the stack to. */ + // env: { account: '123456789012', region: 'us-east-1' }, + + /* For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html */ +}); diff --git a/packages/aws-cdk/lib/init-templates/v2/app/javascript/test/%name%.test.template.js b/packages/aws-cdk/lib/init-templates/v2/app/javascript/test/%name%.test.template.js index e662bff225941..79db241da8e0e 100644 --- a/packages/aws-cdk/lib/init-templates/v2/app/javascript/test/%name%.test.template.js +++ b/packages/aws-cdk/lib/init-templates/v2/app/javascript/test/%name%.test.template.js @@ -7,5 +7,5 @@ test('Empty Stack', () => { const stack = new %name.PascalCased%.%name.PascalCased%Stack(app, 'MyTestStack'); // THEN const actual = app.synth().getStackArtifact(stack.artifactId).template; - expect(actual).toEqual({}); + expect(actual.Resources || {}).toEqual({}); }); diff --git a/packages/aws-cdk/lib/init-templates/v2/app/python/%name.PythonModule%/%name.PythonModule%_stack.template.py b/packages/aws-cdk/lib/init-templates/v2/app/python/%name.PythonModule%/%name.PythonModule%_stack.template.py index 40bad7e3b032d..34f669bde7832 100644 --- a/packages/aws-cdk/lib/init-templates/v2/app/python/%name.PythonModule%/%name.PythonModule%_stack.template.py +++ b/packages/aws-cdk/lib/init-templates/v2/app/python/%name.PythonModule%/%name.PythonModule%_stack.template.py @@ -1,4 +1,5 @@ -import aws_cdk_lib as core +from aws_cdk import Stack +from constructs import Construct class %name.PascalCased%Stack(core.Stack): diff --git a/packages/aws-cdk/lib/init-templates/v2/app/python/app.template.py b/packages/aws-cdk/lib/init-templates/v2/app/python/app.template.py index 5d1fa551c1c70..65cd03f7253da 100644 --- a/packages/aws-cdk/lib/init-templates/v2/app/python/app.template.py +++ b/packages/aws-cdk/lib/init-templates/v2/app/python/app.template.py @@ -1,11 +1,28 @@ #!/usr/bin/env python3 +import os -import aws_cdk_lib as core +import aws_cdk as cdk from %name.PythonModule%.%name.PythonModule%_stack import %name.PascalCased%Stack -app = core.App() -%name.PascalCased%Stack(app, "%name.PascalCased%Stack") +app = cdk.App() +%name.PascalCased%Stack(app, "%name.PascalCased%Stack", + # If you don't specify 'env', this stack will be environment-agnostic. + # Account/Region-dependent features and context lookups will not work, + # but a single synthesized template can be deployed anywhere. + + # Uncomment the next line to specialize this stack for the AWS Account + # and Region that are implied by the current CLI configuration. + + #env=cdk.Environment(account=os.getenv('CDK_DEFAULT_ACCOUNT'), region=os.getenv('CDK_DEFAULT_REGION')), + + # Uncomment the next line if you know exactly what Account and Region you + # want to deploy the stack to. */ + + #env=cdk.Environment(account='123456789012', region='us-east-1'), + + # For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html + ) app.synth() diff --git a/packages/aws-cdk/lib/init-templates/v2/app/python/setup.template.py b/packages/aws-cdk/lib/init-templates/v2/app/python/setup.template.py index 4aadde6ecede7..de40700458a80 100644 --- a/packages/aws-cdk/lib/init-templates/v2/app/python/setup.template.py +++ b/packages/aws-cdk/lib/init-templates/v2/app/python/setup.template.py @@ -29,8 +29,6 @@ "Intended Audience :: Developers", - "License :: OSI Approved :: Apache Software License", - "Programming Language :: JavaScript", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.6", diff --git a/packages/aws-cdk/lib/init-templates/v2/app/typescript/bin/%name%.template.ts b/packages/aws-cdk/lib/init-templates/v2/app/typescript/bin/%name%.template.ts index 2a54cb5615400..d29a34d0b3c79 100644 --- a/packages/aws-cdk/lib/init-templates/v2/app/typescript/bin/%name%.template.ts +++ b/packages/aws-cdk/lib/init-templates/v2/app/typescript/bin/%name%.template.ts @@ -4,4 +4,18 @@ import * as cdk from 'aws-cdk-lib'; import { %name.PascalCased%Stack } from '../lib/%name%-stack'; const app = new cdk.App(); -new %name.PascalCased%Stack(app, '%name.PascalCased%Stack'); +new %name.PascalCased%Stack(app, '%name.PascalCased%Stack', { + /* If you don't specify 'env', this stack will be environment-agnostic. + * Account/Region-dependent features and context lookups will not work, + * but a single synthesized template can be deployed anywhere. */ + + /* Uncomment the next line to specialize this stack for the AWS Account + * and Region that are implied by the current CLI configuration. */ + // env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION }, + + /* Uncomment the next line if you know exactly what Account and Region you + * want to deploy the stack to. */ + // env: { account: '123456789012', region: 'us-east-1' }, + + /* For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html */ +}); \ No newline at end of file diff --git a/packages/aws-cdk/lib/init-templates/v2/app/typescript/test/%name%.test.template.ts b/packages/aws-cdk/lib/init-templates/v2/app/typescript/test/%name%.test.template.ts index 6baa631335298..a2542902315c8 100644 --- a/packages/aws-cdk/lib/init-templates/v2/app/typescript/test/%name%.test.template.ts +++ b/packages/aws-cdk/lib/init-templates/v2/app/typescript/test/%name%.test.template.ts @@ -7,5 +7,5 @@ test('Empty Stack', () => { const stack = new %name.PascalCased%.%name.PascalCased%Stack(app, 'MyTestStack'); // THEN const actual = app.synth().getStackArtifact(stack.artifactId).template; - expect(actual).toEqual({}); + expect(actual.Resources ?? {}).toEqual({}); }); diff --git a/packages/aws-cdk/lib/init-templates/v2/lib/typescript/test/%name%.test.template.ts b/packages/aws-cdk/lib/init-templates/v2/lib/typescript/test/%name%.test.template.ts index 924869ad24bf7..0aa210d01ae5c 100644 --- a/packages/aws-cdk/lib/init-templates/v2/lib/typescript/test/%name%.test.template.ts +++ b/packages/aws-cdk/lib/init-templates/v2/lib/typescript/test/%name%.test.template.ts @@ -8,5 +8,5 @@ test('Empty Stack', () => { new %name.PascalCased%.%name.PascalCased%(stack, 'MyTestConstruct'); // THEN const actual = app.synth().getStackArtifact(stack.artifactId).template; - expect(actual).toEqual({}); + expect(actual.Resources ?? {}).toEqual({}); }); diff --git a/packages/aws-cdk/lib/init-templates/v2/sample-app/csharp/src/%name.PascalCased%/%name.PascalCased%Stack.template.cs b/packages/aws-cdk/lib/init-templates/v2/sample-app/csharp/src/%name.PascalCased%/%name.PascalCased%Stack.template.cs index db2baa2ca3924..365330ed65925 100644 --- a/packages/aws-cdk/lib/init-templates/v2/sample-app/csharp/src/%name.PascalCased%/%name.PascalCased%Stack.template.cs +++ b/packages/aws-cdk/lib/init-templates/v2/sample-app/csharp/src/%name.PascalCased%/%name.PascalCased%Stack.template.cs @@ -1,4 +1,4 @@ -using Amazon.CDK.Lib; +using Amazon.CDK; using Amazon.CDK.AWS.SNS; using Amazon.CDK.AWS.SNS.Subscriptions; using Amazon.CDK.AWS.SQS; diff --git a/packages/aws-cdk/lib/init-templates/v2/sample-app/csharp/src/%name.PascalCased%/Program.template.cs b/packages/aws-cdk/lib/init-templates/v2/sample-app/csharp/src/%name.PascalCased%/Program.template.cs index ce88608d08cfe..20d5337f09888 100644 --- a/packages/aws-cdk/lib/init-templates/v2/sample-app/csharp/src/%name.PascalCased%/Program.template.cs +++ b/packages/aws-cdk/lib/init-templates/v2/sample-app/csharp/src/%name.PascalCased%/Program.template.cs @@ -1,4 +1,4 @@ -using Amazon.CDK.Lib; +using Amazon.CDK; namespace %name.PascalCased% { diff --git a/packages/aws-cdk/lib/init-templates/v2/sample-app/fsharp/src/%name.PascalCased%/%name.PascalCased%Stack.template.fs b/packages/aws-cdk/lib/init-templates/v2/sample-app/fsharp/src/%name.PascalCased%/%name.PascalCased%Stack.template.fs index fb527366dfb7b..1582e37f4faaf 100644 --- a/packages/aws-cdk/lib/init-templates/v2/sample-app/fsharp/src/%name.PascalCased%/%name.PascalCased%Stack.template.fs +++ b/packages/aws-cdk/lib/init-templates/v2/sample-app/fsharp/src/%name.PascalCased%/%name.PascalCased%Stack.template.fs @@ -1,6 +1,6 @@ namespace %name.PascalCased% -open Amazon.CDK.Lib +open Amazon.CDK open Amazon.CDK.AWS.SNS open Amazon.CDK.AWS.SNS.Subscriptions open Amazon.CDK.AWS.SQS diff --git a/packages/aws-cdk/lib/init-templates/v2/sample-app/fsharp/src/%name.PascalCased%/Program.template.fs b/packages/aws-cdk/lib/init-templates/v2/sample-app/fsharp/src/%name.PascalCased%/Program.template.fs index 4b28d1e03ba9a..dc618af3fbbf1 100644 --- a/packages/aws-cdk/lib/init-templates/v2/sample-app/fsharp/src/%name.PascalCased%/Program.template.fs +++ b/packages/aws-cdk/lib/init-templates/v2/sample-app/fsharp/src/%name.PascalCased%/Program.template.fs @@ -1,4 +1,4 @@ -open Amazon.CDK.Lib +open Amazon.CDK open %name.PascalCased% [] diff --git a/packages/aws-cdk/lib/init-templates/v2/sample-app/java/pom.template.xml b/packages/aws-cdk/lib/init-templates/v2/sample-app/java/pom.template.xml index 7f10c89a54dd4..c6628e62b18a2 100644 --- a/packages/aws-cdk/lib/init-templates/v2/sample-app/java/pom.template.xml +++ b/packages/aws-cdk/lib/init-templates/v2/sample-app/java/pom.template.xml @@ -35,7 +35,7 @@ software.amazon.awscdk - lib + aws-cdk-lib ${cdk.version} diff --git a/packages/aws-cdk/lib/init-templates/v2/sample-app/python/%name.PythonModule%/%name.PythonModule%_stack.template.py b/packages/aws-cdk/lib/init-templates/v2/sample-app/python/%name.PythonModule%/%name.PythonModule%_stack.template.py index 7629e4361788b..b74e7d6438146 100644 --- a/packages/aws-cdk/lib/init-templates/v2/sample-app/python/%name.PythonModule%/%name.PythonModule%_stack.template.py +++ b/packages/aws-cdk/lib/init-templates/v2/sample-app/python/%name.PythonModule%/%name.PythonModule%_stack.template.py @@ -1,5 +1,7 @@ -import aws_cdk_lib as core -from aws_cdk_lib import ( +from constructs import Construct +from aws_cdk import ( + Duration, + Stack, aws_iam as iam, aws_sqs as sqs, aws_sns as sns, diff --git a/packages/aws-cdk/lib/init-templates/v2/sample-app/python/app.template.py b/packages/aws-cdk/lib/init-templates/v2/sample-app/python/app.template.py index f53ecf105b8ca..1f64e6a67bc56 100644 --- a/packages/aws-cdk/lib/init-templates/v2/sample-app/python/app.template.py +++ b/packages/aws-cdk/lib/init-templates/v2/sample-app/python/app.template.py @@ -1,11 +1,11 @@ #!/usr/bin/env python3 -import aws_cdk_lib as core +import aws_cdk as cdk from %name.PythonModule%.%name.PythonModule%_stack import %name.PascalCased%Stack -app = core.App() +app = cdk.App() %name.PascalCased%Stack(app, "%name.StackName%", env={'region': 'us-west-2'}) app.synth() diff --git a/packages/aws-cdk/lib/init-templates/v2/sample-app/python/setup.template.py b/packages/aws-cdk/lib/init-templates/v2/sample-app/python/setup.template.py index 585578354a190..3bcffe32b2e8f 100644 --- a/packages/aws-cdk/lib/init-templates/v2/sample-app/python/setup.template.py +++ b/packages/aws-cdk/lib/init-templates/v2/sample-app/python/setup.template.py @@ -29,8 +29,6 @@ "Intended Audience :: Developers", - "License :: OSI Approved :: Apache Software License", - "Programming Language :: JavaScript", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.6", diff --git a/packages/aws-cdk/lib/plugin.ts b/packages/aws-cdk/lib/plugin.ts index 4b4ad7956edc3..705fa3c3d859d 100644 --- a/packages/aws-cdk/lib/plugin.ts +++ b/packages/aws-cdk/lib/plugin.ts @@ -17,7 +17,6 @@ import { error } from './logging'; * } * } * - * @experimental */ export interface Plugin { /** @@ -38,7 +37,6 @@ export interface Plugin { /** * A utility to manage plug-ins. * - * @experimental */ export class PluginHost { public static instance = new PluginHost(); diff --git a/packages/aws-cdk/lib/serialize.ts b/packages/aws-cdk/lib/serialize.ts index 36b99b3e1be64..62a9bb70c3322 100644 --- a/packages/aws-cdk/lib/serialize.ts +++ b/packages/aws-cdk/lib/serialize.ts @@ -1,5 +1,5 @@ -import * as yaml_cfn from '@aws-cdk/yaml-cfn'; import * as fs from 'fs-extra'; +import * as yaml_cfn from './util/yaml-cfn'; /** * Stringify to YAML diff --git a/packages/aws-cdk/lib/util/yaml-cfn.ts b/packages/aws-cdk/lib/util/yaml-cfn.ts new file mode 100644 index 0000000000000..e46c8f8d6bf72 --- /dev/null +++ b/packages/aws-cdk/lib/util/yaml-cfn.ts @@ -0,0 +1,59 @@ +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): yaml_types.Schema.CustomTag { + return { + identify(value: any) { return typeof value === 'string'; }, + tag: `!${intrinsicName}`, + resolve: (_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', 'GetAtt', +].map(name => makeTagForCfnIntrinsic(name, true)).concat( + makeTagForCfnIntrinsic('Ref', false), + makeTagForCfnIntrinsic('Condition', false), +); + +function parseYamlStrWithCfnTags(text: string): any { + return yaml.parse(text, { + customTags: shortForms, + schema: 'core', + }); +} diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index d9daa6c7cdb79..b061bffc1d7d9 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -39,16 +39,16 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/core": "0.0.0", - "@octokit/rest": "^18.3.5", + "@octokit/rest": "^18.5.3", "@types/archiver": "^5.1.0", "@types/fs-extra": "^8.1.1", "@types/glob": "^7.1.3", - "@types/jest": "^26.0.21", - "@types/minimatch": "^3.0.3", + "@types/jest": "^26.0.23", + "@types/minimatch": "^3.0.4", "@types/mockery": "^1.4.29", - "@types/node": "^10.17.55", + "@types/node": "^10.17.59", "@types/promptly": "^3.0.1", - "@types/semver": "^7.3.4", + "@types/semver": "^7.3.5", "@types/sinon": "^9.0.11", "@types/table": "^6.0.0", "@types/uuid": "^8.3.0", @@ -62,8 +62,8 @@ "nock": "^13.0.11", "pkglint": "0.0.0", "sinon": "^9.2.4", - "ts-jest": "^26.5.4", - "ts-mock-imports": "^1.3.3", + "ts-jest": "^26.5.5", + "ts-mock-imports": "^1.3.4", "xml-js": "^1.6.11" }, "dependencies": { @@ -71,7 +71,6 @@ "@aws-cdk/cloudformation-diff": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/region-info": "0.0.0", - "@aws-cdk/yaml-cfn": "0.0.0", "archiver": "^5.3.0", "aws-sdk": "^2.848.0", "camelcase": "^6.2.0", @@ -84,11 +83,12 @@ "minimatch": ">=3.0", "promptly": "^3.2.0", "proxy-agent": "^4.0.1", - "semver": "^7.3.4", + "semver": "^7.3.5", "source-map-support": "^0.5.19", - "table": "^6.0.7", + "table": "^6.6.0", "uuid": "^8.3.2", "wrap-ansi": "^7.0.0", + "yaml": "1.10.2", "yargs": "^16.2.0" }, "repository": { @@ -104,6 +104,12 @@ "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, + "nozem": { + "ostools": ["git", "date", "cat", "dotnet", "mvn", "npm"], + "env": { + "CODEBUILD_RESOLVED_SOURCE_VERSION": "|nzm-build" + } + }, "stability": "stable", "maturity": "stable", "publishConfig": { diff --git a/packages/aws-cdk/test/api/cloud-assembly.test.ts b/packages/aws-cdk/test/api/cloud-assembly.test.ts index 6559718b9f51a..c85146d71e423 100644 --- a/packages/aws-cdk/test/api/cloud-assembly.test.ts +++ b/packages/aws-cdk/test/api/cloud-assembly.test.ts @@ -73,6 +73,50 @@ test('select behavior: repeat', async () => { expect(x.stackCount).toBe(1); }); +test('select behavior with nested assemblies: all', async () => { + // GIVEN + const cxasm = await testNestedCloudAssembly(); + + // WHEN + const x = await cxasm.selectStacks([], { defaultBehavior: DefaultSelection.AllStacks }); + + // THEN + expect(x.stackCount).toBe(3); +}); + +test('select behavior with nested assemblies: none', async () => { + // GIVEN + const cxasm = await testNestedCloudAssembly(); + + // WHEN + const x = await cxasm.selectStacks([], { defaultBehavior: DefaultSelection.None }); + + // THEN + expect(x.stackCount).toBe(0); +}); + +test('select behavior with nested assemblies: single', async () => { + // GIVEN + const cxasm = await testNestedCloudAssembly(); + + // WHEN + await expect(cxasm.selectStacks([], { defaultBehavior: DefaultSelection.OnlySingle })) + .rejects.toThrow('Since this app includes more than a single stack, specify which stacks to use (wildcards are supported) or specify `--all`'); +}); + +test('select behavior with nested assemblies: repeat', async() => { + // GIVEN + const cxasm = await testNestedCloudAssembly(); + + // WHEN + const x = await cxasm.selectStacks(['withouterrors', 'withouterrors', 'nested'], { + defaultBehavior: DefaultSelection.AllStacks, + }); + + // THEN + expect(x.stackCount).toBe(2); +}); + async function testCloudAssembly({ env }: { env?: string, versionReporting?: boolean } = {}) { const cloudExec = new MockCloudExecutable({ stacks: [{ @@ -97,3 +141,43 @@ async function testCloudAssembly({ env }: { env?: string, versionReporting?: boo return cloudExec.synthesize(); } + +async function testNestedCloudAssembly({ env }: { env?: string, versionReporting?: boolean } = {}) { + const cloudExec = new MockCloudExecutable({ + stacks: [{ + stackName: 'withouterrors', + env, + template: { resource: 'noerrorresource' }, + }, + { + stackName: 'witherrors', + env, + template: { resource: 'errorresource' }, + metadata: { + '/resource': [ + { + type: cxschema.ArtifactMetadataEntryType.ERROR, + data: 'this is an error', + }, + ], + }, + }], + nestedAssemblies: [{ + stacks: [{ + stackName: 'nested', + env, + template: { resource: 'nestederror' }, + metadata: { + '/resource': [ + { + type: cxschema.ArtifactMetadataEntryType.ERROR, + data: 'this is another error', + }, + ], + }, + }], + }], + }); + + return cloudExec.synthesize(); +} diff --git a/packages/aws-cdk/test/api/deploy-stack.test.ts b/packages/aws-cdk/test/api/deploy-stack.test.ts index 8fffb321ef995..7e4c5484e2f5a 100644 --- a/packages/aws-cdk/test/api/deploy-stack.test.ts +++ b/packages/aws-cdk/test/api/deploy-stack.test.ts @@ -1,4 +1,4 @@ -import { deployStack, ToolkitInfo } from '../../lib'; +import { deployStack, ToolkitInfo } from '../../lib/api'; import { DEFAULT_FAKE_TEMPLATE, testStack } from '../util'; import { MockedObject, mockResolvedEnvironment, MockSdk, MockSdkProvider, SyncHandlerSubsetOf } from '../util/mock-sdk'; diff --git a/packages/aws-cdk/test/api/sdk-provider.test.ts b/packages/aws-cdk/test/api/sdk-provider.test.ts index c09577d740870..c7dfbbcfeb45c 100644 --- a/packages/aws-cdk/test/api/sdk-provider.test.ts +++ b/packages/aws-cdk/test/api/sdk-provider.test.ts @@ -4,9 +4,9 @@ import * as AWS from 'aws-sdk'; import type { ConfigurationOptions } from 'aws-sdk/lib/config-base'; import * as promptly from 'promptly'; import * as uuid from 'uuid'; -import { PluginHost } from '../../lib'; import { ISDK, Mode, SDK, SdkProvider } from '../../lib/api/aws-auth'; import * as logging from '../../lib/logging'; +import { PluginHost } from '../../lib/plugin'; import * as bockfs from '../bockfs'; import { withMocked } from '../util'; import { FakeSts, RegisterRoleOptions, RegisterUserOptions } from './fake-sts'; diff --git a/packages/aws-cdk/test/api/toolkit-info.test.ts b/packages/aws-cdk/test/api/toolkit-info.test.ts index 113164404325e..1ef00d113142f 100644 --- a/packages/aws-cdk/test/api/toolkit-info.test.ts +++ b/packages/aws-cdk/test/api/toolkit-info.test.ts @@ -1,4 +1,4 @@ -import { ToolkitInfo } from '../../lib'; +import { ToolkitInfo } from '../../lib/api'; import { errorWithCode, mockBootstrapStack, MockSdk } from '../util/mock-sdk'; diff --git a/packages/aws-cdk/test/assets.test.ts b/packages/aws-cdk/test/assets.test.ts index 2426e20aa0972..c632a0cf620e0 100644 --- a/packages/aws-cdk/test/assets.test.ts +++ b/packages/aws-cdk/test/assets.test.ts @@ -1,5 +1,5 @@ import { AssetMetadataEntry } from '@aws-cdk/cloud-assembly-schema'; -import { ToolkitInfo } from '../lib'; +import { ToolkitInfo } from '../lib/api'; import { addMetadataAssetsToManifest } from '../lib/assets'; import { AssetManifestBuilder } from '../lib/util/asset-manifest-builder'; import { testStack } from './util'; diff --git a/packages/aws-cdk/test/cdk-toolkit.test.ts b/packages/aws-cdk/test/cdk-toolkit.test.ts index 9266d9bc10646..5b918889e55a8 100644 --- a/packages/aws-cdk/test/cdk-toolkit.test.ts +++ b/packages/aws-cdk/test/cdk-toolkit.test.ts @@ -18,6 +18,9 @@ beforeEach(() => { MockStack.MOCK_STACK_A, MockStack.MOCK_STACK_B, ], + nestedAssemblies: [{ + stacks: [MockStack.MOCK_STACK_C], + }], }); }); @@ -30,6 +33,7 @@ function defaultToolkitSetup() { cloudFormation: new FakeCloudFormation({ 'Test-Stack-A': { Foo: 'Bar' }, 'Test-Stack-B': { Baz: 'Zinga!' }, + 'Test-Stack-C': { Baz: 'Zinga!' }, }), }); } @@ -44,6 +48,15 @@ describe('deploy', () => { await toolkit.deploy({ stackNames: ['Test-Stack-A', 'Test-Stack-B'] }); }); + test('with stacks all stacks specified as double wildcard', async () => { + // GIVEN + const toolkit = defaultToolkitSetup(); + + // WHEN + await toolkit.deploy({ stackNames: ['**'] }); + }); + + test('with one stack specified', async () => { // GIVEN const toolkit = defaultToolkitSetup(); @@ -146,6 +159,40 @@ describe('synth', () => { // THEN await expect(toolkit.synth(['Test-Stack-A'], false, true)).resolves.toBeUndefined(); }); + + describe('post-synth validation', () => { + beforeEach(() => { + cloudExecutable = new MockCloudExecutable({ + stacks: [ + MockStack.MOCK_STACK_A, + MockStack.MOCK_STACK_B, + ], + nestedAssemblies: [{ + stacks: [MockStack.MOCK_STACK_WITH_ERROR], + }], + }); + }); + }); + + afterEach(() => { + process.env.STACKS_TO_VALIDATE = undefined; + }); + + test('with STACKS_TO_VALIDATE containing a failed stack', async() => { + process.env.STACKS_TO_VALIDATE = 'Test-Stack-A;Test-Stack-A/witherrors'; + + const toolkit = defaultToolkitSetup(); + + await expect(toolkit.synth(['Test-Stack-A'], false, true)).rejects.toBeDefined(); + }); + + test('with STACKS_TO_VALIDATE not containing a failed stack', async() => { + process.env.STACKS_TO_VALIDATE = 'Test-Stack-A'; + + const toolkit = defaultToolkitSetup(); + + await toolkit.synth(['Test-Stack-A'], false, true); + }); }); class MockStack { @@ -179,6 +226,36 @@ class MockStack { ], }, }; + public static readonly MOCK_STACK_C: TestStackArtifact = { + stackName: 'Test-Stack-C', + template: { Resources: { TempalteName: 'Test-Stack-C' } }, + env: 'aws://123456789012/bermuda-triangle-1', + metadata: { + '/Test-Stack-C': [ + { + type: cxschema.ArtifactMetadataEntryType.STACK_TAGS, + data: [ + { key: 'Baz', value: 'Zinga!' }, + ], + }, + ], + }, + displayName: 'Test-Stack-A/Test-Stack-C', + }; + public static readonly MOCK_STACK_WITH_ERROR: TestStackArtifact = { + stackName: 'witherrors', + env: 'aws://123456789012/bermuda-triangle-1', + template: { resource: 'errorresource' }, + metadata: { + '/resource': [ + { + type: cxschema.ArtifactMetadataEntryType.ERROR, + data: 'this is an error', + }, + ], + }, + displayName: 'Test-Stack-A/witherrors', + } } class FakeCloudFormation extends CloudFormationDeployments { @@ -202,7 +279,7 @@ class FakeCloudFormation extends CloudFormationDeployments { } public deployStack(options: DeployStackOptions): Promise { - expect([MockStack.MOCK_STACK_A.stackName, MockStack.MOCK_STACK_B.stackName]) + expect([MockStack.MOCK_STACK_A.stackName, MockStack.MOCK_STACK_B.stackName, MockStack.MOCK_STACK_C.stackName]) .toContain(options.stack.stackName); expect(options.tags).toEqual(this.expectedTags[options.stack.stackName]); expect(options.notificationArns).toEqual(this.expectedNotificationArns); @@ -220,6 +297,8 @@ class FakeCloudFormation extends CloudFormationDeployments { return Promise.resolve({}); case MockStack.MOCK_STACK_B.stackName: return Promise.resolve({}); + case MockStack.MOCK_STACK_C.stackName: + return Promise.resolve({}); default: return Promise.reject(`Not an expected mock stack: ${stack.stackName}`); } diff --git a/packages/aws-cdk/test/integ/cli/bootstrapping.integtest.ts b/packages/aws-cdk/test/integ/cli/bootstrapping.integtest.ts index c6ba2e53ec2d8..e8510d3e49aee 100644 --- a/packages/aws-cdk/test/integ/cli/bootstrapping.integtest.ts +++ b/packages/aws-cdk/test/integ/cli/bootstrapping.integtest.ts @@ -6,11 +6,12 @@ import { integTest } from '../helpers/test-helpers'; jest.setTimeout(600_000); integTest('can bootstrap without execution', withDefaultFixture(async (fixture) => { - const bootstrapStackName = fixture.fullStackName('bootstrap-stack'); + const bootstrapStackName = fixture.bootstrapStackName; - await fixture.cdk(['bootstrap', - '--toolkit-stack-name', bootstrapStackName, - '--no-execute']); + await fixture.cdkBootstrapLegacy({ + toolkitStackName: bootstrapStackName, + noExecute: true, + }); const resp = await fixture.aws.cloudFormation('describeStacks', { StackName: bootstrapStackName, @@ -20,7 +21,7 @@ integTest('can bootstrap without execution', withDefaultFixture(async (fixture) })); integTest('upgrade legacy bootstrap stack to new bootstrap stack while in use', withDefaultFixture(async (fixture) => { - const bootstrapStackName = fixture.fullStackName('bootstrap-stack'); + const bootstrapStackName = fixture.bootstrapStackName; const legacyBootstrapBucketName = `aws-cdk-bootstrap-integ-test-legacy-bckt-${randomString()}`; const newBootstrapBucketName = `aws-cdk-bootstrap-integ-test-v2-bckt-${randomString()}`; @@ -28,9 +29,10 @@ integTest('upgrade legacy bootstrap stack to new bootstrap stack while in use', fixture.rememberToDeleteBucket(newBootstrapBucketName); // This one shouldn't leak if the test succeeds, but let's be safe in case it doesn't // Legacy bootstrap - await fixture.cdk(['bootstrap', - '--toolkit-stack-name', bootstrapStackName, - '--bootstrap-bucket-name', legacyBootstrapBucketName]); + await fixture.cdkBootstrapLegacy({ + toolkitStackName: bootstrapStackName, + bootstrapBucketName: legacyBootstrapBucketName, + }); // Deploy stack that uses file assets await fixture.cdkDeploy('lambda', { @@ -38,14 +40,10 @@ integTest('upgrade legacy bootstrap stack to new bootstrap stack while in use', }); // Upgrade bootstrap stack to "new" style - await fixture.cdk(['bootstrap', - '--toolkit-stack-name', bootstrapStackName, - '--bootstrap-bucket-name', newBootstrapBucketName, - '--qualifier', fixture.qualifier, - '--cloudformation-execution-policies', 'arn:aws:iam::aws:policy/AdministratorAccess'], { - modEnv: { - CDK_NEW_BOOTSTRAP: '1', - }, + await fixture.cdkBootstrapModern({ + toolkitStackName: bootstrapStackName, + bootstrapBucketName: newBootstrapBucketName, + cfnExecutionPolicy: 'arn:aws:iam::aws:policy/AdministratorAccess', }); // (Force) deploy stack again @@ -59,14 +57,10 @@ integTest('upgrade legacy bootstrap stack to new bootstrap stack while in use', })); integTest('can and deploy if omitting execution policies', withDefaultFixture(async (fixture) => { - const bootstrapStackName = fixture.fullStackName('bootstrap-stack'); + const bootstrapStackName = fixture.bootstrapStackName; - await fixture.cdk(['bootstrap', - '--toolkit-stack-name', bootstrapStackName, - '--qualifier', fixture.qualifier], { - modEnv: { - CDK_NEW_BOOTSTRAP: '1', - }, + await fixture.cdkBootstrapModern({ + toolkitStackName: bootstrapStackName, }); // Deploy stack that uses file assets @@ -80,15 +74,11 @@ integTest('can and deploy if omitting execution policies', withDefaultFixture(as })); integTest('deploy new style synthesis to new style bootstrap', withDefaultFixture(async (fixture) => { - const bootstrapStackName = fixture.fullStackName('bootstrap-stack'); - - await fixture.cdk(['bootstrap', - '--toolkit-stack-name', bootstrapStackName, - '--qualifier', fixture.qualifier, - '--cloudformation-execution-policies', 'arn:aws:iam::aws:policy/AdministratorAccess'], { - modEnv: { - CDK_NEW_BOOTSTRAP: '1', - }, + const bootstrapStackName = fixture.bootstrapStackName; + + await fixture.cdkBootstrapModern({ + toolkitStackName: bootstrapStackName, + cfnExecutionPolicy: 'arn:aws:iam::aws:policy/AdministratorAccess', }); // Deploy stack that uses file assets @@ -102,15 +92,11 @@ integTest('deploy new style synthesis to new style bootstrap', withDefaultFixtur })); integTest('deploy new style synthesis to new style bootstrap (with docker image)', withDefaultFixture(async (fixture) => { - const bootstrapStackName = fixture.fullStackName('bootstrap-stack'); - - await fixture.cdk(['bootstrap', - '--toolkit-stack-name', bootstrapStackName, - '--qualifier', fixture.qualifier, - '--cloudformation-execution-policies', 'arn:aws:iam::aws:policy/AdministratorAccess'], { - modEnv: { - CDK_NEW_BOOTSTRAP: '1', - }, + const bootstrapStackName = fixture.bootstrapStackName; + + await fixture.cdkBootstrapModern({ + toolkitStackName: bootstrapStackName, + cfnExecutionPolicy: 'arn:aws:iam::aws:policy/AdministratorAccess', }); // Deploy stack that uses file assets @@ -124,15 +110,11 @@ integTest('deploy new style synthesis to new style bootstrap (with docker image) })); integTest('deploy old style synthesis to new style bootstrap', withDefaultFixture(async (fixture) => { - const bootstrapStackName = fixture.fullStackName('bootstrap-stack'); - - await fixture.cdk(['bootstrap', - '--toolkit-stack-name', bootstrapStackName, - '--qualifier', fixture.qualifier, - '--cloudformation-execution-policies', 'arn:aws:iam::aws:policy/AdministratorAccess'], { - modEnv: { - CDK_NEW_BOOTSTRAP: '1', - }, + const bootstrapStackName = fixture.bootstrapStackName; + + await fixture.cdkBootstrapModern({ + toolkitStackName: bootstrapStackName, + cfnExecutionPolicy: 'arn:aws:iam::aws:policy/AdministratorAccess', }); // Deploy stack that uses file assets @@ -144,9 +126,11 @@ integTest('deploy old style synthesis to new style bootstrap', withDefaultFixtur })); integTest('deploying new style synthesis to old style bootstrap fails', withDefaultFixture(async (fixture) => { - const bootstrapStackName = fixture.fullStackName('bootstrap-stack'); + const bootstrapStackName = fixture.bootstrapStackName; - await fixture.cdk(['bootstrap', '--toolkit-stack-name', bootstrapStackName]); + await fixture.cdkBootstrapLegacy({ + toolkitStackName: bootstrapStackName, + }); // Deploy stack that uses file assets, this fails because the bootstrap stack // is version checked. @@ -159,9 +143,14 @@ integTest('deploying new style synthesis to old style bootstrap fails', withDefa })); integTest('can create a legacy bootstrap stack with --public-access-block-configuration=false', withDefaultFixture(async (fixture) => { - const bootstrapStackName = fixture.fullStackName('bootstrap-stack-1'); + const bootstrapStackName = fixture.bootstrapStackName; - await fixture.cdk(['bootstrap', '-v', '--toolkit-stack-name', bootstrapStackName, '--public-access-block-configuration', 'false', '--tags', 'Foo=Bar']); + await fixture.cdkBootstrapLegacy({ + verbose: true, + toolkitStackName: bootstrapStackName, + publicAccessBlockConfiguration: false, + tags: 'Foo=Bar', + }); const response = await fixture.aws.cloudFormation('describeStacks', { StackName: bootstrapStackName }); expect(response.Stacks?.[0].Tags).toEqual([ @@ -170,13 +159,20 @@ integTest('can create a legacy bootstrap stack with --public-access-block-config })); integTest('can create multiple legacy bootstrap stacks', withDefaultFixture(async (fixture) => { - const bootstrapStackName1 = fixture.fullStackName('bootstrap-stack-1'); - const bootstrapStackName2 = fixture.fullStackName('bootstrap-stack-2'); + const bootstrapStackName1 = `${fixture.bootstrapStackName}-1`; + const bootstrapStackName2 = `${fixture.bootstrapStackName}-2`; // deploy two toolkit stacks into the same environment (see #1416) // one with tags - await fixture.cdk(['bootstrap', '-v', '--toolkit-stack-name', bootstrapStackName1, '--tags', 'Foo=Bar']); - await fixture.cdk(['bootstrap', '-v', '--toolkit-stack-name', bootstrapStackName2]); + await fixture.cdkBootstrapLegacy({ + verbose: true, + toolkitStackName: bootstrapStackName1, + tags: 'Foo=Bar', + }); + await fixture.cdkBootstrapLegacy({ + verbose: true, + toolkitStackName: bootstrapStackName2, + }); const response = await fixture.aws.cloudFormation('describeStacks', { StackName: bootstrapStackName1 }); expect(response.Stacks?.[0].Tags).toEqual([ @@ -185,10 +181,12 @@ integTest('can create multiple legacy bootstrap stacks', withDefaultFixture(asyn })); integTest('can dump the template, modify and use it to deploy a custom bootstrap stack', withDefaultFixture(async (fixture) => { - let template = await fixture.cdk(['bootstrap', '--show-template'], { - captureStderr: false, - modEnv: { - CDK_NEW_BOOTSTRAP: '1', + let template = await fixture.cdkBootstrapModern({ + // toolkitStackName doesn't matter for this particular invocation + toolkitStackName: fixture.bootstrapStackName, + showTemplate: true, + cliOptions: { + captureStderr: false, }, }); @@ -201,42 +199,46 @@ integTest('can dump the template, modify and use it to deploy a custom bootstrap const filename = path.join(fixture.integTestDir, `${fixture.qualifier}-template.yaml`); fs.writeFileSync(filename, template, { encoding: 'utf-8' }); - await fixture.cdk(['bootstrap', - '--toolkit-stack-name', fixture.fullStackName('bootstrap-stack'), - '--qualifier', fixture.qualifier, - '--template', filename, - '--cloudformation-execution-policies', 'arn:aws:iam::aws:policy/AdministratorAccess'], { - modEnv: { - CDK_NEW_BOOTSTRAP: '1', - }, + await fixture.cdkBootstrapModern({ + toolkitStackName: fixture.bootstrapStackName, + template: filename, + cfnExecutionPolicy: 'arn:aws:iam::aws:policy/AdministratorAccess', }); })); integTest('switch on termination protection, switch is left alone on re-bootstrap', withDefaultFixture(async (fixture) => { - const bootstrapStackName = fixture.fullStackName('bootstrap-stack'); + const bootstrapStackName = fixture.bootstrapStackName; - await fixture.cdk(['bootstrap', '-v', '--toolkit-stack-name', bootstrapStackName, - '--termination-protection', 'true', - '--qualifier', fixture.qualifier, - '--cloudformation-execution-policies', 'arn:aws:iam::aws:policy/AdministratorAccess'], { - modEnv: { CDK_NEW_BOOTSTRAP: '1' }, + await fixture.cdkBootstrapModern({ + verbose: true, + toolkitStackName: bootstrapStackName, + terminationProtection: true, + cfnExecutionPolicy: 'arn:aws:iam::aws:policy/AdministratorAccess', + }); + await fixture.cdkBootstrapModern({ + verbose: true, + toolkitStackName: bootstrapStackName, + force: true, }); - await fixture.cdk(['bootstrap', '-v', '--toolkit-stack-name', bootstrapStackName, '--force'], { modEnv: { CDK_NEW_BOOTSTRAP: '1' } }); const response = await fixture.aws.cloudFormation('describeStacks', { StackName: bootstrapStackName }); expect(response.Stacks?.[0].EnableTerminationProtection).toEqual(true); })); integTest('add tags, left alone on re-bootstrap', withDefaultFixture(async (fixture) => { - const bootstrapStackName = fixture.fullStackName('bootstrap-stack'); + const bootstrapStackName = fixture.bootstrapStackName; - await fixture.cdk(['bootstrap', '-v', '--toolkit-stack-name', bootstrapStackName, - '--tags', 'Foo=Bar', - '--qualifier', fixture.qualifier, - '--cloudformation-execution-policies', 'arn:aws:iam::aws:policy/AdministratorAccess'], { - modEnv: { CDK_NEW_BOOTSTRAP: '1' }, + await fixture.cdkBootstrapModern({ + verbose: true, + toolkitStackName: bootstrapStackName, + tags: 'Foo=Bar', + cfnExecutionPolicy: 'arn:aws:iam::aws:policy/AdministratorAccess', + }); + await fixture.cdkBootstrapModern({ + verbose: true, + toolkitStackName: bootstrapStackName, + force: true, }); - await fixture.cdk(['bootstrap', '-v', '--toolkit-stack-name', bootstrapStackName, '--force'], { modEnv: { CDK_NEW_BOOTSTRAP: '1' } }); const response = await fixture.aws.cloudFormation('describeStacks', { StackName: bootstrapStackName }); expect(response.Stacks?.[0].Tags).toEqual([ @@ -245,15 +247,11 @@ integTest('add tags, left alone on re-bootstrap', withDefaultFixture(async (fixt })); integTest('can deploy modern-synthesized stack even if bootstrap stack name is unknown', withDefaultFixture(async (fixture) => { - const bootstrapStackName = fixture.fullStackName('bootstrap-stack'); - - await fixture.cdk(['bootstrap', - '--toolkit-stack-name', bootstrapStackName, - '--qualifier', fixture.qualifier, - '--cloudformation-execution-policies', 'arn:aws:iam::aws:policy/AdministratorAccess'], { - modEnv: { - CDK_NEW_BOOTSTRAP: '1', - }, + const bootstrapStackName = fixture.bootstrapStackName; + + await fixture.cdkBootstrapModern({ + toolkitStackName: bootstrapStackName, + cfnExecutionPolicy: 'arn:aws:iam::aws:policy/AdministratorAccess', }); // Deploy stack that uses file assets @@ -266,4 +264,4 @@ integTest('can deploy modern-synthesized stack even if bootstrap stack name is u '--context', '@aws-cdk/core:newStyleStackSynthesis=1', ], }); -})); \ No newline at end of file +})); diff --git a/packages/aws-cdk/test/integ/helpers/aws.ts b/packages/aws-cdk/test/integ/helpers/aws.ts index 7c6435fdfba91..c7208ab569a65 100644 --- a/packages/aws-cdk/test/integ/helpers/aws.ts +++ b/packages/aws-cdk/test/integ/helpers/aws.ts @@ -45,6 +45,8 @@ export class AwsClients { public async deleteStacks(...stackNames: string[]) { if (stackNames.length === 0) { return; } + // We purposely do all stacks serially, because they've been ordered + // to do the bootstrap stack last. for (const stackName of stackNames) { await this.cloudFormation('updateTerminationProtection', { EnableTerminationProtection: false, @@ -53,10 +55,8 @@ export class AwsClients { await this.cloudFormation('deleteStack', { StackName: stackName, }); - } - await retry(this.output, `Deleting ${stackNames}`, retry.forSeconds(600), async () => { - for (const stackName of stackNames) { + await retry(this.output, `Deleting ${stackName}`, retry.forSeconds(600), async () => { const status = await this.stackStatus(stackName); if (status !== undefined && status.endsWith('_FAILED')) { throw retry.abort(new Error(`'${stackName}' is in state '${status}'`)); @@ -64,8 +64,8 @@ export class AwsClients { if (status !== undefined) { throw new Error(`Delete of '${stackName}' not complete yet`); } - } - }); + }); + } } public async stackStatus(stackName: string): Promise { diff --git a/packages/aws-cdk/test/integ/helpers/cdk.ts b/packages/aws-cdk/test/integ/helpers/cdk.ts index 3758998a63206..8bf256140d13b 100644 --- a/packages/aws-cdk/test/integ/helpers/cdk.ts +++ b/packages/aws-cdk/test/integ/helpers/cdk.ts @@ -189,6 +189,63 @@ export async function cloneDirectory(source: string, target: string, output?: No await shell(['cp', '-R', source + '/*', target], { output }); } +interface CommonCdkBootstrapCommandOptions { + readonly toolkitStackName: string; + + /** + * @default false + */ + readonly verbose?: boolean; + + /** + * @default - auto-generated CloudFormation name + */ + readonly bootstrapBucketName?: string; + + readonly cliOptions?: CdkCliOptions; + + /** + * @default - none + */ + readonly tags?: string; +} + +export interface CdkLegacyBootstrapCommandOptions extends CommonCdkBootstrapCommandOptions { + /** + * @default false + */ + readonly noExecute?: boolean; + + /** + * @default true + */ + readonly publicAccessBlockConfiguration?: boolean; +} + +export interface CdkModernBootstrapCommandOptions extends CommonCdkBootstrapCommandOptions { + /** + * @default false + */ + readonly force?: boolean; + + /** + * @default - none + */ + readonly cfnExecutionPolicy?: string; + + /** + * @default false + */ + readonly showTemplate?: boolean; + + readonly template?: string; + + /** + * @default false + */ + readonly terminationProtection?: boolean; +} + export class TestFixture { public readonly qualifier = randomString().substr(0, 10); private readonly bucketsToDelete = new Array(); @@ -239,6 +296,78 @@ export class TestFixture { ...this.fullStackName(stackNames)], options); } + public async cdkBootstrapLegacy(options: CdkLegacyBootstrapCommandOptions): Promise { + const args = ['bootstrap']; + + if (options.verbose) { + args.push('-v'); + } + args.push('--toolkit-stack-name', options.toolkitStackName); + if (options.bootstrapBucketName) { + args.push('--bootstrap-bucket-name', options.bootstrapBucketName); + } + if (options.noExecute) { + args.push('--no-execute'); + } + if (options.publicAccessBlockConfiguration !== undefined) { + args.push('--public-access-block-configuration', options.publicAccessBlockConfiguration.toString()); + } + if (options.tags) { + args.push('--tags', options.tags); + } + + return this.cdk(args, { + ...options.cliOptions, + modEnv: { + ...options.cliOptions?.modEnv, + // so that this works for V2, + // where the "new" bootstrap is the default + CDK_LEGACY_BOOTSTRAP: '1', + }, + }); + } + + public async cdkBootstrapModern(options: CdkModernBootstrapCommandOptions): Promise { + const args = ['bootstrap']; + + if (options.verbose) { + args.push('-v'); + } + if (options.showTemplate) { + args.push('--show-template'); + } + if (options.template) { + args.push('--template', options.template); + } + args.push('--toolkit-stack-name', options.toolkitStackName); + if (options.bootstrapBucketName) { + args.push('--bootstrap-bucket-name', options.bootstrapBucketName); + } + args.push('--qualifier', this.qualifier); + if (options.cfnExecutionPolicy) { + args.push('--cloudformation-execution-policies', options.cfnExecutionPolicy); + } + if (options.terminationProtection !== undefined) { + args.push('--termination-protection', options.terminationProtection.toString()); + } + if (options.force) { + args.push('--force'); + } + if (options.tags) { + args.push('--tags', options.tags); + } + + return this.cdk(args, { + ...options.cliOptions, + modEnv: { + ...options.cliOptions?.modEnv, + // so that this works for V1, + // where the "old" bootstrap is the default + CDK_NEW_BOOTSTRAP: '1', + }, + }); + } + public async cdk(args: string[], options: CdkCliOptions = {}) { const verbose = options.verbose ?? true; @@ -253,6 +382,10 @@ export class TestFixture { }); } + public get bootstrapStackName() { + return this.fullStackName('bootstrap-stack'); + } + public fullStackName(stackName: string): string; public fullStackName(stackNames: string[]): string[]; public fullStackName(stackNames: string | string[]): string | string[] { @@ -279,6 +412,8 @@ export class TestFixture { public async dispose(success: boolean) { const stacksToDelete = await this.deleteableStacks(this.stackNamePrefix); + this.sortBootstrapStacksToTheEnd(stacksToDelete); + // Bootstrap stacks have buckets that need to be cleaned const bucketNames = stacksToDelete.map(stack => outputFromStack('BucketName', stack)).filter(defined); await Promise.all(bucketNames.map(b => this.aws.emptyBucket(b))); @@ -329,6 +464,18 @@ export class TestFixture { .filter(s => statusFilter.includes(s.StackStatus)) .filter(s => s.RootId === undefined); // Only delete parent stacks. Nested stacks are deleted in the process } + + private sortBootstrapStacksToTheEnd(stacks: AWS.CloudFormation.Stack[]) { + stacks.sort((a, b) => { + const aBs = a.StackName.startsWith(this.bootstrapStackName); + const bBs = b.StackName.startsWith(this.bootstrapStackName); + + return aBs != bBs + // '+' converts a boolean to 0 or 1 + ? (+aBs) - (+bBs) + : a.StackName.localeCompare(b.StackName); + }); + } } /** @@ -365,8 +512,9 @@ let sanityChecked: boolean | undefined; * by hand so let's just mass-automate it. */ async function ensureBootstrapped(fixture: TestFixture) { - // Old-style bootstrap stack with default name + // Use the default name for the bootstrap stack if (await fixture.aws.stackStatus('CDKToolkit') === undefined) { + // use whatever version of bootstrap is the default for this particular version of the CLI await fixture.cdk(['bootstrap', `aws://${await fixture.aws.account()}/${fixture.aws.region}`]); } } @@ -511,4 +659,4 @@ const installNpm7 = memoize0(async (): Promise => { 'npm@7']); return path.join(installDir, 'node_modules', '.bin', 'npm'); -}); \ No newline at end of file +}); diff --git a/packages/aws-cdk/test/integ/init/test-all.sh b/packages/aws-cdk/test/integ/init/test-all.sh index cbca0f859feb2..f191d37bf4296 100755 --- a/packages/aws-cdk/test/integ/init/test-all.sh +++ b/packages/aws-cdk/test/integ/init/test-all.sh @@ -7,5 +7,6 @@ $scriptdir/test-java.sh $scriptdir/test-javascript.sh $scriptdir/test-python.sh $scriptdir/test-typescript.sh +$scriptdir/test-go.sh echo "SUCCESS" diff --git a/packages/aws-cdk/test/integ/init/test-go.sh b/packages/aws-cdk/test/integ/init/test-go.sh new file mode 100755 index 0000000000000..6b461f3e25ef5 --- /dev/null +++ b/packages/aws-cdk/test/integ/init/test-go.sh @@ -0,0 +1,26 @@ +#!/bin/bash +#------------------------------------------------------------------ +# setup +#------------------------------------------------------------------ +set -eu +scriptdir=$(cd $(dirname $0) && pwd) +source ${scriptdir}/common.bash + +header Go + +#------------------------------------------------------------------ + +if [[ "${1:-}" == "" ]]; then + templates="app" +else + templates="$@" +fi + +for template in $templates; do + echo "Trying Go template $template" + + setup + + cdk init -l go $template + cdk synth +done diff --git a/packages/aws-cdk/test/integ/run-against-dist.bash b/packages/aws-cdk/test/integ/run-against-dist.bash index d3d349b9302f3..0d5dc245df5e7 100644 --- a/packages/aws-cdk/test/integ/run-against-dist.bash +++ b/packages/aws-cdk/test/integ/run-against-dist.bash @@ -4,8 +4,6 @@ npmws=/tmp/cdk-rundist rm -rf $npmws mkdir -p $npmws -set -x - # This script must create 1 or 2 traps, and the 'trap' command will replace # the previous trap, so get some 'dynamic traps' mechanism in place TRAPS=() @@ -43,6 +41,11 @@ function serve_npm_packages() { tarballs_glob="$dist_root/js/*.tgz" + if [[ -f package.json ]]; then + echo "Do not run this script in a directory with a package.json! It will most likely break!" >&2 + # Cowardly not running 'exit 1' because I'm not sure I won't mess up the build/canaries by doing so + fi + # When using '--daemon', 'npm install' first so the files are permanent, or # 'npx' will remove them too soon. npm install serve-npm-tarballs diff --git a/packages/aws-cdk/test/util.ts b/packages/aws-cdk/test/util.ts index e15a1f6537354..060c75d29f63a 100644 --- a/packages/aws-cdk/test/util.ts +++ b/packages/aws-cdk/test/util.ts @@ -17,11 +17,13 @@ export interface TestStackArtifact { assets?: cxschema.AssetMetadataEntry[]; properties?: Partial; terminationProtection?: boolean; + displayName?: string; } export interface TestAssembly { stacks: TestStackArtifact[]; missing?: cxschema.MissingContext[]; + nestedAssemblies?: TestAssembly[]; } export class MockCloudExecutable extends CloudExecutable { @@ -47,9 +49,7 @@ function clone(obj: any) { return JSON.parse(JSON.stringify(obj)); } -export function testAssembly(assembly: TestAssembly): cxapi.CloudAssembly { - const builder = new cxapi.CloudAssemblyBuilder(); - +function addAttributes(assembly: TestAssembly, builder: cxapi.CloudAssemblyBuilder) { for (const stack of assembly.stacks) { const templateFile = `${stack.stackName}.template.json`; const template = stack.template ?? DEFAULT_FAKE_TEMPLATE; @@ -79,6 +79,20 @@ export function testAssembly(assembly: TestAssembly): cxapi.CloudAssembly { templateFile, terminationProtection: stack.terminationProtection, }, + displayName: stack.displayName, + }); + } +} + +export function testAssembly(assembly: TestAssembly): cxapi.CloudAssembly { + const builder = new cxapi.CloudAssemblyBuilder(); + addAttributes(assembly, builder); + + if (assembly.nestedAssemblies != null && assembly.nestedAssemblies.length > 0) { + assembly.nestedAssemblies?.forEach((nestedAssembly: TestAssembly, i: number) => { + const nestedAssemblyBuilder = builder.createNestedAssembly(`nested${i}`, `nested${i}`); + addAttributes(nestedAssembly, nestedAssemblyBuilder); + nestedAssemblyBuilder.buildAssembly(); }); } diff --git a/packages/aws-cdk/test/util/mock-sdk.ts b/packages/aws-cdk/test/util/mock-sdk.ts index 9d1f1426a77a6..30dbbd682a5a4 100644 --- a/packages/aws-cdk/test/util/mock-sdk.ts +++ b/packages/aws-cdk/test/util/mock-sdk.ts @@ -1,6 +1,7 @@ import * as cxapi from '@aws-cdk/cx-api'; import * as AWS from 'aws-sdk'; -import { Account, ISDK, SDK, SdkProvider, ToolkitInfo } from '../../lib'; +import { Account, ISDK, SDK, SdkProvider } from '../../lib/api/aws-auth'; +import { ToolkitInfo } from '../../lib/api/toolkit-info'; import { CloudFormationStack } from '../../lib/api/util/cloudformation'; const FAKE_CREDENTIALS = new AWS.Credentials({ accessKeyId: 'ACCESS', secretAccessKey: 'SECRET', sessionToken: 'TOKEN ' }); diff --git a/packages/aws-cdk/test/util/mock-toolkitinfo.ts b/packages/aws-cdk/test/util/mock-toolkitinfo.ts index f52ae4cf78267..326fa9dea8140 100644 --- a/packages/aws-cdk/test/util/mock-toolkitinfo.ts +++ b/packages/aws-cdk/test/util/mock-toolkitinfo.ts @@ -1,4 +1,4 @@ -import { ISDK, ToolkitInfo } from '../../lib'; +import { ISDK, ToolkitInfo } from '../../lib/api'; import { CloudFormationStack } from '../../lib/api/util/cloudformation'; export interface MockToolkitInfoProps { diff --git a/packages/aws-cdk/test/version.test.ts b/packages/aws-cdk/test/version.test.ts index 49ddb4b12aa8d..01b120c463a6b 100644 --- a/packages/aws-cdk/test/version.test.ts +++ b/packages/aws-cdk/test/version.test.ts @@ -6,6 +6,8 @@ import * as sinon from 'sinon'; import * as logging from '../lib/logging'; import { latestVersionIfHigher, VersionCheckTTL, displayVersionMessage } from '../lib/version'; +jest.setTimeout(10_000); + const setTimeout = promisify(_setTimeout); function tmpfile(): string { diff --git a/packages/awslint/.eslintrc.js b/packages/awslint/.eslintrc.js index 61dd8dd001f63..941ceb58503ad 100644 --- a/packages/awslint/.eslintrc.js +++ b/packages/awslint/.eslintrc.js @@ -1,3 +1,202 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); -baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; -module.exports = baseConfig; +// This cannot reference the build rules from cdk-build-tools as this +// package is itself used by cdk-build-tools. +module.exports = { + env: { + jest: true, + node: true, + }, + plugins: [ + '@typescript-eslint', + 'import', + 'cdk', + 'jest', + ], + parser: '@typescript-eslint/parser', + parserOptions: { + ecmaVersion: '2018', + sourceType: 'module', + project: './tsconfig.json', + }, + extends: [ + 'plugin:import/typescript', + 'plugin:jest/recommended', + ], + settings: { + 'import/parsers': { + '@typescript-eslint/parser': ['.ts', '.tsx'], + }, + 'import/resolver': { + node: {}, + typescript: { + directory: './tsconfig.json', + }, + }, + }, + ignorePatterns: ['*.js', '*.d.ts', 'node_modules/', '*.generated.ts'], + rules: { + 'cdk/construct-import-order': [ 'error' ], + 'cdk/no-core-construct': [ 'error' ], + 'cdk/no-qualified-construct': [ 'error' ], + // Require use of the `import { foo } from 'bar';` form instead of `import foo = require('bar');` + '@typescript-eslint/no-require-imports': ['error'], + '@typescript-eslint/indent': ['error', 2], + + // Style + 'quotes': ['error', 'single', { avoidEscape: true }], + 'comma-dangle': ['error', 'always-multiline'], // ensures clean diffs, see https://medium.com/@nikgraf/why-you-should-enforce-dangling-commas-for-multiline-statements-d034c98e36f8 + 'comma-spacing': ['error', { before: false, after: true }], // space after, no space before + 'no-multi-spaces': ['error', { ignoreEOLComments: false }], // no multi spaces + 'array-bracket-spacing': ['error', 'never'], // [1, 2, 3] + 'array-bracket-newline': ['error', 'consistent'], // enforce consistent line breaks between brackets + 'object-curly-spacing': ['error', 'always'], // { key: 'value' } + 'object-curly-newline': ['error', { multiline: true, consistent: true }], // enforce consistent line breaks between braces + 'object-property-newline': ['error', { allowAllPropertiesOnSameLine: true }], // enforce "same line" or "multiple line" on object properties + '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': [ + 'error', + { + devDependencies: [ // Only allow importing devDependencies from: + '**/build-tools/**', // --> Build tools + '**/test/**', // --> Unit tests + ], + optionalDependencies: false, // Disallow importing optional dependencies (those shouldn't be in use in the project) + peerDependencies: false, // Disallow importing peer dependencies (that aren't also direct dependencies) + }, + ], + + // Require all imported libraries actually resolve (!!required for import/no-extraneous-dependencies to work!!) + 'import/no-unresolved': ['error'], + + // Require an ordering on all imports -- unfortunately a different ordering than TSLint used to + // enforce, but there are no compatible ESLint rules as far as I can tell :( + // + // WARNING for now, otherwise this will mess up all open PRs. Make it into an error after a transitionary period. + 'import/order': ['warn', { + groups: ['builtin', 'external'], + alphabetize: { order: 'asc', caseInsensitive: true }, + }], + + // disallow import of deprecated punycode package + 'no-restricted-imports': [ + 'error', { + paths: [ + { + name: 'punycode', + message: `Package 'punycode' has to be imported with trailing slash, see warning in https://github.com/bestiejs/punycode.js#installation`, + }, + ], + patterns: ['!punycode/'], + }, + ], + + // Cannot import from the same module twice + 'no-duplicate-imports': ['error'], + + // Cannot shadow names + 'no-shadow': ['off'], + '@typescript-eslint/no-shadow': ['error'], + + // Required spacing in property declarations (copied from TSLint, defaults are good) + 'key-spacing': ['error'], + + // Require semicolons + 'semi': ['error', 'always'], + + // Don't unnecessarily quote properties + 'quote-props': ['error', 'consistent-as-needed'], + + // No multiple empty lines + 'no-multiple-empty-lines': ['error'], + + // Max line lengths + 'max-len': ['error', { + code: 150, + ignoreUrls: true, // Most common reason to disable it + ignoreStrings: true, // These are not fantastic but necessary for error messages + ignoreTemplateLiterals: true, + ignoreComments: true, + ignoreRegExpLiterals: true, + }], + + // 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'], + + // Useless diff results + 'no-trailing-spaces': ['error'], + + // Must use foo.bar instead of foo['bar'] if possible + 'dot-notation': ['error'], + + // Must use 'import' statements (disabled because it doesn't add a lot over no-require-imports) + // '@typescript-eslint/no-var-requires': ['error'], + + // Are you sure | is not a typo for || ? + 'no-bitwise': ['error'], + + // Oh ho ho naming. Everyone's favorite topic! + // FIXME: there's no way to do this properly. The proposed tslint replacement + // works very differently, also checking names in object literals, which we use all over the + // place for configs, mockfs, nodeunit tests, etc. + // + // The maintainer does not want to change behavior. + // https://github.com/typescript-eslint/typescript-eslint/issues/1483 + // + // There is no good replacement for tslint's name checking, currently. We will have to make do + // with jsii's validation. + /* + '@typescript-eslint/naming-convention': ['error', + + // We could maybe be more specific in a number of these but I didn't want to + // spend too much effort. Knock yourself out if you feel like it. + { selector: 'enumMember', format: ['PascalCase', 'UPPER_CASE'] }, + { selector: 'variableLike', format: ['camelCase', 'UPPER_CASE'], leadingUnderscore: 'allow' }, + { selector: 'typeLike', format: ['PascalCase'], leadingUnderscore: 'allow' }, + { selector: 'memberLike', format: ['camelCase', 'PascalCase', 'UPPER_CASE'], leadingUnderscore: 'allow' }, + + // FIXME: there's no way to disable name checking in object literals. Maintainer won't have it + // https://github.com/typescript-eslint/typescript-eslint/issues/1483 + ], + */ + + // Member ordering + '@typescript-eslint/member-ordering': ['error', { + default: [ + 'public-static-field', + 'public-static-method', + 'protected-static-field', + 'protected-static-method', + 'private-static-field', + 'private-static-method', + + 'field', + + // Constructors + 'constructor', // = ["public-constructor", "protected-constructor", "private-constructor"] + + // Methods + 'method', + ], + }], + + // Overrides for plugin:jest/recommended + "jest/expect-expect": "off", + "jest/no-conditional-expect": "off", + "jest/no-done-callback": "off", // Far too many of these in the codebase. + "jest/no-standalone-expect": "off", // nodeunitShim confuses this check. + "jest/valid-expect": "off", // expect from '@aws-cdk/assert' can take a second argument + "jest/valid-title": "off", // A little over-zealous with test('test foo') being an error. + }, +}; diff --git a/packages/awslint/lib/rules/docs.ts b/packages/awslint/lib/rules/docs.ts index fda92170bd80a..8c5107d8450ac 100644 --- a/packages/awslint/lib/rules/docs.ts +++ b/packages/awslint/lib/rules/docs.ts @@ -1,3 +1,4 @@ +import { Stability } from '@jsii/spec'; import * as reflect from 'jsii-reflect'; import { Linter } from '../linter'; import { CoreTypes } from './core-types'; @@ -71,6 +72,21 @@ docsLinter.add({ }, }); +docsLinter.add({ + code: 'no-experimental-apis', + message: 'The use of @experimental in not allowed', + eval: e => { + if (!isPublic(e.ctx)) { return; } + // technically we should ban the use of @experimental in the codebase. Since jsii marks all symbols + // of experimental modules as experimental we can't. + if (isModuleExperimental(e.ctx.assembly)) { + return; + } + const sym = e.ctx.documentable; + e.assert(sym.docs.docs.stability !== Stability.Experimental, e.ctx.errorKey); + }, +}); + function isPublic(ctx: DocsLinterContext) { switch (ctx.kind) { case 'class-property': @@ -97,6 +113,10 @@ function isCfnType(ctx: DocsLinterContext) { } } +function isModuleExperimental(assembly: reflect.Assembly) { + return assembly.spec.docs?.stability === Stability.Experimental; +} + function flatMap(array: readonly T[], callbackfn: (value: T, index: number, array: readonly T[]) => U[]): U[] { return Array.prototype.concat(...array.map(callbackfn)); } diff --git a/packages/awslint/package.json b/packages/awslint/package.json index 892c71823bed0..c0e95b9f90d12 100644 --- a/packages/awslint/package.json +++ b/packages/awslint/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "description": "Enforces the AWS Construct Library guidelines", "scripts": { - "build": "tsc -b && npm run lint && chmod +x bin/awslint", + "build": "tsc -b && eslint . --ext=.ts && pkglint && chmod +x bin/awslint", "lint": "eslint . --ext=.ts && pkglint", "test": "echo ok", "watch": "tsc -b -w", @@ -16,18 +16,28 @@ "awslint": "bin/awslint" }, "dependencies": { - "@jsii/spec": "^1.25.0", + "@jsii/spec": "^1.29.0", "camelcase": "^6.2.0", "colors": "^1.4.0", "fs-extra": "^9.1.0", - "jsii-reflect": "^1.25.0", + "jsii-reflect": "^1.29.0", "yargs": "^16.2.0" }, "devDependencies": { "@types/fs-extra": "^8.1.1", + "@types/jest": "^26.0.23", "@types/yargs": "^15.0.13", "pkglint": "0.0.0", - "typescript": "~3.9.9" + "typescript": "~3.9.9", + "@typescript-eslint/eslint-plugin": "^4.22.1", + "@typescript-eslint/parser": "^4.22.1", + "eslint": "^7.25.0", + "eslint-import-resolver-node": "^0.3.4", + "eslint-import-resolver-typescript": "^2.4.0", + "eslint-plugin-cdk": "0.0.0", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-jest": "^24.3.6", + "jest": "^26.6.3" }, "repository": { "type": "git", @@ -50,6 +60,9 @@ "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, + "nozem": { + "ostools": ["chmod", "npm"] + }, "publishConfig": { "tag": "latest" } diff --git a/packages/cdk-assets/.gitignore b/packages/cdk-assets/.gitignore index 4a1600cd2eca0..d24092a6feda2 100644 --- a/packages/cdk-assets/.gitignore +++ b/packages/cdk-assets/.gitignore @@ -17,10 +17,12 @@ nyc.config.js !test/integ/run-wrappers/dist !test/integ/cli/**/* -.* assets.json npm-shrinkwrap.json !.eslintrc.js !jest.config.js -junit.xml \ No newline at end of file +junit.xml + +# Ignore this symlink, we recreate it at test time +test/test-archive-follow/data/linked diff --git a/packages/cdk-assets/package.json b/packages/cdk-assets/package.json index 6df6c69730a29..b5e1744e4be0e 100644 --- a/packages/cdk-assets/package.json +++ b/packages/cdk-assets/package.json @@ -32,15 +32,15 @@ "devDependencies": { "@types/archiver": "^5.1.0", "@types/glob": "^7.1.3", - "@types/jest": "^26.0.21", + "@types/jest": "^26.0.23", "@types/jszip": "^3.4.1", "@types/mock-fs": "^4.13.0", - "@types/node": "^10.17.55", + "@types/node": "^10.17.59", "@types/yargs": "^15.0.13", "cdk-build-tools": "0.0.0", "jest": "^26.6.3", "jszip": "^3.6.0", - "mock-fs": "^4.13.0", + "mock-fs": "^4.14.0", "pkglint": "0.0.0" }, "dependencies": { @@ -67,6 +67,9 @@ "cdk-package": { "shrinkWrap": true }, + "nozem": { + "ostools": ["unzip", "diff", "rm"] + }, "stability": "experimental", "maturity": "experimental", "publishConfig": { diff --git a/packages/cdk-assets/test/archive.test.ts b/packages/cdk-assets/test/archive.test.ts index afa8b87175b42..92245dc653494 100644 --- a/packages/cdk-assets/test/archive.test.ts +++ b/packages/cdk-assets/test/archive.test.ts @@ -1,6 +1,6 @@ import { exec as _exec } from 'child_process'; import * as crypto from 'crypto'; -import { constants, promises as fs } from 'fs'; +import { constants, exists, promises as fs } from 'fs'; import * as os from 'os'; import * as path from 'path'; import { promisify } from 'util'; @@ -8,6 +8,7 @@ import * as jszip from 'jszip'; import { zipDirectory } from '../lib/private/archive'; import { rmRfSync } from '../lib/private/fs-extra'; const exec = promisify(_exec); +const pathExists = promisify(exists); test('zipDirectory can take a directory and produce a zip from it', async () => { const stagingDir = await fs.mkdtemp(path.join(os.tmpdir(), 'test.archive')); @@ -59,6 +60,18 @@ test('zipDirectory follows symlinks', async () => { const stagingDir = await fs.mkdtemp(path.join(os.tmpdir(), 'test.archive')); const extractDir = await fs.mkdtemp(path.join(os.tmpdir(), 'test.archive.follow')); try { + // First MAKE the symlink we're going to follow. We can't check it into git, because + // CodeBuild/CodePipeline (I forget which) is going to replace symlinks with a textual + // representation of its target upon checkout, for security reasons. So, to make sure + // the symlink exists, we need to create it at build time. + const symlinkPath = path.join(__dirname, 'test-archive-follow', 'data', 'linked'); + const symlinkTarget = '../linked'; + + if (await pathExists(symlinkPath)) { + await fs.unlink(symlinkPath); + } + await fs.symlink(symlinkTarget, symlinkPath, 'dir'); + const originalDir = path.join(__dirname, 'test-archive-follow', 'data'); const zipFile = path.join(stagingDir, 'output.zip'); diff --git a/packages/cdk-assets/test/test-archive-follow/data/linked b/packages/cdk-assets/test/test-archive-follow/data/linked deleted file mode 120000 index c9365cd25131c..0000000000000 --- a/packages/cdk-assets/test/test-archive-follow/data/linked +++ /dev/null @@ -1 +0,0 @@ -../linked \ No newline at end of file diff --git a/packages/cdk-dasm/.gitignore b/packages/cdk-dasm/.gitignore index 88e6bb7a9196f..871afacdb4bbf 100644 --- a/packages/cdk-dasm/.gitignore +++ b/packages/cdk-dasm/.gitignore @@ -3,3 +3,4 @@ !deps.js test/fixture/.jsii cdk.schema.json +!jest.config.js \ No newline at end of file diff --git a/packages/cdk-dasm/package.json b/packages/cdk-dasm/package.json index 06785f7619185..eb248837815bc 100644 --- a/packages/cdk-dasm/package.json +++ b/packages/cdk-dasm/package.json @@ -26,18 +26,22 @@ }, "license": "Apache-2.0", "dependencies": { - "codemaker": "^1.25.0", + "codemaker": "^1.29.0", "yaml": "1.10.2" }, "devDependencies": { - "@types/jest": "^26.0.21", + "@types/jest": "^26.0.23", "@types/yaml": "1.9.7", - "jest": "^26.6.3" + "jest": "^26.6.3", + "typescript": "~3.9.9" }, "keywords": [ "aws", "cdk" ], + "nozem": { + "ostools": ["chmod"] + }, "homepage": "https://github.com/aws/aws-cdk", "engines": { "node": ">= 8.10.0" diff --git a/packages/decdk/package.json b/packages/decdk/package.json index 591d6165b33df..210bc6ee109db 100644 --- a/packages/decdk/package.json +++ b/packages/decdk/package.json @@ -39,6 +39,7 @@ "@aws-cdk/aws-apigatewayv2-integrations": "0.0.0", "@aws-cdk/aws-appconfig": "0.0.0", "@aws-cdk/aws-appflow": "0.0.0", + "@aws-cdk/aws-appintegrations": "0.0.0", "@aws-cdk/aws-applicationautoscaling": "0.0.0", "@aws-cdk/aws-applicationinsights": "0.0.0", "@aws-cdk/aws-appmesh": "0.0.0", @@ -77,6 +78,7 @@ "@aws-cdk/aws-codestarnotifications": "0.0.0", "@aws-cdk/aws-cognito": "0.0.0", "@aws-cdk/aws-config": "0.0.0", + "@aws-cdk/aws-customerprofiles": "0.0.0", "@aws-cdk/aws-databrew": "0.0.0", "@aws-cdk/aws-datapipeline": "0.0.0", "@aws-cdk/aws-datasync": "0.0.0", @@ -107,13 +109,16 @@ "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-events-targets": "0.0.0", "@aws-cdk/aws-eventschemas": "0.0.0", + "@aws-cdk/aws-fis": "0.0.0", "@aws-cdk/aws-fms": "0.0.0", "@aws-cdk/aws-fsx": "0.0.0", "@aws-cdk/aws-gamelift": "0.0.0", "@aws-cdk/aws-globalaccelerator": "0.0.0", + "@aws-cdk/aws-globalaccelerator-endpoints": "0.0.0", "@aws-cdk/aws-glue": "0.0.0", "@aws-cdk/aws-greengrass": "0.0.0", "@aws-cdk/aws-greengrassv2": "0.0.0", + "@aws-cdk/aws-groundstation": "0.0.0", "@aws-cdk/aws-guardduty": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-imagebuilder": "0.0.0", @@ -122,6 +127,7 @@ "@aws-cdk/aws-iot1click": "0.0.0", "@aws-cdk/aws-iotanalytics": "0.0.0", "@aws-cdk/aws-iotevents": "0.0.0", + "@aws-cdk/aws-iotfleethub": "0.0.0", "@aws-cdk/aws-iotsitewise": "0.0.0", "@aws-cdk/aws-iotthingsgraph": "0.0.0", "@aws-cdk/aws-iotwireless": "0.0.0", @@ -139,8 +145,10 @@ "@aws-cdk/aws-lambda-nodejs": "0.0.0", "@aws-cdk/aws-lambda-python": "0.0.0", "@aws-cdk/aws-licensemanager": "0.0.0", + "@aws-cdk/aws-lambda-go": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-logs-destinations": "0.0.0", + "@aws-cdk/aws-lookoutmetrics": "0.0.0", "@aws-cdk/aws-lookoutvision": "0.0.0", "@aws-cdk/aws-macie": "0.0.0", "@aws-cdk/aws-managedblockchain": "0.0.0", @@ -154,6 +162,7 @@ "@aws-cdk/aws-neptune": "0.0.0", "@aws-cdk/aws-networkfirewall": "0.0.0", "@aws-cdk/aws-networkmanager": "0.0.0", + "@aws-cdk/aws-nimblestudio": "0.0.0", "@aws-cdk/aws-opsworks": "0.0.0", "@aws-cdk/aws-opsworkscm": "0.0.0", "@aws-cdk/aws-pinpoint": "0.0.0", @@ -173,6 +182,7 @@ "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/aws-s3-deployment": "0.0.0", "@aws-cdk/aws-s3-notifications": "0.0.0", + "@aws-cdk/aws-s3objectlambda": "0.0.0", "@aws-cdk/aws-s3outposts": "0.0.0", "@aws-cdk/aws-sagemaker": "0.0.0", "@aws-cdk/aws-sam": "0.0.0", @@ -208,21 +218,20 @@ "@aws-cdk/lambda-layer-kubectl": "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.2.0", + "constructs": "^3.3.69", "fs-extra": "^9.1.0", - "jsii-reflect": "^1.25.0", + "jsii-reflect": "^1.29.0", "jsonschema": "^1.4.0", "yaml": "1.10.2", "yargs": "^16.2.0" }, "devDependencies": { "@types/fs-extra": "^8.1.1", - "@types/jest": "^26.0.21", + "@types/jest": "^26.0.23", "@types/yaml": "1.9.7", "@types/yargs": "^15.0.13", "jest": "^26.6.3", - "jsii": "^1.25.0" + "jsii": "^1.29.0" }, "keywords": [ "aws", diff --git a/packages/monocdk/package.json b/packages/monocdk/package.json index 2978fe7a2e8d0..0a5750d59db78 100644 --- a/packages/monocdk/package.json +++ b/packages/monocdk/package.json @@ -71,6 +71,11 @@ "python": { "distName": "monocdk", "module": "monocdk" + }, + "go": { + "moduleName": "github.com/aws/aws-cdk-go", + "packageName": "awscdk", + "versionSuffix": "-devpreview" } }, "projectReferences": false @@ -100,7 +105,7 @@ "jsonschema": "^1.4.0", "minimatch": "^3.0.4", "punycode": "^2.1.1", - "semver": "^7.3.4", + "semver": "^7.3.5", "yaml": "1.10.2" }, "devDependencies": { @@ -117,6 +122,7 @@ "@aws-cdk/aws-apigatewayv2-integrations": "0.0.0", "@aws-cdk/aws-appconfig": "0.0.0", "@aws-cdk/aws-appflow": "0.0.0", + "@aws-cdk/aws-appintegrations": "0.0.0", "@aws-cdk/aws-applicationautoscaling": "0.0.0", "@aws-cdk/aws-applicationinsights": "0.0.0", "@aws-cdk/aws-appmesh": "0.0.0", @@ -155,6 +161,7 @@ "@aws-cdk/aws-codestarnotifications": "0.0.0", "@aws-cdk/aws-cognito": "0.0.0", "@aws-cdk/aws-config": "0.0.0", + "@aws-cdk/aws-customerprofiles": "0.0.0", "@aws-cdk/aws-databrew": "0.0.0", "@aws-cdk/aws-datapipeline": "0.0.0", "@aws-cdk/aws-datasync": "0.0.0", @@ -186,13 +193,16 @@ "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-events-targets": "0.0.0", "@aws-cdk/aws-eventschemas": "0.0.0", + "@aws-cdk/aws-fis": "0.0.0", "@aws-cdk/aws-fms": "0.0.0", "@aws-cdk/aws-fsx": "0.0.0", "@aws-cdk/aws-gamelift": "0.0.0", "@aws-cdk/aws-globalaccelerator": "0.0.0", + "@aws-cdk/aws-globalaccelerator-endpoints": "0.0.0", "@aws-cdk/aws-glue": "0.0.0", "@aws-cdk/aws-greengrass": "0.0.0", "@aws-cdk/aws-greengrassv2": "0.0.0", + "@aws-cdk/aws-groundstation": "0.0.0", "@aws-cdk/aws-guardduty": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-imagebuilder": "0.0.0", @@ -201,6 +211,7 @@ "@aws-cdk/aws-iot1click": "0.0.0", "@aws-cdk/aws-iotanalytics": "0.0.0", "@aws-cdk/aws-iotevents": "0.0.0", + "@aws-cdk/aws-iotfleethub": "0.0.0", "@aws-cdk/aws-iotsitewise": "0.0.0", "@aws-cdk/aws-iotthingsgraph": "0.0.0", "@aws-cdk/aws-iotwireless": "0.0.0", @@ -216,10 +227,12 @@ "@aws-cdk/aws-lambda-destinations": "0.0.0", "@aws-cdk/aws-lambda-event-sources": "0.0.0", "@aws-cdk/aws-lambda-nodejs": "0.0.0", + "@aws-cdk/aws-lambda-go": "0.0.0", "@aws-cdk/aws-lambda-python": "0.0.0", "@aws-cdk/aws-licensemanager": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-logs-destinations": "0.0.0", + "@aws-cdk/aws-lookoutmetrics": "0.0.0", "@aws-cdk/aws-lookoutvision": "0.0.0", "@aws-cdk/aws-macie": "0.0.0", "@aws-cdk/aws-managedblockchain": "0.0.0", @@ -233,6 +246,7 @@ "@aws-cdk/aws-neptune": "0.0.0", "@aws-cdk/aws-networkfirewall": "0.0.0", "@aws-cdk/aws-networkmanager": "0.0.0", + "@aws-cdk/aws-nimblestudio": "0.0.0", "@aws-cdk/aws-opsworks": "0.0.0", "@aws-cdk/aws-opsworkscm": "0.0.0", "@aws-cdk/aws-pinpoint": "0.0.0", @@ -252,6 +266,7 @@ "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/aws-s3-deployment": "0.0.0", "@aws-cdk/aws-s3-notifications": "0.0.0", + "@aws-cdk/aws-s3objectlambda": "0.0.0", "@aws-cdk/aws-s3outposts": "0.0.0", "@aws-cdk/aws-sagemaker": "0.0.0", "@aws-cdk/aws-sam": "0.0.0", @@ -289,9 +304,9 @@ "@aws-cdk/region-info": "0.0.0", "@aws-cdk/yaml-cfn": "0.0.0", "@types/fs-extra": "^8.1.1", - "@types/node": "^10.17.55", + "@types/node": "^10.17.59", "cdk-build-tools": "0.0.0", - "constructs": "^3.2.0", + "constructs": "^3.3.69", "fs-extra": "^9.1.0", "pkglint": "0.0.0", "ts-node": "^9.1.1", @@ -299,7 +314,7 @@ "ubergen": "0.0.0" }, "peerDependencies": { - "constructs": "^3.2.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "engines": { @@ -309,6 +324,7 @@ "aws", "cdk" ], + "nozem": false, "awscdkio": { "announce": false }, diff --git a/packages/monocdk/rosetta/README-custom-resource-provider.ts-fixture b/packages/monocdk/rosetta/README-custom-resource-provider.ts-fixture new file mode 100644 index 0000000000000..ae4b1befd4b20 --- /dev/null +++ b/packages/monocdk/rosetta/README-custom-resource-provider.ts-fixture @@ -0,0 +1,18 @@ +import { CfnOutput, Construct, Token } from '@aws-cdk/core'; + +declare interface SumProps { + readonly lhs: number; + readonly rhs: number; +} +declare class Sum extends Construct { + public readonly result: number; + constructor(scope: Construct, id: string, props: SumProps); +} + +class fixture$construct extends Construct { + public constructor(scope: Construct, id: string) { + super(scope, id); + + /// here + } +} diff --git a/packages/monocdk/rosetta/client-vpn.ts-fixture b/packages/monocdk/rosetta/client-vpn.ts-fixture new file mode 100644 index 0000000000000..4886d590211df --- /dev/null +++ b/packages/monocdk/rosetta/client-vpn.ts-fixture @@ -0,0 +1,17 @@ +// Fixture with packages imported and a VPC created +import { Construct, Stack } from '@aws-cdk/core'; +import iam = require('@aws-cdk/aws-iam'); +import ec2 = require('@aws-cdk/aws-ec2'); + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + const vpc = new ec2.Vpc(this, 'VPC'); + const samlProvider = new iam.SamlProvider(this, 'Provider', { + metadataDocument: SamlMetadataDocument.fromXml('xml'), + }) + + /// here + } +} diff --git a/packages/monocdk/rosetta/conns.ts-fixture b/packages/monocdk/rosetta/conns.ts-fixture new file mode 100644 index 0000000000000..f29d9a1816a6e --- /dev/null +++ b/packages/monocdk/rosetta/conns.ts-fixture @@ -0,0 +1,26 @@ +// Fixture with fake connectables +import { Construct, Stack } from '@aws-cdk/core'; +import ec2 = require('@aws-cdk/aws-ec2'); + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + const vpc = new ec2.Vpc(this, 'VPC'); + + const loadBalancer = new FakeConnectable(); + const appFleet = new FakeConnectable(); + const dbFleet = new FakeConnectable(); + const rdsDatabase = new FakeConnectable(); + const fleet1 = new FakeConnectable(); + const fleet2 = new FakeConnectable(); + const listener = new FakeConnectable(); + const myEndpoint = new FakeConnectable(); + + /// here + } +} + +class FakeConnectable implements ec2.IConnectable { + public readonly connections = new ec2.Connections({ securityGroups: [] }); +} diff --git a/packages/monocdk/rosetta/default.ts-fixture b/packages/monocdk/rosetta/default.ts-fixture new file mode 100644 index 0000000000000..558cc09b1c049 --- /dev/null +++ b/packages/monocdk/rosetta/default.ts-fixture @@ -0,0 +1,65 @@ +import * as cfn from '@aws-cdk/aws-cloudformation'; +import * as customresources from '@aws-cdk/custom-resources'; +import * as iam from '@aws-cdk/aws-iam'; +import * as lambda from '@aws-cdk/aws-lambda'; +import * as sns from '@aws-cdk/aws-sns'; +import * as sqs from '@aws-cdk/aws-sqs'; +import * as s3 from '@aws-cdk/aws-s3'; +import { + App, + Aws, + CfnCondition, + CfnDynamicReference, + CfnDynamicReferenceService, + CfnInclude, + CfnJson, + CfnMapping, + CfnOutput, + CfnParameter, + CfnResource, + CfnResourceProps, + ConcreteDependable, + Construct, + CustomResource, + CustomResourceProvider, + CustomResourceProviderRuntime, + DependableTrait, + Duration, + Fn, + IConstruct, + SecretValue, + Size, + SizeRoundingBehavior, + Stack, + StackProps, + Stage, + Token, +} from '@aws-cdk/core'; + +declare const app: App; +declare const arn: 'arn:partition:service:region:account-id:resource-id'; +declare const cfnResource: CfnResource; +declare const construct: Construct; +declare const constructA: Construct; +declare const constructB: Construct; +declare const constructC: Construct; +declare const functionProps: lambda.FunctionProps; +declare const isCompleteHandler: lambda.Function; +declare const myBucket: s3.IBucket; +declare const myFunction: lambda.IFunction; +declare const myProvider: CustomResourceProvider; +declare const myTopic: sns.ITopic; +declare const onEventHandler: lambda.Function; +declare const resourceProps: CfnResourceProps; +declare const stack: Stack; + +declare class MyStack extends Stack {} +declare class YourStack extends Stack {} + +class fixture$construct extends Construct { + public constructor(scope: Construct, id: string) { + super(scope, id); + + /// here + } +} diff --git a/packages/monocdk/rosetta/with-batch-job.ts-fixture b/packages/monocdk/rosetta/with-batch-job.ts-fixture new file mode 100644 index 0000000000000..47672ba140841 --- /dev/null +++ b/packages/monocdk/rosetta/with-batch-job.ts-fixture @@ -0,0 +1,38 @@ +// Fixture with packages imported, but nothing else +import { Stack } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import * as tasks from '@aws-cdk/aws-stepfunctions-tasks'; +import * as batch from '@aws-cdk/aws-batch'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecs from '@aws-cdk/aws-ecs'; +import * as path from 'path'; + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + const vpc = ec2.Vpc.fromLookup(this, 'Vpc', { + isDefault: true, + }); + + const batchQueue = new batch.JobQueue(this, 'JobQueue', { + computeEnvironments: [ + { + order: 1, + computeEnvironment: new batch.ComputeEnvironment(this, 'ComputeEnv', { + computeResources: { vpc }, + }), + }, + ], + }); + + const batchJobDefinition = new batch.JobDefinition(this, 'JobDefinition', { + container: { + image: ecs.ContainerImage.fromAsset(path.resolve(__dirname, 'batchjob-image')), + }, + }); + + /// here + } +} diff --git a/packages/monocdk/rosetta/with-channel.ts-fixture b/packages/monocdk/rosetta/with-channel.ts-fixture new file mode 100644 index 0000000000000..44da118b81afa --- /dev/null +++ b/packages/monocdk/rosetta/with-channel.ts-fixture @@ -0,0 +1,15 @@ +// Fixture with packages imported, but nothing else +import { Duration, Stack } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import * as ivs from '@aws-cdk/aws-ivs'; + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + const myChannelArn = 'arn:aws:ivs:us-west-2:123456789012:channel/abcdABCDefgh'; + const myChannel = ivs.Channel.fromChannelArn(this, 'Channel', myChannelArn); + + /// here + } +} \ No newline at end of file diff --git a/packages/monocdk/rosetta/with-cluster.ts-fixture b/packages/monocdk/rosetta/with-cluster.ts-fixture new file mode 100644 index 0000000000000..c638d8b4d04fa --- /dev/null +++ b/packages/monocdk/rosetta/with-cluster.ts-fixture @@ -0,0 +1,19 @@ +import { Duration, Stack } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as neptune from '@aws-cdk/aws-neptune'; + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + const vpc = new ec2.Vpc(this, 'VPC', { maxAzs: 2 }); + + const cluster = new neptune.DatabaseCluster(this, 'Database', { + vpc, + instanceType: neptune.InstanceType.R5_LARGE, + }); + + /// here + } +} \ No newline at end of file diff --git a/packages/monocdk/rosetta/with-filesystem-instance.ts-fixture b/packages/monocdk/rosetta/with-filesystem-instance.ts-fixture new file mode 100644 index 0000000000000..092b572afa726 --- /dev/null +++ b/packages/monocdk/rosetta/with-filesystem-instance.ts-fixture @@ -0,0 +1,30 @@ +// Fixture with file system and an EC2 instance created in a VPC +import { Stack } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import * as efs from '@aws-cdk/aws-efs'; +import * as ec2 from '@aws-cdk/aws-ec2'; + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + const vpc = new ec2.Vpc(this, 'VPC'); + + const fileSystem = new efs.FileSystem(this, 'FileSystem', { + vpc, + }); + + const instance = new ec2.Instance(this, 'instance', { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.T2, ec2.InstanceSize.LARGE), + machineImage: new ec2.AmazonLinuxImage({ + generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2 + }), + vpc, + vpcSubnets: { + subnetType: ec2.SubnetType.PUBLIC, + } + }); + + /// here + } +} diff --git a/packages/monocdk/rosetta/with-lambda-trigger.ts-fixture b/packages/monocdk/rosetta/with-lambda-trigger.ts-fixture new file mode 100644 index 0000000000000..de9aa90eedfc2 --- /dev/null +++ b/packages/monocdk/rosetta/with-lambda-trigger.ts-fixture @@ -0,0 +1,26 @@ +// Fixture with packages imported, but nothing else +import { Stack } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import * as cognito from '@aws-cdk/aws-cognito'; +import * as iam from '@aws-cdk/aws-iam'; +import * as lambda from '@aws-cdk/aws-lambda'; + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + const postAuthFn = new lambda.Function(this, 'postAuthFn', { + code: lambda.Code.fromInline('post authentication'), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler', + }); + + const userpool = new cognito.UserPool(this, 'myuserpool', { + lambdaTriggers: { + postAuthentication: postAuthFn, + }, + }); + + /// here + } +} diff --git a/packages/monocdk/rosetta/with-vpc.ts-fixture b/packages/monocdk/rosetta/with-vpc.ts-fixture new file mode 100644 index 0000000000000..dd8e539f8cf9f --- /dev/null +++ b/packages/monocdk/rosetta/with-vpc.ts-fixture @@ -0,0 +1,13 @@ +// Fixture with packages imported and a VPC created +import { Construct, Stack } from '@aws-cdk/core'; +import ec2 = require('@aws-cdk/aws-ec2'); + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + const vpc = new ec2.Vpc(this, 'VPC'); + + /// here + } +} diff --git a/patches/@lerna+package-graph+4.0.0.patch b/patches/@lerna+package-graph+4.0.0.patch new file mode 100644 index 0000000000000..e1677faa27c88 --- /dev/null +++ b/patches/@lerna+package-graph+4.0.0.patch @@ -0,0 +1,23 @@ +diff --git a/node_modules/@lerna/package-graph/index.js b/node_modules/@lerna/package-graph/index.js +index 804aae0..72c22b9 100644 +--- a/node_modules/@lerna/package-graph/index.js ++++ b/node_modules/@lerna/package-graph/index.js +@@ -218,6 +218,8 @@ class PackageGraph extends Map { + /** @type {(PackageGraphNode | CyclicPackageGraphNode)[]} */ + const walkStack = []; + ++ const seen = new Set(); ++ + function visits(baseNode, dependentNode) { + if (nodeToCycle.has(baseNode)) { + return; +@@ -228,6 +230,9 @@ class PackageGraph extends Map { + topLevelDependent = nodeToCycle.get(topLevelDependent); + } + ++ if (seen.has(topLevelDependent)) { return; } ++ seen.add(topLevelDependent); ++ + if ( + topLevelDependent === baseNode || + (topLevelDependent.isCycle && topLevelDependent.has(baseNode.name)) diff --git a/patches/README.md b/patches/README.md new file mode 100644 index 0000000000000..64be828bc94d0 --- /dev/null +++ b/patches/README.md @@ -0,0 +1,43 @@ +# Vendored modules + +Only for build tools. + +## @lerna/package-graph + +A patched version of the module that drastically improves the time it takes to +check for cycles in the package dependency graph (5 minutes down to 1 second). + +Uses a cache to avoid checking the same node twice. Submitted upstream +as: https://github.com/lerna/lerna/pull/2874 + +Before: + +``` +$ time node_modules/.bin/lerna exec pwd +... +lerna success exec Executed command in 217 packages: "pwd" + 273.24 real 272.27 user 2.04 sys +``` + +After: + +``` +$ time node_modules/.bin/lerna exec pwd +... +lerna success exec Executed command in 219 packages: "pwd" + 1.11 real 0.99 user 0.82 sys +``` + +## jsii-rosetta+1.28.0.patch + +jsii-rosetta uses multiple worker threads by default to speed up sample extraction. +It defaults to spawning workers equal to half the number of cores. On extremely +powerful build machines (e.g., CodeBuild X2_LARGE compute with 72 vCPUs), +the high number of workers (36) results in thrash and high memory usage due to +duplicate loads of source files. This was causing the v2 builds to fail with: +"FATAL ERROR: NewSpace::Rebalance Allocation failed - JavaScript heap out of memory" + +The patch simply limits the top number of worker threads to an arbitrarily-chosen +maximum limit of 16. We could simply disable the worker threads, but this takes much +longer to process. With single-threading, rosetta takes ~35 minutes to extract samples +from the CDK; with 16 workers, it takes ~3.5 minutes. diff --git a/patches/jsii-rosetta+1.28.0.patch b/patches/jsii-rosetta+1.28.0.patch new file mode 100644 index 0000000000000..89dc133e267ca --- /dev/null +++ b/patches/jsii-rosetta+1.28.0.patch @@ -0,0 +1,14 @@ +diff --git a/node_modules/jsii-rosetta/lib/commands/extract.js b/node_modules/jsii-rosetta/lib/commands/extract.js +index e695ea9..539038e 100644 +--- a/node_modules/jsii-rosetta/lib/commands/extract.js ++++ b/node_modules/jsii-rosetta/lib/commands/extract.js +@@ -104,7 +104,8 @@ exports.singleThreadedTranslateAll = singleThreadedTranslateAll; + async function workerBasedTranslateAll(worker, snippets, includeCompilerDiagnostics) { + // Use about half the advertised cores because hyperthreading doesn't seem to help that + // much (on my machine, using more than half the cores actually makes it slower). +- const N = Math.max(1, Math.ceil(os.cpus().length / 2)); ++ // Cap to a reasonable top-level limit to prevent thrash on machines with many, many cores. ++ const N = Math.min(16, Math.max(1, Math.ceil(os.cpus().length / 2))); + const snippetArr = Array.from(snippets); + const groups = util_1.divideEvenly(N, snippetArr); + logging.info(`Translating ${snippetArr.length} snippets using ${groups.length} workers`); diff --git a/scripts/check-yarn-lock.js b/scripts/check-yarn-lock.js new file mode 100755 index 0000000000000..285128b3b18a6 --- /dev/null +++ b/scripts/check-yarn-lock.js @@ -0,0 +1,54 @@ +/** + * Yarn v1 doesn't repect --frozen-lockfile entirely when using yarn workspaces. + * The net effect is that if a dependency in one of our packages is not in the yarn.lock file, + * yarn will happily install any/latest version of that package, even when --frozen-lockfile + * is provided. + * + * This script manually verifies that all dependencies listed in our package.json files are + * present in yarn.lock, and will fail if not. + * + * See: + * https://github.com/yarnpkg/yarn/issues/4098 + * https://github.com/yarnpkg/yarn/issues/6291 + */ + +const fs = require('fs'); +const path = require('path'); +const { Project } = require("@lerna/project"); +const lockfileParser = require('@yarnpkg/lockfile'); + +function repoRoot() { + return path.join(__dirname, '..'); +} + +function yarnLockPackages() { + const yarnLockfile = fs.readFileSync(path.join(repoRoot(), 'yarn.lock'), 'utf8'); + const lockfileResult = lockfileParser.parse(yarnLockfile); + + if (lockfileResult.type !== 'success') { + throw new Error(`Error finding or parsing lockfile: ${lockfileResult.type}`); + } + + return new Set(Object.keys(lockfileResult.object)); +} + +async function main() { + const yarnPackages = yarnLockPackages(); + const projects = await new Project(repoRoot()).getPackages(); + + function errorIfNotInYarnLock(package, dependencyName, dependencyVersion) { + const dependencyId = `${dependencyName}@${dependencyVersion}`; + const isLocalDependency = dependencyVersion === '0.0.0' || dependencyVersion === '^0.0.0'; + if (!isLocalDependency && !yarnPackages.has(dependencyId)) { + throw new Error(`ERROR! Dependency ${dependencyId} from ${package.name} not present in yarn.lock. Please run yarn update and try again!`); + } + } + + projects.forEach((p) => { + Object.entries(p.devDependencies ?? {}).forEach(([depName, depVersion]) => errorIfNotInYarnLock(p, depName, depVersion)); + Object.entries(p.peerDependencies ?? {}).forEach(([depName, depVersion]) => errorIfNotInYarnLock(p, depName, depVersion)); + Object.entries(p.dependencies ?? {}).forEach(([depName, depVersion]) => errorIfNotInYarnLock(p, depName, depVersion)); + }); +} + +main(); diff --git a/scripts/list-deprecated-apis.js b/scripts/list-deprecated-apis.js new file mode 100755 index 0000000000000..284022b4825e1 --- /dev/null +++ b/scripts/list-deprecated-apis.js @@ -0,0 +1,53 @@ +#!/usr/bin/env node +const path = require('path'); + +const jsiiReflect = require('jsii-reflect'); + +async function main() { + const typesystem = new jsiiReflect.TypeSystem(); + // Decdk depends on everything, so that's a perfect directory to load as closure + await typesystem.loadNpmDependencies(path.resolve(__dirname, '..', 'packages', 'decdk'), { validate: false }); + + process.stdout.write(`# List of deprecated APIs in v1\n`); + process.stdout.write('\n'); + process.stdout.write(`| Module | API Element | Message |\n`); + process.stdout.write(`|--------|-------------|---------|\n`); + + for (const assembly of typesystem.assemblies) { + for (const type of assembly.types) { + printIfDeprecated(assembly.fqn, type.name, type); + + if (type.isEnumType()) { + type.members.forEach(e => printIfDeprecated(assembly.fqn, `${type.name}.${e.name}`, e)); + } + if (type.isInterfaceType() || type.isClassType() || type.isDataType()) { + type.ownProperties.forEach(p => printIfDeprecated(assembly.fqn, `${type.name}.${p.name}`, p)); + type.ownMethods.forEach(method => { + printIfDeprecated(assembly.fqn, `${type.name}.${method.name}()`, method); + method.parameters.forEach(p => printIfDeprecated(assembly.fqn, `${type.name}.${method.name}(): ${p.name}`, p)); + }); + } + } + } +} + +function printIfDeprecated(mod, name, el) { + try { + if (el.docs.deprecated) { + // Add zero-width spaces after . and _ to allow for line breaking long identifiers + // (WindowsVersion.WINDOWS_SERVER_2012_RTM_CHINESE_TRADITIONAL_HONG_KONG_SAR_64BIT_BASE is a fun one...) + const apiName = name.replace(/(\.|_)/g, '$1\u200B'); + + // Some deprecation reasons start with '- ' for misguided reasons. Get rid of it, and also get rid of newlines. + const reason = el.docs.deprecationReason.replace(/^-/, '').replace(/\n/g, ' ').trim(); + + process.stdout.write(`| ${mod} | ${apiName} | ${reason} |\n`); + } + } catch (e) { + console.error(`While processing ${mod}.${name}:`, e); + } +} + +main().catch(e => console.error(e)); + + diff --git a/tools/cdk-build-tools/.gitignore b/tools/cdk-build-tools/.gitignore index 19127ac2d8966..d4e9f37312ba3 100644 --- a/tools/cdk-build-tools/.gitignore +++ b/tools/cdk-build-tools/.gitignore @@ -5,4 +5,5 @@ dist *.snk !.eslintrc.js +!config/*.js junit.xml \ No newline at end of file diff --git a/tools/cdk-build-tools/bin/cdk-package.ts b/tools/cdk-build-tools/bin/cdk-package.ts index fd9a9aac2aa58..145d7967acb6d 100644 --- a/tools/cdk-build-tools/bin/cdk-package.ts +++ b/tools/cdk-build-tools/bin/cdk-package.ts @@ -3,6 +3,7 @@ import * as fs from 'fs-extra'; import * as yargs from 'yargs'; import * as yarnCling from 'yarn-cling'; import { shell } from '../lib/os'; +import { cdkPackageOptions, isJsii, isPrivate } from '../lib/package-info'; import { Timers } from '../lib/timer'; const timers = new Timers(); @@ -22,26 +23,26 @@ async function main() { }) .argv; - // if this is a jsii package, use jsii-packmak + const options = cdkPackageOptions(); + const outdir = 'dist'; - const pkg = await fs.readJson('package.json'); // if this is a private module, don't package - if (pkg.private) { + if (isPrivate()) { process.stdout.write('No packaging for private modules.\n'); return; } // If we need to shrinkwrap this, do so now. - const packageOptions = pkg['cdk-package'] ?? {}; - if (packageOptions.shrinkWrap) { + if (options.shrinkWrap) { await yarnCling.generateShrinkwrap({ packageJsonFile: 'package.json', outputFile: 'npm-shrinkwrap.json', }); } - if (pkg.jsii) { + // if this is a jsii package, use jsii-packmak + if (isJsii()) { const command = [args['jsii-pacmak'], args.verbose ? '-vvv' : '-v', ...args.targets ? flatMap(args.targets, (target: string) => ['-t', target]) : [], @@ -55,8 +56,13 @@ async function main() { await fs.mkdirp(target); await fs.move(tarball, path.join(target, path.basename(tarball))); } + + if (options.post) { + await shell(options.post, { timers }); + } } + main().then(() => { buildTimer.end(); process.stdout.write(`Package complete. ${timers.display()}\n`); diff --git a/tools/cdk-build-tools/bin/cdk-test.ts b/tools/cdk-build-tools/bin/cdk-test.ts index 5a9ad332568ef..4dead7e1675f9 100644 --- a/tools/cdk-build-tools/bin/cdk-test.ts +++ b/tools/cdk-build-tools/bin/cdk-test.ts @@ -56,7 +56,7 @@ async function main() { // that can only be a filename relative to '--cwd', but if we set '--cwd' // nyc doesn't find the source files anymore. // - // We end up symlinking nyc.config.js into the package. + // We end up copying nyc.config.js into the package. const nycConfig = 'nyc.config.js'; // Delete file if it exists @@ -66,7 +66,7 @@ async function main() { if (e.code !== 'ENOENT') { return; } } - await fs.ensureSymlink(configFilePath('nyc.config.js'), nycConfig); + await fs.copyFile(configFilePath('nyc.config.js'), nycConfig); testCommand.push(...[args.nyc, '--clean']); testCommand.push(args.nodeunit); diff --git a/tools/cdk-build-tools/config/.gitignore b/tools/cdk-build-tools/config/.gitignore deleted file mode 100644 index d4aa116a26c73..0000000000000 --- a/tools/cdk-build-tools/config/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!*.js diff --git a/tools/cdk-build-tools/config/eslintrc.js b/tools/cdk-build-tools/config/eslintrc.js index 8fda93acca482..dd70c99416cd3 100644 --- a/tools/cdk-build-tools/config/eslintrc.js +++ b/tools/cdk-build-tools/config/eslintrc.js @@ -205,5 +205,6 @@ module.exports = { "jest/no-standalone-expect": "off", // nodeunitShim confuses this check. "jest/valid-expect": "off", // expect from '@aws-cdk/assert' can take a second argument "jest/valid-title": "off", // A little over-zealous with test('test foo') being an error. + "jest/no-identical-title": "off", // TEMPORARY - Disabling this until https://github.com/jest-community/eslint-plugin-jest/issues/836 is resolved }, }; diff --git a/tools/cdk-build-tools/config/jest.config.js b/tools/cdk-build-tools/config/jest.config.js index a71d55e8d0089..b8e056af3c8a3 100644 --- a/tools/cdk-build-tools/config/jest.config.js +++ b/tools/cdk-build-tools/config/jest.config.js @@ -3,7 +3,7 @@ module.exports = { "js", ], testMatch: [ - "**/?(*.)+(test).js", + "/test/**/?(*.)+(test).js", ], testEnvironment: "node", coverageThreshold: { diff --git a/tools/cdk-build-tools/lib/compile.ts b/tools/cdk-build-tools/lib/compile.ts index fe63d0c8f346e..173fea93685b5 100644 --- a/tools/cdk-build-tools/lib/compile.ts +++ b/tools/cdk-build-tools/lib/compile.ts @@ -7,7 +7,7 @@ import { Timers } from './timer'; */ export async function compileCurrentPackage(options: CDKBuildOptions, timers: Timers, compilers: CompilerOverrides = {}): Promise { const env = options.env; - await shell(packageCompiler(compilers), { timers, env }); + await shell(packageCompiler(compilers, options), { timers, env }); // Find files in bin/ that look like they should be executable, and make them so. const scripts = currentPackageJson().bin || {}; diff --git a/tools/cdk-build-tools/lib/package-info.ts b/tools/cdk-build-tools/lib/package-info.ts index 9e12b86b80580..2ed8abff6171b 100644 --- a/tools/cdk-build-tools/lib/package-info.ts +++ b/tools/cdk-build-tools/lib/package-info.ts @@ -24,6 +24,13 @@ export function cdkBuildOptions(): CDKBuildOptions { return currentPackageJson()['cdk-build'] || {}; } +/** + * Return the cdk-package options + */ +export function cdkPackageOptions(): CDKPackageOptions { + return currentPackageJson()['cdk-package'] || {}; +} + /** * Whether this is a jsii package */ @@ -31,6 +38,13 @@ export function isJsii(): boolean { return currentPackageJson().jsii !== undefined; } +/** + * Whether this is a private package + */ +export function isPrivate(): boolean { + return currentPackageJson().private !== undefined; +} + export interface File { filename: string; path: string; @@ -81,9 +95,13 @@ export interface CompilerOverrides { /** * Return the compiler for this package (either tsc or jsii) */ -export function packageCompiler(compilers: CompilerOverrides): string[] { +export function packageCompiler(compilers: CompilerOverrides, options?: CDKBuildOptions): string[] { if (isJsii()) { - return [compilers.jsii || require.resolve('jsii/bin/jsii'), '--silence-warnings=reserved-word']; + const args = ['--silence-warnings=reserved-word']; + if (options?.stripDeprecated) { + args.push('--strip-deprecated'); + } + return [compilers.jsii || require.resolve('jsii/bin/jsii'), ...args]; } else { return [compilers.tsc || require.resolve('typescript/bin/tsc'), '--build']; } @@ -148,6 +166,24 @@ export interface CDKBuildOptions { * Environment variables to be passed to 'cdk-build' and all of its child processes. */ env?: NodeJS.ProcessEnv; + + /** + * Whether deprecated symbols should be stripped from the jsii assembly and typescript declaration files. + * @see https://aws.github.io/jsii/user-guides/lib-author/toolchain/jsii/#-strip-deprecated + */ + stripDeprecated?: boolean; +} + +export interface CDKPackageOptions { + /** + * Should this package be shrinkwrap + */ + shrinkWrap?: boolean; + + /* + * An optional command (formatted as a list of strings) to run after packaging + */ + post?: string[]; } /** diff --git a/tools/cdk-build-tools/package.json b/tools/cdk-build-tools/package.json index 6d64a070e9afc..ba0af73cb118f 100644 --- a/tools/cdk-build-tools/package.json +++ b/tools/cdk-build-tools/package.json @@ -34,30 +34,33 @@ "license": "Apache-2.0", "devDependencies": { "@types/fs-extra": "^8.1.1", - "@types/jest": "^26.0.21", + "@types/jest": "^26.0.23", "@types/yargs": "^15.0.13", + "@types/semver": "^7.3.5", "pkglint": "0.0.0" }, "dependencies": { - "@typescript-eslint/eslint-plugin": "^4.18.0", - "@typescript-eslint/parser": "^4.18.0", + "@typescript-eslint/eslint-plugin": "^4.22.1", + "@typescript-eslint/parser": "^4.22.1", "awslint": "0.0.0", "colors": "^1.4.0", - "eslint": "^7.22.0", + "eslint": "^7.25.0", "eslint-import-resolver-node": "^0.3.4", "eslint-import-resolver-typescript": "^2.4.0", "eslint-plugin-cdk": "0.0.0", "eslint-plugin-import": "^2.22.1", - "eslint-plugin-jest": "^24.3.2", + "eslint-plugin-jest": "^24.3.6", "fs-extra": "^9.1.0", "jest": "^26.6.3", - "jsii": "^1.25.0", - "jsii-pacmak": "^1.25.0", + "jest-junit": "^11.1.0", + "jsii": "^1.29.0", + "jsii-pacmak": "^1.29.0", + "jsii-reflect": "^1.29.0", "markdownlint-cli": "^0.27.1", "nodeunit": "^0.11.3", "nyc": "^15.1.0", - "semver": "^7.3.4", - "ts-jest": "^26.5.4", + "semver": "^7.3.5", + "ts-jest": "^26.5.5", "typescript": "~3.9.9", "yargs": "^16.2.0", "yarn-cling": "0.0.0" @@ -70,6 +73,9 @@ "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, + "nozem": { + "ostools": ["chmod"] + }, "ubergen": { "exclude": true } diff --git a/tools/cdk-build-tools/tsconfig.json b/tools/cdk-build-tools/tsconfig.json index f6b1789bd46ad..6b870d2cb95a2 100644 --- a/tools/cdk-build-tools/tsconfig.json +++ b/tools/cdk-build-tools/tsconfig.json @@ -13,7 +13,7 @@ "noFallthroughCasesInSwitch": true, "resolveJsonModule": true, "composite": true, - "incremental": true, + "incremental": true }, "include": ["**/*.ts"] } diff --git a/tools/cdk-integ-tools/bin/cdk-integ-assert.ts b/tools/cdk-integ-tools/bin/cdk-integ-assert.ts index 2fd262a933792..3c5cb049cf0d0 100644 --- a/tools/cdk-integ-tools/bin/cdk-integ-assert.ts +++ b/tools/cdk-integ-tools/bin/cdk-integ-assert.ts @@ -1,6 +1,6 @@ #!/usr/bin/env node // Verify that all integration tests still match their expected output -import { canonicalizeTemplate } from '@aws-cdk/assert'; +import { canonicalizeTemplate } from '@aws-cdk/assert-internal'; import { diffTemplate, formatDifferences } from '@aws-cdk/cloudformation-diff'; import { DEFAULT_SYNTH_OPTIONS, IntegrationTests } from '../lib/integ-helpers'; diff --git a/tools/cdk-integ-tools/lib/integ-helpers.ts b/tools/cdk-integ-tools/lib/integ-helpers.ts index bf65e8cbb8b9a..5aabc99210663 100644 --- a/tools/cdk-integ-tools/lib/integ-helpers.ts +++ b/tools/cdk-integ-tools/lib/integ-helpers.ts @@ -1,9 +1,8 @@ // Helper functions for integration tests import { spawnSync } from 'child_process'; import * as path from 'path'; -import { FUTURE_FLAGS } from '@aws-cdk/cx-api'; +import { AVAILABILITY_ZONE_FALLBACK_CONTEXT_KEY, FUTURE_FLAGS } from '@aws-cdk/cx-api'; import * as fs from 'fs-extra'; -import { AVAILABILITY_ZONE_FALLBACK_CONTEXT_KEY } from '../../../packages/@aws-cdk/cx-api/lib'; const CDK_OUTDIR = 'cdk-integ.out'; diff --git a/tools/cdk-integ-tools/package.json b/tools/cdk-integ-tools/package.json index bb9fbacb970b0..4526dcb65e6b2 100644 --- a/tools/cdk-integ-tools/package.json +++ b/tools/cdk-integ-tools/package.json @@ -37,7 +37,7 @@ "dependencies": { "@aws-cdk/cloudformation-diff": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "@aws-cdk/assert": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0", "aws-cdk": "0.0.0", "fs-extra": "^9.1.0", "yargs": "^16.2.0" @@ -51,7 +51,7 @@ "node": ">= 10.13.0 <13 || >=13.7.0" }, "peerDependencies": { - "@aws-cdk/assert": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0" }, "ubergen": { "exclude": true diff --git a/tools/cfn2ts/lib/codegen.ts b/tools/cfn2ts/lib/codegen.ts index c06fce32e10ff..f952bb34a832e 100644 --- a/tools/cfn2ts/lib/codegen.ts +++ b/tools/cfn2ts/lib/codegen.ts @@ -439,7 +439,6 @@ export default class CodeGenerator { this.code.line(' *'); this.code.line(' * @param inspector - tree inspector to collect and process attributes'); this.code.line(' *'); - this.code.line(' * @stability experimental'); this.code.line(' */'); this.code.openBlock(`public inspect(inspector: ${CORE}.TreeInspector)`); this.code.line(`inspector.addAttribute("${TreeAttributes.CFN_TYPE}", ${resource.className}.CFN_RESOURCE_TYPE_NAME);`); diff --git a/tools/cfn2ts/package.json b/tools/cfn2ts/package.json index 355b6ea897edb..b487b3f04c021 100644 --- a/tools/cfn2ts/package.json +++ b/tools/cfn2ts/package.json @@ -30,14 +30,14 @@ "license": "Apache-2.0", "dependencies": { "@aws-cdk/cfnspec": "0.0.0", - "codemaker": "^1.25.0", + "codemaker": "^1.29.0", "fast-json-patch": "^3.0.0-1", "fs-extra": "^9.1.0", "yargs": "^16.2.0" }, "devDependencies": { "@types/fs-extra": "^8.1.1", - "@types/jest": "^26.0.21", + "@types/jest": "^26.0.23", "@types/yargs": "^15.0.13", "cdk-build-tools": "0.0.0", "jest": "^26.6.3", diff --git a/tools/eslint-plugin-cdk/package.json b/tools/eslint-plugin-cdk/package.json index 490c8d98229c1..bf221962cbf2f 100644 --- a/tools/eslint-plugin-cdk/package.json +++ b/tools/eslint-plugin-cdk/package.json @@ -12,17 +12,17 @@ "build+test": "npm run build && npm test" }, "devDependencies": { - "@types/eslint": "^7.2.7", + "@types/eslint": "^7.2.10", "@types/fs-extra": "^8.1.1", - "@types/jest": "^26.0.21", - "@types/node": "^10.17.55", + "@types/jest": "^26.0.23", + "@types/node": "^10.17.59", "eslint-plugin-rulesdir": "^0.2.0", "jest": "^26.6.3", "typescript": "~3.9.9" }, "dependencies": { - "@typescript-eslint/parser": "^4.18.0", - "eslint": "^7.22.0", + "@typescript-eslint/parser": "^4.22.1", + "eslint": "^7.25.0", "fs-extra": "^9.1.0" }, "jest": { diff --git a/tools/nodeunit-shim/package.json b/tools/nodeunit-shim/package.json index c576c1271a271..63c784d19321c 100644 --- a/tools/nodeunit-shim/package.json +++ b/tools/nodeunit-shim/package.json @@ -12,8 +12,8 @@ "build+test": "npm run build && npm test" }, "devDependencies": { - "@types/jest": "^26.0.21", - "@types/node": "^10.17.55", + "@types/jest": "^26.0.23", + "@types/node": "^10.17.59", "typescript": "~3.9.9" }, "dependencies": { diff --git a/tools/pkglint/.eslintrc.js b/tools/pkglint/.eslintrc.js index 61dd8dd001f63..941ceb58503ad 100644 --- a/tools/pkglint/.eslintrc.js +++ b/tools/pkglint/.eslintrc.js @@ -1,3 +1,202 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); -baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; -module.exports = baseConfig; +// This cannot reference the build rules from cdk-build-tools as this +// package is itself used by cdk-build-tools. +module.exports = { + env: { + jest: true, + node: true, + }, + plugins: [ + '@typescript-eslint', + 'import', + 'cdk', + 'jest', + ], + parser: '@typescript-eslint/parser', + parserOptions: { + ecmaVersion: '2018', + sourceType: 'module', + project: './tsconfig.json', + }, + extends: [ + 'plugin:import/typescript', + 'plugin:jest/recommended', + ], + settings: { + 'import/parsers': { + '@typescript-eslint/parser': ['.ts', '.tsx'], + }, + 'import/resolver': { + node: {}, + typescript: { + directory: './tsconfig.json', + }, + }, + }, + ignorePatterns: ['*.js', '*.d.ts', 'node_modules/', '*.generated.ts'], + rules: { + 'cdk/construct-import-order': [ 'error' ], + 'cdk/no-core-construct': [ 'error' ], + 'cdk/no-qualified-construct': [ 'error' ], + // Require use of the `import { foo } from 'bar';` form instead of `import foo = require('bar');` + '@typescript-eslint/no-require-imports': ['error'], + '@typescript-eslint/indent': ['error', 2], + + // Style + 'quotes': ['error', 'single', { avoidEscape: true }], + 'comma-dangle': ['error', 'always-multiline'], // ensures clean diffs, see https://medium.com/@nikgraf/why-you-should-enforce-dangling-commas-for-multiline-statements-d034c98e36f8 + 'comma-spacing': ['error', { before: false, after: true }], // space after, no space before + 'no-multi-spaces': ['error', { ignoreEOLComments: false }], // no multi spaces + 'array-bracket-spacing': ['error', 'never'], // [1, 2, 3] + 'array-bracket-newline': ['error', 'consistent'], // enforce consistent line breaks between brackets + 'object-curly-spacing': ['error', 'always'], // { key: 'value' } + 'object-curly-newline': ['error', { multiline: true, consistent: true }], // enforce consistent line breaks between braces + 'object-property-newline': ['error', { allowAllPropertiesOnSameLine: true }], // enforce "same line" or "multiple line" on object properties + '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': [ + 'error', + { + devDependencies: [ // Only allow importing devDependencies from: + '**/build-tools/**', // --> Build tools + '**/test/**', // --> Unit tests + ], + optionalDependencies: false, // Disallow importing optional dependencies (those shouldn't be in use in the project) + peerDependencies: false, // Disallow importing peer dependencies (that aren't also direct dependencies) + }, + ], + + // Require all imported libraries actually resolve (!!required for import/no-extraneous-dependencies to work!!) + 'import/no-unresolved': ['error'], + + // Require an ordering on all imports -- unfortunately a different ordering than TSLint used to + // enforce, but there are no compatible ESLint rules as far as I can tell :( + // + // WARNING for now, otherwise this will mess up all open PRs. Make it into an error after a transitionary period. + 'import/order': ['warn', { + groups: ['builtin', 'external'], + alphabetize: { order: 'asc', caseInsensitive: true }, + }], + + // disallow import of deprecated punycode package + 'no-restricted-imports': [ + 'error', { + paths: [ + { + name: 'punycode', + message: `Package 'punycode' has to be imported with trailing slash, see warning in https://github.com/bestiejs/punycode.js#installation`, + }, + ], + patterns: ['!punycode/'], + }, + ], + + // Cannot import from the same module twice + 'no-duplicate-imports': ['error'], + + // Cannot shadow names + 'no-shadow': ['off'], + '@typescript-eslint/no-shadow': ['error'], + + // Required spacing in property declarations (copied from TSLint, defaults are good) + 'key-spacing': ['error'], + + // Require semicolons + 'semi': ['error', 'always'], + + // Don't unnecessarily quote properties + 'quote-props': ['error', 'consistent-as-needed'], + + // No multiple empty lines + 'no-multiple-empty-lines': ['error'], + + // Max line lengths + 'max-len': ['error', { + code: 150, + ignoreUrls: true, // Most common reason to disable it + ignoreStrings: true, // These are not fantastic but necessary for error messages + ignoreTemplateLiterals: true, + ignoreComments: true, + ignoreRegExpLiterals: true, + }], + + // 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'], + + // Useless diff results + 'no-trailing-spaces': ['error'], + + // Must use foo.bar instead of foo['bar'] if possible + 'dot-notation': ['error'], + + // Must use 'import' statements (disabled because it doesn't add a lot over no-require-imports) + // '@typescript-eslint/no-var-requires': ['error'], + + // Are you sure | is not a typo for || ? + 'no-bitwise': ['error'], + + // Oh ho ho naming. Everyone's favorite topic! + // FIXME: there's no way to do this properly. The proposed tslint replacement + // works very differently, also checking names in object literals, which we use all over the + // place for configs, mockfs, nodeunit tests, etc. + // + // The maintainer does not want to change behavior. + // https://github.com/typescript-eslint/typescript-eslint/issues/1483 + // + // There is no good replacement for tslint's name checking, currently. We will have to make do + // with jsii's validation. + /* + '@typescript-eslint/naming-convention': ['error', + + // We could maybe be more specific in a number of these but I didn't want to + // spend too much effort. Knock yourself out if you feel like it. + { selector: 'enumMember', format: ['PascalCase', 'UPPER_CASE'] }, + { selector: 'variableLike', format: ['camelCase', 'UPPER_CASE'], leadingUnderscore: 'allow' }, + { selector: 'typeLike', format: ['PascalCase'], leadingUnderscore: 'allow' }, + { selector: 'memberLike', format: ['camelCase', 'PascalCase', 'UPPER_CASE'], leadingUnderscore: 'allow' }, + + // FIXME: there's no way to disable name checking in object literals. Maintainer won't have it + // https://github.com/typescript-eslint/typescript-eslint/issues/1483 + ], + */ + + // Member ordering + '@typescript-eslint/member-ordering': ['error', { + default: [ + 'public-static-field', + 'public-static-method', + 'protected-static-field', + 'protected-static-method', + 'private-static-field', + 'private-static-method', + + 'field', + + // Constructors + 'constructor', // = ["public-constructor", "protected-constructor", "private-constructor"] + + // Methods + 'method', + ], + }], + + // Overrides for plugin:jest/recommended + "jest/expect-expect": "off", + "jest/no-conditional-expect": "off", + "jest/no-done-callback": "off", // Far too many of these in the codebase. + "jest/no-standalone-expect": "off", // nodeunitShim confuses this check. + "jest/valid-expect": "off", // expect from '@aws-cdk/assert' can take a second argument + "jest/valid-title": "off", // A little over-zealous with test('test foo') being an error. + }, +}; diff --git a/tools/pkglint/lib/rules.ts b/tools/pkglint/lib/rules.ts index 1dd32c1c96392..9d047c14f9faf 100644 --- a/tools/pkglint/lib/rules.ts +++ b/tools/pkglint/lib/rules.ts @@ -16,6 +16,8 @@ import { const AWS_SERVICE_NAMES = require('./aws-service-official-names.json'); // eslint-disable-line @typescript-eslint/no-require-imports +const PKGLINT_VERSION = require('../package.json').version; // eslint-disable-line @typescript-eslint/no-require-imports + /** * Verify that the package name matches the directory name */ @@ -625,10 +627,11 @@ export class NoPeerDependenciesMonocdk extends ValidationRule { * Note: v1 and v2 use different versions respectively. */ export class ConstructsVersion extends ValidationRule { - public readonly name = 'deps/constructs'; - private readonly expectedRange = cdkMajorVersion() === 2 + public static readonly VERSION = cdkMajorVersion() === 2 ? '10.0.0-pre.5' - : '^3.2.0'; + : '^3.3.69'; + + public readonly name = 'deps/constructs'; public validate(pkg: PackageJson) { const toCheck = new Array(); @@ -644,7 +647,7 @@ export class ConstructsVersion extends ValidationRule { } for (const cfg of toCheck) { - expectJSON(this.name, pkg, `${cfg}.constructs`, this.expectedRange); + expectJSON(this.name, pkg, `${cfg}.constructs`, ConstructsVersion.VERSION); } } } @@ -926,10 +929,13 @@ export class MustDependOnBuildTools extends ValidationRule { public validate(pkg: PackageJson): void { if (!shouldUseCDKBuildTools(pkg)) { return; } + // We can't ACTUALLY require cdk-build-tools/package.json here, + // because WE don't depend on cdk-build-tools and we don't know if + // the package does. expectDevDependency(this.name, pkg, 'cdk-build-tools', - `${require('../../cdk-build-tools/package.json').version}`); // eslint-disable-line @typescript-eslint/no-require-imports + `${PKGLINT_VERSION}`); // eslint-disable-line @typescript-eslint/no-require-imports } } @@ -1000,14 +1006,13 @@ export class MustDependonCdkByPointVersions extends ValidationRule { // across the repo: in local builds, this should be 0.0.0 and in CI builds // this would be the actual version of the repo after it's been aligned // using scripts/align-version.sh - const expectedVersion = require('../../../package.json').version; // eslint-disable-line @typescript-eslint/no-require-imports + const expectedVersion = require(path.join(monoRepoRoot(), 'package.json')).version; // eslint-disable-line @typescript-eslint/no-require-imports const ignore = [ '@aws-cdk/cloudformation-diff', '@aws-cdk/cfnspec', '@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)) { @@ -1147,10 +1152,14 @@ export class MustHaveIntegCommand extends ValidationRule { if (!hasIntegTests(pkg)) { return; } expectJSON(this.name, pkg, 'scripts.integ', 'cdk-integ'); + + // We can't ACTUALLY require cdk-build-tools/package.json here, + // because WE don't depend on cdk-build-tools and we don't know if + // the package does. expectDevDependency(this.name, pkg, 'cdk-integ-tools', - `${require('../../cdk-integ-tools/package.json').version}`); // eslint-disable-line @typescript-eslint/no-require-imports + `${PKGLINT_VERSION}`); // eslint-disable-line @typescript-eslint/no-require-imports } } @@ -1173,7 +1182,7 @@ export class PkgLintAsScript extends ValidationRule { public validate(pkg: PackageJson): void { const script = 'pkglint -f'; - expectDevDependency(this.name, pkg, 'pkglint', `${require('../package.json').version}`); // eslint-disable-line @typescript-eslint/no-require-imports + expectDevDependency(this.name, pkg, 'pkglint', `${PKGLINT_VERSION}`); // eslint-disable-line @typescript-eslint/no-require-imports if (!pkg.npmScript('pkglint')) { pkg.report({ @@ -1321,8 +1330,7 @@ export class Cfn2Ts extends ValidationRule { /** * Packages inside JSII packages (typically used for embedding Lambda handles) - * must only have dev dependencies and their node_modules must have been - * blacklisted for publishing + * must only have dev dependencies and their node_modules must not be published. * * We might loosen this at some point but we'll have to bundle all runtime dependencies * and we don't have good transitive license checks. @@ -1339,7 +1347,7 @@ export class PackageInJsiiPackageNoRuntimeDeps extends ValidationRule { if (Object.keys(innerPkg.dependencies).length > 0) { pkg.report({ ruleName: `${this.name}:1`, - message: `NPM Package '${innerPkg.packageName}' inside jsii package can only have devDepencencies`, + message: `NPM Package '${innerPkg.packageName}' inside jsii package '${pkg.packageName}', can only have devDependencies`, }); } @@ -1377,7 +1385,7 @@ export class YarnNohoistBundledDependencies extends ValidationRule { const bundled: string[] = pkg.json.bundleDependencies || pkg.json.bundledDependencies || []; if (bundled.length === 0) { return; } - const repoPackageJson = path.resolve(__dirname, '../../../package.json'); + const repoPackageJson = path.resolve(monoRepoRoot(), 'package.json'); const nohoist: string[] = require(repoPackageJson).workspaces.nohoist; // eslint-disable-line @typescript-eslint/no-require-imports @@ -1407,7 +1415,7 @@ export class ConstructsDependency extends ValidationRule { public readonly name = 'constructs/dependency'; public validate(pkg: PackageJson) { - const REQUIRED_VERSION = '^3.2.0'; + const REQUIRED_VERSION = ConstructsVersion.VERSION;; if (pkg.devDependencies?.constructs && pkg.devDependencies?.constructs !== REQUIRED_VERSION) { pkg.report({ @@ -1441,6 +1449,28 @@ export class ConstructsDependency extends ValidationRule { } } +/** + * Packages must depend on 'assert-internal', not on '@aws-cdk/assert' + */ +export class AssertDependency extends ValidationRule { + public readonly name = 'assert/assert-dependency'; + + public validate(pkg: PackageJson) { + const devDeps = pkg.json.devDependencies ?? {}; + + if ('@aws-cdk/assert' in devDeps) { + pkg.report({ + ruleName: this.name, + message: 'Package should depend on \'@aws-cdk/assert-internal\', not on \'@aws-cdk/assert\'', + fix: () => { + pkg.json.devDependencies['@aws-cdk/assert-internal'] = pkg.json.devDependencies['@aws-cdk/assert']; + delete pkg.json.devDependencies['@aws-cdk/assert']; + }, + }); + } + } +} + /** * Do not announce new versions of AWS CDK modules in awscdk.io because it is very very spammy * and actually causes the @awscdkio twitter account to be blocked. @@ -1551,7 +1581,6 @@ export class UbergenPackageVisibility extends ValidationRule { '@aws-cdk/cloudformation-diff', '@aws-cdk/cx-api', '@aws-cdk/region-info', - '@aws-cdk/yaml-cfn', 'aws-cdk-lib', 'aws-cdk', 'awslint', @@ -1596,13 +1625,108 @@ export class UbergenPackageVisibility extends ValidationRule { } } +/** + * No experimental dependencies. + * In v2 all experimental modules will be released separately from aws-cdk-lib. This means that: + * 1. Stable modules can't depend on experimental modules as it will creates a cyclic dependency. + * 2. Experimental modules shouldn't depend on experimental modules as it will create a coupling between their graduation (cause of 1). + * 2 specify "shouldn't" as in some cases we might allow it (using the `excludedDependencies` map), but the default is to not allow it. + */ +export class NoExperimentalDependents extends ValidationRule { + public name = 'no-experimental-dependencies'; + + // experimental -> experimental dependencies that are allowed for now. + private readonly excludedDependencies = new Map([ + ['@aws-cdk/aws-secretsmanager', ['@aws-cdk/aws-sam']], + ['@aws-cdk/aws-kinesisanalytics-flink', ['@aws-cdk/aws-kinesisanalytics']], + ['@aws-cdk/aws-apigatewayv2-integrations', ['@aws-cdk/aws-apigatewayv2']], + ['@aws-cdk/aws-apigatewayv2-authorizers', ['@aws-cdk/aws-apigatewayv2']], + ['@aws-cdk/aws-events-targets', ['@aws-cdk/aws-kinesisfirehose']], + ]); + + private readonly excludedModules = ['@aws-cdk/cloudformation-include']; + + public validate(pkg: PackageJson): void { + if (this.excludedModules.includes(pkg.packageName)) { + return; + } + if (!isCdkModuleName(pkg.packageName)) { + return; + } + + if (!isIncludedInMonolith(pkg)) { + return; + } + + Object.keys(pkg.dependencies).forEach(dep => { + if (!isCdkModuleName(dep)) { + return; + } + + // eslint-disable-next-line @typescript-eslint/no-require-imports + const stability = require(`${dep}/package.json`).stability; + if (stability === 'experimental') { + if (this.excludedDependencies.get(pkg.packageName)?.includes(dep)) { + return; + } + pkg.report({ + ruleName: this.name, + message: `It is not allowed to depend on experimental modules. ${pkg.packageName} added a dependency on experimental module ${dep}`, + }); + } + }); + } + +} + +/* + * Enforces that the aws-cdk-lib README contains all of the core documentation from the @aws-cdk/core README + * so users of CDKv2 see all of the core documentation when viewing the aws-cdk-lib docs. + */ +export class AwsCdkLibReadmeMatchesCore extends ValidationRule { + public readonly name = 'package-info/README.md/aws-cdk-lib-and-core'; + private readonly CORE_DOC_SECTION_REGEX = /<\!--BEGIN CORE DOCUMENTATION-->[\s\S]+<\!--END CORE DOCUMENTATION-->/m; + + public validate(pkg: PackageJson): void { + if (pkg.json.name !== 'aws-cdk-lib') { return; } + + const coreReadmeFile = path.join(monoRepoRoot(), 'packages', '@aws-cdk', 'core', 'README.md'); + const readmeFile = path.join(pkg.packageRoot, 'README.md'); + + const awsCoreMatch = fs.readFileSync(coreReadmeFile, { encoding: 'utf8' }).match(this.CORE_DOC_SECTION_REGEX); + const awsCdkLibReadme = fs.readFileSync(readmeFile, { encoding: 'utf8' }); + const awsCdkLibMatch = awsCdkLibReadme.match(this.CORE_DOC_SECTION_REGEX); + + const missingSectionMsg = '@aws-cdk/core and aws-cdk-lib READMEs must include section markers () to define what content should be shared between them'; + if (!awsCoreMatch) { + pkg.report({ + ruleName: this.name, + message: missingSectionMsg, + }); + } else if (!awsCdkLibMatch) { + pkg.report({ + ruleName: this.name, + message: missingSectionMsg, + fix: () => fs.writeFileSync(readmeFile, [awsCdkLibReadme, awsCoreMatch[0]].join('\n')), + }); + } else if (awsCoreMatch[0] !== awsCdkLibMatch[0]) { + pkg.report({ + ruleName: this.name, + message: 'aws-cdk-lib README does not include a core documentation section that matches @aws-cdk/core', + fix: () => fs.writeFileSync(readmeFile, awsCdkLibMatch.input!.replace(this.CORE_DOC_SECTION_REGEX, awsCoreMatch[0])), + }); + } + } +} + + /** * Determine whether this is a JSII package * * A package is a JSII package if there is 'jsii' section in the package.json */ function isJSII(pkg: PackageJson): boolean { - return pkg.json.jsii; + return (pkg.json.jsii !== undefined); } /** @@ -1666,6 +1790,20 @@ function readBannerFile(file: string): string { function cdkMajorVersion() { // eslint-disable-next-line @typescript-eslint/no-require-imports - const releaseJson = require(`${__dirname}/../../../release.json`); + const releaseJson = require(`${monoRepoRoot()}/release.json`); return releaseJson.majorVersion as number; } + +/** + * Should this package be included in the monolithic package. + */ +function isIncludedInMonolith(pkg: PackageJson): boolean { + if (pkg.json.ubergen?.exclude) { + return false; + } else if (!isJSII(pkg)) { + return false; + } else if (pkg.json.deprecated) { + return false; + } + return true; +} \ No newline at end of file diff --git a/tools/pkglint/lib/util.ts b/tools/pkglint/lib/util.ts index 10b4415a6c3ca..019dc244c4176 100644 --- a/tools/pkglint/lib/util.ts +++ b/tools/pkglint/lib/util.ts @@ -164,7 +164,7 @@ export function findUpward(dir: string, pred: (x: string) => boolean): string | } export function monoRepoRoot() { - const ret = findUpward(process.cwd(), d => fs.existsSync(path.join(d, 'lerna.json'))); + const ret = findUpward(process.cwd(), d => fs.existsSync(path.join(d, 'lerna.json')) || fs.existsSync(path.join(d, '.nzmroot'))); if (!ret) { throw new Error('Could not find lerna.json'); } diff --git a/tools/pkglint/package.json b/tools/pkglint/package.json index 0bfea5465a4a0..bf21ffaeabb62 100644 --- a/tools/pkglint/package.json +++ b/tools/pkglint/package.json @@ -36,19 +36,31 @@ "license": "Apache-2.0", "devDependencies": { "@types/fs-extra": "^8.1.1", - "@types/semver": "^7.3.4", + "@types/glob": "^7.1.3", + "@types/jest": "^26.0.23", + "@types/semver": "^7.3.5", "@types/yargs": "^15.0.13", + "@typescript-eslint/eslint-plugin": "^4.22.1", + "@typescript-eslint/parser": "^4.22.1", + "eslint": "^7.25.0", + "eslint-import-resolver-node": "^0.3.4", + "eslint-import-resolver-typescript": "^2.4.0", "eslint-plugin-cdk": "0.0.0", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-jest": "^24.3.6", "jest": "^26.6.3", "typescript": "~3.9.9" }, + "nozem": { + "ostools": ["chmod", "cp"] + }, "dependencies": { "case": "^1.6.3", "colors": "^1.4.0", "fs-extra": "^9.1.0", "glob": "^7.1.6", - "npm-bundled": "^1.1.1", - "semver": "^7.3.4", + "npm-bundled": "^1.1.2", + "semver": "^7.3.5", "yargs": "^16.2.0" } } diff --git a/tools/prlint/index.js b/tools/prlint/index.js index addb026ec6924..6f8de5cb38dbb 100755 --- a/tools/prlint/index.js +++ b/tools/prlint/index.js @@ -83,13 +83,20 @@ function hasLabel(issue, labelName) { * to be said note, but got misspelled as "BREAKING CHANGES:" or * "BREAKING CHANGES(module):" */ -function validateBreakingChangeFormat(body) { +function validateBreakingChangeFormat(title, body) { const re = /^BREAKING.*$/m; const m = re.exec(body); if (m) { if (!m[0].startsWith('BREAKING CHANGE: ')) { throw new LinterError(`Breaking changes should be indicated by starting a line with 'BREAKING CHANGE: ', variations are not allowed. (found: '${m[0]}')`); } + if (m[0].substr('BREAKING CHANGE:'.length).trim().length === 0) { + throw new LinterError("The description of the first breaking change should immediately follow the 'BREAKING CHANGE: ' clause") + } + const titleRe = /^[a-z]+\([0-9a-z-_]+\)/; + if (!titleRe.exec(title)) { + throw new LinterError("The title of this PR must specify the module name that the first breaking change should be associated to"); + } } } @@ -125,7 +132,7 @@ async function validatePr(number) { fixContainsTest(issue, files); } - validateBreakingChangeFormat(issue.body); + validateBreakingChangeFormat(issue.title, issue.body); console.log("✅ Success") diff --git a/tools/prlint/package.json b/tools/prlint/package.json index c9e6e895d56d4..d30230c2d9cd2 100644 --- a/tools/prlint/package.json +++ b/tools/prlint/package.json @@ -13,9 +13,13 @@ "dependencies": { "github-api": "^3.4.0" }, + "devDependencies": { + "jest": "^26.6.3", + "make-runnable": "^1.3.8" + }, "scripts": { "build": "echo success", - "test": "echo success", + "test": "jest", "build+test": "npm run build test && npm run test" } } diff --git a/tools/prlint/test/index.test.js b/tools/prlint/test/index.test.js new file mode 100644 index 0000000000000..eda53bb5ce137 --- /dev/null +++ b/tools/prlint/test/index.test.js @@ -0,0 +1,69 @@ +const GitHub = require('github-api'); +jest.mock('github-api'); +const linter = require('../index'); + +beforeEach(() => { + GitHub.mockClear(); +}); + +describe('breaking changes format', () => { + test('disallow variations to "BREAKING CHANGE:"', async () => { + const issue = { + body: 'BREAKING CHANGES:', + labels: [{ name: 'pr-linter/exempt-test' }, { name: 'pr-linter/exempt-readme' }] + }; + configureMock(issue, undefined); + await expect(linter.validatePr(1000)).rejects.toThrow(/'BREAKING CHANGE: ', variations are not allowed/); + }); + + test('the first breaking change should immediately follow "BREAKING CHANGE:"', async () => { + const issue = { + body: `BREAKING CHANGE: + * **module:** another change`, + labels: [{ name: 'pr-linter/exempt-test' }, { name: 'pr-linter/exempt-readme' }] + }; + configureMock(issue, undefined); + await expect(linter.validatePr(1000)).rejects.toThrow(/description of the first breaking change should immediately follow/); + }); + + test('invalid title', async () => { + const issue = { + title: 'chore(foo/bar): some title', + body: 'BREAKING CHANGE: this breaking change', + labels: [{ name: 'pr-linter/exempt-test' }, { name: 'pr-linter/exempt-readme' }] + }; + configureMock(issue, undefined); + await expect(linter.validatePr(1000)).rejects.toThrow(/must specify the module name that the first breaking change/); + }); + + test('valid title', async () => { + const issue = { + title: 'chore(foo): some title', + body: 'BREAKING CHANGE: this breaking change', + labels: [{ name: 'pr-linter/exempt-test' }, { name: 'pr-linter/exempt-readme' }] + }; + configureMock(issue, undefined); + await linter.validatePr(1000); // not throw + }); +}); + +function configureMock(issue, prFiles) { + GitHub.mockImplementation(() => { + return { + getIssues: () => { + return { + getIssue: () => { + return { data: issue }; + }, + }; + }, + getRepo: () => { + return { + listPullRequestFiles: () => { + return { data: prFiles }; + } + } + } + }; + }); +} \ No newline at end of file diff --git a/tools/ubergen/bin/ubergen.ts b/tools/ubergen/bin/ubergen.ts index 62d1bd2a0bb9b..487ac4c7340e2 100644 --- a/tools/ubergen/bin/ubergen.ts +++ b/tools/ubergen/bin/ubergen.ts @@ -1,7 +1,7 @@ import * as console from 'console'; -import * as os from 'os'; import * as path from 'path'; import * as process from 'process'; +import cfn2ts from 'cfn2ts'; import * as fs from 'fs-extra'; import * as ts from 'typescript'; @@ -59,9 +59,14 @@ interface PackageJson { readonly name: string; readonly types: string; readonly version: string; + readonly stability: string; readonly [key: string]: unknown; + readonly 'cdk-build': { + readonly cloudformation: string[] | string; + }; readonly ubergen?: { readonly deprecatedPackages?: readonly string[]; + readonly excludeExperimentalModules?: boolean; }; } @@ -73,7 +78,7 @@ function findWorkspacePath(): string { return _findRootPath(process.cwd()); function _findRootPath(part: string): string { - if (process.cwd() === os.homedir()) { + if (part === path.resolve(part, '..')) { throw new Error('couldn\'t find a \'lerna.json\' file when walking up the directory tree, are you in a aws-cdk project?'); } @@ -214,13 +219,20 @@ async function verifyDependencies(packageJson: any, libraries: readonly LibraryR async function prepareSourceFiles(libraries: readonly LibraryReference[], packageJson: PackageJson) { console.log('📝 Preparing source files...'); + if (packageJson.ubergen?.excludeExperimentalModules) { + console.log('\t 👩🏻‍🔬 \'excludeExperimentalModules\' enabled. Regenerating all experimental modules as L1s using cfn2ts...'); + } + await fs.remove(LIB_ROOT); const indexStatements = new Array(); for (const library of libraries) { const libDir = path.join(LIB_ROOT, library.shortName); - await transformPackage(library, packageJson, libDir, libraries); + const copied = await transformPackage(library, packageJson, libDir, libraries); + if (!copied) { + continue; + } if (library.shortName === 'core') { indexStatements.push(`export * from './${library.shortName}';`); } else { @@ -260,7 +272,28 @@ async function transformPackage( ) { await fs.mkdirp(destination); - await copyOrTransformFiles(library.root, destination, allLibraries, uberPackageJson); + if (uberPackageJson.ubergen?.excludeExperimentalModules && library.packageJson.stability === 'experimental') { + // when stripExperimental is enabled, we only want to add the L1s of experimental modules. + let cfnScopes = library.packageJson['cdk-build'].cloudformation; + + if (cfnScopes === undefined) { + return false; + } + cfnScopes = Array.isArray(cfnScopes) ? cfnScopes : [cfnScopes]; + + const destinationLib = path.join(destination, 'lib'); + await fs.mkdirp(destinationLib); + await cfn2ts(cfnScopes, destinationLib); + // create a lib/index.ts which only exports the generated files + fs.writeFileSync(path.join(destinationLib, 'index.ts'), + /// logic copied from `create-missing-libraries.ts` + cfnScopes.map(s => (s === 'AWS::Serverless' ? 'AWS::SAM' : s).split('::')[1].toLocaleLowerCase()) + .map(s => `export * from './${s}.generated';`) + .join('\n')); + await copyOrTransformFiles(destination, destination, allLibraries, uberPackageJson); + } else { + await copyOrTransformFiles(library.root, destination, allLibraries, uberPackageJson); + } await fs.writeFile( path.join(destination, 'index.ts'), @@ -284,6 +317,7 @@ async function transformPackage( { encoding: 'utf8' }, ); } + return true; } function transformTargets(monoConfig: PackageJson['jsii']['targets'], targets: PackageJson['jsii']['targets']): PackageJson['jsii']['targets'] { @@ -360,6 +394,12 @@ async function copyOrTransformFiles(from: string, to: string, libraries: readonl : fqn.replace('@aws-cdk', uberPackageJson.name); } await fs.writeJson(destination, cfnTypes2Classes, { spaces: 2 }); + } else if (name === 'README.md') { + return fs.writeFile( + destination, + await rewriteReadmeImports(source), + { encoding: 'utf8' }, + ); } else { return fs.copyFile(source, destination); } @@ -368,6 +408,37 @@ async function copyOrTransformFiles(from: string, to: string, libraries: readonl await Promise.all(promises); } +/** + * Rewrites the imports in README.md from v1 ('@aws-cdk/...') to v2 ('aws-cdk-lib'). + * Uses the module imports (import { aws_foo as foo } from 'aws-cdk-lib') for module imports, + * and "barrel" imports for types (import { Bucket } from 'aws-cdk-lib/aws-s3'). + */ +async function rewriteReadmeImports(fromFile: string): Promise { + const readmeOriginal = await fs.readFile(fromFile, { encoding: 'utf8' }); + return readmeOriginal + // import * as s3 from '@aws-cdk/aws-s3' + .replace(/^(\s*)import \* as (.*) from (?:'|")@aws-cdk\/(.*)(?:'|");(\s*)$/gm, rewriteCdkImports) + // import s3 = require('@aws-cdk/aws-s3') + .replace(/^(\s*)import (.*) = require\((?:'|")@aws-cdk\/(.*)(?:'|")\);(\s*)$/gm, rewriteCdkImports) + // import { Bucket } from '@aws-cdk/aws-s3' + .replace(/^(\s*)import ({.*}) from (?:'|")@aws-cdk\/(.*)(?:'|");(\s*)$/gm, rewriteCdkTypeImports); + + function rewriteCdkImports(_match: string, prefix: string, alias: string, module: string, suffix: string): string { + if (module === 'core') { + return `${prefix}import * as ${alias} from 'aws-cdk-lib';${suffix}`; + } else { + return `${prefix}import { ${module.replace(/-/g, '_')} as ${alias} } from 'aws-cdk-lib';${suffix}`; + } + } + function rewriteCdkTypeImports(_match: string, prefix: string, types: string, module: string, suffix: string): string { + if (module === 'core') { + return `${prefix}import ${types} from 'aws-cdk-lib';${suffix}`; + } else { + return `${prefix}import ${types} from 'aws-cdk-lib/${module}';${suffix}`; + } + } +} + async function rewriteImports(fromFile: string, targetDir: string, libraries: readonly LibraryReference[]): Promise { const sourceFile = ts.createSourceFile( fromFile, diff --git a/tools/ubergen/package.json b/tools/ubergen/package.json index 65c88331540a8..93afb53f2bd28 100644 --- a/tools/ubergen/package.json +++ b/tools/ubergen/package.json @@ -33,7 +33,8 @@ }, "dependencies": { "fs-extra": "^9.1.0", - "typescript": "~3.9.9" + "typescript": "~3.9.9", + "cfn2ts": "0.0.0" }, "keywords": [ "aws", diff --git a/tools/yarn-cling/.gitignore b/tools/yarn-cling/.gitignore index f12543313a31d..884f5381e01ab 100644 --- a/tools/yarn-cling/.gitignore +++ b/tools/yarn-cling/.gitignore @@ -11,4 +11,5 @@ dist coverage nyc.config.js !.eslintrc.js +!test/test-fixture/package1/node_modules/ junit.xml \ No newline at end of file diff --git a/tools/yarn-cling/lib/hoisting.ts b/tools/yarn-cling/lib/hoisting.ts index 5f920fe3ce7f1..7031b9891108a 100644 --- a/tools/yarn-cling/lib/hoisting.ts +++ b/tools/yarn-cling/lib/hoisting.ts @@ -1,51 +1,149 @@ -import { PackageLockPackage } from "./types"; +import { PackageLockPackage } from './types'; /** * Hoist package-lock dependencies in-place + * + * This happens in two phases: + * + * 1) Move every package into the parent scope (as long as it introduces no conflicts). + * This step mutates the dependency tree. + * 2) Once no more packages can be moved up, clean up the tree. This step mutates the + * tree declarations but cannot change versions of required packages. Two cleanups: + * 2a) Remove duplicates down the tree (same version that is inherited from above) + * 2b) Remove useless packages that aren't depended upon by anything in that subtree. + * To determine whether a package is useful or useless in a tree, we record + * each package's original dependencies before we start messing around in the + * tree. + * + * This two-phase process replaces a proces that did move-and-delete as one step, which + * sometimes would hoist a package into a place that was previously vacated by a conflicting + * version, thereby causing the wrong version to be loaded. + * + * Hoisting is still rather expensive on a large tree (~100ms), we should find ways to + * speed it up. */ -export function hoistDependencies(packageLockDeps: Record) { - let didChange; - do { - didChange = false; - simplify(packageLockDeps); - } while (didChange); +export function hoistDependencies(packageTree: PackageLockPackage) { + const originalDependencies = new Map(); + recordOriginalDependencies(packageTree); - // For each of the deps, move each dependency that has the same version into the current array - function simplify(dependencies: Record) { - for (const depPackage of Object.values(dependencies)) { - moveChildrenUp(depPackage, dependencies); + moveUp(packageTree); + removeDupes(packageTree, []); + removeUseless(packageTree); + + // Move the children of the parent onto the same level if there are no conflicts + function moveUp(node: PackageLockPackage, parent?: PackageLockPackage) { + if (!node.dependencies) { return; } + + // Recurse + for (const child of Object.values(node.dependencies)) { + moveUp(child, node); + } + + // Then push packages from the current node into its parent + if (parent) { + for (const [depName, depPackage] of Object.entries(node.dependencies)) { + if (!parent.dependencies?.[depName]) { + // It's new and there's no version conflict, we can move it up. + parent.dependencies![depName] = depPackage; + } + } } - return dependencies; } - // Move the children of the parent onto the same level if there are no conflicts - function moveChildrenUp(parent: PackageLockPackage, parentContainer: Record) { - if (!parent.dependencies) { return; } - - // Then push packages from the mutable parent into ITS parent - for (const [depName, depPackage] of Object.entries(parent.dependencies)) { - if (!parentContainer[depName]) { - // It's new, we can move it up. - parentContainer[depName] = depPackage; - delete parent.dependencies[depName]; - didChange = true; - - // Recurse on the package we just moved - moveChildrenUp(depPackage, parentContainer); - } else if (parentContainer[depName].version === depPackage.version) { - // Already exists, no conflict, delete the child, no need to recurse - delete parent.dependencies[depName]; - didChange = true; - } else { - // There is a conflict, leave the second package where it is, but do recurse. - moveChildrenUp(depPackage, parent.dependencies); + function removeDupes(node: PackageLockPackage, rootPath: Array) { + if (!node.dependencies) { return; } + + // Any dependencies here that are the same in the parent can be removed + for (const [depName, depPackage] of Object.entries(node.dependencies)) { + if (findInheritedDepVersion(depName, rootPath) === depPackage.version) { + delete node.dependencies[depName]; } } - // Cleanup for nice printing - if (Object.keys(parent.dependencies).length === 0) { - delete parent.dependencies; - didChange = true; + // Recurse + for (const child of Object.values(node.dependencies)) { + removeDupes(child, [node, ...rootPath]); } } + + function removeUseless(node: PackageLockPackage) { + if (!node.dependencies) { return; } + for (const [depName, depPkg] of Object.entries(node.dependencies)) { + if (!necessaryInTree(depName, depPkg.version, node)) { + delete node.dependencies[depName]; + } + } + + // Recurse + for (const child of Object.values(node.dependencies)) { + removeUseless(child); + } + + // If we ended up with empty dependencies, just get rid of the key (for clean printing) + if (Object.keys(node.dependencies).length === 0) { + delete node.dependencies; + } + } + + function findInheritedDepVersion(name: string, parentDependenciesChain: Array) { + for (const deps of parentDependenciesChain) { + if (deps.dependencies?.[name]) { + return deps.dependencies[name].version; + } + } + return undefined; + } + + function recordOriginalDependencies(node: PackageLockPackage) { + if (!node.dependencies) { return; } + + let list = originalDependencies.get(node); + if (!list) { + list = []; + originalDependencies.set(node, list); + } + + for (const [depName, depPkg] of Object.entries(node.dependencies)) { + list.push(`${depName}@${depPkg.version}`); + recordOriginalDependencies(depPkg); + } + } + + function necessaryInTree(name: string, version: string, tree: PackageLockPackage) { + if (originalDependencies.get(tree)?.includes(`${name}@${version}`)) { + return true; + } + if (!tree.dependencies) { return false; } + + for (const depPackage of Object.values(tree.dependencies)) { + if (necessaryInTree(name, version, depPackage)) { return true; } + } + return false; + } +} + +export function renderTree(tree: PackageLockPackage): string[] { + const ret = new Array(); + recurse(tree.dependencies ?? {}, []); + return ret.sort(compareSplit); + + function recurse(n: Record, parts: string[]) { + for (const [k, v] of Object.entries(n)) { + ret.push([...parts, k].join('.') + '=' + v.version); + recurse(v.dependencies ?? {}, [...parts, k]); + } + } + + function compareSplit(a: string, b: string): number { + // Sort so that: 'a=1', 'a.b=2' get sorted in that order. + const as = a.split(/\.|=/g); + const bs = b.split(/\.|=/g); + + for (let i = 0; i < as.length && i < bs.length; i++) { + const cmp = as[i].localeCompare(bs[i]); + if (cmp !== 0) { return cmp; } + } + + return as.length - bs.length; + } } diff --git a/tools/yarn-cling/lib/index.ts b/tools/yarn-cling/lib/index.ts index 38a766c27d7e5..0ca255547e5e2 100644 --- a/tools/yarn-cling/lib/index.ts +++ b/tools/yarn-cling/lib/index.ts @@ -1,6 +1,7 @@ import { promises as fs, exists } from 'fs'; import * as path from 'path'; import * as lockfile from '@yarnpkg/lockfile'; +import * as semver from 'semver'; import { hoistDependencies } from './hoisting'; import { PackageJson, PackageLock, PackageLockEntry, PackageLockPackage, YarnLock } from './types'; @@ -37,7 +38,7 @@ export async function generateShrinkwrap(options: ShrinkwrapOptions): Promise { - return { + const lockFile = { name: pkgJson.name, version: pkgJson.version, lockfileVersion: 1, requires: true, dependencies: await dependenciesFor(pkgJson.dependencies || {}, yarnLock, rootDir), }; + + checkRequiredVersions(lockFile); + + return lockFile; } // eslint-disable-next-line max-len @@ -186,4 +191,77 @@ async function findPackageDir(depName: string, rootDir: string) { } throw new Error(`Did not find '${depName}' upwards of '${rootDir}'`); +} + +/** + * We may sometimes try to adjust a package version to a version that's incompatible with the declared requirement. + * + * For example, this recently happened for 'netmask', where the package we + * depend on has `{ requires: { netmask: '^1.0.6', } }`, but we need to force-substitute in version `2.0.1`. + * + * If NPM processes the shrinkwrap and encounters the following situation: + * + * ``` + * { + * netmask: { version: '2.0.1' }, + * resolver: { + * requires: { + * netmask: '^1.0.6' + * } + * } + * } + * ``` + * + * NPM is going to disregard the swhinkrwap and still give `resolver` its own private + * copy of netmask `^1.0.6`. + * + * We tried overriding the `requires` version, and that works for `npm install` (yay) + * but if anyone runs `npm ls` afterwards, `npm ls` is going to check the actual source + * `package.jsons` against the actual `node_modules` file tree, and complain that the + * versions don't match. + * + * We run `npm ls` in our tests to make sure our dependency tree is sane, and our customers + * might too, so this is not a great solution. + * + * To cut any discussion short in the future, we're going to detect this situation and + * tell our future selves that is cannot and will not work, and we should find another + * solution. + */ +export function checkRequiredVersions(root: PackageLock | PackageLockPackage) { + recurse(root, []); + + function recurse(entry: PackageLock | PackageLockPackage, parentChain: PackageLockEntry[]) { + // On the root, 'requires' is the value 'true', for God knows what reason. Don't care about those. + if (typeof entry.requires === 'object') { + + // For every 'requires' dependency, find the version it actually got resolved to and compare. + for (const [name, range] of Object.entries(entry.requires)) { + const resolvedPackage = findResolved(name, [entry, ...parentChain]); + if (!resolvedPackage) { continue; } + + if (!semver.satisfies(resolvedPackage.version, range)) { + // Ruh-roh. + throw new Error(`Looks like we're trying to force '${name}' to version '${resolvedPackage.version}', but the dependency ` + + `is specified as '${range}'. This can never properly work via shrinkwrapping. Try vendoring a patched ` + + 'version of the intermediary dependencies instead.'); + } + } + } + + for (const dep of Object.values(entry.dependencies ?? {})) { + recurse(dep, [entry, ...parentChain]); + } + } + + /** + * Find a package name in a package lock tree. + */ + function findResolved(name: string, chain: PackageLockEntry[]) { + for (const level of chain) { + if (level.dependencies?.[name]) { + return level.dependencies?.[name]; + } + } + return undefined; + } } \ No newline at end of file diff --git a/tools/yarn-cling/lib/types.ts b/tools/yarn-cling/lib/types.ts index 0f800cc50de52..2af924f90cb6f 100644 --- a/tools/yarn-cling/lib/types.ts +++ b/tools/yarn-cling/lib/types.ts @@ -29,8 +29,8 @@ export interface ResolvedYarnPackage { export interface PackageLock extends PackageLockEntry { name: string; - lockfileVersion: 1; - requires: true; + lockfileVersion: number; + requires: boolean; } export interface PackageLockEntry { diff --git a/tools/yarn-cling/package.json b/tools/yarn-cling/package.json index ceeacb4544b08..14bb7e2ffef4c 100644 --- a/tools/yarn-cling/package.json +++ b/tools/yarn-cling/package.json @@ -38,15 +38,17 @@ ] }, "devDependencies": { - "@types/jest": "^26.0.21", - "@types/node": "^10.17.55", + "@types/jest": "^26.0.23", + "@types/node": "^10.17.59", "@types/yarnpkg__lockfile": "^1.1.4", + "@types/semver": "^7.3.5", "jest": "^26.6.3", "pkglint": "0.0.0", "typescript": "~3.9.9" }, "dependencies": { - "@yarnpkg/lockfile": "^1.1.0" + "@yarnpkg/lockfile": "^1.1.0", + "semver": "^7.3.5" }, "keywords": [ "aws", @@ -56,6 +58,9 @@ "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, + "nozem": { + "ostools": ["ln"] + }, "ubergen": { "exclude": true } diff --git a/tools/yarn-cling/test/cling.test.ts b/tools/yarn-cling/test/cling.test.ts index 6b5854db688ed..1628d2415a1ae 100644 --- a/tools/yarn-cling/test/cling.test.ts +++ b/tools/yarn-cling/test/cling.test.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import { generateShrinkwrap } from "../lib"; +import { checkRequiredVersions, generateShrinkwrap } from '../lib'; test('generate lock for fixture directory', async () => { const lockFile = await generateShrinkwrap({ @@ -9,27 +9,27 @@ test('generate lock for fixture directory', async () => { expect(lockFile).toEqual({ lockfileVersion: 1, - name: "package1", + name: 'package1', requires: true, - version: "1.1.1", + version: '1.1.1', dependencies: { package2: { - version: "2.2.2", + version: '2.2.2', }, registrydependency1: { dependencies: { registrydependency2: { - integrity: "sha512-pineapple", - resolved: "https://registry.bla.com/stuff", - version: "2.3.999", + integrity: 'sha512-pineapple', + resolved: 'https://registry.bla.com/stuff', + version: '2.3.999', }, }, - integrity: "sha512-banana", + integrity: 'sha512-banana', requires: { - registrydependency2: "^2.3.4", + registrydependency2: '^2.3.4', }, - resolved: "https://registry.bla.com/stuff", - version: "1.2.999", + resolved: 'https://registry.bla.com/stuff', + version: '1.2.999', }, }, }); @@ -43,26 +43,48 @@ test('generate hoisted lock for fixture directory', async () => { expect(lockFile).toEqual({ lockfileVersion: 1, - name: "package1", + name: 'package1', requires: true, - version: "1.1.1", + version: '1.1.1', dependencies: { package2: { - version: "2.2.2", + version: '2.2.2', }, registrydependency1: { - integrity: "sha512-banana", + integrity: 'sha512-banana', requires: { - registrydependency2: "^2.3.4", + registrydependency2: '^2.3.4', }, - resolved: "https://registry.bla.com/stuff", - version: "1.2.999", + resolved: 'https://registry.bla.com/stuff', + version: '1.2.999', }, registrydependency2: { - integrity: "sha512-pineapple", - resolved: "https://registry.bla.com/stuff", - version: "2.3.999", + integrity: 'sha512-pineapple', + resolved: 'https://registry.bla.com/stuff', + version: '2.3.999', }, }, }); -}); \ No newline at end of file +}); + +test('fail when requires cannot be satisfied', async () => { + const lockFile = { + lockfileVersion: 1, + name: 'package1', + requires: true, + version: '1.1.1', + dependencies: { + package1: { + version: '2.2.2', + requires: { + package2: '^3.3.3', // <- this needs to be adjusted + }, + }, + package2: { + version: '4.4.4', + }, + }, + }; + + expect(() => checkRequiredVersions(lockFile)).toThrow(/This can never/); +}); diff --git a/tools/yarn-cling/test/hoisting.test.ts b/tools/yarn-cling/test/hoisting.test.ts index b48606f65e128..e5bcc13144451 100644 --- a/tools/yarn-cling/test/hoisting.test.ts +++ b/tools/yarn-cling/test/hoisting.test.ts @@ -1,138 +1,188 @@ -import { hoistDependencies } from "../lib/hoisting"; -import { PackageLockPackage } from "../lib/types"; +import { hoistDependencies, renderTree } from '../lib/hoisting'; +import { PackageLockPackage } from '../lib/types'; -type Tree = Record; +type DependencyTree = PackageLockPackage; test('nonconflicting tree gets flattened', () => { // GIVEN - const tree: Tree = { + const tree: DependencyTree = pkg('*', { stringutil: { version: '1.0.0', dependencies: { - leftpad: { version: '2.0.0' } + leftpad: { version: '2.0.0' }, }, }, numutil: { version: '3.0.0', dependencies: { - isodd: { version: '4.0.0' } + isodd: { version: '4.0.0' }, }, }, - }; + }); // WHEN hoistDependencies(tree); // THEN - expect(tree).toEqual({ - stringutil: { version: '1.0.0' }, - leftpad: { version: '2.0.0' }, - numutil: { version: '3.0.0' }, - isodd: { version: '4.0.0' }, - }); + expect(renderTree(tree)).toEqual([ + 'isodd=4.0.0', + 'leftpad=2.0.0', + 'numutil=3.0.0', + 'stringutil=1.0.0', + ]); }); test('matching versions get deduped', () => { // GIVEN - const tree: Tree = { + const tree: DependencyTree = pkg('*', { stringutil: { version: '1.0.0', dependencies: { - leftpad: { version: '2.0.0' } + leftpad: { version: '2.0.0' }, }, }, numutil: { version: '3.0.0', dependencies: { leftpad: { version: '2.0.0' }, - isodd: { version: '4.0.0' } + isodd: { version: '4.0.0' }, }, }, - }; + }); // WHEN hoistDependencies(tree); // THEN - expect(tree).toEqual({ - stringutil: { version: '1.0.0' }, - leftpad: { version: '2.0.0' }, - numutil: { version: '3.0.0' }, - isodd: { version: '4.0.0' }, - }); + expect(renderTree(tree)).toEqual([ + 'isodd=4.0.0', + 'leftpad=2.0.0', + 'numutil=3.0.0', + 'stringutil=1.0.0', + ]); }); test('conflicting versions get left in place', () => { // GIVEN - const tree: Tree = { + const tree: DependencyTree = pkg('*', { stringutil: { version: '1.0.0', dependencies: { - leftpad: { version: '2.0.0' } + leftpad: { version: '2.0.0' }, }, }, numutil: { version: '3.0.0', dependencies: { leftpad: { version: '5.0.0' }, - isodd: { version: '4.0.0' } + isodd: { version: '4.0.0' }, }, }, - }; + }); // WHEN hoistDependencies(tree); // THEN - expect(tree).toEqual({ - stringutil: { version: '1.0.0' }, - leftpad: { version: '2.0.0' }, - numutil: { - version: '3.0.0', - dependencies: { - leftpad: { version: '5.0.0' }, - }, - }, - isodd: { version: '4.0.0' }, - }); + expect(renderTree(tree)).toEqual([ + 'isodd=4.0.0', + 'leftpad=2.0.0', + 'numutil=3.0.0', + 'numutil.leftpad=5.0.0', + 'stringutil=1.0.0', + ]); }); test('dependencies of deduped packages are not hoisted into useless positions', () => { // GIVEN + const tree: DependencyTree = pkg('*', { + stringutil: pkg('1.0.0', { + leftpad: pkg('2.0.0', { + spacemaker: pkg('3.0.0'), + }), + }), + leftpad: pkg('2.0.0', { + spacemaker: pkg('3.0.0'), + }), + spacemaker: pkg('4.0.0'), + }); - const tree: Tree = { - stringutil: { - version: '1.0.0', - dependencies: { - leftpad: { - version: '2.0.0', - dependencies: { - spacemaker: { version: '3.0.0' }, - } - } - }, - }, - leftpad: { - version: '2.0.0', - dependencies: { - spacemaker: { version: '3.0.0' }, - } - }, - spacemaker: { version: '4.0.0' } - }; + // WHEN + hoistDependencies(tree); + + // THEN + expect(renderTree(tree)).toEqual([ + 'leftpad=2.0.0', + 'leftpad.spacemaker=3.0.0', + 'spacemaker=4.0.0', + 'stringutil=1.0.0', + ]); +}); + +test('dont hoist into a parent if it would cause an incorrect version there', () => { + // GIVEN + const tree: DependencyTree = pkg('*', { + stringutil: pkg('1.0.0', { + spacemaker: pkg('10.0.0'), + leftPad: pkg('2.0.0', { + spacemaker: pkg('3.0.0'), + }), + }), + leftPad: pkg('1.0.0'), // Prevents previous leftPad from being hoisted + }); // WHEN hoistDependencies(tree); // THEN - expect(tree).toEqual({ - stringutil: { version: '1.0.0' }, - leftpad: { - version: '2.0.0', - dependencies: { - spacemaker: { version: '3.0.0' } - } - }, - spacemaker: { version: '4.0.0' }, + expect(renderTree(tree)).toEqual([ + 'leftPad=1.0.0', + 'spacemaker=10.0.0', + 'stringutil=1.0.0', + 'stringutil.leftPad=2.0.0', + 'stringutil.leftPad.spacemaker=3.0.0', + ]); +}); + +test('order of hoisting shouldnt produce a broken situation', () => { + // GIVEN + const tree: DependencyTree = pkg('*', { + stringutil: pkg('1.0.0', { + wrapper: pkg('100.0.0', { + leftPad: pkg('2.0.0', { + spacemaker: pkg('3.0.0'), + }), + }), + spacemaker: pkg('4.0.0'), // Prevents spacemaker from being hoisted here, but then leftPad also shouldn't be + }), }); -}); \ No newline at end of file + + // WHEN + hoistDependencies(tree); + + // THEN + /* // Both answers are fine but the current algorithm picks the 2nd + expect(renderTree(tree)).toEqual([ + 'leftPad=2.0.0', + 'spacemaker=3.0.0', + 'stringutil=1.0.0', + 'stringutil.spacemaker=4.0.0', + 'wrapper=100.0.0', + ]); + */ + expect(renderTree(tree)).toEqual([ + 'leftPad=2.0.0', + 'leftPad.spacemaker=3.0.0', + 'spacemaker=4.0.0', + 'stringutil=1.0.0', + 'wrapper=100.0.0', + ]); +}); + +function pkg(version: string, dependencies?: Record): PackageLockPackage { + return { + version, + ...dependencies? { dependencies } : undefined, + }; +} + diff --git a/version.v1.json b/version.v1.json index 0a93d433950d0..3a232490b680f 100644 --- a/version.v1.json +++ b/version.v1.json @@ -1,3 +1,3 @@ { - "version": "1.94.1" + "version": "1.102.0" } diff --git a/yarn.lock b/yarn.lock index 474f8606db1fa..c177d227d54a8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -326,80 +326,6 @@ 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" - integrity sha512-KSCAHwNWro0CF2ukxufCitT9K5LjL/KuMmNzSu8wuwN2rjyKHD8+cmOsiybK+W5hdnwc5M1SmRlVCaMHQo+3rg== - dependencies: - "@evocateur/npm-registry-fetch" "^4.0.0" - aproba "^2.0.0" - figgy-pudding "^3.5.1" - get-stream "^4.0.0" - npm-package-arg "^6.1.0" - -"@evocateur/libnpmpublish@^1.2.2": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@evocateur/libnpmpublish/-/libnpmpublish-1.2.2.tgz#55df09d2dca136afba9c88c759ca272198db9f1a" - integrity sha512-MJrrk9ct1FeY9zRlyeoyMieBjGDG9ihyyD9/Ft6MMrTxql9NyoEx2hw9casTIP4CdqEVu+3nQ2nXxoJ8RCXyFg== - dependencies: - "@evocateur/npm-registry-fetch" "^4.0.0" - aproba "^2.0.0" - figgy-pudding "^3.5.1" - get-stream "^4.0.0" - lodash.clonedeep "^4.5.0" - normalize-package-data "^2.4.0" - npm-package-arg "^6.1.0" - semver "^5.5.1" - ssri "^6.0.1" - -"@evocateur/npm-registry-fetch@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@evocateur/npm-registry-fetch/-/npm-registry-fetch-4.0.0.tgz#8c4c38766d8d32d3200fcb0a83f064b57365ed66" - integrity sha512-k1WGfKRQyhJpIr+P17O5vLIo2ko1PFLKwoetatdduUSt/aQ4J2sJrJwwatdI5Z3SiYk/mRH9S3JpdmMFd/IK4g== - dependencies: - JSONStream "^1.3.4" - bluebird "^3.5.1" - figgy-pudding "^3.4.1" - lru-cache "^5.1.1" - make-fetch-happen "^5.0.0" - npm-package-arg "^6.1.0" - safe-buffer "^5.1.2" - -"@evocateur/pacote@^9.6.3": - version "9.6.5" - resolved "https://registry.yarnpkg.com/@evocateur/pacote/-/pacote-9.6.5.tgz#33de32ba210b6f17c20ebab4d497efc6755f4ae5" - integrity sha512-EI552lf0aG2nOV8NnZpTxNo2PcXKPmDbF9K8eCBFQdIZwHNGN/mi815fxtmUMa2wTa1yndotICIDt/V0vpEx2w== - dependencies: - "@evocateur/npm-registry-fetch" "^4.0.0" - bluebird "^3.5.3" - cacache "^12.0.3" - chownr "^1.1.2" - figgy-pudding "^3.5.1" - get-stream "^4.1.0" - glob "^7.1.4" - infer-owner "^1.0.4" - lru-cache "^5.1.1" - make-fetch-happen "^5.0.0" - minimatch "^3.0.4" - minipass "^2.3.5" - mississippi "^3.0.0" - mkdirp "^0.5.1" - normalize-package-data "^2.5.0" - npm-package-arg "^6.1.0" - npm-packlist "^1.4.4" - npm-pick-manifest "^3.0.0" - osenv "^0.1.5" - promise-inflight "^1.0.1" - promise-retry "^1.1.1" - protoduck "^5.0.1" - rimraf "^2.6.3" - safe-buffer "^5.2.0" - semver "^5.7.0" - ssri "^6.0.1" - tar "^4.4.10" - unique-filename "^1.1.1" - which "^1.3.1" - "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -587,705 +513,683 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" -"@jsii/spec@^1.25.0": - version "1.25.0" - resolved "https://registry.yarnpkg.com/@jsii/spec/-/spec-1.25.0.tgz#535b85aa26d3db1d188c04300a2e20529eeee7fd" - integrity sha512-Zr56+uqZLoxI8qxIZZEweZdYBo0KqWf+q25m/okgwcKV4njCZuh0APXzeT/ebSkSOHQ3tneEE+g2EP/8IPP2og== +"@jsii/spec@^1.29.0": + version "1.29.0" + resolved "https://registry.yarnpkg.com/@jsii/spec/-/spec-1.29.0.tgz#2378bbacd94e0159c6344c1556af0129e4d3e2f4" + integrity sha512-Y0ouCaYVPy7KjQ8di6Hu4xizKYp4klqqDf08BaEgqd38TzqBuO0abgcd9OJFUQyoDnCCWTdGBfqTo2xfvW9Pbw== dependencies: jsonschema "^1.4.0" -"@lerna/add@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/add/-/add-3.21.0.tgz#27007bde71cc7b0a2969ab3c2f0ae41578b4577b" - integrity sha512-vhUXXF6SpufBE1EkNEXwz1VLW03f177G9uMOFMQkp6OJ30/PWg4Ekifuz9/3YfgB2/GH8Tu4Lk3O51P2Hskg/A== - dependencies: - "@evocateur/pacote" "^9.6.3" - "@lerna/bootstrap" "3.21.0" - "@lerna/command" "3.21.0" - "@lerna/filter-options" "3.20.0" - "@lerna/npm-conf" "3.16.0" - "@lerna/validation-error" "3.13.0" +"@lerna/add@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/add/-/add-4.0.0.tgz#c36f57d132502a57b9e7058d1548b7a565ef183f" + integrity sha512-cpmAH1iS3k8JBxNvnMqrGTTjbY/ZAiKa1ChJzFevMYY3eeqbvhsBKnBcxjRXtdrJ6bd3dCQM+ZtK+0i682Fhng== + dependencies: + "@lerna/bootstrap" "4.0.0" + "@lerna/command" "4.0.0" + "@lerna/filter-options" "4.0.0" + "@lerna/npm-conf" "4.0.0" + "@lerna/validation-error" "4.0.0" dedent "^0.7.0" - npm-package-arg "^6.1.0" - p-map "^2.1.0" - semver "^6.2.0" + npm-package-arg "^8.1.0" + p-map "^4.0.0" + pacote "^11.2.6" + semver "^7.3.4" -"@lerna/bootstrap@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/bootstrap/-/bootstrap-3.21.0.tgz#bcd1b651be5b0970b20d8fae04c864548123aed6" - integrity sha512-mtNHlXpmvJn6JTu0KcuTTPl2jLsDNud0QacV/h++qsaKbhAaJr/FElNZ5s7MwZFUM3XaDmvWzHKaszeBMHIbBw== - dependencies: - "@lerna/command" "3.21.0" - "@lerna/filter-options" "3.20.0" - "@lerna/has-npm-version" "3.16.5" - "@lerna/npm-install" "3.16.5" - "@lerna/package-graph" "3.18.5" - "@lerna/pulse-till-done" "3.13.0" - "@lerna/rimraf-dir" "3.16.5" - "@lerna/run-lifecycle" "3.16.2" - "@lerna/run-topologically" "3.18.5" - "@lerna/symlink-binary" "3.17.0" - "@lerna/symlink-dependencies" "3.17.0" - "@lerna/validation-error" "3.13.0" +"@lerna/bootstrap@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/bootstrap/-/bootstrap-4.0.0.tgz#5f5c5e2c6cfc8fcec50cb2fbe569a8c607101891" + integrity sha512-RkS7UbeM2vu+kJnHzxNRCLvoOP9yGNgkzRdy4UV2hNalD7EP41bLvRVOwRYQ7fhc2QcbhnKNdOBihYRL0LcKtw== + dependencies: + "@lerna/command" "4.0.0" + "@lerna/filter-options" "4.0.0" + "@lerna/has-npm-version" "4.0.0" + "@lerna/npm-install" "4.0.0" + "@lerna/package-graph" "4.0.0" + "@lerna/pulse-till-done" "4.0.0" + "@lerna/rimraf-dir" "4.0.0" + "@lerna/run-lifecycle" "4.0.0" + "@lerna/run-topologically" "4.0.0" + "@lerna/symlink-binary" "4.0.0" + "@lerna/symlink-dependencies" "4.0.0" + "@lerna/validation-error" "4.0.0" dedent "^0.7.0" - get-port "^4.2.0" - multimatch "^3.0.0" - npm-package-arg "^6.1.0" + get-port "^5.1.1" + multimatch "^5.0.0" + npm-package-arg "^8.1.0" npmlog "^4.1.2" - p-finally "^1.0.0" - p-map "^2.1.0" - p-map-series "^1.0.0" - p-waterfall "^1.0.0" - read-package-tree "^5.1.6" - semver "^6.2.0" + p-map "^4.0.0" + p-map-series "^2.1.0" + p-waterfall "^2.1.1" + read-package-tree "^5.3.1" + semver "^7.3.4" -"@lerna/changed@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/changed/-/changed-3.21.0.tgz#108e15f679bfe077af500f58248c634f1044ea0b" - integrity sha512-hzqoyf8MSHVjZp0gfJ7G8jaz+++mgXYiNs9iViQGA8JlN/dnWLI5sWDptEH3/B30Izo+fdVz0S0s7ydVE3pWIw== +"@lerna/changed@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/changed/-/changed-4.0.0.tgz#b9fc76cea39b9292a6cd263f03eb57af85c9270b" + integrity sha512-cD+KuPRp6qiPOD+BO6S6SN5cARspIaWSOqGBpGnYzLb4uWT8Vk4JzKyYtc8ym1DIwyoFXHosXt8+GDAgR8QrgQ== dependencies: - "@lerna/collect-updates" "3.20.0" - "@lerna/command" "3.21.0" - "@lerna/listable" "3.18.5" - "@lerna/output" "3.13.0" + "@lerna/collect-updates" "4.0.0" + "@lerna/command" "4.0.0" + "@lerna/listable" "4.0.0" + "@lerna/output" "4.0.0" -"@lerna/check-working-tree@3.16.5": - version "3.16.5" - resolved "https://registry.yarnpkg.com/@lerna/check-working-tree/-/check-working-tree-3.16.5.tgz#b4f8ae61bb4523561dfb9f8f8d874dd46bb44baa" - integrity sha512-xWjVBcuhvB8+UmCSb5tKVLB5OuzSpw96WEhS2uz6hkWVa/Euh1A0/HJwn2cemyK47wUrCQXtczBUiqnq9yX5VQ== +"@lerna/check-working-tree@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/check-working-tree/-/check-working-tree-4.0.0.tgz#257e36a602c00142e76082a19358e3e1ae8dbd58" + integrity sha512-/++bxM43jYJCshBiKP5cRlCTwSJdRSxVmcDAXM+1oUewlZJVSVlnks5eO0uLxokVFvLhHlC5kHMc7gbVFPHv6Q== dependencies: - "@lerna/collect-uncommitted" "3.16.5" - "@lerna/describe-ref" "3.16.5" - "@lerna/validation-error" "3.13.0" + "@lerna/collect-uncommitted" "4.0.0" + "@lerna/describe-ref" "4.0.0" + "@lerna/validation-error" "4.0.0" -"@lerna/child-process@3.16.5": - version "3.16.5" - resolved "https://registry.yarnpkg.com/@lerna/child-process/-/child-process-3.16.5.tgz#38fa3c18064aa4ac0754ad80114776a7b36a69b2" - integrity sha512-vdcI7mzei9ERRV4oO8Y1LHBZ3A5+ampRKg1wq5nutLsUA4mEBN6H7JqjWOMY9xZemv6+kATm2ofjJ3lW5TszQg== +"@lerna/child-process@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/child-process/-/child-process-4.0.0.tgz#341b96a57dffbd9705646d316e231df6fa4df6e1" + integrity sha512-XtCnmCT9eyVsUUHx6y/CTBYdV9g2Cr/VxyseTWBgfIur92/YKClfEtJTbOh94jRT62hlKLqSvux/UhxXVh613Q== dependencies: - chalk "^2.3.1" - execa "^1.0.0" - strong-log-transformer "^2.0.0" + chalk "^4.1.0" + execa "^5.0.0" + strong-log-transformer "^2.1.0" -"@lerna/clean@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/clean/-/clean-3.21.0.tgz#c0b46b5300cc3dae2cda3bec14b803082da3856d" - integrity sha512-b/L9l+MDgE/7oGbrav6rG8RTQvRiZLO1zTcG17zgJAAuhlsPxJExMlh2DFwJEVi2les70vMhHfST3Ue1IMMjpg== - dependencies: - "@lerna/command" "3.21.0" - "@lerna/filter-options" "3.20.0" - "@lerna/prompt" "3.18.5" - "@lerna/pulse-till-done" "3.13.0" - "@lerna/rimraf-dir" "3.16.5" - p-map "^2.1.0" - p-map-series "^1.0.0" - p-waterfall "^1.0.0" - -"@lerna/cli@3.18.5": - version "3.18.5" - resolved "https://registry.yarnpkg.com/@lerna/cli/-/cli-3.18.5.tgz#c90c461542fcd35b6d5b015a290fb0dbfb41d242" - integrity sha512-erkbxkj9jfc89vVs/jBLY/fM0I80oLmJkFUV3Q3wk9J3miYhP14zgVEBsPZY68IZlEjT6T3Xlq2xO1AVaatHsA== - dependencies: - "@lerna/global-options" "3.13.0" +"@lerna/clean@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/clean/-/clean-4.0.0.tgz#8f778b6f2617aa2a936a6b5e085ae62498e57dc5" + integrity sha512-uugG2iN9k45ITx2jtd8nEOoAtca8hNlDCUM0N3lFgU/b1mEQYAPRkqr1qs4FLRl/Y50ZJ41wUz1eazS+d/0osA== + dependencies: + "@lerna/command" "4.0.0" + "@lerna/filter-options" "4.0.0" + "@lerna/prompt" "4.0.0" + "@lerna/pulse-till-done" "4.0.0" + "@lerna/rimraf-dir" "4.0.0" + p-map "^4.0.0" + p-map-series "^2.1.0" + p-waterfall "^2.1.1" + +"@lerna/cli@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/cli/-/cli-4.0.0.tgz#8eabd334558836c1664df23f19acb95e98b5bbf3" + integrity sha512-Neaw3GzFrwZiRZv2g7g6NwFjs3er1vhraIniEs0jjVLPMNC4eata0na3GfE5yibkM/9d3gZdmihhZdZ3EBdvYA== + dependencies: + "@lerna/global-options" "4.0.0" dedent "^0.7.0" npmlog "^4.1.2" - yargs "^14.2.2" + yargs "^16.2.0" -"@lerna/collect-uncommitted@3.16.5": - version "3.16.5" - resolved "https://registry.yarnpkg.com/@lerna/collect-uncommitted/-/collect-uncommitted-3.16.5.tgz#a494d61aac31cdc7aec4bbe52c96550274132e63" - integrity sha512-ZgqnGwpDZiWyzIQVZtQaj9tRizsL4dUOhuOStWgTAw1EMe47cvAY2kL709DzxFhjr6JpJSjXV5rZEAeU3VE0Hg== +"@lerna/collect-uncommitted@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/collect-uncommitted/-/collect-uncommitted-4.0.0.tgz#855cd64612969371cfc2453b90593053ff1ba779" + integrity sha512-ufSTfHZzbx69YNj7KXQ3o66V4RC76ffOjwLX0q/ab//61bObJ41n03SiQEhSlmpP+gmFbTJ3/7pTe04AHX9m/g== dependencies: - "@lerna/child-process" "3.16.5" - chalk "^2.3.1" - figgy-pudding "^3.5.1" + "@lerna/child-process" "4.0.0" + chalk "^4.1.0" npmlog "^4.1.2" -"@lerna/collect-updates@3.20.0": - version "3.20.0" - resolved "https://registry.yarnpkg.com/@lerna/collect-updates/-/collect-updates-3.20.0.tgz#62f9d76ba21a25b7d9fbf31c02de88744a564bd1" - integrity sha512-qBTVT5g4fupVhBFuY4nI/3FSJtQVcDh7/gEPOpRxoXB/yCSnT38MFHXWl+y4einLciCjt/+0x6/4AG80fjay2Q== +"@lerna/collect-updates@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/collect-updates/-/collect-updates-4.0.0.tgz#8e208b1bafd98a372ff1177f7a5e288f6bea8041" + integrity sha512-bnNGpaj4zuxsEkyaCZLka9s7nMs58uZoxrRIPJ+nrmrZYp1V5rrd+7/NYTuunOhY2ug1sTBvTAxj3NZQ+JKnOw== dependencies: - "@lerna/child-process" "3.16.5" - "@lerna/describe-ref" "3.16.5" + "@lerna/child-process" "4.0.0" + "@lerna/describe-ref" "4.0.0" minimatch "^3.0.4" npmlog "^4.1.2" - slash "^2.0.0" + slash "^3.0.0" -"@lerna/command@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/command/-/command-3.21.0.tgz#9a2383759dc7b700dacfa8a22b2f3a6e190121f7" - integrity sha512-T2bu6R8R3KkH5YoCKdutKv123iUgUbW8efVjdGCDnCMthAQzoentOJfDeodBwn0P2OqCl3ohsiNVtSn9h78fyQ== - dependencies: - "@lerna/child-process" "3.16.5" - "@lerna/package-graph" "3.18.5" - "@lerna/project" "3.21.0" - "@lerna/validation-error" "3.13.0" - "@lerna/write-log-file" "3.13.0" +"@lerna/command@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/command/-/command-4.0.0.tgz#991c7971df8f5bf6ae6e42c808869a55361c1b98" + integrity sha512-LM9g3rt5FsPNFqIHUeRwWXLNHJ5NKzOwmVKZ8anSp4e1SPrv2HNc1V02/9QyDDZK/w+5POXH5lxZUI1CHaOK/A== + dependencies: + "@lerna/child-process" "4.0.0" + "@lerna/package-graph" "4.0.0" + "@lerna/project" "4.0.0" + "@lerna/validation-error" "4.0.0" + "@lerna/write-log-file" "4.0.0" clone-deep "^4.0.1" dedent "^0.7.0" - execa "^1.0.0" + execa "^5.0.0" is-ci "^2.0.0" npmlog "^4.1.2" -"@lerna/conventional-commits@3.22.0": - version "3.22.0" - resolved "https://registry.yarnpkg.com/@lerna/conventional-commits/-/conventional-commits-3.22.0.tgz#2798f4881ee2ef457bdae027ab7d0bf0af6f1e09" - integrity sha512-z4ZZk1e8Mhz7+IS8NxHr64wyklHctCJyWpJKEZZPJiLFJ8yKto/x38O80R10pIzC0rr8Sy/OsjSH4bl0TbbgqA== +"@lerna/conventional-commits@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/conventional-commits/-/conventional-commits-4.0.0.tgz#660fb2c7b718cb942ead70110df61f18c6f99750" + integrity sha512-CSUQRjJHFrH8eBn7+wegZLV3OrNc0Y1FehYfYGhjLE2SIfpCL4bmfu/ViYuHh9YjwHaA+4SX6d3hR+xkeseKmw== dependencies: - "@lerna/validation-error" "3.13.0" - conventional-changelog-angular "^5.0.3" - conventional-changelog-core "^3.1.6" - conventional-recommended-bump "^5.0.0" - fs-extra "^8.1.0" - get-stream "^4.0.0" + "@lerna/validation-error" "4.0.0" + conventional-changelog-angular "^5.0.12" + conventional-changelog-core "^4.2.2" + conventional-recommended-bump "^6.1.0" + fs-extra "^9.1.0" + get-stream "^6.0.0" lodash.template "^4.5.0" - npm-package-arg "^6.1.0" + npm-package-arg "^8.1.0" npmlog "^4.1.2" - pify "^4.0.1" - semver "^6.2.0" + pify "^5.0.0" + semver "^7.3.4" -"@lerna/create-symlink@3.16.2": - version "3.16.2" - resolved "https://registry.yarnpkg.com/@lerna/create-symlink/-/create-symlink-3.16.2.tgz#412cb8e59a72f5a7d9463e4e4721ad2070149967" - integrity sha512-pzXIJp6av15P325sgiIRpsPXLFmkisLhMBCy4764d+7yjf2bzrJ4gkWVMhsv4AdF0NN3OyZ5jjzzTtLNqfR+Jw== +"@lerna/create-symlink@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/create-symlink/-/create-symlink-4.0.0.tgz#8c5317ce5ae89f67825443bd7651bf4121786228" + integrity sha512-I0phtKJJdafUiDwm7BBlEUOtogmu8+taxq6PtIrxZbllV9hWg59qkpuIsiFp+no7nfRVuaasNYHwNUhDAVQBig== dependencies: - "@zkochan/cmd-shim" "^3.1.0" - fs-extra "^8.1.0" + cmd-shim "^4.1.0" + fs-extra "^9.1.0" npmlog "^4.1.2" -"@lerna/create@3.22.0": - version "3.22.0" - resolved "https://registry.yarnpkg.com/@lerna/create/-/create-3.22.0.tgz#d6bbd037c3dc5b425fe5f6d1b817057c278f7619" - integrity sha512-MdiQQzCcB4E9fBF1TyMOaAEz9lUjIHp1Ju9H7f3lXze5JK6Fl5NYkouAvsLgY6YSIhXMY8AHW2zzXeBDY4yWkw== +"@lerna/create@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/create/-/create-4.0.0.tgz#b6947e9b5dfb6530321952998948c3e63d64d730" + integrity sha512-mVOB1niKByEUfxlbKTM1UNECWAjwUdiioIbRQZEeEabtjCL69r9rscIsjlGyhGWCfsdAG5wfq4t47nlDXdLLag== dependencies: - "@evocateur/pacote" "^9.6.3" - "@lerna/child-process" "3.16.5" - "@lerna/command" "3.21.0" - "@lerna/npm-conf" "3.16.0" - "@lerna/validation-error" "3.13.0" - camelcase "^5.0.0" + "@lerna/child-process" "4.0.0" + "@lerna/command" "4.0.0" + "@lerna/npm-conf" "4.0.0" + "@lerna/validation-error" "4.0.0" dedent "^0.7.0" - fs-extra "^8.1.0" - globby "^9.2.0" - init-package-json "^1.10.3" - npm-package-arg "^6.1.0" - p-reduce "^1.0.0" - pify "^4.0.1" - semver "^6.2.0" - slash "^2.0.0" - validate-npm-package-license "^3.0.3" + fs-extra "^9.1.0" + globby "^11.0.2" + init-package-json "^2.0.2" + npm-package-arg "^8.1.0" + p-reduce "^2.1.0" + pacote "^11.2.6" + pify "^5.0.0" + semver "^7.3.4" + slash "^3.0.0" + validate-npm-package-license "^3.0.4" validate-npm-package-name "^3.0.0" - whatwg-url "^7.0.0" + whatwg-url "^8.4.0" + yargs-parser "20.2.4" -"@lerna/describe-ref@3.16.5": - version "3.16.5" - resolved "https://registry.yarnpkg.com/@lerna/describe-ref/-/describe-ref-3.16.5.tgz#a338c25aaed837d3dc70b8a72c447c5c66346ac0" - integrity sha512-c01+4gUF0saOOtDBzbLMFOTJDHTKbDFNErEY6q6i9QaXuzy9LNN62z+Hw4acAAZuJQhrVWncVathcmkkjvSVGw== +"@lerna/describe-ref@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/describe-ref/-/describe-ref-4.0.0.tgz#53c53b4ea65fdceffa072a62bfebe6772c45d9ec" + integrity sha512-eTU5+xC4C5Gcgz+Ey4Qiw9nV2B4JJbMulsYJMW8QjGcGh8zudib7Sduj6urgZXUYNyhYpRs+teci9M2J8u+UvQ== dependencies: - "@lerna/child-process" "3.16.5" + "@lerna/child-process" "4.0.0" npmlog "^4.1.2" -"@lerna/diff@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/diff/-/diff-3.21.0.tgz#e6df0d8b9916167ff5a49fcb02ac06424280a68d" - integrity sha512-5viTR33QV3S7O+bjruo1SaR40m7F2aUHJaDAC7fL9Ca6xji+aw1KFkpCtVlISS0G8vikUREGMJh+c/VMSc8Usw== +"@lerna/diff@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/diff/-/diff-4.0.0.tgz#6d3071817aaa4205a07bf77cfc6e932796d48b92" + integrity sha512-jYPKprQVg41+MUMxx6cwtqsNm0Yxx9GDEwdiPLwcUTFx+/qKCEwifKNJ1oGIPBxyEHX2PFCOjkK39lHoj2qiag== dependencies: - "@lerna/child-process" "3.16.5" - "@lerna/command" "3.21.0" - "@lerna/validation-error" "3.13.0" + "@lerna/child-process" "4.0.0" + "@lerna/command" "4.0.0" + "@lerna/validation-error" "4.0.0" npmlog "^4.1.2" -"@lerna/exec@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/exec/-/exec-3.21.0.tgz#17f07533893cb918a17b41bcc566dc437016db26" - integrity sha512-iLvDBrIE6rpdd4GIKTY9mkXyhwsJ2RvQdB9ZU+/NhR3okXfqKc6py/24tV111jqpXTtZUW6HNydT4dMao2hi1Q== - dependencies: - "@lerna/child-process" "3.16.5" - "@lerna/command" "3.21.0" - "@lerna/filter-options" "3.20.0" - "@lerna/profiler" "3.20.0" - "@lerna/run-topologically" "3.18.5" - "@lerna/validation-error" "3.13.0" - p-map "^2.1.0" - -"@lerna/filter-options@3.20.0": - version "3.20.0" - resolved "https://registry.yarnpkg.com/@lerna/filter-options/-/filter-options-3.20.0.tgz#0f0f5d5a4783856eece4204708cc902cbc8af59b" - integrity sha512-bmcHtvxn7SIl/R9gpiNMVG7yjx7WyT0HSGw34YVZ9B+3xF/83N3r5Rgtjh4hheLZ+Q91Or0Jyu5O3Nr+AwZe2g== - dependencies: - "@lerna/collect-updates" "3.20.0" - "@lerna/filter-packages" "3.18.0" +"@lerna/exec@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/exec/-/exec-4.0.0.tgz#eb6cb95cb92d42590e9e2d628fcaf4719d4a8be6" + integrity sha512-VGXtL/b/JfY84NB98VWZpIExfhLOzy0ozm/0XaS4a2SmkAJc5CeUfrhvHxxkxiTBLkU+iVQUyYEoAT0ulQ8PCw== + dependencies: + "@lerna/child-process" "4.0.0" + "@lerna/command" "4.0.0" + "@lerna/filter-options" "4.0.0" + "@lerna/profiler" "4.0.0" + "@lerna/run-topologically" "4.0.0" + "@lerna/validation-error" "4.0.0" + p-map "^4.0.0" + +"@lerna/filter-options@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/filter-options/-/filter-options-4.0.0.tgz#ac94cc515d7fa3b47e2f7d74deddeabb1de5e9e6" + integrity sha512-vV2ANOeZhOqM0rzXnYcFFCJ/kBWy/3OA58irXih9AMTAlQLymWAK0akWybl++sUJ4HB9Hx12TOqaXbYS2NM5uw== + dependencies: + "@lerna/collect-updates" "4.0.0" + "@lerna/filter-packages" "4.0.0" dedent "^0.7.0" - figgy-pudding "^3.5.1" npmlog "^4.1.2" -"@lerna/filter-packages@3.18.0": - version "3.18.0" - resolved "https://registry.yarnpkg.com/@lerna/filter-packages/-/filter-packages-3.18.0.tgz#6a7a376d285208db03a82958cfb8172e179b4e70" - integrity sha512-6/0pMM04bCHNATIOkouuYmPg6KH3VkPCIgTfQmdkPJTullERyEQfNUKikrefjxo1vHOoCACDpy65JYyKiAbdwQ== +"@lerna/filter-packages@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/filter-packages/-/filter-packages-4.0.0.tgz#b1f70d70e1de9cdd36a4e50caa0ac501f8d012f2" + integrity sha512-+4AJIkK7iIiOaqCiVTYJxh/I9qikk4XjNQLhE3kixaqgMuHl1NQ99qXRR0OZqAWB9mh8Z1HA9bM5K1HZLBTOqA== dependencies: - "@lerna/validation-error" "3.13.0" - multimatch "^3.0.0" + "@lerna/validation-error" "4.0.0" + multimatch "^5.0.0" npmlog "^4.1.2" -"@lerna/get-npm-exec-opts@3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@lerna/get-npm-exec-opts/-/get-npm-exec-opts-3.13.0.tgz#d1b552cb0088199fc3e7e126f914e39a08df9ea5" - integrity sha512-Y0xWL0rg3boVyJk6An/vurKzubyJKtrxYv2sj4bB8Mc5zZ3tqtv0ccbOkmkXKqbzvNNF7VeUt1OJ3DRgtC/QZw== +"@lerna/get-npm-exec-opts@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/get-npm-exec-opts/-/get-npm-exec-opts-4.0.0.tgz#dc955be94a4ae75c374ef9bce91320887d34608f" + integrity sha512-yvmkerU31CTWS2c7DvmAWmZVeclPBqI7gPVr5VATUKNWJ/zmVcU4PqbYoLu92I9Qc4gY1TuUplMNdNuZTSL7IQ== dependencies: npmlog "^4.1.2" -"@lerna/get-packed@3.16.0": - version "3.16.0" - resolved "https://registry.yarnpkg.com/@lerna/get-packed/-/get-packed-3.16.0.tgz#1b316b706dcee86c7baa55e50b087959447852ff" - integrity sha512-AjsFiaJzo1GCPnJUJZiTW6J1EihrPkc2y3nMu6m3uWFxoleklsSCyImumzVZJssxMi3CPpztj8LmADLedl9kXw== +"@lerna/get-packed@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/get-packed/-/get-packed-4.0.0.tgz#0989d61624ac1f97e393bdad2137c49cd7a37823" + integrity sha512-rfWONRsEIGyPJTxFzC8ECb3ZbsDXJbfqWYyeeQQDrJRPnEJErlltRLPLgC2QWbxFgFPsoDLeQmFHJnf0iDfd8w== dependencies: - fs-extra "^8.1.0" - ssri "^6.0.1" - tar "^4.4.8" + fs-extra "^9.1.0" + ssri "^8.0.1" + tar "^6.1.0" -"@lerna/github-client@3.22.0": - version "3.22.0" - resolved "https://registry.yarnpkg.com/@lerna/github-client/-/github-client-3.22.0.tgz#5d816aa4f76747ed736ae64ff962b8f15c354d95" - integrity sha512-O/GwPW+Gzr3Eb5bk+nTzTJ3uv+jh5jGho9BOqKlajXaOkMYGBELEAqV5+uARNGWZFvYAiF4PgqHb6aCUu7XdXg== +"@lerna/github-client@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/github-client/-/github-client-4.0.0.tgz#2ced67721363ef70f8e12ffafce4410918f4a8a4" + integrity sha512-2jhsldZtTKXYUBnOm23Lb0Fx8G4qfSXF9y7UpyUgWUj+YZYd+cFxSuorwQIgk5P4XXrtVhsUesIsli+BYSThiw== dependencies: - "@lerna/child-process" "3.16.5" + "@lerna/child-process" "4.0.0" "@octokit/plugin-enterprise-rest" "^6.0.1" - "@octokit/rest" "^16.28.4" - git-url-parse "^11.1.2" + "@octokit/rest" "^18.1.0" + git-url-parse "^11.4.4" npmlog "^4.1.2" -"@lerna/gitlab-client@3.15.0": - version "3.15.0" - resolved "https://registry.yarnpkg.com/@lerna/gitlab-client/-/gitlab-client-3.15.0.tgz#91f4ec8c697b5ac57f7f25bd50fe659d24aa96a6" - integrity sha512-OsBvRSejHXUBMgwWQqNoioB8sgzL/Pf1pOUhHKtkiMl6aAWjklaaq5HPMvTIsZPfS6DJ9L5OK2GGZuooP/5c8Q== +"@lerna/gitlab-client@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/gitlab-client/-/gitlab-client-4.0.0.tgz#00dad73379c7b38951d4b4ded043504c14e2b67d" + integrity sha512-OMUpGSkeDWFf7BxGHlkbb35T7YHqVFCwBPSIR6wRsszY8PAzCYahtH3IaJzEJyUg6vmZsNl0FSr3pdA2skhxqA== dependencies: - node-fetch "^2.5.0" + node-fetch "^2.6.1" npmlog "^4.1.2" - whatwg-url "^7.0.0" - -"@lerna/global-options@3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@lerna/global-options/-/global-options-3.13.0.tgz#217662290db06ad9cf2c49d8e3100ee28eaebae1" - integrity sha512-SlZvh1gVRRzYLVluz9fryY1nJpZ0FHDGB66U9tFfvnnxmueckRQxLopn3tXj3NU1kc3QANT2I5BsQkOqZ4TEFQ== - -"@lerna/has-npm-version@3.16.5": - version "3.16.5" - resolved "https://registry.yarnpkg.com/@lerna/has-npm-version/-/has-npm-version-3.16.5.tgz#ab83956f211d8923ea6afe9b979b38cc73b15326" - integrity sha512-WL7LycR9bkftyqbYop5rEGJ9sRFIV55tSGmbN1HLrF9idwOCD7CLrT64t235t3t4O5gehDnwKI5h2U3oxTrF8Q== - dependencies: - "@lerna/child-process" "3.16.5" - semver "^6.2.0" - -"@lerna/import@3.22.0": - version "3.22.0" - resolved "https://registry.yarnpkg.com/@lerna/import/-/import-3.22.0.tgz#1a5f0394f38e23c4f642a123e5e1517e70d068d2" - integrity sha512-uWOlexasM5XR6tXi4YehODtH9Y3OZrFht3mGUFFT3OIl2s+V85xIGFfqFGMTipMPAGb2oF1UBLL48kR43hRsOg== - dependencies: - "@lerna/child-process" "3.16.5" - "@lerna/command" "3.21.0" - "@lerna/prompt" "3.18.5" - "@lerna/pulse-till-done" "3.13.0" - "@lerna/validation-error" "3.13.0" + whatwg-url "^8.4.0" + +"@lerna/global-options@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/global-options/-/global-options-4.0.0.tgz#c7d8b0de6a01d8a845e2621ea89e7f60f18c6a5f" + integrity sha512-TRMR8afAHxuYBHK7F++Ogop2a82xQjoGna1dvPOY6ltj/pEx59pdgcJfYcynYqMkFIk8bhLJJN9/ndIfX29FTQ== + +"@lerna/has-npm-version@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/has-npm-version/-/has-npm-version-4.0.0.tgz#d3fc3292c545eb28bd493b36e6237cf0279f631c" + integrity sha512-LQ3U6XFH8ZmLCsvsgq1zNDqka0Xzjq5ibVN+igAI5ccRWNaUsE/OcmsyMr50xAtNQMYMzmpw5GVLAivT2/YzCg== + dependencies: + "@lerna/child-process" "4.0.0" + semver "^7.3.4" + +"@lerna/import@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/import/-/import-4.0.0.tgz#bde656c4a451fa87ae41733ff8a8da60547c5465" + integrity sha512-FaIhd+4aiBousKNqC7TX1Uhe97eNKf5/SC7c5WZANVWtC7aBWdmswwDt3usrzCNpj6/Wwr9EtEbYROzxKH8ffg== + dependencies: + "@lerna/child-process" "4.0.0" + "@lerna/command" "4.0.0" + "@lerna/prompt" "4.0.0" + "@lerna/pulse-till-done" "4.0.0" + "@lerna/validation-error" "4.0.0" dedent "^0.7.0" - fs-extra "^8.1.0" - p-map-series "^1.0.0" + fs-extra "^9.1.0" + p-map-series "^2.1.0" -"@lerna/info@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/info/-/info-3.21.0.tgz#76696b676fdb0f35d48c83c63c1e32bb5e37814f" - integrity sha512-0XDqGYVBgWxUquFaIptW2bYSIu6jOs1BtkvRTWDDhw4zyEdp6q4eaMvqdSap1CG+7wM5jeLCi6z94wS0AuiuwA== +"@lerna/info@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/info/-/info-4.0.0.tgz#b9fb0e479d60efe1623603958a831a88b1d7f1fc" + integrity sha512-8Uboa12kaCSZEn4XRfPz5KU9XXoexSPS4oeYGj76s2UQb1O1GdnEyfjyNWoUl1KlJ2i/8nxUskpXIftoFYH0/Q== dependencies: - "@lerna/command" "3.21.0" - "@lerna/output" "3.13.0" - envinfo "^7.3.1" + "@lerna/command" "4.0.0" + "@lerna/output" "4.0.0" + envinfo "^7.7.4" -"@lerna/init@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/init/-/init-3.21.0.tgz#1e810934dc8bf4e5386c031041881d3b4096aa5c" - integrity sha512-6CM0z+EFUkFfurwdJCR+LQQF6MqHbYDCBPyhu/d086LRf58GtYZYj49J8mKG9ktayp/TOIxL/pKKjgLD8QBPOg== +"@lerna/init@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/init/-/init-4.0.0.tgz#dadff67e6dfb981e8ccbe0e6a310e837962f6c7a" + integrity sha512-wY6kygop0BCXupzWj5eLvTUqdR7vIAm0OgyV9WHpMYQGfs1V22jhztt8mtjCloD/O0nEe4tJhdG62XU5aYmPNQ== dependencies: - "@lerna/child-process" "3.16.5" - "@lerna/command" "3.21.0" - fs-extra "^8.1.0" - p-map "^2.1.0" - write-json-file "^3.2.0" + "@lerna/child-process" "4.0.0" + "@lerna/command" "4.0.0" + fs-extra "^9.1.0" + p-map "^4.0.0" + write-json-file "^4.3.0" -"@lerna/link@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/link/-/link-3.21.0.tgz#8be68ff0ccee104b174b5bbd606302c2f06e9d9b" - integrity sha512-tGu9GxrX7Ivs+Wl3w1+jrLi1nQ36kNI32dcOssij6bg0oZ2M2MDEFI9UF2gmoypTaN9uO5TSsjCFS7aR79HbdQ== +"@lerna/link@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/link/-/link-4.0.0.tgz#c3a38aabd44279d714e90f2451e31b63f0fb65ba" + integrity sha512-KlvPi7XTAcVOByfaLlOeYOfkkDcd+bejpHMCd1KcArcFTwijOwXOVi24DYomIeHvy6HsX/IUquJ4PPUJIeB4+w== dependencies: - "@lerna/command" "3.21.0" - "@lerna/package-graph" "3.18.5" - "@lerna/symlink-dependencies" "3.17.0" - p-map "^2.1.0" - slash "^2.0.0" + "@lerna/command" "4.0.0" + "@lerna/package-graph" "4.0.0" + "@lerna/symlink-dependencies" "4.0.0" + p-map "^4.0.0" + slash "^3.0.0" -"@lerna/list@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/list/-/list-3.21.0.tgz#42f76fafa56dea13b691ec8cab13832691d61da2" - integrity sha512-KehRjE83B1VaAbRRkRy6jLX1Cin8ltsrQ7FHf2bhwhRHK0S54YuA6LOoBnY/NtA8bHDX/Z+G5sMY78X30NS9tg== +"@lerna/list@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/list/-/list-4.0.0.tgz#24b4e6995bd73f81c556793fe502b847efd9d1d7" + integrity sha512-L2B5m3P+U4Bif5PultR4TI+KtW+SArwq1i75QZ78mRYxPc0U/piau1DbLOmwrdqr99wzM49t0Dlvl6twd7GHFg== dependencies: - "@lerna/command" "3.21.0" - "@lerna/filter-options" "3.20.0" - "@lerna/listable" "3.18.5" - "@lerna/output" "3.13.0" + "@lerna/command" "4.0.0" + "@lerna/filter-options" "4.0.0" + "@lerna/listable" "4.0.0" + "@lerna/output" "4.0.0" -"@lerna/listable@3.18.5": - version "3.18.5" - resolved "https://registry.yarnpkg.com/@lerna/listable/-/listable-3.18.5.tgz#e82798405b5ed8fc51843c8ef1e7a0e497388a1a" - integrity sha512-Sdr3pVyaEv5A7ZkGGYR7zN+tTl2iDcinryBPvtuv20VJrXBE8wYcOks1edBTcOWsPjCE/rMP4bo1pseyk3UTsg== +"@lerna/listable@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/listable/-/listable-4.0.0.tgz#d00d6cb4809b403f2b0374fc521a78e318b01214" + integrity sha512-/rPOSDKsOHs5/PBLINZOkRIX1joOXUXEtyUs5DHLM8q6/RP668x/1lFhw6Dx7/U+L0+tbkpGtZ1Yt0LewCLgeQ== dependencies: - "@lerna/query-graph" "3.18.5" - chalk "^2.3.1" + "@lerna/query-graph" "4.0.0" + chalk "^4.1.0" columnify "^1.5.4" -"@lerna/log-packed@3.16.0": - version "3.16.0" - resolved "https://registry.yarnpkg.com/@lerna/log-packed/-/log-packed-3.16.0.tgz#f83991041ee77b2495634e14470b42259fd2bc16" - integrity sha512-Fp+McSNBV/P2mnLUYTaSlG8GSmpXM7krKWcllqElGxvAqv6chk2K3c2k80MeVB4WvJ9tRjUUf+i7HUTiQ9/ckQ== +"@lerna/log-packed@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/log-packed/-/log-packed-4.0.0.tgz#95168fe2e26ac6a71e42f4be857519b77e57a09f" + integrity sha512-+dpCiWbdzgMAtpajLToy9PO713IHoE6GV/aizXycAyA07QlqnkpaBNZ8DW84gHdM1j79TWockGJo9PybVhrrZQ== dependencies: - byte-size "^5.0.1" + byte-size "^7.0.0" columnify "^1.5.4" has-unicode "^2.0.1" npmlog "^4.1.2" -"@lerna/npm-conf@3.16.0": - version "3.16.0" - resolved "https://registry.yarnpkg.com/@lerna/npm-conf/-/npm-conf-3.16.0.tgz#1c10a89ae2f6c2ee96962557738685300d376827" - integrity sha512-HbO3DUrTkCAn2iQ9+FF/eisDpWY5POQAOF1m7q//CZjdC2HSW3UYbKEGsSisFxSfaF9Z4jtrV+F/wX6qWs3CuA== +"@lerna/npm-conf@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/npm-conf/-/npm-conf-4.0.0.tgz#b259fd1e1cee2bf5402b236e770140ff9ade7fd2" + integrity sha512-uS7H02yQNq3oejgjxAxqq/jhwGEE0W0ntr8vM3EfpCW1F/wZruwQw+7bleJQ9vUBjmdXST//tk8mXzr5+JXCfw== dependencies: - config-chain "^1.1.11" - pify "^4.0.1" + config-chain "^1.1.12" + pify "^5.0.0" -"@lerna/npm-dist-tag@3.18.5": - version "3.18.5" - resolved "https://registry.yarnpkg.com/@lerna/npm-dist-tag/-/npm-dist-tag-3.18.5.tgz#9ef9abb7c104077b31f6fab22cc73b314d54ac55" - integrity sha512-xw0HDoIG6HreVsJND9/dGls1c+lf6vhu7yJoo56Sz5bvncTloYGLUppIfDHQr4ZvmPCK8rsh0euCVh2giPxzKQ== +"@lerna/npm-dist-tag@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/npm-dist-tag/-/npm-dist-tag-4.0.0.tgz#d1e99b4eccd3414142f0548ad331bf2d53f3257a" + integrity sha512-F20sg28FMYTgXqEQihgoqSfwmq+Id3zT23CnOwD+XQMPSy9IzyLf1fFVH319vXIw6NF6Pgs4JZN2Qty6/CQXGw== dependencies: - "@evocateur/npm-registry-fetch" "^4.0.0" - "@lerna/otplease" "3.18.5" - figgy-pudding "^3.5.1" - npm-package-arg "^6.1.0" + "@lerna/otplease" "4.0.0" + npm-package-arg "^8.1.0" + npm-registry-fetch "^9.0.0" npmlog "^4.1.2" -"@lerna/npm-install@3.16.5": - version "3.16.5" - resolved "https://registry.yarnpkg.com/@lerna/npm-install/-/npm-install-3.16.5.tgz#d6bfdc16f81285da66515ae47924d6e278d637d3" - integrity sha512-hfiKk8Eku6rB9uApqsalHHTHY+mOrrHeWEs+gtg7+meQZMTS3kzv4oVp5cBZigndQr3knTLjwthT/FX4KvseFg== +"@lerna/npm-install@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/npm-install/-/npm-install-4.0.0.tgz#31180be3ab3b7d1818a1a0c206aec156b7094c78" + integrity sha512-aKNxq2j3bCH3eXl3Fmu4D54s/YLL9WSwV8W7X2O25r98wzrO38AUN6AB9EtmAx+LV/SP15et7Yueg9vSaanRWg== dependencies: - "@lerna/child-process" "3.16.5" - "@lerna/get-npm-exec-opts" "3.13.0" - fs-extra "^8.1.0" - npm-package-arg "^6.1.0" + "@lerna/child-process" "4.0.0" + "@lerna/get-npm-exec-opts" "4.0.0" + fs-extra "^9.1.0" + npm-package-arg "^8.1.0" npmlog "^4.1.2" - signal-exit "^3.0.2" - write-pkg "^3.1.0" + signal-exit "^3.0.3" + write-pkg "^4.0.0" -"@lerna/npm-publish@3.18.5": - version "3.18.5" - resolved "https://registry.yarnpkg.com/@lerna/npm-publish/-/npm-publish-3.18.5.tgz#240e4039959fd9816b49c5b07421e11b5cb000af" - integrity sha512-3etLT9+2L8JAx5F8uf7qp6iAtOLSMj+ZYWY6oUgozPi/uLqU0/gsMsEXh3F0+YVW33q0M61RpduBoAlOOZnaTg== +"@lerna/npm-publish@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/npm-publish/-/npm-publish-4.0.0.tgz#84eb62e876fe949ae1fd62c60804423dbc2c4472" + integrity sha512-vQb7yAPRo5G5r77DRjHITc9piR9gvEKWrmfCH7wkfBnGWEqu7n8/4bFQ7lhnkujvc8RXOsYpvbMQkNfkYibD/w== dependencies: - "@evocateur/libnpmpublish" "^1.2.2" - "@lerna/otplease" "3.18.5" - "@lerna/run-lifecycle" "3.16.2" - figgy-pudding "^3.5.1" - fs-extra "^8.1.0" - npm-package-arg "^6.1.0" + "@lerna/otplease" "4.0.0" + "@lerna/run-lifecycle" "4.0.0" + fs-extra "^9.1.0" + libnpmpublish "^4.0.0" + npm-package-arg "^8.1.0" npmlog "^4.1.2" - pify "^4.0.1" - read-package-json "^2.0.13" + pify "^5.0.0" + read-package-json "^3.0.0" -"@lerna/npm-run-script@3.16.5": - version "3.16.5" - resolved "https://registry.yarnpkg.com/@lerna/npm-run-script/-/npm-run-script-3.16.5.tgz#9c2ec82453a26c0b46edc0bb7c15816c821f5c15" - integrity sha512-1asRi+LjmVn3pMjEdpqKJZFT/3ZNpb+VVeJMwrJaV/3DivdNg7XlPK9LTrORuKU4PSvhdEZvJmSlxCKyDpiXsQ== +"@lerna/npm-run-script@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/npm-run-script/-/npm-run-script-4.0.0.tgz#dfebf4f4601442e7c0b5214f9fb0d96c9350743b" + integrity sha512-Jmyh9/IwXJjOXqKfIgtxi0bxi1pUeKe5bD3S81tkcy+kyng/GNj9WSqD5ZggoNP2NP//s4CLDAtUYLdP7CU9rA== dependencies: - "@lerna/child-process" "3.16.5" - "@lerna/get-npm-exec-opts" "3.13.0" + "@lerna/child-process" "4.0.0" + "@lerna/get-npm-exec-opts" "4.0.0" npmlog "^4.1.2" -"@lerna/otplease@3.18.5": - version "3.18.5" - resolved "https://registry.yarnpkg.com/@lerna/otplease/-/otplease-3.18.5.tgz#b77b8e760b40abad9f7658d988f3ea77d4fd0231" - integrity sha512-S+SldXAbcXTEDhzdxYLU0ZBKuYyURP/ND2/dK6IpKgLxQYh/z4ScljPDMyKymmEvgiEJmBsPZAAPfmNPEzxjog== +"@lerna/otplease@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/otplease/-/otplease-4.0.0.tgz#84972eb43448f8a1077435ba1c5e59233b725850" + integrity sha512-Sgzbqdk1GH4psNiT6hk+BhjOfIr/5KhGBk86CEfHNJTk9BK4aZYyJD4lpDbDdMjIV4g03G7pYoqHzH765T4fxw== dependencies: - "@lerna/prompt" "3.18.5" - figgy-pudding "^3.5.1" + "@lerna/prompt" "4.0.0" -"@lerna/output@3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@lerna/output/-/output-3.13.0.tgz#3ded7cc908b27a9872228a630d950aedae7a4989" - integrity sha512-7ZnQ9nvUDu/WD+bNsypmPG5MwZBwu86iRoiW6C1WBuXXDxM5cnIAC1m2WxHeFnjyMrYlRXM9PzOQ9VDD+C15Rg== +"@lerna/output@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/output/-/output-4.0.0.tgz#b1d72215c0e35483e4f3e9994debc82c621851f2" + integrity sha512-Un1sHtO1AD7buDQrpnaYTi2EG6sLF+KOPEAMxeUYG5qG3khTs2Zgzq5WE3dt2N/bKh7naESt20JjIW6tBELP0w== dependencies: npmlog "^4.1.2" -"@lerna/pack-directory@3.16.4": - version "3.16.4" - resolved "https://registry.yarnpkg.com/@lerna/pack-directory/-/pack-directory-3.16.4.tgz#3eae5f91bdf5acfe0384510ed53faddc4c074693" - integrity sha512-uxSF0HZeGyKaaVHz5FroDY9A5NDDiCibrbYR6+khmrhZtY0Bgn6hWq8Gswl9iIlymA+VzCbshWIMX4o2O8C8ng== +"@lerna/pack-directory@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/pack-directory/-/pack-directory-4.0.0.tgz#8b617db95d20792f043aaaa13a9ccc0e04cb4c74" + integrity sha512-NJrmZNmBHS+5aM+T8N6FVbaKFScVqKlQFJNY2k7nsJ/uklNKsLLl6VhTQBPwMTbf6Tf7l6bcKzpy7aePuq9UiQ== dependencies: - "@lerna/get-packed" "3.16.0" - "@lerna/package" "3.16.0" - "@lerna/run-lifecycle" "3.16.2" - figgy-pudding "^3.5.1" - npm-packlist "^1.4.4" + "@lerna/get-packed" "4.0.0" + "@lerna/package" "4.0.0" + "@lerna/run-lifecycle" "4.0.0" + npm-packlist "^2.1.4" npmlog "^4.1.2" - tar "^4.4.10" - temp-write "^3.4.0" + tar "^6.1.0" + temp-write "^4.0.0" -"@lerna/package-graph@3.18.5": - version "3.18.5" - resolved "https://registry.yarnpkg.com/@lerna/package-graph/-/package-graph-3.18.5.tgz#c740e2ea3578d059e551633e950690831b941f6b" - integrity sha512-8QDrR9T+dBegjeLr+n9WZTVxUYUhIUjUgZ0gvNxUBN8S1WB9r6H5Yk56/MVaB64tA3oGAN9IIxX6w0WvTfFudA== +"@lerna/package-graph@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/package-graph/-/package-graph-4.0.0.tgz#16a00253a8ac810f72041481cb46bcee8d8123dd" + integrity sha512-QED2ZCTkfXMKFoTGoccwUzjHtZMSf3UKX14A4/kYyBms9xfFsesCZ6SLI5YeySEgcul8iuIWfQFZqRw+Qrjraw== dependencies: - "@lerna/prerelease-id-from-version" "3.16.0" - "@lerna/validation-error" "3.13.0" - npm-package-arg "^6.1.0" + "@lerna/prerelease-id-from-version" "4.0.0" + "@lerna/validation-error" "4.0.0" + npm-package-arg "^8.1.0" npmlog "^4.1.2" - semver "^6.2.0" + semver "^7.3.4" -"@lerna/package@3.16.0": - version "3.16.0" - resolved "https://registry.yarnpkg.com/@lerna/package/-/package-3.16.0.tgz#7e0a46e4697ed8b8a9c14d59c7f890e0d38ba13c" - integrity sha512-2lHBWpaxcBoiNVbtyLtPUuTYEaB/Z+eEqRS9duxpZs6D+mTTZMNy6/5vpEVSCBmzvdYpyqhqaYjjSLvjjr5Riw== +"@lerna/package@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/package/-/package-4.0.0.tgz#1b4c259c4bcff45c876ee1d591a043aacbc0d6b7" + integrity sha512-l0M/izok6FlyyitxiQKr+gZLVFnvxRQdNhzmQ6nRnN9dvBJWn+IxxpM+cLqGACatTnyo9LDzNTOj2Db3+s0s8Q== dependencies: - load-json-file "^5.3.0" - npm-package-arg "^6.1.0" - write-pkg "^3.1.0" + load-json-file "^6.2.0" + npm-package-arg "^8.1.0" + write-pkg "^4.0.0" -"@lerna/prerelease-id-from-version@3.16.0": - version "3.16.0" - resolved "https://registry.yarnpkg.com/@lerna/prerelease-id-from-version/-/prerelease-id-from-version-3.16.0.tgz#b24bfa789f5e1baab914d7b08baae9b7bd7d83a1" - integrity sha512-qZyeUyrE59uOK8rKdGn7jQz+9uOpAaF/3hbslJVFL1NqF9ELDTqjCPXivuejMX/lN4OgD6BugTO4cR7UTq/sZA== +"@lerna/prerelease-id-from-version@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/prerelease-id-from-version/-/prerelease-id-from-version-4.0.0.tgz#c7e0676fcee1950d85630e108eddecdd5b48c916" + integrity sha512-GQqguzETdsYRxOSmdFZ6zDBXDErIETWOqomLERRY54f4p+tk4aJjoVdd9xKwehC9TBfIFvlRbL1V9uQGHh1opg== dependencies: - semver "^6.2.0" + semver "^7.3.4" -"@lerna/profiler@3.20.0": - version "3.20.0" - resolved "https://registry.yarnpkg.com/@lerna/profiler/-/profiler-3.20.0.tgz#0f6dc236f4ea8f9ea5f358c6703305a4f32ad051" - integrity sha512-bh8hKxAlm6yu8WEOvbLENm42i2v9SsR4WbrCWSbsmOElx3foRnMlYk7NkGECa+U5c3K4C6GeBbwgqs54PP7Ljg== +"@lerna/profiler@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/profiler/-/profiler-4.0.0.tgz#8a53ab874522eae15d178402bff90a14071908e9" + integrity sha512-/BaEbqnVh1LgW/+qz8wCuI+obzi5/vRE8nlhjPzdEzdmWmZXuCKyWSEzAyHOJWw1ntwMiww5dZHhFQABuoFz9Q== dependencies: - figgy-pudding "^3.5.1" - fs-extra "^8.1.0" + fs-extra "^9.1.0" npmlog "^4.1.2" - upath "^1.2.0" + upath "^2.0.1" -"@lerna/project@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/project/-/project-3.21.0.tgz#5d784d2d10c561a00f20320bcdb040997c10502d" - integrity sha512-xT1mrpET2BF11CY32uypV2GPtPVm6Hgtha7D81GQP9iAitk9EccrdNjYGt5UBYASl4CIDXBRxwmTTVGfrCx82A== +"@lerna/project@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/project/-/project-4.0.0.tgz#ff84893935833533a74deff30c0e64ddb7f0ba6b" + integrity sha512-o0MlVbDkD5qRPkFKlBZsXZjoNTWPyuL58564nSfZJ6JYNmgAptnWPB2dQlAc7HWRZkmnC2fCkEdoU+jioPavbg== dependencies: - "@lerna/package" "3.16.0" - "@lerna/validation-error" "3.13.0" - cosmiconfig "^5.1.0" + "@lerna/package" "4.0.0" + "@lerna/validation-error" "4.0.0" + cosmiconfig "^7.0.0" dedent "^0.7.0" - dot-prop "^4.2.0" - glob-parent "^5.0.0" - globby "^9.2.0" - load-json-file "^5.3.0" + dot-prop "^6.0.1" + glob-parent "^5.1.1" + globby "^11.0.2" + load-json-file "^6.2.0" npmlog "^4.1.2" - p-map "^2.1.0" - resolve-from "^4.0.0" - write-json-file "^3.2.0" + p-map "^4.0.0" + resolve-from "^5.0.0" + write-json-file "^4.3.0" -"@lerna/prompt@3.18.5": - version "3.18.5" - resolved "https://registry.yarnpkg.com/@lerna/prompt/-/prompt-3.18.5.tgz#628cd545f225887d060491ab95df899cfc5218a1" - integrity sha512-rkKj4nm1twSbBEb69+Em/2jAERK8htUuV8/xSjN0NPC+6UjzAwY52/x9n5cfmpa9lyKf/uItp7chCI7eDmNTKQ== +"@lerna/prompt@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/prompt/-/prompt-4.0.0.tgz#5ec69a803f3f0db0ad9f221dad64664d3daca41b" + integrity sha512-4Ig46oCH1TH5M7YyTt53fT6TuaKMgqUUaqdgxvp6HP6jtdak6+amcsqB8YGz2eQnw/sdxunx84DfI9XpoLj4bQ== dependencies: - inquirer "^6.2.0" + inquirer "^7.3.3" npmlog "^4.1.2" -"@lerna/publish@3.22.1": - version "3.22.1" - resolved "https://registry.yarnpkg.com/@lerna/publish/-/publish-3.22.1.tgz#b4f7ce3fba1e9afb28be4a1f3d88222269ba9519" - integrity sha512-PG9CM9HUYDreb1FbJwFg90TCBQooGjj+n/pb3gw/eH5mEDq0p8wKdLFe0qkiqUkm/Ub5C8DbVFertIo0Vd0zcw== - dependencies: - "@evocateur/libnpmaccess" "^3.1.2" - "@evocateur/npm-registry-fetch" "^4.0.0" - "@evocateur/pacote" "^9.6.3" - "@lerna/check-working-tree" "3.16.5" - "@lerna/child-process" "3.16.5" - "@lerna/collect-updates" "3.20.0" - "@lerna/command" "3.21.0" - "@lerna/describe-ref" "3.16.5" - "@lerna/log-packed" "3.16.0" - "@lerna/npm-conf" "3.16.0" - "@lerna/npm-dist-tag" "3.18.5" - "@lerna/npm-publish" "3.18.5" - "@lerna/otplease" "3.18.5" - "@lerna/output" "3.13.0" - "@lerna/pack-directory" "3.16.4" - "@lerna/prerelease-id-from-version" "3.16.0" - "@lerna/prompt" "3.18.5" - "@lerna/pulse-till-done" "3.13.0" - "@lerna/run-lifecycle" "3.16.2" - "@lerna/run-topologically" "3.18.5" - "@lerna/validation-error" "3.13.0" - "@lerna/version" "3.22.1" - figgy-pudding "^3.5.1" - fs-extra "^8.1.0" - npm-package-arg "^6.1.0" +"@lerna/publish@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/publish/-/publish-4.0.0.tgz#f67011305adeba120066a3b6d984a5bb5fceef65" + integrity sha512-K8jpqjHrChH22qtkytA5GRKIVFEtqBF6JWj1I8dWZtHs4Jywn8yB1jQ3BAMLhqmDJjWJtRck0KXhQQKzDK2UPg== + dependencies: + "@lerna/check-working-tree" "4.0.0" + "@lerna/child-process" "4.0.0" + "@lerna/collect-updates" "4.0.0" + "@lerna/command" "4.0.0" + "@lerna/describe-ref" "4.0.0" + "@lerna/log-packed" "4.0.0" + "@lerna/npm-conf" "4.0.0" + "@lerna/npm-dist-tag" "4.0.0" + "@lerna/npm-publish" "4.0.0" + "@lerna/otplease" "4.0.0" + "@lerna/output" "4.0.0" + "@lerna/pack-directory" "4.0.0" + "@lerna/prerelease-id-from-version" "4.0.0" + "@lerna/prompt" "4.0.0" + "@lerna/pulse-till-done" "4.0.0" + "@lerna/run-lifecycle" "4.0.0" + "@lerna/run-topologically" "4.0.0" + "@lerna/validation-error" "4.0.0" + "@lerna/version" "4.0.0" + fs-extra "^9.1.0" + libnpmaccess "^4.0.1" + npm-package-arg "^8.1.0" + npm-registry-fetch "^9.0.0" npmlog "^4.1.2" - p-finally "^1.0.0" - p-map "^2.1.0" - p-pipe "^1.2.0" - semver "^6.2.0" + p-map "^4.0.0" + p-pipe "^3.1.0" + pacote "^11.2.6" + semver "^7.3.4" -"@lerna/pulse-till-done@3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@lerna/pulse-till-done/-/pulse-till-done-3.13.0.tgz#c8e9ce5bafaf10d930a67d7ed0ccb5d958fe0110" - integrity sha512-1SOHpy7ZNTPulzIbargrgaJX387csN7cF1cLOGZiJQA6VqnS5eWs2CIrG8i8wmaUavj2QlQ5oEbRMVVXSsGrzA== +"@lerna/pulse-till-done@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/pulse-till-done/-/pulse-till-done-4.0.0.tgz#04bace7d483a8205c187b806bcd8be23d7bb80a3" + integrity sha512-Frb4F7QGckaybRhbF7aosLsJ5e9WuH7h0KUkjlzSByVycxY91UZgaEIVjS2oN9wQLrheLMHl6SiFY0/Pvo0Cxg== dependencies: npmlog "^4.1.2" -"@lerna/query-graph@3.18.5": - version "3.18.5" - resolved "https://registry.yarnpkg.com/@lerna/query-graph/-/query-graph-3.18.5.tgz#df4830bb5155273003bf35e8dda1c32d0927bd86" - integrity sha512-50Lf4uuMpMWvJ306be3oQDHrWV42nai9gbIVByPBYJuVW8dT8O8pA3EzitNYBUdLL9/qEVbrR0ry1HD7EXwtRA== +"@lerna/query-graph@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/query-graph/-/query-graph-4.0.0.tgz#09dd1c819ac5ee3f38db23931143701f8a6eef63" + integrity sha512-YlP6yI3tM4WbBmL9GCmNDoeQyzcyg1e4W96y/PKMZa5GbyUvkS2+Jc2kwPD+5KcXou3wQZxSPzR3Te5OenaDdg== dependencies: - "@lerna/package-graph" "3.18.5" - figgy-pudding "^3.5.1" + "@lerna/package-graph" "4.0.0" -"@lerna/resolve-symlink@3.16.0": - version "3.16.0" - resolved "https://registry.yarnpkg.com/@lerna/resolve-symlink/-/resolve-symlink-3.16.0.tgz#37fc7095fabdbcf317c26eb74e0d0bde8efd2386" - integrity sha512-Ibj5e7njVHNJ/NOqT4HlEgPFPtPLWsO7iu59AM5bJDcAJcR96mLZ7KGVIsS2tvaO7akMEJvt2P+ErwCdloG3jQ== +"@lerna/resolve-symlink@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/resolve-symlink/-/resolve-symlink-4.0.0.tgz#6d006628a210c9b821964657a9e20a8c9a115e14" + integrity sha512-RtX8VEUzqT+uLSCohx8zgmjc6zjyRlh6i/helxtZTMmc4+6O4FS9q5LJas2uGO2wKvBlhcD6siibGt7dIC3xZA== dependencies: - fs-extra "^8.1.0" + fs-extra "^9.1.0" npmlog "^4.1.2" - read-cmd-shim "^1.0.1" + read-cmd-shim "^2.0.0" -"@lerna/rimraf-dir@3.16.5": - version "3.16.5" - resolved "https://registry.yarnpkg.com/@lerna/rimraf-dir/-/rimraf-dir-3.16.5.tgz#04316ab5ffd2909657aaf388ea502cb8c2f20a09" - integrity sha512-bQlKmO0pXUsXoF8lOLknhyQjOZsCc0bosQDoX4lujBXSWxHVTg1VxURtWf2lUjz/ACsJVDfvHZbDm8kyBk5okA== +"@lerna/rimraf-dir@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/rimraf-dir/-/rimraf-dir-4.0.0.tgz#2edf3b62d4eb0ef4e44e430f5844667d551ec25a" + integrity sha512-QNH9ABWk9mcMJh2/muD9iYWBk1oQd40y6oH+f3wwmVGKYU5YJD//+zMiBI13jxZRtwBx0vmBZzkBkK1dR11cBg== dependencies: - "@lerna/child-process" "3.16.5" + "@lerna/child-process" "4.0.0" npmlog "^4.1.2" - path-exists "^3.0.0" - rimraf "^2.6.2" + path-exists "^4.0.0" + rimraf "^3.0.2" -"@lerna/run-lifecycle@3.16.2": - version "3.16.2" - resolved "https://registry.yarnpkg.com/@lerna/run-lifecycle/-/run-lifecycle-3.16.2.tgz#67b288f8ea964db9ea4fb1fbc7715d5bbb0bce00" - integrity sha512-RqFoznE8rDpyyF0rOJy3+KjZCeTkO8y/OB9orPauR7G2xQ7PTdCpgo7EO6ZNdz3Al+k1BydClZz/j78gNCmL2A== +"@lerna/run-lifecycle@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/run-lifecycle/-/run-lifecycle-4.0.0.tgz#e648a46f9210a9bcd7c391df6844498cb5079334" + integrity sha512-IwxxsajjCQQEJAeAaxF8QdEixfI7eLKNm4GHhXHrgBu185JcwScFZrj9Bs+PFKxwb+gNLR4iI5rpUdY8Y0UdGQ== dependencies: - "@lerna/npm-conf" "3.16.0" - figgy-pudding "^3.5.1" - npm-lifecycle "^3.1.2" + "@lerna/npm-conf" "4.0.0" + npm-lifecycle "^3.1.5" npmlog "^4.1.2" -"@lerna/run-topologically@3.18.5": - version "3.18.5" - resolved "https://registry.yarnpkg.com/@lerna/run-topologically/-/run-topologically-3.18.5.tgz#3cd639da20e967d7672cb88db0f756b92f2fdfc3" - integrity sha512-6N1I+6wf4hLOnPW+XDZqwufyIQ6gqoPfHZFkfWlvTQ+Ue7CuF8qIVQ1Eddw5HKQMkxqN10thKOFfq/9NQZ4NUg== +"@lerna/run-topologically@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/run-topologically/-/run-topologically-4.0.0.tgz#af846eeee1a09b0c2be0d1bfb5ef0f7b04bb1827" + integrity sha512-EVZw9hGwo+5yp+VL94+NXRYisqgAlj0jWKWtAIynDCpghRxCE5GMO3xrQLmQgqkpUl9ZxQFpICgYv5DW4DksQA== dependencies: - "@lerna/query-graph" "3.18.5" - figgy-pudding "^3.5.1" - p-queue "^4.0.0" + "@lerna/query-graph" "4.0.0" + p-queue "^6.6.2" -"@lerna/run@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/run/-/run-3.21.0.tgz#2a35ec84979e4d6e42474fe148d32e5de1cac891" - integrity sha512-fJF68rT3veh+hkToFsBmUJ9MHc9yGXA7LSDvhziAojzOb0AI/jBDp6cEcDQyJ7dbnplba2Lj02IH61QUf9oW0Q== - dependencies: - "@lerna/command" "3.21.0" - "@lerna/filter-options" "3.20.0" - "@lerna/npm-run-script" "3.16.5" - "@lerna/output" "3.13.0" - "@lerna/profiler" "3.20.0" - "@lerna/run-topologically" "3.18.5" - "@lerna/timer" "3.13.0" - "@lerna/validation-error" "3.13.0" - p-map "^2.1.0" - -"@lerna/symlink-binary@3.17.0": - version "3.17.0" - resolved "https://registry.yarnpkg.com/@lerna/symlink-binary/-/symlink-binary-3.17.0.tgz#8f8031b309863814883d3f009877f82e38aef45a" - integrity sha512-RLpy9UY6+3nT5J+5jkM5MZyMmjNHxZIZvXLV+Q3MXrf7Eaa1hNqyynyj4RO95fxbS+EZc4XVSk25DGFQbcRNSQ== - dependencies: - "@lerna/create-symlink" "3.16.2" - "@lerna/package" "3.16.0" - fs-extra "^8.1.0" - p-map "^2.1.0" +"@lerna/run@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/run/-/run-4.0.0.tgz#4bc7fda055a729487897c23579694f6183c91262" + integrity sha512-9giulCOzlMPzcZS/6Eov6pxE9gNTyaXk0Man+iCIdGJNMrCnW7Dme0Z229WWP/UoxDKg71F2tMsVVGDiRd8fFQ== + dependencies: + "@lerna/command" "4.0.0" + "@lerna/filter-options" "4.0.0" + "@lerna/npm-run-script" "4.0.0" + "@lerna/output" "4.0.0" + "@lerna/profiler" "4.0.0" + "@lerna/run-topologically" "4.0.0" + "@lerna/timer" "4.0.0" + "@lerna/validation-error" "4.0.0" + p-map "^4.0.0" + +"@lerna/symlink-binary@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/symlink-binary/-/symlink-binary-4.0.0.tgz#21009f62d53a425f136cb4c1a32c6b2a0cc02d47" + integrity sha512-zualodWC4q1QQc1pkz969hcFeWXOsVYZC5AWVtAPTDfLl+TwM7eG/O6oP+Rr3fFowspxo6b1TQ6sYfDV6HXNWA== + dependencies: + "@lerna/create-symlink" "4.0.0" + "@lerna/package" "4.0.0" + fs-extra "^9.1.0" + p-map "^4.0.0" -"@lerna/symlink-dependencies@3.17.0": - version "3.17.0" - resolved "https://registry.yarnpkg.com/@lerna/symlink-dependencies/-/symlink-dependencies-3.17.0.tgz#48d6360e985865a0e56cd8b51b308a526308784a" - integrity sha512-KmjU5YT1bpt6coOmdFueTJ7DFJL4H1w5eF8yAQ2zsGNTtZ+i5SGFBWpb9AQaw168dydc3s4eu0W0Sirda+F59Q== +"@lerna/symlink-dependencies@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/symlink-dependencies/-/symlink-dependencies-4.0.0.tgz#8910eca084ae062642d0490d8972cf2d98e9ebbd" + integrity sha512-BABo0MjeUHNAe2FNGty1eantWp8u83BHSeIMPDxNq0MuW2K3CiQRaeWT3EGPAzXpGt0+hVzBrA6+OT0GPn7Yuw== dependencies: - "@lerna/create-symlink" "3.16.2" - "@lerna/resolve-symlink" "3.16.0" - "@lerna/symlink-binary" "3.17.0" - fs-extra "^8.1.0" - p-finally "^1.0.0" - p-map "^2.1.0" - p-map-series "^1.0.0" + "@lerna/create-symlink" "4.0.0" + "@lerna/resolve-symlink" "4.0.0" + "@lerna/symlink-binary" "4.0.0" + fs-extra "^9.1.0" + p-map "^4.0.0" + p-map-series "^2.1.0" -"@lerna/timer@3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@lerna/timer/-/timer-3.13.0.tgz#bcd0904551db16e08364d6c18e5e2160fc870781" - integrity sha512-RHWrDl8U4XNPqY5MQHkToWS9jHPnkLZEt5VD+uunCKTfzlxGnRCr3/zVr8VGy/uENMYpVP3wJa4RKGY6M0vkRw== +"@lerna/timer@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/timer/-/timer-4.0.0.tgz#a52e51bfcd39bfd768988049ace7b15c1fd7a6da" + integrity sha512-WFsnlaE7SdOvjuyd05oKt8Leg3ENHICnvX3uYKKdByA+S3g+TCz38JsNs7OUZVt+ba63nC2nbXDlUnuT2Xbsfg== -"@lerna/validation-error@3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@lerna/validation-error/-/validation-error-3.13.0.tgz#c86b8f07c5ab9539f775bd8a54976e926f3759c3" - integrity sha512-SiJP75nwB8GhgwLKQfdkSnDufAaCbkZWJqEDlKOUPUvVOplRGnfL+BPQZH5nvq2BYSRXsksXWZ4UHVnQZI/HYA== +"@lerna/validation-error@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/validation-error/-/validation-error-4.0.0.tgz#af9d62fe8304eaa2eb9a6ba1394f9aa807026d35" + integrity sha512-1rBOM5/koiVWlRi3V6dB863E1YzJS8v41UtsHgMr6gB2ncJ2LsQtMKlJpi3voqcgh41H8UsPXR58RrrpPpufyw== dependencies: npmlog "^4.1.2" -"@lerna/version@3.22.1": - version "3.22.1" - resolved "https://registry.yarnpkg.com/@lerna/version/-/version-3.22.1.tgz#9805a9247a47ee62d6b81bd9fa5fb728b24b59e2" - integrity sha512-PSGt/K1hVqreAFoi3zjD0VEDupQ2WZVlVIwesrE5GbrL2BjXowjCsTDPqblahDUPy0hp6h7E2kG855yLTp62+g== - dependencies: - "@lerna/check-working-tree" "3.16.5" - "@lerna/child-process" "3.16.5" - "@lerna/collect-updates" "3.20.0" - "@lerna/command" "3.21.0" - "@lerna/conventional-commits" "3.22.0" - "@lerna/github-client" "3.22.0" - "@lerna/gitlab-client" "3.15.0" - "@lerna/output" "3.13.0" - "@lerna/prerelease-id-from-version" "3.16.0" - "@lerna/prompt" "3.18.5" - "@lerna/run-lifecycle" "3.16.2" - "@lerna/run-topologically" "3.18.5" - "@lerna/validation-error" "3.13.0" - chalk "^2.3.1" +"@lerna/version@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/version/-/version-4.0.0.tgz#532659ec6154d8a8789c5ab53878663e244e3228" + integrity sha512-otUgiqs5W9zGWJZSCCMRV/2Zm2A9q9JwSDS7s/tlKq4mWCYriWo7+wsHEA/nPTMDyYyBO5oyZDj+3X50KDUzeA== + dependencies: + "@lerna/check-working-tree" "4.0.0" + "@lerna/child-process" "4.0.0" + "@lerna/collect-updates" "4.0.0" + "@lerna/command" "4.0.0" + "@lerna/conventional-commits" "4.0.0" + "@lerna/github-client" "4.0.0" + "@lerna/gitlab-client" "4.0.0" + "@lerna/output" "4.0.0" + "@lerna/prerelease-id-from-version" "4.0.0" + "@lerna/prompt" "4.0.0" + "@lerna/run-lifecycle" "4.0.0" + "@lerna/run-topologically" "4.0.0" + "@lerna/validation-error" "4.0.0" + chalk "^4.1.0" dedent "^0.7.0" - load-json-file "^5.3.0" + load-json-file "^6.2.0" minimatch "^3.0.4" npmlog "^4.1.2" - p-map "^2.1.0" - p-pipe "^1.2.0" - p-reduce "^1.0.0" - p-waterfall "^1.0.0" - semver "^6.2.0" - slash "^2.0.0" - temp-write "^3.4.0" - write-json-file "^3.2.0" + p-map "^4.0.0" + p-pipe "^3.1.0" + p-reduce "^2.1.0" + p-waterfall "^2.1.1" + semver "^7.3.4" + slash "^3.0.0" + temp-write "^4.0.0" + write-json-file "^4.3.0" -"@lerna/write-log-file@3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@lerna/write-log-file/-/write-log-file-3.13.0.tgz#b78d9e4cfc1349a8be64d91324c4c8199e822a26" - integrity sha512-RibeMnDPvlL8bFYW5C8cs4mbI3AHfQef73tnJCQ/SgrXZHehmHnsyWUiE7qDQCAo+B1RfTapvSyFF69iPj326A== +"@lerna/write-log-file@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@lerna/write-log-file/-/write-log-file-4.0.0.tgz#18221a38a6a307d6b0a5844dd592ad53fa27091e" + integrity sha512-XRG5BloiArpXRakcnPHmEHJp+4AtnhRtpDIHSghmXD5EichI1uD73J7FgPp30mm2pDRq3FdqB0NbwSEsJ9xFQg== dependencies: npmlog "^4.1.2" - write-file-atomic "^2.3.0" - -"@mrmlnc/readdir-enhanced@^2.2.1": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" - integrity sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g== - dependencies: - call-me-maybe "^1.0.1" - glob-to-regexp "^0.3.0" + write-file-atomic "^3.0.3" "@nodelib/fs.scandir@2.1.4": version "2.1.4" @@ -1300,11 +1204,6 @@ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz#a3f2dd61bab43b8db8fa108a121cfffe4c676655" integrity sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q== -"@nodelib/fs.stat@^1.1.2": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" - integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== - "@nodelib/fs.walk@^1.2.3": version "1.2.6" resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz#cce9396b30aa5afe9e3756608f5831adcb53d063" @@ -1313,7 +1212,66 @@ "@nodelib/fs.scandir" "2.1.4" fastq "^1.6.0" -"@octokit/auth-token@^2.4.0", "@octokit/auth-token@^2.4.4": +"@npmcli/ci-detect@^1.0.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@npmcli/ci-detect/-/ci-detect-1.3.0.tgz#6c1d2c625fb6ef1b9dea85ad0a5afcbef85ef22a" + integrity sha512-oN3y7FAROHhrAt7Rr7PnTSwrHrZVRTS2ZbyxeQwSSYD0ifwM3YNgQqbaRmjcWoPyq77MjchusjJDspbzMmip1Q== + +"@npmcli/git@^2.0.1": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-2.0.6.tgz#47b97e96b2eede3f38379262fa3bdfa6eae57bf2" + integrity sha512-a1MnTfeRPBaKbFY07fd+6HugY1WAkKJzdiJvlRub/9o5xz2F/JtPacZZapx5zRJUQFIzSL677vmTSxEcDMrDbg== + dependencies: + "@npmcli/promise-spawn" "^1.1.0" + lru-cache "^6.0.0" + mkdirp "^1.0.3" + npm-pick-manifest "^6.0.0" + promise-inflight "^1.0.1" + promise-retry "^2.0.1" + semver "^7.3.2" + unique-filename "^1.1.1" + which "^2.0.2" + +"@npmcli/installed-package-contents@^1.0.6": + version "1.0.7" + resolved "https://registry.yarnpkg.com/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz#ab7408c6147911b970a8abe261ce512232a3f4fa" + integrity sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw== + dependencies: + npm-bundled "^1.1.1" + npm-normalize-package-bin "^1.0.1" + +"@npmcli/move-file@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" + integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg== + dependencies: + mkdirp "^1.0.4" + rimraf "^3.0.2" + +"@npmcli/node-gyp@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@npmcli/node-gyp/-/node-gyp-1.0.2.tgz#3cdc1f30e9736dbc417373ed803b42b1a0a29ede" + integrity sha512-yrJUe6reVMpktcvagumoqD9r08fH1iRo01gn1u0zoCApa9lnZGEigVKUd2hzsCId4gdtkZZIVscLhNxMECKgRg== + +"@npmcli/promise-spawn@^1.1.0", "@npmcli/promise-spawn@^1.2.0", "@npmcli/promise-spawn@^1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz#42d4e56a8e9274fba180dabc0aea6e38f29274f5" + integrity sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg== + dependencies: + infer-owner "^1.0.4" + +"@npmcli/run-script@^1.8.2": + version "1.8.4" + resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-1.8.4.tgz#03ced92503a6fe948cbc0975ce39210bc5e824d6" + integrity sha512-Yd9HXTtF1JGDXZw0+SOn+mWLYS0e7bHBHVC/2C8yqs4wUrs/k8rwBSinD7rfk+3WG/MFGRZKxjyoD34Pch2E/A== + dependencies: + "@npmcli/node-gyp" "^1.0.2" + "@npmcli/promise-spawn" "^1.3.2" + infer-owner "^1.0.4" + node-gyp "^7.1.0" + read-package-json-fast "^2.0.1" + +"@octokit/auth-token@^2.4.4": version "2.4.5" resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.5.tgz#568ccfb8cb46f36441fac094ce34f7a875b197f3" integrity sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA== @@ -1356,18 +1314,16 @@ resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-5.3.2.tgz#b8ac43c5c3d00aef61a34cf744e315110c78deb4" integrity sha512-NxF1yfYOUO92rCx3dwvA2onF30Vdlg7YUkMVXkeptqpzA3tRLplThhFleV/UKWFgh7rpKu1yYRbvNDUtzSopKA== +"@octokit/openapi-types@^6.2.0": + version "6.2.0" + resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-6.2.0.tgz#6ea796b20c7111b9e422a4d607f796c1179622cd" + integrity sha512-V2vFYuawjpP5KUb8CPYsq20bXT4qnE8sH1QKpYqUlcNOntBiRr/VzGVvY0s+YXGgrVbFUVO4EI0VnHYSVBWfBg== + "@octokit/plugin-enterprise-rest@^6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz#e07896739618dab8da7d4077c658003775f95437" integrity sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw== -"@octokit/plugin-paginate-rest@^1.1.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-1.1.2.tgz#004170acf8c2be535aba26727867d692f7b488fc" - integrity sha512-jbsSoi5Q1pj63sC16XIUboklNw+8tL9VOnJsWycWYR78TKss5PVpIPb1TUUcMQ+bBh7cY579cVAWmf5qG+dw+Q== - dependencies: - "@octokit/types" "^2.0.1" - "@octokit/plugin-paginate-rest@^2.6.2": version "2.13.2" resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.13.2.tgz#7b8244a0dd7a31135ba2adc58a533213837bfe87" @@ -1375,19 +1331,11 @@ dependencies: "@octokit/types" "^6.11.0" -"@octokit/plugin-request-log@^1.0.0", "@octokit/plugin-request-log@^1.0.2": +"@octokit/plugin-request-log@^1.0.2": version "1.0.3" resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.3.tgz#70a62be213e1edc04bb8897ee48c311482f9700d" integrity sha512-4RFU4li238jMJAzLgAwkBAw+4Loile5haQMQr+uhFq27BmyJXcXSKvoQKqh0agsZEiUlW6iSv3FAgvmGkur7OQ== -"@octokit/plugin-rest-endpoint-methods@2.4.0": - version "2.4.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-2.4.0.tgz#3288ecf5481f68c494dd0602fc15407a59faf61e" - integrity sha512-EZi/AWhtkdfAYi01obpX0DF7U6b1VRr30QNQ5xSFPITMdLSfhcBqjamE3F+sKcxPbD7eZuMHu3Qkk2V+JGxBDQ== - dependencies: - "@octokit/types" "^2.0.1" - deprecation "^2.3.1" - "@octokit/plugin-rest-endpoint-methods@4.13.5": version "4.13.5" resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.13.5.tgz#ad76285b82fe05fbb4adf2774a9c887f3534a880" @@ -1396,14 +1344,13 @@ "@octokit/types" "^6.12.2" deprecation "^2.3.1" -"@octokit/request-error@^1.0.2": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-1.2.1.tgz#ede0714c773f32347576c25649dc013ae6b31801" - integrity sha512-+6yDyk1EES6WK+l3viRDElw96MvwfJxCt45GvmjDUKWjYIb3PJZQkq3i46TwGwoPD4h8NmTrENmtyA1FwbmhRA== +"@octokit/plugin-rest-endpoint-methods@5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.0.1.tgz#631b8d4edc6798b03489911252a25f2a4e58c594" + integrity sha512-vvWbPtPqLyIzJ7A4IPdTl+8IeuKAwMJ4LjvmqWOOdfSuqWQYZXq2CEd0hsnkidff2YfKlguzujHs/reBdAx8Sg== dependencies: - "@octokit/types" "^2.0.0" - deprecation "^2.0.0" - once "^1.4.0" + "@octokit/types" "^6.13.1" + deprecation "^2.3.1" "@octokit/request-error@^2.0.0", "@octokit/request-error@^2.0.5": version "2.0.5" @@ -1414,7 +1361,7 @@ deprecation "^2.0.0" once "^1.4.0" -"@octokit/request@^5.2.0", "@octokit/request@^5.3.0", "@octokit/request@^5.4.12": +"@octokit/request@^5.3.0", "@octokit/request@^5.4.12": version "5.4.14" resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.4.14.tgz#ec5f96f78333bb2af390afa5ff66f114b063bc96" integrity sha512-VkmtacOIQp9daSnBmDI92xNIeLuSRDOIuplp/CJomkvzt7M18NXgG044Cx/LFKLgjKt9T2tZR6AtJayba9GTSA== @@ -1428,29 +1375,7 @@ once "^1.4.0" universal-user-agent "^6.0.0" -"@octokit/rest@^16.28.4": - version "16.43.2" - resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-16.43.2.tgz#c53426f1e1d1044dee967023e3279c50993dd91b" - integrity sha512-ngDBevLbBTFfrHZeiS7SAMAZ6ssuVmXuya+F/7RaVvlysgGa1JKJkKWY+jV6TCJYcW0OALfJ7nTIGXcBXzycfQ== - dependencies: - "@octokit/auth-token" "^2.4.0" - "@octokit/plugin-paginate-rest" "^1.1.1" - "@octokit/plugin-request-log" "^1.0.0" - "@octokit/plugin-rest-endpoint-methods" "2.4.0" - "@octokit/request" "^5.2.0" - "@octokit/request-error" "^1.0.2" - atob-lite "^2.0.0" - before-after-hook "^2.0.0" - btoa-lite "^1.0.0" - deprecation "^2.0.0" - lodash.get "^4.4.2" - lodash.set "^4.3.2" - lodash.uniq "^4.5.0" - octokit-pagination-methods "^1.1.0" - once "^1.4.0" - universal-user-agent "^4.0.0" - -"@octokit/rest@^18.3.5": +"@octokit/rest@^18.1.0": version "18.3.5" resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.3.5.tgz#a89903d46e0b4273bd3234674ec2777a651d68ab" integrity sha512-ZPeRms3WhWxQBEvoIh0zzf8xdU2FX0Capa7+lTca8YHmRsO3QNJzf1H3PcuKKsfgp91/xVDRtX91sTe1kexlbw== @@ -1460,12 +1385,15 @@ "@octokit/plugin-request-log" "^1.0.2" "@octokit/plugin-rest-endpoint-methods" "4.13.5" -"@octokit/types@^2.0.0", "@octokit/types@^2.0.1": - version "2.16.2" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-2.16.2.tgz#4c5f8da3c6fecf3da1811aef678fda03edac35d2" - integrity sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q== +"@octokit/rest@^18.5.3": + version "18.5.3" + resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.5.3.tgz#6a2e6006a87ebbc34079c419258dd29ec9ff659d" + integrity sha512-KPAsUCr1DOdLVbZJgGNuE/QVLWEaVBpFQwDAz/2Cnya6uW2wJ/P5RVGk0itx7yyN1aGa8uXm2pri4umEqG1JBA== dependencies: - "@types/node" ">= 8" + "@octokit/core" "^3.2.3" + "@octokit/plugin-paginate-rest" "^2.6.2" + "@octokit/plugin-request-log" "^1.0.2" + "@octokit/plugin-rest-endpoint-methods" "5.0.1" "@octokit/types@^6.0.3", "@octokit/types@^6.11.0", "@octokit/types@^6.12.2", "@octokit/types@^6.7.1": version "6.12.2" @@ -1474,6 +1402,13 @@ dependencies: "@octokit/openapi-types" "^5.3.2" +"@octokit/types@^6.13.1": + version "6.14.0" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.14.0.tgz#587529b4a461d8b7621b99845718dc5c79281f52" + integrity sha512-43qHvDsPsKgNt4W4al3dyU6s2XZ7ZMsiiIw8rQcM9CyEo7g9W8/6m1W4xHuRqmEjTfG1U4qsE/E4Jftw1/Ak1g== + dependencies: + "@octokit/openapi-types" "^6.2.0" + "@sinonjs/commons@^1.6.0", "@sinonjs/commons@^1.7.0", "@sinonjs/commons@^1.8.1": version "1.8.2" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.2.tgz#858f5c4b48d80778fde4b9d541f27edc0d56488b" @@ -1514,10 +1449,10 @@ dependencies: "@types/glob" "*" -"@types/aws-lambda@^8.10.72": - version "8.10.72" - resolved "https://registry.yarnpkg.com/@types/aws-lambda/-/aws-lambda-8.10.72.tgz#af2a6eeaf39be9674e3856f1870d9d15cf75e2e0" - integrity sha512-jOrTwAhSiUtBIN/QsWNKlI4+4aDtpZ0sr2BRvKW6XQZdspgHUSHPcuzxbzCRiHUiDQ+0026u5TSE38VyIhNnfA== +"@types/aws-lambda@^8.10.76": + version "8.10.76" + resolved "https://registry.yarnpkg.com/@types/aws-lambda/-/aws-lambda-8.10.76.tgz#a20191677f1f5e32fe1f26739b1d6fbbea9cf636" + integrity sha512-lCTyeRm3NWqSwDnoji0z82Pl0tsOpr1p+33AiNeidgarloWXh3wdiVRUuxEa+sY9S5YLOYGz5X3N3Zvpibvm5w== "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7": version "7.1.13" @@ -1552,10 +1487,10 @@ dependencies: "@babel/types" "^7.3.0" -"@types/eslint@^7.2.7": - version "7.2.7" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.2.7.tgz#f7ef1cf0dceab0ae6f9a976a0a9af14ab1baca26" - integrity sha512-EHXbc1z2GoQRqHaAT7+grxlTJ3WE2YNeD6jlpPoRc83cCoThRY+NUWjCUZaYmk51OICkPXn2hhphcWcWXgNW0Q== +"@types/eslint@^7.2.10": + version "7.2.10" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.2.10.tgz#4b7a9368d46c0f8cd5408c23288a59aa2394d917" + integrity sha512-kUEPnMKrqbtpCq/KTaGFFKAcz6Ethm2EjCoKIDaCmfRBWLbFuTcOJfTlorwbnboXBzahqWLgUp1BQeKHiJzPUQ== dependencies: "@types/estree" "*" "@types/json-schema" "*" @@ -1572,7 +1507,7 @@ dependencies: "@types/node" "*" -"@types/glob@*", "@types/glob@^7.1.1", "@types/glob@^7.1.3": +"@types/glob@*", "@types/glob@^7.1.3": version "7.1.3" resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183" integrity sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w== @@ -1606,10 +1541,10 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@^26.0.21": - version "26.0.21" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.21.tgz#3a73c2731e7e4f0fbaea56ce7ff8c79cf812bd24" - integrity sha512-ab9TyM/69yg7eew9eOwKMUmvIZAKEGZYlq/dhe5/0IMUd/QLJv5ldRMdddSn+u22N13FP3s5jYyktxuBwY0kDA== +"@types/jest@^26.0.23": + version "26.0.23" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.23.tgz#a1b7eab3c503b80451d019efb588ec63522ee4e7" + integrity sha512-ZHLmWMJ9jJ9PTiT58juykZpL7KjwJywFN3Rr2pTSkyQfydf/rk22yS7W8p5DaVUMQ2BQC7oYiU3FjbTM/mYrOA== dependencies: jest-diff "^26.0.0" pretty-format "^26.0.0" @@ -1648,6 +1583,11 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== +"@types/minimatch@^3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.4.tgz#f0ec25dbf2f0e4b18647313ac031134ca5b24b21" + integrity sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA== + "@types/minimist@^1.2.0": version "1.2.1" resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.1.tgz#283f669ff76d7b8260df8ab7a4262cc83d988256" @@ -1665,15 +1605,15 @@ resolved "https://registry.yarnpkg.com/@types/mockery/-/mockery-1.4.29.tgz#9ba22df37f07e3780fff8531d1a38e633f9457a5" integrity sha1-m6It838H43gP/4Ux0aOOYz+UV6U= -"@types/node@*", "@types/node@>= 8", "@types/node@^14.14.33": +"@types/node@*", "@types/node@^14.14.33": version "14.14.35" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.35.tgz#42c953a4e2b18ab931f72477e7012172f4ffa313" integrity sha512-Lt+wj8NVPx0zUmUwumiVXapmaLUcAk3yPuHCFVXras9k5VT9TdhJqKqGVUQCD60OTMCl0qxJ57OiTL0Mic3Iag== -"@types/node@^10.17.55": - version "10.17.55" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.55.tgz#a147f282edec679b894d4694edb5abeb595fecbd" - integrity sha512-koZJ89uLZufDvToeWO5BrC4CR4OUfHnUz2qoPs/daQH6qq3IN62QFxCTZ+bKaCE0xaoCAJYE4AXre8AbghCrhg== +"@types/node@^10.17.59": + version "10.17.59" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.59.tgz#03f440ccf746a27f7da6e141e6cbae64681dbd2f" + integrity sha512-7Uc8IRrL8yZz5ti45RaFxpbU8TxlzdC3HvxV+hOWo1EyLsuKv/w7y0n+TwZzwL3vdx3oZ2k3ubxPq131hNtXyg== "@types/nodeunit@^0.0.31": version "0.0.31" @@ -1685,6 +1625,11 @@ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA== +"@types/parse-json@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + "@types/prettier@^2.0.0": version "2.2.3" resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.2.3.tgz#ef65165aea2924c9359205bf748865b8881753c0" @@ -1707,10 +1652,10 @@ resolved "https://registry.yarnpkg.com/@types/punycode/-/punycode-2.1.0.tgz#89e4f3d09b3f92e87a80505af19be7e0c31d4e83" integrity sha512-PG5aLpW6PJOeV2fHRslP4IOMWn+G+Uq8CfnyJ+PDS8ndCbU+soO+fB3NKCKo0p/Jh2Y4aPaiQZsrOXFdzpcA6g== -"@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/semver@^7.3.5": + version "7.3.5" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.5.tgz#74deebbbcb1e86634dbf10a5b5e8798626f5a597" + integrity sha512-iotVxtCCsPLRAvxMFFgxL8HD2l4mAZ2Oin7/VJ2ooWO0VOK4EGOGmZWZn1uCq7RofR3I/1IOSjCHlFT71eVK0Q== "@types/sinon@^9.0.11": version "9.0.11" @@ -1782,13 +1727,13 @@ resolved "https://registry.yarnpkg.com/@types/yarnpkg__lockfile/-/yarnpkg__lockfile-1.1.4.tgz#445251eb00bd9c1e751f82c7c6bf4f714edfd464" integrity sha512-/emrKCfQMQmFCqRqqBJ0JueHBT06jBRM3e8OgnvDUcvuExONujIk2hFA5dNsN9Nt41ljGVDdChvCydATZ+KOZw== -"@typescript-eslint/eslint-plugin@^4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.18.0.tgz#50fbce93211b5b690895d20ebec6fe8db48af1f6" - integrity sha512-Lzkc/2+7EoH7+NjIWLS2lVuKKqbEmJhtXe3rmfA8cyiKnZm3IfLf51irnBcmow8Q/AptVV0XBZmBJKuUJTe6cQ== +"@typescript-eslint/eslint-plugin@^4.22.1": + version "4.22.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.22.1.tgz#6bcdbaa4548553ab861b4e5f34936ead1349a543" + integrity sha512-kVTAghWDDhsvQ602tHBc6WmQkdaYbkcTwZu+7l24jtJiYvm9l+/y/b2BZANEezxPDiX5MK2ZecE+9BFi/YJryw== dependencies: - "@typescript-eslint/experimental-utils" "4.18.0" - "@typescript-eslint/scope-manager" "4.18.0" + "@typescript-eslint/experimental-utils" "4.22.1" + "@typescript-eslint/scope-manager" "4.22.1" debug "^4.1.1" functional-red-black-tree "^1.0.1" lodash "^4.17.15" @@ -1796,7 +1741,19 @@ semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/experimental-utils@4.18.0", "@typescript-eslint/experimental-utils@^4.0.1": +"@typescript-eslint/experimental-utils@4.22.1": + version "4.22.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.22.1.tgz#3938a5c89b27dc9a39b5de63a62ab1623ab27497" + integrity sha512-svYlHecSMCQGDO2qN1v477ax/IDQwWhc7PRBiwAdAMJE7GXk5stF4Z9R/8wbRkuX/5e9dHqbIWxjeOjckK3wLQ== + dependencies: + "@types/json-schema" "^7.0.3" + "@typescript-eslint/scope-manager" "4.22.1" + "@typescript-eslint/types" "4.22.1" + "@typescript-eslint/typescript-estree" "4.22.1" + eslint-scope "^5.0.0" + eslint-utils "^2.0.0" + +"@typescript-eslint/experimental-utils@^4.0.1": version "4.18.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.18.0.tgz#ed6c955b940334132b17100d2917449b99a91314" integrity sha512-92h723Kblt9JcT2RRY3QS2xefFKar4ZQFVs3GityOKWQYgtajxt/tuXIzL7sVCUlM1hgreiV5gkGYyBpdOwO6A== @@ -1808,14 +1765,14 @@ eslint-scope "^5.0.0" eslint-utils "^2.0.0" -"@typescript-eslint/parser@^4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.18.0.tgz#a211edb14a69fc5177054bec04c95b185b4dde21" - integrity sha512-W3z5S0ZbecwX3PhJEAnq4mnjK5JJXvXUDBYIYGoweCyWyuvAKfGHvzmpUzgB5L4cRBb+cTu9U/ro66dx7dIimA== +"@typescript-eslint/parser@^4.22.1": + version "4.22.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.22.1.tgz#a95bda0fd01d994a15fc3e99dc984294f25c19cc" + integrity sha512-l+sUJFInWhuMxA6rtirzjooh8cM/AATAe3amvIkqKFeMzkn85V+eLzb1RyuXkHak4dLfYzOmF6DXPyflJvjQnw== dependencies: - "@typescript-eslint/scope-manager" "4.18.0" - "@typescript-eslint/types" "4.18.0" - "@typescript-eslint/typescript-estree" "4.18.0" + "@typescript-eslint/scope-manager" "4.22.1" + "@typescript-eslint/types" "4.22.1" + "@typescript-eslint/typescript-estree" "4.22.1" debug "^4.1.1" "@typescript-eslint/scope-manager@4.18.0": @@ -1826,11 +1783,24 @@ "@typescript-eslint/types" "4.18.0" "@typescript-eslint/visitor-keys" "4.18.0" +"@typescript-eslint/scope-manager@4.22.1": + version "4.22.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.22.1.tgz#5bb357f94f9cd8b94e6be43dd637eb73b8f355b4" + integrity sha512-d5bAiPBiessSmNi8Amq/RuLslvcumxLmyhf1/Xa9IuaoFJ0YtshlJKxhlbY7l2JdEk3wS0EnmnfeJWSvADOe0g== + dependencies: + "@typescript-eslint/types" "4.22.1" + "@typescript-eslint/visitor-keys" "4.22.1" + "@typescript-eslint/types@4.18.0": version "4.18.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.18.0.tgz#bebe323f81f2a7e2e320fac9415e60856267584a" integrity sha512-/BRociARpj5E+9yQ7cwCF/SNOWwXJ3qhjurMuK2hIFUbr9vTuDeu476Zpu+ptxY2kSxUHDGLLKy+qGq2sOg37A== +"@typescript-eslint/types@4.22.1": + version "4.22.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.22.1.tgz#bf99c6cec0b4a23d53a61894816927f2adad856a" + integrity sha512-2HTkbkdAeI3OOcWbqA8hWf/7z9c6gkmnWNGz0dKSLYLWywUlkOAQ2XcjhlKLj5xBFDf8FgAOF5aQbnLRvgNbCw== + "@typescript-eslint/typescript-estree@4.18.0": version "4.18.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.18.0.tgz#756d3e61da8c16ab99185532c44872f4cd5538cb" @@ -1844,6 +1814,19 @@ semver "^7.3.2" tsutils "^3.17.1" +"@typescript-eslint/typescript-estree@4.22.1": + version "4.22.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.22.1.tgz#dca379eead8cdfd4edc04805e83af6d148c164f9" + integrity sha512-p3We0pAPacT+onSGM+sPR+M9CblVqdA9F1JEdIqRVlxK5Qth4ochXQgIyb9daBomyQKAXbygxp1aXQRV0GC79A== + dependencies: + "@typescript-eslint/types" "4.22.1" + "@typescript-eslint/visitor-keys" "4.22.1" + debug "^4.1.1" + globby "^11.0.1" + is-glob "^4.0.1" + semver "^7.3.2" + tsutils "^3.17.1" + "@typescript-eslint/visitor-keys@4.18.0": version "4.18.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.18.0.tgz#4e6fe2a175ee33418318a029610845a81e2ff7b6" @@ -1852,21 +1835,20 @@ "@typescript-eslint/types" "4.18.0" eslint-visitor-keys "^2.0.0" +"@typescript-eslint/visitor-keys@4.22.1": + version "4.22.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.22.1.tgz#6045ae25a11662c671f90b3a403d682dfca0b7a6" + integrity sha512-WPkOrIRm+WCLZxXQHCi+WG8T2MMTUFR70rWjdWYddLT7cEfb2P4a3O/J2U1FBVsSFTocXLCoXWY6MZGejeStvQ== + dependencies: + "@typescript-eslint/types" "4.22.1" + eslint-visitor-keys "^2.0.0" + "@yarnpkg/lockfile@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== -"@zkochan/cmd-shim@^3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@zkochan/cmd-shim/-/cmd-shim-3.1.0.tgz#2ab8ed81f5bb5452a85f25758eb9b8681982fd2e" - integrity sha512-o8l0+x7C7sMZU3v9GuJIAU10qQLtwR1dtRQIOmlNMtyaqhmpXOzx1HWiYoWfmmf9HHZoAkXpc9TM9PQYF9d4Jg== - dependencies: - is-windows "^1.0.0" - mkdirp-promise "^5.0.1" - mz "^2.5.0" - -JSONStream@^1.0.4, JSONStream@^1.3.4: +JSONStream@^1.0.4: version "1.3.5" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== @@ -1874,7 +1856,7 @@ JSONStream@^1.0.4, JSONStream@^1.3.4: jsonparse "^1.2.0" through ">=2.2.7 <3" -abab@^2.0.3, abab@^2.0.5: +abab@^2.0.3: version "2.0.5" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== @@ -1907,23 +1889,11 @@ acorn@^7.1.1, acorn@^7.4.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.0.5: - version "8.1.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.1.0.tgz#52311fd7037ae119cbb134309e901aa46295b3fe" - integrity sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA== - add-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" integrity sha1-anmQQ3ynNtXhKI25K9MmbV9csqo= -agent-base@4, agent-base@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" - integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== - dependencies: - es6-promisify "^5.0.0" - agent-base@6, agent-base@^6.0.0: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -1931,18 +1901,13 @@ agent-base@6, agent-base@^6.0.0: dependencies: debug "4" -agent-base@~4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" - integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg== - dependencies: - es6-promisify "^5.0.0" - -agentkeepalive@^3.4.1: - version "3.5.2" - resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-3.5.2.tgz#a113924dd3fa24a0bc3b78108c450c2abee00f67" - integrity sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ== +agentkeepalive@^4.1.3: + version "4.1.4" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.1.4.tgz#d928028a4862cb11718e55227872e842a44c945b" + integrity sha512-+V/rGa3EuU74H6wR04plBb7Ks10FbtUQgRj/FQOG7uUIEuaINI+AiqJR1k6t3SVNs7o7ZjIdus6706qqzVq8jQ== dependencies: + debug "^4.1.0" + depd "^1.1.2" humanize-ms "^1.2.1" aggregate-error@^3.0.0: @@ -1973,16 +1938,21 @@ ajv@^7.0.2: require-from-string "^2.0.2" uri-js "^4.2.2" +ajv@^8.0.1: + version "8.0.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.0.2.tgz#1396e27f208ed56dd5638ab5a251edeb1c91d402" + integrity sha512-V0HGxJd0PiDF0ecHYIesTOqfd1gJguwQUOYfMfAWnRsWQEXfc5ifbUFhD3Wjc+O+y7VAqL+g07prq9gHQ/JOZQ== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + ansi-colors@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== -ansi-escapes@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" - integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== - ansi-escapes@^4.2.1: version "4.3.1" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" @@ -2024,11 +1994,6 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" -any-promise@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" - integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= - anymatch@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" @@ -2064,7 +2029,7 @@ append-transform@^2.0.0: dependencies: default-require-extensions "^3.0.0" -aproba@^1.0.3, aproba@^1.1.1: +aproba@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== @@ -2148,10 +2113,10 @@ arr-union@^3.1.0: resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= -array-differ@^2.0.3: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-2.1.0.tgz#4b9c1c3f14b906757082925769e8ab904f4801b1" - integrity sha512-KbUpJgx909ZscOc/7CLATBFam7P1Z1QRQInvgT0UztM9Q72aGKCunKASAl7WNW0tnPmPyEMeMhdsfWhfmW037w== +array-differ@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b" + integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg== array-filter@^1.0.0: version "1.0.0" @@ -2179,23 +2144,11 @@ array-includes@^3.1.1: get-intrinsic "^1.1.1" is-string "^1.0.5" -array-union@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= - 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" - integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= - array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" @@ -2215,6 +2168,11 @@ arrify@^1.0.1: resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= +arrify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" + integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== + asap@^2.0.0: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" @@ -2264,11 +2222,6 @@ at-least-node@^1.0.0: resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== -atob-lite@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/atob-lite/-/atob-lite-2.0.0.tgz#0fef5ad46f1bd7a8502c65727f0367d5ee43d696" - integrity sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY= - atob@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" @@ -2413,7 +2366,7 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" -before-after-hook@^2.0.0, before-after-hook@^2.2.0: +before-after-hook@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.0.tgz#09c40d92e936c64777aa385c4e9b904f8147eaf0" integrity sha512-jH6rKQIfroBbhEXVmI7XmXe3ix5S/PgJqpzdDPnR8JGLHWNYLsYZ6tK5iWOF/Ra3oqEX0NobXGlzbiylIzVphQ== @@ -2432,7 +2385,7 @@ bl@^4.0.3: 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.0: version "3.7.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== @@ -2498,11 +2451,6 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" -btoa-lite@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337" - integrity sha1-M3dm2hWAEhD92VbCLpxokaudAzc= - buffer-crc32@^0.2.1, buffer-crc32@^0.2.13: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" @@ -2540,36 +2488,38 @@ byline@^5.0.0: resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1" integrity sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE= -byte-size@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-5.0.1.tgz#4b651039a5ecd96767e71a3d7ed380e48bed4191" - integrity sha512-/XuKeqWocKsYa/cBY1YbSJSWWqTi4cFgr9S6OyM7PBaPbr9zvNGwWP33vt0uqGhwDdN+y3yhbXVILEUpnwEWGw== +byte-size@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-7.0.1.tgz#b1daf3386de7ab9d706b941a748dbfc71130dee3" + integrity sha512-crQdqyCwhokxwV1UyDzLZanhkugAgft7vt0qbbdt60C6Zf3CAiGmtUCylbtYwrU6loOUw3euGrNtW1J651ot1A== bytes@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== -cacache@^12.0.0, cacache@^12.0.3: - version "12.0.4" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c" - integrity sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ== +cacache@^15.0.5: + version "15.0.5" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.0.5.tgz#69162833da29170d6732334643c60e005f5f17d0" + integrity sha512-lloiL22n7sOjEEXdL8NAjTgv9a1u43xICE9/203qonkZUCj5X1UEWIdf2/Y0d6QcCtMzbKQyhrcDbdvlZTs/+A== dependencies: - bluebird "^3.5.5" - chownr "^1.1.1" - figgy-pudding "^3.5.1" + "@npmcli/move-file" "^1.0.1" + chownr "^2.0.0" + fs-minipass "^2.0.0" glob "^7.1.4" - graceful-fs "^4.1.15" - infer-owner "^1.0.3" - lru-cache "^5.1.1" - mississippi "^3.0.0" - mkdirp "^0.5.1" - move-concurrently "^1.0.1" + infer-owner "^1.0.4" + lru-cache "^6.0.0" + minipass "^3.1.1" + minipass-collect "^1.0.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.2" + mkdirp "^1.0.3" + p-map "^4.0.0" promise-inflight "^1.0.1" - rimraf "^2.6.3" - ssri "^6.0.1" + rimraf "^3.0.2" + ssri "^8.0.0" + tar "^6.0.2" unique-filename "^1.1.1" - y18n "^4.0.0" cache-base@^1.0.1: version "1.0.1" @@ -2614,30 +2564,6 @@ call-bind@^1.0.0, call-bind@^1.0.2: function-bind "^1.1.1" get-intrinsic "^1.0.2" -call-me-maybe@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" - integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= - -caller-callsite@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" - integrity sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ= - dependencies: - callsites "^2.0.0" - -caller-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" - integrity sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ= - dependencies: - caller-callsite "^2.0.0" - -callsites@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" - integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= - callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -2651,15 +2577,6 @@ camelcase-keys@^2.0.0: camelcase "^2.0.0" map-obj "^1.0.0" -camelcase-keys@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-4.2.0.tgz#a2aa5fb1af688758259c32c141426d78923b9b77" - integrity sha1-oqpfsa9oh1glnDLBQUJteJI7m3c= - dependencies: - camelcase "^4.1.0" - map-obj "^2.0.0" - quick-lru "^1.0.0" - camelcase-keys@^6.2.2: version "6.2.2" resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" @@ -2674,11 +2591,6 @@ camelcase@^2.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= -camelcase@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" - integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= - camelcase@^5.0.0, camelcase@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" @@ -2732,7 +2644,7 @@ cdk8s@^0.33.0: json-stable-stringify "^1.0.1" yaml "2.0.0-1" -chalk@^2.0.0, chalk@^2.3.1, chalk@^2.4.2: +chalk@^2.0.0, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -2741,7 +2653,7 @@ chalk@^2.0.0, chalk@^2.3.1, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0: +chalk@^4.0.0, chalk@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== @@ -2764,11 +2676,16 @@ charenc@0.0.2: resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= -chownr@^1.1.1, chownr@^1.1.2: +chownr@^1.1.1: version "1.1.4" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + ci-info@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" @@ -2806,17 +2723,17 @@ cli-color@~0.1.6: dependencies: es5-ext "0.8.x" -cli-cursor@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== dependencies: - restore-cursor "^2.0.0" + restore-cursor "^3.1.0" -cli-width@^2.0.0: - version "2.2.1" - 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@^5.0.0: version "5.0.0" @@ -2864,6 +2781,13 @@ clone@^2.1.2: resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= +cmd-shim@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-4.1.0.tgz#b3a904a6743e9fede4148c6f3800bf2a08135bdd" + integrity sha512-lb9L7EM4I/ZRVuljLPEtUJOP+xiQVknZ4ZMpMgEp4JzNldPb27HU03hi6K1/6CoIuit/Zm/LQXySErFeXxDprw== + dependencies: + mkdirp-infer-owner "^2.0.0" + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -2874,10 +2798,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.25.0: - version "1.25.0" - resolved "https://registry.yarnpkg.com/codemaker/-/codemaker-1.25.0.tgz#987abcdf4f1ea7c3d71083dded4ce72941044710" - integrity sha512-54qCHs6X6llXIAztHCo2IyzzvuH9GrEecwxxTU925M3EJV4z+7PMiI1AollZxSeyY2pGO5TjNlAQAyLXETI3NQ== +codemaker@^1.29.0: + version "1.29.0" + resolved "https://registry.yarnpkg.com/codemaker/-/codemaker-1.29.0.tgz#c262d1149681348103c7a79913a9a39ba13098f5" + integrity sha512-dNUTiOhxNYB7MV75bLLCie1gr0SUh6wEOPc5OyZob4mLj51OETYIeRYILEiz39QVKLRx6YSbKoCY/S4PqQ0PNQ== dependencies: camelcase "^6.2.0" decamelize "^5.0.0" @@ -2998,16 +2922,6 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -concat-stream@^1.5.0: - version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - concat-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-2.0.0.tgz#414cf5af790a48c60ab9be4527d56d5e41133cb1" @@ -3018,7 +2932,7 @@ concat-stream@^2.0.0: readable-stream "^3.0.2" typedarray "^0.0.6" -config-chain@^1.1.11: +config-chain@^1.1.12: version "1.1.12" resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa" integrity sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA== @@ -3031,17 +2945,17 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= -constructs@^3.2.0: - version "3.3.65" - resolved "https://registry.yarnpkg.com/constructs/-/constructs-3.3.65.tgz#e1cef2a91ccbf10a10147e38e238b1a3482ee2a6" - integrity sha512-/tjHzxwK4Nz9SAm40kkC2mij3Y3LngVVj/dvk7Xpex25/PMhVRYy1pmJ0/5I5Y6bAMG1HRjcSAyf4k9YZyxJjw== +constructs@^3.3.69: + version "3.3.71" + resolved "https://registry.yarnpkg.com/constructs/-/constructs-3.3.71.tgz#5a3e968de484ad327bc2650aa4a7f37a39834ac5" + integrity sha512-3KFtTsA7OV27m/+pJhN4iJkKzHbPIPvyvEX5BQ/JCAWjfCHOQEVpIgxHLpT4i8L1OFta+pJrzcEVAHo6UitwqA== contains-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= -conventional-changelog-angular@^5.0.12, conventional-changelog-angular@^5.0.3: +conventional-changelog-angular@^5.0.12: version "5.0.12" resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.12.tgz#c979b8b921cbfe26402eb3da5bbfda02d865a2b9" integrity sha512-5GLsbnkR/7A89RyHLvvoExbiGbd9xKdKqDTrArnPbOqBqG/2wIosu0fHwpeIRI8Tl94MhVNBXcLJZl92ZQ5USw== @@ -3088,26 +3002,7 @@ conventional-changelog-conventionalcommits@4.5.0, conventional-changelog-convent lodash "^4.17.15" q "^1.5.1" -conventional-changelog-core@^3.1.6: - version "3.2.3" - resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-3.2.3.tgz#b31410856f431c847086a7dcb4d2ca184a7d88fb" - integrity sha512-LMMX1JlxPIq/Ez5aYAYS5CpuwbOk6QFp8O4HLAcZxe3vxoCtABkhfjetk8IYdRB9CDQGwJFLR3Dr55Za6XKgUQ== - dependencies: - conventional-changelog-writer "^4.0.6" - conventional-commits-parser "^3.0.3" - dateformat "^3.0.0" - get-pkg-repo "^1.0.0" - git-raw-commits "2.0.0" - git-remote-origin-url "^2.0.0" - git-semver-tags "^2.0.3" - lodash "^4.2.1" - normalize-package-data "^2.3.5" - q "^1.5.1" - read-pkg "^3.0.0" - read-pkg-up "^3.0.0" - through2 "^3.0.0" - -conventional-changelog-core@^4.2.1: +conventional-changelog-core@^4.2.1, conventional-changelog-core@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-4.2.2.tgz#f0897df6d53b5d63dec36b9442bd45354f8b3ce5" integrity sha512-7pDpRUiobQDNkwHyJG7k9f6maPo9tfPzkSWbRq97GGiZqisElhnvUZSvyQH20ogfOjntB5aadvv6NNcKL1sReg== @@ -3164,12 +3059,12 @@ conventional-changelog-jshint@^2.0.9: compare-func "^2.0.0" q "^1.5.1" -conventional-changelog-preset-loader@^2.1.1, conventional-changelog-preset-loader@^2.3.4: +conventional-changelog-preset-loader@^2.3.4: version "2.3.4" resolved "https://registry.yarnpkg.com/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz#14a855abbffd59027fd602581f1f34d9862ea44c" integrity sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g== -conventional-changelog-writer@^4.0.18, conventional-changelog-writer@^4.0.6: +conventional-changelog-writer@^4.0.18: version "4.1.0" resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-4.1.0.tgz#1ca7880b75aa28695ad33312a1f2366f4b12659f" integrity sha512-WwKcUp7WyXYGQmkLsX4QmU42AZ1lqlvRW9mqoyiQzdD+rJWbTepdWoKJuwXTS+yq79XKnQNa93/roViPQrAQgw== @@ -3202,7 +3097,7 @@ conventional-changelog@3.1.24, conventional-changelog@^3.1.24: conventional-changelog-jshint "^2.0.9" conventional-changelog-preset-loader "^2.3.4" -conventional-commits-filter@^2.0.2, conventional-commits-filter@^2.0.7: +conventional-commits-filter@^2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz#f8d9b4f182fce00c9af7139da49365b136c8a0b3" integrity sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA== @@ -3210,7 +3105,7 @@ conventional-commits-filter@^2.0.2, conventional-commits-filter@^2.0.7: lodash.ismatch "^4.4.0" modify-values "^1.0.0" -conventional-commits-parser@^3.0.3, conventional-commits-parser@^3.2.0: +conventional-commits-parser@^3.2.0: version "3.2.1" resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-3.2.1.tgz#ba44f0b3b6588da2ee9fd8da508ebff50d116ce2" integrity sha512-OG9kQtmMZBJD/32NEw5IhN5+HnBqVjy03eC+I71I0oQRFA5rOgA4OtPOYG7mz1GkCfCNxn3gKIX8EiHJYuf1cA== @@ -3223,7 +3118,7 @@ conventional-commits-parser@^3.0.3, conventional-commits-parser@^3.2.0: through2 "^4.0.0" trim-off-newlines "^1.0.0" -conventional-recommended-bump@6.1.0: +conventional-recommended-bump@6.1.0, conventional-recommended-bump@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/conventional-recommended-bump/-/conventional-recommended-bump-6.1.0.tgz#cfa623285d1de554012f2ffde70d9c8a22231f55" integrity sha512-uiApbSiNGM/kkdL9GTOLAqC4hbptObFo4wW2QRyHsKciGAfQuLU1ShZ1BIVI/+K2BE/W1AWYQMCXAsv4dyKPaw== @@ -3237,20 +3132,6 @@ conventional-recommended-bump@6.1.0: meow "^8.0.0" q "^1.5.1" -conventional-recommended-bump@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/conventional-recommended-bump/-/conventional-recommended-bump-5.0.1.tgz#5af63903947b6e089e77767601cb592cabb106ba" - integrity sha512-RVdt0elRcCxL90IrNP0fYCpq1uGt2MALko0eyeQ+zQuDVWtMGAy9ng6yYn3kax42lCj9+XBxQ8ZN6S9bdKxDhQ== - dependencies: - concat-stream "^2.0.0" - conventional-changelog-preset-loader "^2.1.1" - conventional-commits-filter "^2.0.2" - conventional-commits-parser "^3.0.3" - git-raw-commits "2.0.0" - git-semver-tags "^2.0.3" - meow "^4.0.0" - q "^1.5.1" - convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" @@ -3258,18 +3139,6 @@ convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: dependencies: safe-buffer "~5.1.1" -copy-concurrently@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" - integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== - dependencies: - aproba "^1.1.1" - fs-write-stream-atomic "^1.0.8" - iferr "^0.1.5" - mkdirp "^0.5.1" - rimraf "^2.5.4" - run-queue "^1.0.0" - copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" @@ -3280,15 +3149,16 @@ core-util-is@1.0.2, core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= -cosmiconfig@^5.1.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" - integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== +cosmiconfig@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.0.tgz#ef9b44d773959cae63ddecd122de23853b60f8d3" + integrity sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA== dependencies: - import-fresh "^2.0.0" - is-directory "^0.3.1" - js-yaml "^3.13.1" - parse-json "^4.0.0" + "@types/parse-json" "^4.0.0" + import-fresh "^3.2.1" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.10.0" coveralls@^3.0.2: version "3.1.0" @@ -3341,7 +3211,7 @@ cross-spawn@^4: lru-cache "^4.0.1" which "^1.2.9" -cross-spawn@^6.0.0: +cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== @@ -3352,7 +3222,7 @@ cross-spawn@^6.0.0: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^7.0.0, cross-spawn@^7.0.2: +cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -3376,7 +3246,7 @@ cssom@~0.3.6: resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== -cssstyle@^2.3.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== @@ -3390,18 +3260,6 @@ currently-unhandled@^0.4.1: dependencies: array-find-index "^1.0.1" -cyclist@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" - integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= - -dargs@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/dargs/-/dargs-4.1.0.tgz#03a9dbb4b5c2f139bf14ae53f0b8a2a6a86f4e17" - integrity sha1-A6nbtLXC8Tm/FK5T8LiipqhvThc= - dependencies: - number-is-nan "^1.0.0" - dargs@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" @@ -3443,13 +3301,6 @@ dateformat@^3.0.0: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== -debug@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: version "4.3.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" @@ -3464,19 +3315,12 @@ debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: dependencies: ms "2.0.0" -debug@^3.1.0: - version "3.2.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" - integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== - dependencies: - ms "^2.1.1" - debuglog@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= -decamelize-keys@^1.0.0, decamelize-keys@^1.1.0: +decamelize-keys@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk= @@ -3494,7 +3338,7 @@ decamelize@^5.0.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-5.0.0.tgz#88358157b010ef133febfd27c18994bd80c6215b" integrity sha512-U75DcT5hrio3KNtvdULAWnLiAPbFUC4191ldxMmj4FA/mRuBnmDwU0boNfPyFRhnan+Jm+haLeSn3P0afcBn4w== -decimal.js@^10.2.1: +decimal.js@^10.2.0: version "10.2.1" resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.2.1.tgz#238ae7b0f0c793d3e3cea410108b35a2c01426a3" integrity sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw== @@ -3619,7 +3463,7 @@ delegates@^1.0.0: resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= -depd@~1.1.2: +depd@^1.1.2, depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= @@ -3679,13 +3523,6 @@ difflib@~0.2.1: dependencies: heap ">= 0.2.0" -dir-glob@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4" - integrity sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw== - 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" @@ -3720,13 +3557,6 @@ domexception@^2.0.1: dependencies: webidl-conversions "^5.0.0" -dot-prop@^4.2.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.1.tgz#45884194a71fc2cda71cbb4bceb3a4dd2f433ba4" - integrity sha512-l0p4+mIuJIua0mhxGoh4a+iNL9bmeK5DvnSVQa6T0OhrVmaEa1XScX5Etc673FePCJOArq/4Pa2cLGODUWTPOQ== - dependencies: - is-obj "^1.0.0" - dot-prop@^5.1.0: version "5.3.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" @@ -3734,6 +3564,13 @@ dot-prop@^5.1.0: dependencies: is-obj "^2.0.0" +dot-prop@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-6.0.1.tgz#fc26b3cf142b9e59b74dbd39ed66ce620c681083" + integrity sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA== + dependencies: + is-obj "^2.0.0" + dotenv-json@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/dotenv-json/-/dotenv-json-1.0.0.tgz#fc7f672aafea04bed33818733b9f94662332815c" @@ -3764,16 +3601,6 @@ duplexer@^0.1.1: resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== -duplexify@^3.4.2, duplexify@^3.6.0: - version "3.7.1" - resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" - integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== - dependencies: - end-of-stream "^1.0.0" - inherits "^2.0.1" - readable-stream "^2.0.0" - stream-shift "^1.0.0" - ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -3807,14 +3634,14 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== -encoding@^0.1.11: +encoding@^0.1.12: version "0.1.13" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== dependencies: iconv-lite "^0.6.2" -end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1: +end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== @@ -3843,15 +3670,15 @@ env-paths@^2.2.0: resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== -envinfo@^7.3.1: +envinfo@^7.7.4: version "7.7.4" resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.7.4.tgz#c6311cdd38a0e86808c1c9343f667e4267c4a320" integrity sha512-TQXTYFVVwwluWSFis6K2XKxgrD22jEv0FTuLCQI+OjH7rn93+iY0fSSFM5lrSxFY+H1+B0/cvvlamr3UsBivdQ== -err-code@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960" - integrity sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA= +err-code@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" + integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== error-ex@^1.2.0, error-ex@^1.3.1: version "1.3.2" @@ -3915,22 +3742,10 @@ es6-error@^4.0.1: resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== -es6-promise@^4.0.3: - version "4.2.8" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" - integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== - -es6-promisify@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" - integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= - dependencies: - es6-promise "^4.0.3" - -esbuild@^0.9.3: - version "0.9.3" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.9.3.tgz#09293a0b824159c6aa2488d1c6c22f57d8448f74" - integrity sha512-G8k0olucZp3LJ7I/p8y388t+IEyb2Y78nHrLeIxuqZqh6TYqDYP/B/7drAvYKfh83CGwKal9txVP+FTypsPJug== +esbuild@^0.11.18: + version "0.11.18" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.11.18.tgz#b587ec9e84d2e291b545e3c6342b5b703fd009cb" + integrity sha512-KD7v4N9b5B8bxPUNn/3GA9r0HWo4nJk3iwjZ+2zG1ffg+r8ig+wqj7sW6zgI6Sn4/B2FnbzqWxcAokAGGM5zwQ== escalade@^3.1.1: version "3.1.1" @@ -3952,7 +3767,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.8.1: +escodegen@^1.14.1, escodegen@^1.8.1: version "1.14.3" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== @@ -3964,18 +3779,6 @@ escodegen@^1.8.1: optionalDependencies: source-map "~0.6.1" -escodegen@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" - integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== - dependencies: - esprima "^4.0.1" - estraverse "^5.2.0" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.6.1" - eslint-config-standard@^14.1.1: version "14.1.1" resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-14.1.1.tgz#830a8e44e7aef7de67464979ad06b406026c56ea" @@ -4035,10 +3838,10 @@ eslint-plugin-import@^2.22.1: resolve "^1.17.0" tsconfig-paths "^3.9.0" -eslint-plugin-jest@^24.3.2: - version "24.3.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.3.2.tgz#30a8b2dea6278d0da1d6fb9d6cd530aaf58050a1" - integrity sha512-cicWDr+RvTAOKS3Q/k03+Z3odt3VCiWamNUHWd6QWbVQWcYJyYgUTu8x0mx9GfeDEimawU5kQC+nQ3MFxIM6bw== +eslint-plugin-jest@^24.3.6: + version "24.3.6" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.3.6.tgz#5f0ca019183c3188c5ad3af8e80b41de6c8e9173" + integrity sha512-WOVH4TIaBLIeCX576rLcOgjNXqP+jNlCiEmRgFTfQtJ52DpwnIQKAVGlGPAN7CZ33bW6eNfHD6s8ZbEUTQubJg== dependencies: "@typescript-eslint/experimental-utils" "^4.0.1" @@ -4094,10 +3897,10 @@ eslint-visitor-keys@^2.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8" integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== -eslint@^7.22.0: - version "7.22.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.22.0.tgz#07ecc61052fec63661a2cab6bd507127c07adc6f" - integrity sha512-3VawOtjSJUQiiqac8MQc+w457iGLfuNGLFn8JmF051tTKbh5/x/0vlcEj8OgDCaw7Ysa2Jn8paGshV7x2abKXg== +eslint@^7.25.0: + version "7.25.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.25.0.tgz#1309e4404d94e676e3e831b3a3ad2b050031eb67" + integrity sha512-TVpSovpvCNpLURIScDRB6g5CYu/ZFq9GfX2hLNIV4dSBKxIWojeDODvYl3t0k0VtMxYeR8OXPCFE5+oHMlGfhw== dependencies: "@babel/code-frame" "7.12.11" "@eslint/eslintrc" "^0.4.0" @@ -4185,10 +3988,10 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -eventemitter3@^3.1.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" - integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== +eventemitter3@^4.0.4: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== events-to-array@^1.0.1: version "1.1.2" @@ -4233,6 +4036,21 @@ execa@^4.0.0: signal-exit "^3.0.2" strip-final-newline "^2.0.0" +execa@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.0.0.tgz#4029b0007998a841fbd1032e5f4de86a3c1e3376" + integrity sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + exit-on-epipe@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz#0bdd92e87d5285d267daa8171d0eb06159689692" @@ -4338,18 +4156,6 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^2.2.6: - version "2.2.7" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d" - integrity sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw== - dependencies: - "@mrmlnc/readdir-enhanced" "^2.2.1" - "@nodelib/fs.stat" "^1.1.2" - glob-parent "^3.1.0" - is-glob "^4.0.0" - merge2 "^1.2.3" - micromatch "^3.1.10" - fast-glob@^3.1.1: version "3.2.5" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.5.tgz#7939af2a656de79a4f1901903ee8adcaa7cb9661" @@ -4398,19 +4204,7 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" -figgy-pudding@^3.4.1, figgy-pudding@^3.5.1: - version "3.5.2" - resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" - integrity sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw== - -figures@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" - integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= - dependencies: - escape-string-regexp "^1.0.5" - -figures@^3.1.0: +figures@^3.0.0, figures@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== @@ -4515,6 +4309,13 @@ find-up@^5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" +find-yarn-workspace-root@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz#f47fb8d239c900eb78179aa81b66673eac88f7bd" + integrity sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ== + dependencies: + micromatch "^4.0.2" + flat-cache@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" @@ -4533,14 +4334,6 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.1.tgz#c4b489e80096d9df1dfc97c79871aea7c617c469" integrity sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA== -flush-write-stream@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" - integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== - dependencies: - inherits "^2.0.3" - readable-stream "^2.3.6" - follow-redirects@^1.10.0, follow-redirects@^1.11.0: version "1.13.3" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267" @@ -4593,14 +4386,6 @@ fragment-cache@^0.2.1: dependencies: map-cache "^0.2.2" -from2@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" - integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.0" - fromentries@^1.2.0: version "1.3.2" resolved "https://registry.yarnpkg.com/fromentries/-/fromentries-1.3.2.tgz#e4bca6808816bf8f93b52750f1127f5a6fd86e3a" @@ -4623,6 +4408,15 @@ fs-exists-cached@^1.0.0: resolved "https://registry.yarnpkg.com/fs-exists-cached/-/fs-exists-cached-1.0.0.tgz#cf25554ca050dc49ae6656b41de42258989dcbce" integrity sha1-zyVVTKBQ3EmuZla0HeQiWJidy84= +fs-extra@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs-extra@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" @@ -4649,15 +4443,12 @@ fs-minipass@^1.2.5: dependencies: minipass "^2.6.0" -fs-write-stream-atomic@^1.0.8: - version "1.0.10" - resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" - integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= +fs-minipass@^2.0.0, fs-minipass@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== dependencies: - graceful-fs "^4.1.2" - iferr "^0.1.5" - imurmurhash "^0.1.4" - readable-stream "1 || 2" + minipass "^3.0.0" fs.realpath@^1.0.0: version "1.0.0" @@ -4706,11 +4497,6 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -genfun@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/genfun/-/genfun-5.0.0.tgz#9dd9710a06900a5c4a5bf57aca5da4e52fe76537" - integrity sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA== - gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -4746,10 +4532,10 @@ get-pkg-repo@^1.0.0: parse-github-repo-url "^1.3.0" through2 "^2.0.0" -get-port@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/get-port/-/get-port-4.2.0.tgz#e37368b1e863b7629c43c5a323625f95cf24b119" - integrity sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw== +get-port@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" + integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== get-stdin@^4.0.1: version "4.0.1" @@ -4761,7 +4547,7 @@ get-stdin@~8.0.0: resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53" integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg== -get-stream@^4.0.0, get-stream@^4.1.0: +get-stream@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== @@ -4775,6 +4561,11 @@ get-stream@^5.0.0: dependencies: pump "^3.0.0" +get-stream@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.0.tgz#3e0012cb6827319da2706e601a1583e8629a6718" + integrity sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg== + get-uri@3: version "3.0.2" resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-3.0.2.tgz#f0ef1356faabc70e1f9404fa3b66b2ba9bfc725c" @@ -4799,17 +4590,6 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" -git-raw-commits@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-2.0.0.tgz#d92addf74440c14bcc5c83ecce3fb7f8a79118b5" - integrity sha512-w4jFEJFgKXMQJ0H0ikBk2S+4KP2VEjhCvLCNqbNRQC8BgGWgLKNCO7a9K9LI+TVT7Gfoloje502sEnctibffgg== - dependencies: - dargs "^4.0.1" - lodash.template "^4.0.2" - meow "^4.0.0" - split2 "^2.0.0" - through2 "^2.0.0" - git-raw-commits@^2.0.8: version "2.0.10" resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-2.0.10.tgz#e2255ed9563b1c9c3ea6bd05806410290297bbc1" @@ -4829,14 +4609,6 @@ git-remote-origin-url@^2.0.0: gitconfiglocal "^1.0.0" pify "^2.3.0" -git-semver-tags@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/git-semver-tags/-/git-semver-tags-2.0.3.tgz#48988a718acf593800f99622a952a77c405bfa34" - integrity sha512-tj4FD4ww2RX2ae//jSrXZzrocla9db5h0V7ikPl1P/WwoZar9epdUhwR7XHXSgc+ZkNq72BEEerqQuicoEQfzA== - dependencies: - meow "^4.0.0" - semver "^6.0.0" - git-semver-tags@^4.0.0, git-semver-tags@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/git-semver-tags/-/git-semver-tags-4.1.1.tgz#63191bcd809b0ec3e151ba4751c16c444e5b5780" @@ -4853,7 +4625,7 @@ git-up@^4.0.0: is-ssh "^1.3.0" parse-url "^5.0.0" -git-url-parse@^11.1.2: +git-url-parse@^11.4.4: version "11.4.4" resolved "https://registry.yarnpkg.com/git-url-parse/-/git-url-parse-11.4.4.tgz#5d747debc2469c17bc385719f7d0427802d83d77" integrity sha512-Y4o9o7vQngQDIU9IjyCmRJBin5iYjI5u9ZITnddRZpD7dcCFQj2sL2XuMNbLRE4b4B/4ENPsp2Q8P44fjAZ0Pw== @@ -4877,26 +4649,13 @@ github-api@^3.4.0: js-base64 "^2.1.9" utf8 "^2.1.1" -glob-parent@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" - integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= - dependencies: - is-glob "^3.1.0" - path-dirname "^1.0.0" - -glob-parent@^5.0.0, glob-parent@^5.1.0: +glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@^5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" -glob-to-regexp@^0.3.0: - version "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.6: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" @@ -4928,7 +4687,7 @@ globals@^13.6.0: dependencies: type-fest "^0.20.2" -globby@^11.0.1: +globby@^11.0.1, globby@^11.0.2: version "11.0.2" resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.2.tgz#1af538b766a3b540ebfb58a32b2e2d5897321d83" integrity sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og== @@ -4940,21 +4699,7 @@ globby@^11.0.1: 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" - integrity sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg== - dependencies: - "@types/glob" "^7.1.1" - array-union "^1.0.2" - dir-glob "^2.2.2" - fast-glob "^2.2.6" - glob "^7.1.3" - ignore "^4.0.3" - pify "^4.0.1" - slash "^2.0.0" - -graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.4, graceful-fs@^4.2.6: +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.3, graceful-fs@^4.2.4, graceful-fs@^4.2.6: version "4.2.6" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== @@ -5077,7 +4822,7 @@ hasha@^5.0.0: resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.6.tgz#087e1f10b046932fc8594dd9e6d378afc9d1e5ac" integrity sha1-CH4fELBGky/IWU3Z5tN4r8nR5aw= -hosted-git-info@^2.1.4, hosted-git-info@^2.7.1: +hosted-git-info@^2.1.4: version "2.8.8" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== @@ -5089,6 +4834,13 @@ hosted-git-info@^4.0.0: dependencies: lru-cache "^6.0.0" +hosted-git-info@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.0.1.tgz#710ef5452ea429a844abc33c981056e7371edab7" + integrity sha512-eT7NrxAsppPRQEBSwKSosReE+v8OzABwEScQYk5d4uxaEPlzxTIku7LINXtBGalthkLhJnq5lBI89PfK43zAKg== + dependencies: + lru-cache "^6.0.0" + html-encoding-sniffer@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" @@ -5101,10 +4853,10 @@ html-escaper@^2.0.0: resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== -http-cache-semantics@^3.8.1: - version "3.8.1" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" - integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== +http-cache-semantics@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" + integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== http-errors@1.7.3: version "1.7.3" @@ -5117,14 +4869,6 @@ http-errors@1.7.3: statuses ">= 1.5.0 < 2" toidentifier "1.0.0" -http-proxy-agent@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" - integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg== - dependencies: - agent-base "4" - debug "3.1.0" - http-proxy-agent@^4.0.0, http-proxy-agent@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" @@ -5151,19 +4895,16 @@ https-proxy-agent@5, https-proxy-agent@^5.0.0: agent-base "6" debug "4" -https-proxy-agent@^2.2.3: - version "2.2.4" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" - integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== - dependencies: - agent-base "^4.3.0" - debug "^3.1.0" - human-signals@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + humanize-ms@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" @@ -5195,19 +4936,14 @@ ieee754@^1.1.13, ieee754@^1.1.4: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -iferr@^0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" - integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= - -ignore-walk@^3.0.1: +ignore-walk@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw== dependencies: minimatch "^3.0.4" -ignore@^4.0.3, ignore@^4.0.6: +ignore@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== @@ -5222,14 +4958,6 @@ immediate@~3.0.5: resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= -import-fresh@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" - integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY= - dependencies: - caller-path "^2.0.0" - resolve-from "^3.0.0" - import-fresh@^3.0.0, import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" @@ -5238,14 +4966,6 @@ import-fresh@^3.0.0, import-fresh@^3.2.1: parent-module "^1.0.0" resolve-from "^4.0.0" -import-local@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" - integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== - dependencies: - pkg-dir "^3.0.0" - resolve-cwd "^2.0.0" - import-local@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.0.2.tgz#a8cfd0431d1de4a2199703d003e3e62364fa6db6" @@ -5266,17 +4986,12 @@ indent-string@^2.1.0: dependencies: repeating "^2.0.0" -indent-string@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" - integrity sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok= - indent-string@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== -infer-owner@^1.0.3, infer-owner@^1.0.4: +infer-owner@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== @@ -5289,7 +5004,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -5299,37 +5014,37 @@ ini@^1.3.2, ini@^1.3.4, ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -init-package-json@^1.10.3: - version "1.10.3" - resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-1.10.3.tgz#45ffe2f610a8ca134f2bd1db5637b235070f6cbe" - integrity sha512-zKSiXKhQveNteyhcj1CoOP8tqp1QuxPIPBl8Bid99DGLFqA1p87M6lNgfjJHSBoWJJlidGOv5rWjyYKEB3g2Jw== +init-package-json@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-2.0.2.tgz#d81a7e6775af9b618f20bba288e440b8d1ce05f3" + integrity sha512-PO64kVeArePvhX7Ff0jVWkpnE1DfGRvaWcStYrPugcJz9twQGYibagKJuIMHCX7ENcp0M6LJlcjLBuLD5KeJMg== dependencies: glob "^7.1.1" - npm-package-arg "^4.0.0 || ^5.0.0 || ^6.0.0" + npm-package-arg "^8.1.0" promzard "^0.3.0" read "~1.0.1" - read-package-json "1 || 2" - semver "2.x || 3.x || 4 || 5" - validate-npm-package-license "^3.0.1" + read-package-json "^3.0.0" + semver "^7.3.2" + validate-npm-package-license "^3.0.4" validate-npm-package-name "^3.0.0" -inquirer@^6.2.0: - version "6.5.2" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" - integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ== +inquirer@^7.3.3: + version "7.3.3" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" + integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== dependencies: - ansi-escapes "^3.2.0" - chalk "^2.4.2" - cli-cursor "^2.1.0" - cli-width "^2.0.0" + 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 "^2.0.0" - lodash "^4.17.12" - mute-stream "0.0.7" - run-async "^2.2.0" - rxjs "^6.4.0" - string-width "^2.1.0" - strip-ansi "^5.1.0" + 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: @@ -5337,7 +5052,12 @@ interpret@^1.0.0: resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== -ip@1.1.5, ip@^1.1.5: +ip-regex@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" + integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= + +ip@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= @@ -5441,11 +5161,6 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2: is-data-descriptor "^1.0.0" kind-of "^6.0.2" -is-directory@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" - integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= - is-docker@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.1.1.tgz#4125a88e44e450d384e09047ede71adc2d144156" @@ -5463,7 +5178,7 @@ is-extendable@^1.0.1: dependencies: is-plain-object "^2.0.4" -is-extglob@^2.1.0, is-extglob@^2.1.1: +is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= @@ -5495,13 +5210,6 @@ is-generator-fn@^2.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== -is-glob@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" - integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= - dependencies: - is-extglob "^2.1.0" - is-glob@^4.0.0, is-glob@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" @@ -5509,6 +5217,11 @@ is-glob@^4.0.0, is-glob@^4.0.1: dependencies: is-extglob "^2.1.1" +is-lambda@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" + integrity sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU= + is-map@^2.0.1, is-map@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" @@ -5536,11 +5249,6 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -is-obj@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" - integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= - is-obj@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" @@ -5556,6 +5264,11 @@ is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= +is-plain-obj@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" @@ -5653,12 +5366,12 @@ is-weakset@^2.0.1: resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.1.tgz#e9a0af88dbd751589f5e50d80f4c98b780884f83" integrity sha512-pi4vhbhVHGLxohUw7PhGsueT4vRGFoXhP7+RGN0jKIv9+8PWYCQTqtADngrxOm2g46hoH0+g8uZZBzMrvVGDmw== -is-windows@^1.0.0, is-windows@^1.0.2: +is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== -is-wsl@^2.2.0: +is-wsl@^2.1.1, is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== @@ -5970,6 +5683,16 @@ jest-jasmine2@^26.6.3: pretty-format "^26.6.2" throat "^5.0.0" +jest-junit@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/jest-junit/-/jest-junit-11.1.0.tgz#79cd53948e44d62b2b30fa23ea0d7a899d2c8d7a" + integrity sha512-c2LFOyKY7+ZxL5zSu+WHmHfsJ2wqbOpeYJ4Uu26yMhFxny2J2NQj6AVS7M+Eaxji9Q/oIDDK5tQy0DGzDp9xOw== + dependencies: + mkdirp "^1.0.4" + strip-ansi "^5.2.0" + uuid "^3.3.3" + xml "^1.0.1" + jest-junit@^12.0.0: version "12.0.0" resolved "https://registry.yarnpkg.com/jest-junit/-/jest-junit-12.0.0.tgz#3ebd4a6a84b50c4ab18323a8f7d9cceb9d845df6" @@ -6270,71 +5993,71 @@ jsesc@^2.5.1: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== -jsii-diff@^1.25.0: - version "1.25.0" - resolved "https://registry.yarnpkg.com/jsii-diff/-/jsii-diff-1.25.0.tgz#410c05422427291c7b19e2d410090b6945eda142" - integrity sha512-rW4mpldvQrUDgDY+9Bvglew6nwXPWyVaePgeYTTB/4+9NEoAE7vecQAYhDokTBRdcOVCaEt5ffucwwawMu2ctQ== +jsii-diff@^1.29.0: + version "1.29.0" + resolved "https://registry.yarnpkg.com/jsii-diff/-/jsii-diff-1.29.0.tgz#572bd3e0c9172fac3f1bf1cc4635501f57bbc8a0" + integrity sha512-Zc+h5C2XUGgVtT3qxerIDtPlvtjie45b5o5bZ6T/R+p0ClULrYmRl74+u1ztLqtOYcVqkhs6Qj11dgyZOCGzBA== dependencies: - "@jsii/spec" "^1.25.0" + "@jsii/spec" "^1.29.0" fs-extra "^9.1.0" - jsii-reflect "^1.25.0" + jsii-reflect "^1.29.0" log4js "^6.3.0" typescript "~3.9.9" yargs "^16.2.0" -jsii-pacmak@^1.25.0: - version "1.25.0" - resolved "https://registry.yarnpkg.com/jsii-pacmak/-/jsii-pacmak-1.25.0.tgz#389bc16b8c7337769c2ed7a03e04262476b9b69b" - integrity sha512-GEVdCYvnwYVnVNdcLDrvStaHqWIXBiZCpM9i4LS2rpA+qSsyXJUF8FV4cj2YFjdHsolUdY1EKY7njSs8XQ+1gg== +jsii-pacmak@^1.29.0: + version "1.29.0" + resolved "https://registry.yarnpkg.com/jsii-pacmak/-/jsii-pacmak-1.29.0.tgz#12db86247f7350379d6a34d9a2aebec816c10152" + integrity sha512-wpVDrvh+hClB4Y68v/sYCcRnXlXoDwEUTC0X+uz9o5xUHs/WfuDglS5AAhq6g51INAQc0ed3anrkqmFcDK6QPw== dependencies: - "@jsii/spec" "^1.25.0" + "@jsii/spec" "^1.29.0" clone "^2.1.2" - codemaker "^1.25.0" + codemaker "^1.29.0" commonmark "^0.29.3" escape-string-regexp "^4.0.0" fs-extra "^9.1.0" - jsii-reflect "^1.25.0" - jsii-rosetta "^1.25.0" - semver "^7.3.4" + jsii-reflect "^1.29.0" + jsii-rosetta "^1.29.0" + semver "^7.3.5" spdx-license-list "^6.4.0" xmlbuilder "^15.1.1" yargs "^16.2.0" -jsii-reflect@^1.25.0: - version "1.25.0" - resolved "https://registry.yarnpkg.com/jsii-reflect/-/jsii-reflect-1.25.0.tgz#713727a07b270d61304a122be7cb50e135b8fdf0" - integrity sha512-ufBgOeGe6WVmx0CO7ABraEYOzhzxvmx6gJuUvOz/8XMe1dIIU2USLW3O1ArkEtIWchN4F2gITdd7I7jhdzzN1A== +jsii-reflect@^1.29.0: + version "1.29.0" + resolved "https://registry.yarnpkg.com/jsii-reflect/-/jsii-reflect-1.29.0.tgz#eaa80f383619586cddab1f296bb5a30c7157c3a0" + integrity sha512-r1XpKsnaMTaI0B2XXJ4rF1rbufqFDThASrArE+SyuuGeWTJxWQ4UtIzvXNVFLbZba0A5hX4K0JxiMIfaRFCEEg== dependencies: - "@jsii/spec" "^1.25.0" + "@jsii/spec" "^1.29.0" colors "^1.4.0" fs-extra "^9.1.0" - oo-ascii-tree "^1.25.0" + oo-ascii-tree "^1.29.0" yargs "^16.2.0" -jsii-rosetta@^1.25.0: - version "1.25.0" - resolved "https://registry.yarnpkg.com/jsii-rosetta/-/jsii-rosetta-1.25.0.tgz#07eb3c26f76f6ce7d56052014d651a8946629a73" - integrity sha512-2g+O5mkXrcsJPrHs71WPvLhcV4JERYUUzfG4rArZQ+YsGYSlpP2K6FdYlAk8haeCeEgyaedNgsbcW9NbxV8p3A== +jsii-rosetta@^1.29.0: + version "1.29.0" + resolved "https://registry.yarnpkg.com/jsii-rosetta/-/jsii-rosetta-1.29.0.tgz#6363df806efd49ab09a0ff2062b7bf2cb289a141" + integrity sha512-WhTlFFm/xp2ictShT7XreBoqNpFj/U4MK4VyHyzYV1jS58uvJJMkwifMz/MOqciqRtWIAvGM3Ria4EB3VqmTfA== dependencies: - "@jsii/spec" "^1.25.0" + "@jsii/spec" "^1.29.0" commonmark "^0.29.3" fs-extra "^9.1.0" typescript "~3.9.9" xmldom "^0.5.0" yargs "^16.2.0" -jsii@^1.25.0: - version "1.25.0" - resolved "https://registry.yarnpkg.com/jsii/-/jsii-1.25.0.tgz#ec60566f6c2c7829d25aa8f1fb14d49c700f621e" - integrity sha512-5dchUvG+RTc48v8euUUNvxKxAlPMIaE9rG8BFp4RiXQiB3EFDTJeeM89cXK4w/vAhjgDlAxMDx3EJr7k6e461A== +jsii@^1.29.0: + version "1.29.0" + resolved "https://registry.yarnpkg.com/jsii/-/jsii-1.29.0.tgz#1f34c29db9299ace0f361e6d72627d4478994396" + integrity sha512-7o1yE/si/nbGsNquSejwxaiPq0iDSTPfDENd7ZyO3xzGIROV8UZSs+VhGyys9t/VF4og8p9s2olkajEN60fzMw== dependencies: - "@jsii/spec" "^1.25.0" + "@jsii/spec" "^1.29.0" case "^1.6.3" colors "^1.4.0" deep-equal "^2.0.5" fs-extra "^9.1.0" log4js "^6.3.0" - semver "^7.3.4" + semver "^7.3.5" semver-intersect "^1.4.0" sort-json "^2.0.0" spdx-license-list "^6.4.0" @@ -6350,7 +6073,7 @@ json-diff@^0.5.4: difflib "~0.2.1" dreamopt "~0.6.0" -json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.1: +json-parse-better-errors@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== @@ -6432,7 +6155,7 @@ jsonify@~0.0.0: resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= -jsonparse@^1.2.0: +jsonparse@^1.2.0, jsonparse@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= @@ -6491,6 +6214,13 @@ kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== +klaw-sync@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/klaw-sync/-/klaw-sync-6.0.0.tgz#1fd2cfd56ebb6250181114f0a581167099c2b28c" + integrity sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ== + dependencies: + graceful-fs "^4.1.11" + kleur@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" @@ -6526,28 +6256,28 @@ lcov-parse@^1.0.0: resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-1.0.0.tgz#eb0d46b54111ebc561acb4c408ef9363bdc8f7e0" integrity sha1-6w1GtUER68VhrLTECO+TY73I9+A= -lerna@^3.22.1: - version "3.22.1" - resolved "https://registry.yarnpkg.com/lerna/-/lerna-3.22.1.tgz#82027ac3da9c627fd8bf02ccfeff806a98e65b62" - integrity sha512-vk1lfVRFm+UuEFA7wkLKeSF7Iz13W+N/vFd48aW2yuS7Kv0RbNm2/qcDPV863056LMfkRlsEe+QYOw3palj5Lg== - dependencies: - "@lerna/add" "3.21.0" - "@lerna/bootstrap" "3.21.0" - "@lerna/changed" "3.21.0" - "@lerna/clean" "3.21.0" - "@lerna/cli" "3.18.5" - "@lerna/create" "3.22.0" - "@lerna/diff" "3.21.0" - "@lerna/exec" "3.21.0" - "@lerna/import" "3.22.0" - "@lerna/info" "3.21.0" - "@lerna/init" "3.21.0" - "@lerna/link" "3.21.0" - "@lerna/list" "3.21.0" - "@lerna/publish" "3.22.1" - "@lerna/run" "3.21.0" - "@lerna/version" "3.22.1" - import-local "^2.0.0" +lerna@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/lerna/-/lerna-4.0.0.tgz#b139d685d50ea0ca1be87713a7c2f44a5b678e9e" + integrity sha512-DD/i1znurfOmNJb0OBw66NmNqiM8kF6uIrzrJ0wGE3VNdzeOhz9ziWLYiRaZDGGwgbcjOo6eIfcx9O5Qynz+kg== + dependencies: + "@lerna/add" "4.0.0" + "@lerna/bootstrap" "4.0.0" + "@lerna/changed" "4.0.0" + "@lerna/clean" "4.0.0" + "@lerna/cli" "4.0.0" + "@lerna/create" "4.0.0" + "@lerna/diff" "4.0.0" + "@lerna/exec" "4.0.0" + "@lerna/import" "4.0.0" + "@lerna/info" "4.0.0" + "@lerna/init" "4.0.0" + "@lerna/link" "4.0.0" + "@lerna/list" "4.0.0" + "@lerna/publish" "4.0.0" + "@lerna/run" "4.0.0" + "@lerna/version" "4.0.0" + import-local "^3.0.2" npmlog "^4.1.2" leven@^3.1.0: @@ -6571,6 +6301,27 @@ levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" +libnpmaccess@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-4.0.1.tgz#17e842e03bef759854adf6eb6c2ede32e782639f" + integrity sha512-ZiAgvfUbvmkHoMTzdwmNWCrQRsDkOC+aM5BDfO0C9aOSwF3R1LdFDBD+Rer1KWtsoQYO35nXgmMR7OUHpDRxyA== + dependencies: + aproba "^2.0.0" + minipass "^3.1.1" + npm-package-arg "^8.0.0" + npm-registry-fetch "^9.0.0" + +libnpmpublish@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/libnpmpublish/-/libnpmpublish-4.0.0.tgz#ad6413914e0dfd78df868ce14ba3d3a4cc8b385b" + integrity sha512-2RwYXRfZAB1x/9udKpZmqEzSqNd7ouBRU52jyG14/xG8EF+O9A62d7/XVR3iABEQHf1iYhkm0Oq9iXjrL3tsXA== + dependencies: + normalize-package-data "^3.0.0" + npm-package-arg "^8.1.0" + npm-registry-fetch "^9.0.0" + semver "^7.1.3" + ssri "^8.0.0" + lie@~3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" @@ -6621,16 +6372,15 @@ load-json-file@^4.0.0: pify "^3.0.0" strip-bom "^3.0.0" -load-json-file@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-5.3.0.tgz#4d3c1e01fa1c03ea78a60ac7af932c9ce53403f3" - integrity sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw== +load-json-file@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-6.2.0.tgz#5c7770b42cafa97074ca2848707c61662f4251a1" + integrity sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ== dependencies: graceful-fs "^4.1.15" - parse-json "^4.0.0" - pify "^4.0.1" - strip-bom "^3.0.0" - type-fest "^0.3.0" + parse-json "^5.0.0" + strip-bom "^4.0.0" + type-fest "^0.6.0" locate-path@^2.0.0: version "2.0.0" @@ -6722,7 +6472,7 @@ lodash.sortby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= -lodash.template@^4.0.2, lodash.template@^4.5.0: +lodash.template@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== @@ -6737,17 +6487,17 @@ lodash.templatesettings@^4.0.0: dependencies: lodash._reinterpolate "^3.0.0" +lodash.truncate@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" + integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= + lodash.union@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg= -lodash.uniq@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" - integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= - -lodash@4.x, lodash@^4.17.12, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.2.1: +lodash@4.x, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -6798,18 +6548,6 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -macos-release@^2.2.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.4.1.tgz#64033d0ec6a5e6375155a74b1a1eba8e509820ac" - integrity sha512-H/QHeBIN1fIGJX517pvK8IEK53yQOW7YcEI55oYtgjDdoCQQz7eJS94qt5kNrscReEyuD/JcdFCm2XBEcGOITg== - -make-dir@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" - integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== - dependencies: - pify "^3.0.0" - make-dir@^2.0.0, make-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" @@ -6830,22 +6568,26 @@ make-error@1.x, make-error@^1.1.1: resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== -make-fetch-happen@^5.0.0: - version "5.0.2" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz#aa8387104f2687edca01c8687ee45013d02d19bd" - integrity sha512-07JHC0r1ykIoruKO8ifMXu+xEU8qOXDFETylktdug6vJDACnP+HKevOu3PXyNPzFyTSlz8vrBYlBO1JZRe8Cag== - dependencies: - agentkeepalive "^3.4.1" - cacache "^12.0.0" - http-cache-semantics "^3.8.1" - http-proxy-agent "^2.1.0" - https-proxy-agent "^2.2.3" - lru-cache "^5.1.1" - mississippi "^3.0.0" - node-fetch-npm "^2.0.2" - promise-retry "^1.1.1" - socks-proxy-agent "^4.0.0" - ssri "^6.0.0" +make-fetch-happen@^8.0.9: + version "8.0.14" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-8.0.14.tgz#aaba73ae0ab5586ad8eaa68bd83332669393e222" + integrity sha512-EsS89h6l4vbfJEtBZnENTOFk8mCRpY5ru36Xe5bcX1KYIli2mkSHqoFsp5O1wMDvTJJzxe/4THpCTtygjeeGWQ== + dependencies: + agentkeepalive "^4.1.3" + cacache "^15.0.5" + http-cache-semantics "^4.1.0" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + is-lambda "^1.0.1" + lru-cache "^6.0.0" + minipass "^3.1.3" + minipass-collect "^1.0.2" + minipass-fetch "^1.3.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + promise-retry "^2.0.1" + socks-proxy-agent "^5.0.0" + ssri "^8.0.0" make-runnable@^1.3.8: version "1.3.8" @@ -6872,11 +6614,6 @@ map-obj@^1.0.0, map-obj@^1.0.1: resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= -map-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-2.0.0.tgz#a65cd29087a92598b8791257a523e021222ac1f9" - integrity sha1-plzSkIepJZi4eRJXpSPgISIqwfk= - map-obj@^4.0.0: version "4.2.0" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.2.0.tgz#0e8bc823e2aaca8a0942567d12ed14f389eec153" @@ -6962,21 +6699,6 @@ meow@^3.3.0: redent "^1.0.0" trim-newlines "^1.0.0" -meow@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/meow/-/meow-4.0.1.tgz#d48598f6f4b1472f35bf6317a95945ace347f975" - integrity sha512-xcSBHD5Z86zaOc+781KrupuHAzeGXSLtiAOmBsiLDiPSaYSB6hdew2ng9EBAnZ62jagG9MHAOdxpDi/lWBFJ/A== - dependencies: - camelcase-keys "^4.0.0" - decamelize-keys "^1.0.0" - loud-rejection "^1.0.0" - minimist "^1.1.3" - minimist-options "^3.0.1" - normalize-package-data "^2.3.4" - read-pkg-up "^3.0.0" - redent "^2.0.0" - trim-newlines "^2.0.0" - meow@^8.0.0: version "8.1.2" resolved "https://registry.yarnpkg.com/meow/-/meow-8.1.2.tgz#bcbe45bda0ee1729d350c03cffc8395a36c4e897" @@ -7011,12 +6733,12 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -merge2@^1.2.3, merge2@^1.3.0: +merge2@^1.3.0: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -micromatch@^3.1.10, micromatch@^3.1.4: +micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== @@ -7055,11 +6777,6 @@ mime-types@^2.1.12, mime-types@~2.1.19: dependencies: mime-db "1.46.0" -mimic-fn@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== - mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" @@ -7086,19 +6803,58 @@ minimist-options@4.1.0: is-plain-obj "^1.1.0" kind-of "^6.0.3" -minimist-options@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-3.0.2.tgz#fba4c8191339e13ecf4d61beb03f070103f3d954" - integrity sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ== - dependencies: - arrify "^1.0.1" - is-plain-obj "^1.1.0" - minimist@>=1.2.2, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5, minimist@~1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +minipass-collect@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" + integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA== + dependencies: + minipass "^3.0.0" + +minipass-fetch@^1.3.0, minipass-fetch@^1.3.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-1.3.3.tgz#34c7cea038c817a8658461bf35174551dce17a0a" + integrity sha512-akCrLDWfbdAWkMLBxJEeWTdNsjML+dt5YgOI4gJ53vuO0vrmYQkUPxa6j6V65s9CcePIr2SSWqjT2EcrNseryQ== + dependencies: + minipass "^3.1.0" + minipass-sized "^1.0.3" + minizlib "^2.0.0" + optionalDependencies: + encoding "^0.1.12" + +minipass-flush@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" + integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw== + dependencies: + minipass "^3.0.0" + +minipass-json-stream@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz#7edbb92588fbfc2ff1db2fc10397acb7b6b44aa7" + integrity sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg== + dependencies: + jsonparse "^1.3.1" + minipass "^3.0.0" + +minipass-pipeline@^1.2.2, minipass-pipeline@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" + integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== + dependencies: + minipass "^3.0.0" + +minipass-sized@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/minipass-sized/-/minipass-sized-1.0.3.tgz#70ee5a7c5052070afacfbc22977ea79def353b70" + integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g== + dependencies: + minipass "^3.0.0" + minipass@^2.2.0, minipass@^2.3.5, minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" @@ -7107,7 +6863,7 @@ minipass@^2.2.0, minipass@^2.3.5, minipass@^2.6.0, minipass@^2.8.6, minipass@^2. safe-buffer "^5.1.2" yallist "^3.0.0" -minipass@^3.0.0: +minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.3.tgz#7d42ff1f39635482e15f9cdb53184deebd5815fd" integrity sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg== @@ -7121,21 +6877,13 @@ minizlib@^1.2.1: dependencies: minipass "^2.9.0" -mississippi@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" - integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== +minizlib@^2.0.0, minizlib@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== dependencies: - concat-stream "^1.5.0" - duplexify "^3.4.2" - end-of-stream "^1.1.0" - flush-write-stream "^1.0.0" - from2 "^2.1.0" - parallel-transform "^1.1.0" - pump "^3.0.0" - pumpify "^1.3.3" - stream-each "^1.1.0" - through2 "^2.0.0" + minipass "^3.0.0" + yallist "^4.0.0" mixin-deep@^1.2.0: version "1.3.2" @@ -7145,14 +6893,16 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp-promise@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz#e9b8f68e552c68a9c1713b84883f7a1dd039b8a1" - integrity sha1-6bj2jlUsaKnBcTuEiD96HdA5uKE= +mkdirp-infer-owner@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mkdirp-infer-owner/-/mkdirp-infer-owner-2.0.0.tgz#55d3b368e7d89065c38f32fd38e638f0ab61d316" + integrity sha512-sdqtiFt3lkOaYvTXSRIUjkIdPTcxgv5+fgqYE/5qgwdw12cOrAuzzgzvVExIkH/ul1oeHN3bCLOWSG3XOqbKKw== dependencies: - mkdirp "*" + chownr "^2.0.0" + infer-owner "^1.0.4" + mkdirp "^1.0.3" -mkdirp@*, mkdirp@1.x, mkdirp@^1.0.4: +mkdirp@1.x, mkdirp@^1.0.3, mkdirp@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== @@ -7164,10 +6914,10 @@ mkdirp@^0.5.0, mkdirp@^0.5.1: dependencies: minimist "^1.2.5" -mock-fs@^4.13.0: - version "4.13.0" - resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.13.0.tgz#31c02263673ec3789f90eb7b6963676aa407a598" - integrity sha512-DD0vOdofJdoaRNtnWcrXe6RQbpHkPPmtqGq14uRX0F8ZKJ5nv89CVTYl/BZdppDxBDaV0hl75htg3abpEWlPZA== +mock-fs@^4.14.0: + version "4.14.0" + resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.14.0.tgz#ce5124d2c601421255985e6e94da80a7357b1b18" + integrity sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw== mockery@^2.1.0: version "2.1.0" @@ -7184,18 +6934,6 @@ module-not-found-error@^1.0.1: resolved "https://registry.yarnpkg.com/module-not-found-error/-/module-not-found-error-1.0.1.tgz#cf8b4ff4f29640674d6cdd02b0e3bc523c2bbdc0" integrity sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA= -move-concurrently@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" - integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= - dependencies: - aproba "^1.1.1" - copy-concurrently "^1.0.0" - fs-write-stream-atomic "^1.0.8" - mkdirp "^0.5.1" - rimraf "^2.5.4" - run-queue "^1.0.3" - ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -7206,40 +6944,27 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.0.0, ms@^2.1.1: +ms@^2.0.0: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -multimatch@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-3.0.0.tgz#0e2534cc6bc238d9ab67e1b9cd5fcd85a6dbf70b" - integrity sha512-22foS/gqQfANZ3o+W7ST2x25ueHDVNWl/b9OlGcLpy/iKxjCpvcNCM51YCenUi7Mt/jAjjqv8JwZRs8YP5sRjA== +multimatch@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-5.0.0.tgz#932b800963cea7a31a033328fa1e0c3a1874dbe6" + integrity sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA== dependencies: - array-differ "^2.0.3" - array-union "^1.0.2" - arrify "^1.0.1" + "@types/minimatch" "^3.0.3" + array-differ "^3.0.0" + array-union "^2.1.0" + arrify "^2.0.1" minimatch "^3.0.4" -mute-stream@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" - integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= - -mute-stream@~0.0.4: +mute-stream@0.0.8, mute-stream@~0.0.4: version "0.0.8" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== -mz@^2.5.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" - integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== - dependencies: - any-promise "^1.0.0" - object-assign "^4.0.1" - thenify-all "^1.0.0" - nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -7272,10 +6997,10 @@ nested-error-stacks@^2.0.0: resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz#0fbdcf3e13fe4994781280524f8b96b0cdff9c61" integrity sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug== -netmask@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/netmask/-/netmask-1.0.6.tgz#20297e89d86f6f6400f250d9f4f6b4c1945fcd35" - integrity sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU= +netmask@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.1.tgz#5a5cbdcbb7b6de650870e15e83d3e9553a414cf4" + integrity sha512-gB8eG6ubxz67c7O2gaGiyWdRUIbH61q7anjgueDqCC9kvIs/b4CTtCMaQKeJbv1/Y7FT19I4zKwYmjnjInRQsg== nice-try@^1.0.4: version "1.0.5" @@ -7303,16 +7028,7 @@ nock@^13.0.11: lodash.set "^4.3.2" propagate "^2.0.0" -node-fetch-npm@^2.0.2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/node-fetch-npm/-/node-fetch-npm-2.0.4.tgz#6507d0e17a9ec0be3bec516958a497cec54bf5a4" - integrity sha512-iOuIQDWDyjhv9qSDrj9aq/klt6F9z1p2otB3AV7v3zBDcL/x+OfGsvGQZZCcMZbUf4Ujw1xGNQkjvGnVT22cKg== - dependencies: - encoding "^0.1.11" - json-parse-better-errors "^1.0.0" - safe-buffer "^5.1.1" - -node-fetch@^2.5.0, node-fetch@^2.6.1: +node-fetch@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== @@ -7334,6 +7050,22 @@ node-gyp@^5.0.2: tar "^4.4.12" which "^1.3.1" +node-gyp@^7.1.0: + version "7.1.2" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-7.1.2.tgz#21a810aebb187120251c3bcec979af1587b188ae" + integrity sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ== + dependencies: + env-paths "^2.2.0" + glob "^7.1.4" + graceful-fs "^4.2.3" + nopt "^5.0.0" + npmlog "^4.1.2" + request "^2.88.2" + rimraf "^3.0.2" + semver "^7.3.2" + tar "^6.0.2" + which "^2.0.2" + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -7384,7 +7116,14 @@ nopt@^4.0.1: abbrev "1" osenv "^0.1.4" -normalize-package-data@^2.0.0, normalize-package-data@^2.3.0, normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.3.5, normalize-package-data@^2.4.0, normalize-package-data@^2.5.0: +nopt@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" + integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== + dependencies: + abbrev "1" + +normalize-package-data@^2.0.0, normalize-package-data@^2.3.0, normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== @@ -7421,14 +7160,28 @@ normalize-url@^3.3.0: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== -npm-bundled@^1.0.1, npm-bundled@^1.1.1: +npm-bundled@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.1.tgz#1edd570865a94cdb1bc8220775e29466c9fb234b" integrity sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA== dependencies: npm-normalize-package-bin "^1.0.1" -npm-lifecycle@^3.1.2: +npm-bundled@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.2.tgz#944c78789bd739035b70baa2ca5cc32b8d860bc1" + integrity sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ== + dependencies: + npm-normalize-package-bin "^1.0.1" + +npm-install-checks@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-4.0.0.tgz#a37facc763a2fde0497ef2c6d0ac7c3fbe00d7b4" + integrity sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w== + dependencies: + semver "^7.1.1" + +npm-lifecycle@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/npm-lifecycle/-/npm-lifecycle-3.1.5.tgz#9882d3642b8c82c815782a12e6a1bfeed0026309" integrity sha512-lDLVkjfZmvmfvpvBzA4vzee9cn+Me4orq0QF8glbswJVEbIcSNWib7qGOffolysc3teCqbbPZZkzbr3GQZTL1g== @@ -7447,33 +7200,48 @@ npm-normalize-package-bin@^1.0.0, npm-normalize-package-bin@^1.0.1: resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== -"npm-package-arg@^4.0.0 || ^5.0.0 || ^6.0.0", npm-package-arg@^6.0.0, npm-package-arg@^6.1.0: - version "6.1.1" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.1.1.tgz#02168cb0a49a2b75bf988a28698de7b529df5cb7" - integrity sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg== +npm-package-arg@^8.0.0, npm-package-arg@^8.0.1, npm-package-arg@^8.1.0, npm-package-arg@^8.1.2: + version "8.1.2" + resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-8.1.2.tgz#b868016ae7de5619e729993fbd8d11dc3c52ab62" + integrity sha512-6Eem455JsSMJY6Kpd3EyWE+n5hC+g9bSyHr9K9U2zqZb7+02+hObQ2c0+8iDk/mNF+8r1MhY44WypKJAkySIYA== dependencies: - hosted-git-info "^2.7.1" - osenv "^0.1.5" - semver "^5.6.0" + hosted-git-info "^4.0.1" + semver "^7.3.4" validate-npm-package-name "^3.0.0" -npm-packlist@^1.4.4: - version "1.4.8" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e" - integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A== +npm-packlist@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-2.1.4.tgz#40e96b2b43787d0546a574542d01e066640d09da" + integrity sha512-Qzg2pvXC9U4I4fLnUrBmcIT4x0woLtUgxUi9eC+Zrcv1Xx5eamytGAfbDWQ67j7xOcQ2VW1I3su9smVTIdu7Hw== dependencies: - ignore-walk "^3.0.1" - npm-bundled "^1.0.1" + glob "^7.1.6" + ignore-walk "^3.0.3" + npm-bundled "^1.1.1" npm-normalize-package-bin "^1.0.1" -npm-pick-manifest@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-3.0.2.tgz#f4d9e5fd4be2153e5f4e5f9b7be8dc419a99abb7" - integrity sha512-wNprTNg+X5nf+tDi+hbjdHhM4bX+mKqv6XmPh7B5eG+QY9VARfQPfCEH013H5GqfNj6ee8Ij2fg8yk0mzps1Vw== +npm-pick-manifest@^6.0.0: + version "6.1.1" + resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz#7b5484ca2c908565f43b7f27644f36bb816f5148" + integrity sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA== + dependencies: + npm-install-checks "^4.0.0" + npm-normalize-package-bin "^1.0.1" + npm-package-arg "^8.1.2" + semver "^7.3.4" + +npm-registry-fetch@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-9.0.0.tgz#86f3feb4ce00313bc0b8f1f8f69daae6face1661" + integrity sha512-PuFYYtnQ8IyVl6ib9d3PepeehcUeHN9IO5N/iCRhyg9tStQcqGQBRVHmfmMWPDERU3KwZoHFvbJ4FPXPspvzbA== dependencies: - figgy-pudding "^3.5.1" - npm-package-arg "^6.0.0" - semver "^5.4.1" + "@npmcli/ci-detect" "^1.0.0" + lru-cache "^6.0.0" + make-fetch-happen "^8.0.9" + minipass "^3.1.3" + minipass-fetch "^1.3.0" + minipass-json-stream "^1.0.1" + minizlib "^2.0.0" + npm-package-arg "^8.0.0" npm-run-path@^2.0.0: version "2.0.2" @@ -7482,7 +7250,7 @@ npm-run-path@^2.0.0: dependencies: path-key "^2.0.0" -npm-run-path@^4.0.0: +npm-run-path@^4.0.0, npm-run-path@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== @@ -7658,11 +7426,6 @@ object.values@^1.1.1: es-abstract "^1.18.0-next.2" has "^1.0.3" -octokit-pagination-methods@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz#cf472edc9d551055f9ef73f6e42b4dbb4c80bea4" - integrity sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ== - once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -7670,24 +7433,25 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" -onetime@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= - dependencies: - mimic-fn "^1.0.0" - -onetime@^5.1.0: +onetime@^5.1.0, onetime@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== dependencies: mimic-fn "^2.1.0" -oo-ascii-tree@^1.25.0: - version "1.25.0" - resolved "https://registry.yarnpkg.com/oo-ascii-tree/-/oo-ascii-tree-1.25.0.tgz#97ce4d7e61a26d9c44117b041bf313a5329edf85" - integrity sha512-bV3aHhVkSc862VMMj1JV9y8yBqzhXCMNE9UFt8w9NwkM7tvw94O8niGlvmFzNx2Hf4+qhO4gYdtRAYQqUaH+1w== +oo-ascii-tree@^1.29.0: + version "1.29.0" + resolved "https://registry.yarnpkg.com/oo-ascii-tree/-/oo-ascii-tree-1.29.0.tgz#101db364fad798656bec7add53cd9ab1a4f2bf4e" + integrity sha512-DUwUL3Yc3lS2znWBlOi5eEU4pKoGGK2IaB/S7XygSBzmSS2jJE6+waAip17FNeNXfC4aXClr95HxZXamCLtYqQ== + +open@^7.4.2: + version "7.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" + integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== + dependencies: + is-docker "^2.0.0" + is-wsl "^2.1.1" opener@^1.5.1: version "1.5.2" @@ -7723,20 +7487,12 @@ 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-name@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/os-name/-/os-name-3.1.0.tgz#dec19d966296e1cd62d701a5a66ee1ddeae70801" - integrity sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg== - dependencies: - macos-release "^2.2.0" - windows-release "^3.1.0" - os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= -osenv@^0.1.4, osenv@^0.1.5: +osenv@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== @@ -7815,17 +7571,10 @@ p-locate@^5.0.0: dependencies: p-limit "^3.0.2" -p-map-series@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-map-series/-/p-map-series-1.0.0.tgz#bf98fe575705658a9e1351befb85ae4c1f07bdca" - integrity sha1-v5j+V1cFZYqeE1G++4WuTB8Hvco= - dependencies: - p-reduce "^1.0.0" - -p-map@^2.1.0: +p-map-series@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" - integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + resolved "https://registry.yarnpkg.com/p-map-series/-/p-map-series-2.1.0.tgz#7560d4c452d9da0c07e692fdbfe6e2c81a2a91f2" + integrity sha512-RpYIIK1zXSNEOdwxcfe7FdvGcs7+y5n8rifMhMNWvaxRNMPINJHF5GDeuVxWqnfrcHPSCnp7Oo5yNXHId9Av2Q== p-map@^3.0.0: version "3.0.0" @@ -7834,22 +7583,37 @@ p-map@^3.0.0: dependencies: aggregate-error "^3.0.0" -p-pipe@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/p-pipe/-/p-pipe-1.2.0.tgz#4b1a11399a11520a67790ee5a0c1d5881d6befe9" - integrity sha1-SxoROZoRUgpneQ7loMHViB1r7+k= - -p-queue@^4.0.0: +p-map@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-4.0.0.tgz#ed0eee8798927ed6f2c2f5f5b77fdb2061a5d346" - integrity sha512-3cRXXn3/O0o3+eVmUroJPSj/esxoEFIm0ZOno/T+NzG/VZgPOqQ8WKmlNqubSEpZmCIngEy34unkHGg83ZIBmg== + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== dependencies: - eventemitter3 "^3.1.0" + aggregate-error "^3.0.0" -p-reduce@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" - integrity sha1-GMKw3ZNqRpClKfgjH1ig/bakffo= +p-pipe@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-pipe/-/p-pipe-3.1.0.tgz#48b57c922aa2e1af6a6404cb7c6bf0eb9cc8e60e" + integrity sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw== + +p-queue@^6.6.2: + version "6.6.2" + resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-6.6.2.tgz#2068a9dcf8e67dd0ec3e7a2bcb76810faa85e426" + integrity sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ== + dependencies: + eventemitter3 "^4.0.4" + p-timeout "^3.2.0" + +p-reduce@^2.0.0, p-reduce@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-2.1.0.tgz#09408da49507c6c274faa31f28df334bc712b64a" + integrity sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw== + +p-timeout@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" + integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg== + dependencies: + p-finally "^1.0.0" p-try@^1.0.0: version "1.0.0" @@ -7861,12 +7625,12 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== -p-waterfall@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-waterfall/-/p-waterfall-1.0.0.tgz#7ed94b3ceb3332782353af6aae11aa9fc235bb00" - integrity sha1-ftlLPOszMngjU69qrhGqn8I1uwA= +p-waterfall@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/p-waterfall/-/p-waterfall-2.1.1.tgz#63153a774f472ccdc4eb281cdb2967fcf158b2ee" + integrity sha512-RRTnDb2TBG/epPRI2yYXsimO0v3BXC8Yd3ogr1545IaqKK17VGhbWVeGGN+XfCm/08OK8635nH31c8bATkHuSw== dependencies: - p-reduce "^1.0.0" + p-reduce "^2.0.0" pac-proxy-agent@^4.1.0: version "4.1.0" @@ -7884,13 +7648,13 @@ pac-proxy-agent@^4.1.0: socks-proxy-agent "5" pac-resolver@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-4.1.0.tgz#4b12e7d096b255a3b84e53f6831f32e9c7e5fe95" - integrity sha512-d6lf2IrZJJ7ooVHr7BfwSjRO1yKSJMaiiWYSHcrxSIUtZrCa4KKGwcztdkZ/E9LFleJfjoi1yl+XLR7AX24nbQ== + version "4.2.0" + resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-4.2.0.tgz#b82bcb9992d48166920bc83c7542abb454bd9bdd" + integrity sha512-rPACZdUyuxT5Io/gFKUeeZFfE5T7ve7cAkE5TUZRRfuKP0u5Hocwe48X7ZEm6mYB+bTB0Qf+xlVlA/RM/i6RCQ== dependencies: degenerator "^2.2.0" ip "^1.1.5" - netmask "^1.0.6" + netmask "^2.0.1" package-hash@^3.0.0: version "3.0.0" @@ -7912,20 +7676,36 @@ package-hash@^4.0.0: lodash.flattendeep "^4.4.0" release-zalgo "^1.0.0" +pacote@^11.2.6: + version "11.3.0" + resolved "https://registry.yarnpkg.com/pacote/-/pacote-11.3.0.tgz#b2e16791a39cd4d9fb9fc1ec240cefe7ea518e6f" + integrity sha512-cygprcGpEVqvDzpuPMkGVXW/ooc2ibpoosuJ4YHcUXozDs9VJP7Vha+41pYppG2MVNis4t1BB8IygIBh7vVr2Q== + dependencies: + "@npmcli/git" "^2.0.1" + "@npmcli/installed-package-contents" "^1.0.6" + "@npmcli/promise-spawn" "^1.2.0" + "@npmcli/run-script" "^1.8.2" + cacache "^15.0.5" + chownr "^2.0.0" + fs-minipass "^2.1.0" + infer-owner "^1.0.4" + minipass "^3.1.3" + mkdirp "^1.0.3" + npm-package-arg "^8.0.1" + npm-packlist "^2.1.4" + npm-pick-manifest "^6.0.0" + npm-registry-fetch "^9.0.0" + promise-retry "^2.0.1" + read-package-json-fast "^2.0.1" + rimraf "^3.0.2" + ssri "^8.0.1" + tar "^6.1.0" + pako@~1.0.2: version "1.0.11" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== -parallel-transform@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc" - integrity sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg== - dependencies: - cyclist "^1.0.1" - inherits "^2.0.3" - readable-stream "^2.1.5" - parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -7983,20 +7763,34 @@ parse-url@^5.0.0: parse-path "^4.0.0" protocols "^1.4.0" -parse5@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" - integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== +parse5@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" + integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= -path-dirname@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" - integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= +patch-package@^6.4.7: + version "6.4.7" + resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-6.4.7.tgz#2282d53c397909a0d9ef92dae3fdeb558382b148" + integrity sha512-S0vh/ZEafZ17hbhgqdnpunKDfzHQibQizx9g8yEf5dcVk3KOflOfdufRXQX8CSEkyOQwuM/bNz1GwKvFj54kaQ== + dependencies: + "@yarnpkg/lockfile" "^1.1.0" + chalk "^2.4.2" + cross-spawn "^6.0.5" + find-yarn-workspace-root "^2.0.0" + fs-extra "^7.0.1" + is-ci "^2.0.0" + klaw-sync "^6.0.0" + minimist "^1.2.0" + open "^7.4.2" + rimraf "^2.6.3" + semver "^5.6.0" + slash "^2.0.0" + tmp "^0.0.33" path-exists@^2.0.0: version "2.1.0" @@ -8095,6 +7889,11 @@ pify@^4.0.1: resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== +pify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-5.0.0.tgz#1f5eca3f5e87ebec28cc6d54a0e4aaf00acc127f" + integrity sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA== + pinkie-promise@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" @@ -8187,13 +7986,13 @@ promise-inflight@^1.0.1: resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= -promise-retry@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-1.1.1.tgz#6739e968e3051da20ce6497fb2b50f6911df3d6d" - integrity sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0= +promise-retry@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" + integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== dependencies: - err-code "^1.0.0" - retry "^0.10.0" + err-code "^2.0.2" + retry "^0.12.0" promptly@^3.2.0: version "3.2.0" @@ -8232,13 +8031,6 @@ protocols@^1.1.0, protocols@^1.4.0: resolved "https://registry.yarnpkg.com/protocols/-/protocols-1.4.8.tgz#48eea2d8f58d9644a4a32caae5d5db290a075ce8" integrity sha512-IgjKyaUSjsROSO8/D49Ab7hP8mJgTYcqApOqdPhLoPxAplXmkp+zRvsrSQjFn5by0rhm4VH0GAUELIPpx7B1yg== -protoduck@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/protoduck/-/protoduck-5.0.1.tgz#03c3659ca18007b69a50fd82a7ebcc516261151f" - integrity sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg== - dependencies: - genfun "^5.0.0" - proxy-agent@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-4.0.1.tgz#326c3250776c7044cd19655ccbfadf2e065a045c" @@ -8272,19 +8064,11 @@ pseudomap@^1.0.2: resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= -psl@^1.1.28, psl@^1.1.33: +psl@^1.1.28: version "1.8.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== -pump@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" - integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - pump@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" @@ -8293,15 +8077,6 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -pumpify@^1.3.3: - version "1.5.1" - resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" - integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== - dependencies: - duplexify "^3.6.0" - inherits "^2.0.3" - pump "^2.0.0" - punycode@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" @@ -8352,11 +8127,6 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.2.tgz#abf64491e6ecf0f38a6502403d4cda04f372dfd3" integrity sha512-dB15eXv3p2jDlbOiNLyMabYg1/sXvppd8DP2J3EOCQ0AkuSXCW2tP7mnVouVLJKgUMY6yP0kcQDVpLCN13h4Xg== -quick-lru@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8" - integrity sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g= - quick-lru@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" @@ -8387,14 +8157,20 @@ react-is@^17.0.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339" integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA== -read-cmd-shim@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-1.0.5.tgz#87e43eba50098ba5a32d0ceb583ab8e43b961c16" - integrity sha512-v5yCqQ/7okKoZZkBQUAfTsQ3sVJtXdNfbPnI5cceppoxEVLYA3k+VtV2omkeo8MS94JCy4fSiUwlRBAwCVRPUA== +read-cmd-shim@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-2.0.0.tgz#4a50a71d6f0965364938e9038476f7eede3928d9" + integrity sha512-HJpV9bQpkl6KwjxlJcBoqu9Ba0PQg8TqSNIOrulGt54a0uup0HtevreFHzYzkm0lpnleRdNBzXznKrgxglEHQw== + +read-package-json-fast@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-2.0.2.tgz#2dcb24d9e8dd50fb322042c8c35a954e6cc7ac9e" + integrity sha512-5fyFUyO9B799foVk4n6ylcoAktG/FbE3jwRKxvwaeSrIunaoMc0u81dzXxjeAFKOce7O5KncdfwpGvvs6r5PsQ== dependencies: - graceful-fs "^4.1.2" + json-parse-even-better-errors "^2.3.0" + npm-normalize-package-bin "^1.0.1" -"read-package-json@1 || 2", read-package-json@^2.0.0, read-package-json@^2.0.13: +read-package-json@^2.0.0: version "2.1.2" resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-2.1.2.tgz#6992b2b66c7177259feb8eaac73c3acd28b9222a" integrity sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA== @@ -8404,7 +8180,17 @@ read-cmd-shim@^1.0.1: normalize-package-data "^2.0.0" npm-normalize-package-bin "^1.0.0" -read-package-tree@^5.1.6: +read-package-json@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-3.0.1.tgz#c7108f0b9390257b08c21e3004d2404c806744b9" + integrity sha512-aLcPqxovhJTVJcsnROuuzQvv6oziQx4zd3JvG0vGCL5MjTONUc4uJ90zCBC6R7W7oUKBNoR/F8pkyfVwlbxqng== + dependencies: + glob "^7.1.1" + json-parse-even-better-errors "^2.3.0" + normalize-package-data "^3.0.0" + npm-normalize-package-bin "^1.0.0" + +read-package-tree@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/read-package-tree/-/read-package-tree-5.3.1.tgz#a32cb64c7f31eb8a6f31ef06f9cedf74068fe636" integrity sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw== @@ -8498,19 +8284,6 @@ read@1, read@^1.0.4, read@~1.0.1: dependencies: mute-stream "~0.0.4" -"readable-stream@1 || 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== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - readable-stream@1.1.x: version "1.1.14" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" @@ -8521,7 +8294,7 @@ readable-stream@1.1.x: isarray "0.0.1" string_decoder "~0.10.x" -"readable-stream@2 || 3", readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: +readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -8530,6 +8303,19 @@ readable-stream@1.1.x: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.0.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== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + readdir-glob@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.1.1.tgz#f0e10bb7bf7bfa7e0add8baffdc54c3f7dbee6c4" @@ -8562,14 +8348,6 @@ redent@^1.0.0: indent-string "^2.1.0" strip-indent "^1.0.1" -redent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-2.0.0.tgz#c1b2007b42d57eb1389079b3c8333639d5e1ccaa" - integrity sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo= - dependencies: - indent-string "^3.0.0" - strip-indent "^2.0.0" - redent@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" @@ -8635,7 +8413,7 @@ request-promise-core@1.1.4: dependencies: lodash "^4.17.19" -request-promise-native@^1.0.9: +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== @@ -8685,13 +8463,6 @@ require-main-filename@^2.0.0: resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== -resolve-cwd@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" - integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo= - dependencies: - resolve-from "^3.0.0" - resolve-cwd@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" @@ -8699,11 +8470,6 @@ resolve-cwd@^3.0.0: dependencies: resolve-from "^5.0.0" -resolve-from@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" - integrity sha1-six699nWiBvItuZTM17rywoYh0g= - resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" @@ -8727,12 +8493,12 @@ resolve@^1.1.6, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.11.1, resolve@^1.13 is-core-module "^2.2.0" path-parse "^1.0.6" -restore-cursor@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== dependencies: - onetime "^2.0.0" + onetime "^5.1.0" signal-exit "^3.0.2" ret@~0.1.10: @@ -8740,10 +8506,10 @@ ret@~0.1.10: resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== -retry@^0.10.0: - version "0.10.1" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" - integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q= +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= reusify@^1.0.4: version "1.0.4" @@ -8755,7 +8521,7 @@ rfdc@^1.1.4: resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== -rimraf@^2.5.4, rimraf@^2.6.2, rimraf@^2.6.3: +rimraf@^2.6.2, rimraf@^2.6.3: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== @@ -8774,7 +8540,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: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== @@ -8786,21 +8552,14 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -run-queue@^1.0.0, run-queue@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" - integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= - dependencies: - aproba "^1.1.1" - -rxjs@^6.4.0: +rxjs@^6.6.0: version "6.6.6" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.6.tgz#14d8417aa5a07c5e633995b525e1e3c0dec03b70" integrity sha512-/oTwee4N4iWzAMAL9xdGKjkEHmIwupR3oXbQjCKywF1BeFohswF3vZdogbmEF6pZkOsXTzWkrZszrWpQTByYVg== dependencies: tslib "^1.9.0" -safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: +safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -8847,7 +8606,7 @@ sax@>=0.6.0, sax@^1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -saxes@^5.0.1: +saxes@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== @@ -8861,23 +8620,30 @@ semver-intersect@^1.4.0: dependencies: semver "^5.0.0" -"semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", semver@^5.0.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1: +"semver@2 || 3 || 4 || 5", semver@^5.0.0, semver@^5.5.0, semver@^5.6.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@7.x, semver@^7.1.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4: +semver@7.x, semver@^7.1.1, semver@^7.1.3, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4: version "7.3.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw== dependencies: lru-cache "^6.0.0" -semver@^6.0.0, semver@^6.1.0, semver@^6.1.1, semver@^6.2.0, semver@^6.3.0: +semver@^6.0.0, semver@^6.1.0, semver@^6.1.1, 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== +semver@^7.3.5: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -8957,7 +8723,7 @@ side-channel@^1.0.3: get-intrinsic "^1.0.2" object-inspect "^1.9.0" -signal-exit@^3.0.0, signal-exit@^3.0.2: +signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== @@ -9047,14 +8813,6 @@ socks-proxy-agent@5, socks-proxy-agent@^5.0.0: debug "4" socks "^2.3.3" -socks-proxy-agent@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz#3c8991f3145b2799e70e11bd5fbc8b1963116386" - integrity sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg== - dependencies: - agent-base "~4.2.1" - socks "~2.3.2" - socks@^2.3.3: version "2.6.0" resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.0.tgz#6b984928461d39871b3666754b9000ecf39dfac2" @@ -9063,14 +8821,6 @@ socks@^2.3.3: ip "^1.1.5" smart-buffer "^4.1.0" -socks@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.3.3.tgz#01129f0a5d534d2b897712ed8aceab7ee65d78e3" - integrity sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA== - dependencies: - ip "1.1.5" - smart-buffer "^4.1.0" - sort-json@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/sort-json/-/sort-json-2.0.0.tgz#a7030d8875adbd4a5ea39a000567ed94c1aa3c50" @@ -9087,6 +8837,13 @@ sort-keys@^2.0.0: dependencies: is-plain-obj "^1.0.0" +sort-keys@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-4.2.0.tgz#6b7638cee42c506fff8c1cecde7376d21315be18" + integrity sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg== + dependencies: + is-plain-obj "^2.0.0" + source-map-resolve@^0.5.0: version "0.5.3" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" @@ -9193,13 +8950,6 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: extend-shallow "^3.0.0" -split2@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/split2/-/split2-2.2.0.tgz#186b2575bcf83e85b7d18465756238ee4ee42493" - integrity sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw== - dependencies: - through2 "^2.0.2" - split2@^3.0.0: version "3.2.2" resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" @@ -9234,12 +8984,12 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" -ssri@^6.0.0, ssri@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" - integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA== +ssri@^8.0.0, ssri@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" + integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== dependencies: - figgy-pudding "^3.5.1" + minipass "^3.1.1" stack-utils@^1.0.2: version "1.0.4" @@ -9255,10 +9005,10 @@ stack-utils@^2.0.2: dependencies: escape-string-regexp "^2.0.0" -standard-version@^9.1.1: - version "9.1.1" - resolved "https://registry.yarnpkg.com/standard-version/-/standard-version-9.1.1.tgz#7561df6351b075a44544ce3d3ebcffcb9582ba5a" - integrity sha512-PF9JnRauBwH7DAkmefYu1mB2Kx0MVG13udqDTFmDUiogbyikBAHBdMrVuauxtAb2YIkyZ3FMYCNv0hqUKMOPww== +standard-version@^9.3.0: + version "9.3.0" + resolved "https://registry.yarnpkg.com/standard-version/-/standard-version-9.3.0.tgz#2e6ff439aa49b2ea8952262f30ae6b70c02467d3" + integrity sha512-cYxxKXhYfI3S9+CA84HmrJa9B88H56V5FQ302iFF2TNwJukJCNoU8FgWt+11YtwKFXRkQQFpepC2QOF7aDq2Ow== dependencies: chalk "^2.4.2" conventional-changelog "3.1.24" @@ -9294,19 +9044,6 @@ stealthy-require@^1.1.1: resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= -stream-each@^1.1.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" - integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== - dependencies: - end-of-stream "^1.1.0" - stream-shift "^1.0.0" - -stream-shift@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" - integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== - streamroller@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-2.2.4.tgz#c198ced42db94086a6193608187ce80a5f2b0e53" @@ -9347,7 +9084,7 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2", string-width@^2.1.0: +"string-width@^1.0.2 || 2": version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== @@ -9471,11 +9208,6 @@ strip-indent@^1.0.1: dependencies: get-stdin "^4.0.1" -strip-indent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68" - integrity sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g= - strip-indent@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" @@ -9493,7 +9225,7 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= -strong-log-transformer@^2.0.0: +strong-log-transformer@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz#0f5ed78d325e0421ac6f90f7f10e691d6ae3ae10" integrity sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA== @@ -9536,7 +9268,7 @@ 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@^6.0.4, table@^6.0.7: +table@^6.0.4: version "6.0.7" resolved "https://registry.yarnpkg.com/table/-/table-6.0.7.tgz#e45897ffbcc1bcf9e8a87bf420f2c9e5a7a52a34" integrity sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g== @@ -9546,6 +9278,19 @@ table@^6.0.4, table@^6.0.7: slice-ansi "^4.0.0" string-width "^4.2.0" +table@^6.6.0: + version "6.6.0" + resolved "https://registry.yarnpkg.com/table/-/table-6.6.0.tgz#905654b79df98d9e9a973de1dd58682532c40e8e" + integrity sha512-iZMtp5tUvcnAdtHpZTWLPF0M7AgiQsURR2DwmxnJwSy8I3+cY+ozzVvYha3BOLG2TB+L0CqjIz+91htuj6yCXg== + dependencies: + ajv "^8.0.1" + lodash.clonedeep "^4.5.0" + lodash.flatten "^4.4.0" + lodash.truncate "^4.4.2" + slice-ansi "^4.0.0" + string-width "^4.2.0" + strip-ansi "^6.0.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" @@ -9636,7 +9381,7 @@ tar-stream@^2.2.0: inherits "^2.0.3" readable-stream "^3.1.1" -tar@^4.4.10, tar@^4.4.12, tar@^4.4.8: +tar@^4.4.12: version "4.4.13" resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== @@ -9649,6 +9394,18 @@ tar@^4.4.10, tar@^4.4.12, tar@^4.4.8: safe-buffer "^5.1.2" yallist "^3.0.3" +tar@^6.0.2, tar@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.0.tgz#d1724e9bcc04b977b18d5c573b333a2207229a83" + integrity sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^3.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + temp-dir@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" @@ -9659,17 +9416,16 @@ temp-dir@^2.0.0: resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-2.0.0.tgz#bde92b05bdfeb1516e804c9c00ad45177f31321e" integrity sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg== -temp-write@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/temp-write/-/temp-write-3.4.0.tgz#8cff630fb7e9da05f047c74ce4ce4d685457d492" - integrity sha1-jP9jD7fp2gXwR8dM5M5NaFRX1JI= +temp-write@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/temp-write/-/temp-write-4.0.0.tgz#cd2e0825fc826ae72d201dc26eef3bf7e6fc9320" + integrity sha512-HIeWmj77uOOHb0QX7siN3OtwV3CTntquin6TNVg6SHOqCP3hYKmox90eeFOGaY1MqJ9WYDDjkyZrW6qS5AWpbw== dependencies: - graceful-fs "^4.1.2" - is-stream "^1.1.0" - make-dir "^1.0.0" - pify "^3.0.0" + graceful-fs "^4.1.15" + is-stream "^2.0.0" + make-dir "^3.0.0" temp-dir "^1.0.0" - uuid "^3.0.1" + uuid "^3.3.2" tempfile@^3.0.0: version "3.0.0" @@ -9716,26 +9472,12 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= -thenify-all@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" - integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= - dependencies: - thenify ">= 3.1.0 < 4" - -"thenify@>= 3.1.0 < 4": - version "3.3.1" - resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" - integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== - dependencies: - any-promise "^1.0.0" - throat@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== -through2@^2.0.0, through2@^2.0.2: +through2@^2.0.0: version "2.0.5" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== @@ -9743,14 +9485,6 @@ through2@^2.0.0, through2@^2.0.2: readable-stream "~2.3.6" xtend "~4.0.1" -through2@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.2.tgz#99f88931cfc761ec7678b41d5d7336b5b6a07bf4" - integrity sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ== - dependencies: - inherits "^2.0.4" - readable-stream "2 || 3" - through2@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764" @@ -9830,21 +9564,14 @@ tough-cookie@^2.3.3, tough-cookie@~2.5.0: psl "^1.1.28" punycode "^2.1.1" -tough-cookie@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" - integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== +tough-cookie@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-3.0.1.tgz#9df4f57e739c26930a018184887f4adb7dca73b2" + integrity sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg== dependencies: - psl "^1.1.33" + ip-regex "^2.1.0" + psl "^1.1.28" punycode "^2.1.1" - universalify "^0.1.2" - -tr46@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" - integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= - dependencies: - punycode "^2.1.0" tr46@^2.0.2: version "2.0.2" @@ -9863,11 +9590,6 @@ trim-newlines@^1.0.0: resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= -trim-newlines@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-2.0.0.tgz#b403d0b91be50c331dfc4b82eeceb22c3de16d20" - integrity sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA= - trim-newlines@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.0.tgz#79726304a6a898aa8373427298d54c2ee8b1cb30" @@ -9883,10 +9605,10 @@ trivial-deferred@^1.0.1: resolved "https://registry.yarnpkg.com/trivial-deferred/-/trivial-deferred-1.0.1.tgz#376d4d29d951d6368a6f7a0ae85c2f4d5e0658f3" integrity sha1-N21NKdlR1jaKb3oK6FwvTV4GWPM= -ts-jest@^26.5.4: - version "26.5.4" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.5.4.tgz#207f4c114812a9c6d5746dd4d1cdf899eafc9686" - integrity sha512-I5Qsddo+VTm94SukBJ4cPimOoFZsYTeElR2xy6H2TOVs+NsvgYglW8KuQgKoApOKuaU/Ix/vrF9ebFZlb5D2Pg== +ts-jest@^26.5.5: + version "26.5.5" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.5.5.tgz#e40481b6ee4dd162626ba481a2be05fa57160ea5" + integrity sha512-7tP4m+silwt1NHqzNRAPjW1BswnAhopTdc2K3HEkRZjF0ZG2F/e/ypVH0xiZIMfItFtD3CX0XFbwPzp9fIEUVg== dependencies: bs-logger "0.x" buffer-from "1.x" @@ -9899,10 +9621,10 @@ ts-jest@^26.5.4: semver "7.x" yargs-parser "20.x" -ts-mock-imports@^1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/ts-mock-imports/-/ts-mock-imports-1.3.3.tgz#7865888382806aa8f09412ab582a8e06f2bd1b6d" - integrity sha512-zCAcb89Y+f3Bhw5VaHrHMh5tiuwAQEl5D3e0r5ELCdLl9EnZpb8Oeei/S60Qf4LORIfmJEXb3TpR5kxtL6j2cg== +ts-mock-imports@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/ts-mock-imports/-/ts-mock-imports-1.3.4.tgz#09f23f2ad24258fd2e6e2723b4ad6172429fc093" + integrity sha512-sfLou3sXExgkq/ia0XKfRLtnXwMBIqfpSoPRT5vQRt8fqSlDPy8PaPz5N6lfkebnb0qW2qM4cKOURYP1L/+yuA== ts-node@^8.0.2: version "8.10.2" @@ -10005,10 +9727,10 @@ type-fest@^0.20.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== -type-fest@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1" - integrity sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ== +type-fest@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.4.1.tgz#8bdf77743385d8a4f13ba95f610f5ccd68c728f8" + integrity sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw== type-fest@^0.6.0: version "0.6.0" @@ -10122,19 +9844,12 @@ unique-slug@^2.0.0: dependencies: imurmurhash "^0.1.4" -universal-user-agent@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-4.0.1.tgz#fd8d6cb773a679a709e967ef8288a31fcc03e557" - integrity sha512-LnST3ebHwVL2aNe4mejI9IQh2HfZ1RLo8Io2HugSif8ekzD1TlWpHpColOB/eh8JHMLkGH3Akqf040I+4ylNxg== - dependencies: - os-name "^3.1.0" - universal-user-agent@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== -universalify@^0.1.0, universalify@^0.1.2: +universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== @@ -10157,10 +9872,10 @@ unset-value@^1.0.0: has-value "^0.3.1" isobject "^3.0.0" -upath@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" - integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== +upath@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/upath/-/upath-2.0.1.tgz#50c73dea68d6f6b990f51d279ce6081665d61a8b" + integrity sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w== uri-js@^4.2.2: version "4.4.1" @@ -10209,7 +9924,7 @@ uuid@3.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== -uuid@^3.0.1, uuid@^3.3.2, uuid@^3.3.3: +uuid@^3.3.2, uuid@^3.3.3: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== @@ -10233,7 +9948,7 @@ v8-to-istanbul@^7.0.0: convert-source-map "^1.6.0" source-map "^0.7.3" -validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.3: +validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== @@ -10290,11 +10005,6 @@ wcwidth@^1.0.0: dependencies: defaults "^1.0.3" -webidl-conversions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" - integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== - webidl-conversions@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" @@ -10317,16 +10027,7 @@ whatwg-mimetype@^2.3.0: resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== -whatwg-url@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" - integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== - dependencies: - lodash.sortby "^4.7.0" - tr46 "^1.0.1" - webidl-conversions "^4.0.2" - -whatwg-url@^8.0.0: +whatwg-url@^8.0.0, whatwg-url@^8.4.0: version "8.4.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.4.0.tgz#50fb9615b05469591d2b2bd6dfaed2942ed72837" integrity sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw== @@ -10395,13 +10096,6 @@ wide-align@^1.1.0: dependencies: string-width "^1.0.2 || 2" -windows-release@^3.1.0: - version "3.3.3" - resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.3.3.tgz#1c10027c7225743eec6b89df160d64c2e0293999" - integrity sha512-OSOGH1QYiW5yVor9TtmXKQvt2vjQqbYS+DqmsZw+r7xDwLXEeT3JGW0ZppFmHx4diyXmxt238KFR3N9jzevBRg== - dependencies: - execa "^1.0.0" - 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" @@ -10444,7 +10138,7 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -write-file-atomic@^2.0.0, write-file-atomic@^2.3.0, write-file-atomic@^2.4.2: +write-file-atomic@^2.4.2: version "2.4.3" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ== @@ -10453,7 +10147,7 @@ write-file-atomic@^2.0.0, write-file-atomic@^2.3.0, write-file-atomic@^2.4.2: imurmurhash "^0.1.4" signal-exit "^3.0.2" -write-file-atomic@^3.0.0: +write-file-atomic@^3.0.0, write-file-atomic@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== @@ -10463,18 +10157,6 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -write-json-file@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-2.3.0.tgz#2b64c8a33004d54b8698c76d585a77ceb61da32f" - integrity sha1-K2TIozAE1UuGmMdtWFp3zrYdoy8= - dependencies: - detect-indent "^5.0.0" - graceful-fs "^4.1.2" - make-dir "^1.0.0" - pify "^3.0.0" - sort-keys "^2.0.0" - write-file-atomic "^2.0.0" - write-json-file@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-3.2.0.tgz#65bbdc9ecd8a1458e15952770ccbadfcff5fe62a" @@ -10487,15 +10169,28 @@ write-json-file@^3.2.0: sort-keys "^2.0.0" write-file-atomic "^2.4.2" -write-pkg@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/write-pkg/-/write-pkg-3.2.0.tgz#0e178fe97820d389a8928bc79535dbe68c2cff21" - integrity sha512-tX2ifZ0YqEFOF1wjRW2Pk93NLsj02+n1UP5RvO6rCs0K6R2g1padvf006cY74PQJKMGS2r42NK7FD0dG6Y6paw== +write-json-file@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-4.3.0.tgz#908493d6fd23225344af324016e4ca8f702dd12d" + integrity sha512-PxiShnxf0IlnQuMYOPPhPkhExoCQuTUNPOa/2JWCYTmBquU9njyyDuwRKN26IZBlp4yn1nt+Agh2HOOBl+55HQ== + dependencies: + detect-indent "^6.0.0" + graceful-fs "^4.1.15" + is-plain-obj "^2.0.0" + make-dir "^3.0.0" + sort-keys "^4.0.0" + write-file-atomic "^3.0.0" + +write-pkg@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/write-pkg/-/write-pkg-4.0.0.tgz#675cc04ef6c11faacbbc7771b24c0abbf2a20039" + integrity sha512-v2UQ+50TNf2rNHJ8NyWttfm/EJUBWMJcx6ZTYZr6Qp52uuegWw/lBkCtCbnYZEmPRNL61m+u67dAmGxo+HTULA== dependencies: sort-keys "^2.0.0" - write-json-file "^2.2.0" + type-fest "^0.4.1" + write-json-file "^3.2.0" -ws@^7.4.4: +ws@^7.2.3: version "7.4.4" resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.4.tgz#383bc9742cb202292c9077ceab6f6047b17f2d59" integrity sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw== @@ -10580,7 +10275,7 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yaml@*, yaml@1.10.2, yaml@^1.5.0: +yaml@*, yaml@1.10.2, yaml@^1.10.0, yaml@^1.5.0: version "1.10.2" resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== @@ -10595,6 +10290,11 @@ yapool@^1.0.0: resolved "https://registry.yarnpkg.com/yapool/-/yapool-1.0.0.tgz#f693f29a315b50d9a9da2646a7a6645c96985b6a" integrity sha1-9pPymjFbUNmp2iZGp6ZkXJaYW2o= +yargs-parser@20.2.4: + version "20.2.4" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== + yargs-parser@20.x, yargs-parser@^20.2.2, yargs-parser@^20.2.3: version "20.2.7" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.7.tgz#61df85c113edfb5a7a4e36eb8aa60ef423cbc90a" @@ -10608,14 +10308,6 @@ yargs-parser@^13.0.0, yargs-parser@^13.1.2: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^15.0.1: - version "15.0.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-15.0.1.tgz#54786af40b820dcb2fb8025b11b4d659d76323b3" - integrity sha512-0OAMV2mAZQrs3FkNpDQcBk1x5HXb8X4twADss4S0Iuk+2dGnLOE/fRHrsYm542GduMveyA77OF4wrNJuanRCWw== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - yargs-parser@^18.1.2: version "18.1.3" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" @@ -10640,23 +10332,6 @@ yargs@^13.2.2: y18n "^4.0.0" yargs-parser "^13.1.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== - dependencies: - cliui "^5.0.0" - decamelize "^1.2.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^15.0.1" - yargs@^15.0.2, yargs@^15.4.1: version "15.4.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8"