diff --git a/.github/workflows/auto-approve.yml b/.github/workflows/auto-approve.yml index 6e186b15f078f..ed29d53382d1f 100644 --- a/.github/workflows/auto-approve.yml +++ b/.github/workflows/auto-approve.yml @@ -7,11 +7,7 @@ on: jobs: auto-approve: - if: > - github.event.pull_request.user.login == 'dependabot[bot]' - || github.event.pull_request.user.login == 'dependabot-preview[bot]' - || (contains(github.event.pull_request.labels.*.name, 'pr/auto-approve') - && github.event.pull_request.user.login == 'aws-cdk-automation') + if: contains(github.event.pull_request.labels.*.name, 'pr/auto-approve') runs-on: ubuntu-latest permissions: pull-requests: write diff --git a/.github/workflows/issue-label-assign.yml b/.github/workflows/issue-label-assign.yml index f4d9f3b293c48..17b33b8455c95 100644 --- a/.github/workflows/issue-label-assign.yml +++ b/.github/workflows/issue-label-assign.yml @@ -60,7 +60,7 @@ jobs: {"area":"@aws-cdk/aws-cloudformation","keywords":["aws-cloudformation","nestedstack"],"labels":["@aws-cdk/aws-cloudformation"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/aws-cloudfront","keywords":["aws-cloudfront","cloud front","cachepolicy","cloudfrontwebdistribution"],"labels":["@aws-cdk/aws-cloudfront"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-cloudfront-origins","keywords":["aws-cloudfront-origins","cloudfront origins"],"labels":["@aws-cdk/aws-cloudfront-origins"],"assignees":["njlynch"]}, - {"area":"@aws-cdk/aws-cloudtrail","keywords":["aws-cloudtrail","cloud trail","trail"],"labels":["@aws-cdk/aws-cloudtrail"],"assignees":["rix0rrr"]}, + {"area":"@aws-cdk/aws-cloudtrail","keywords":["aws-cloudtrail","cloud trail","trail"],"labels":["@aws-cdk/aws-cloudtrail"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-cloudwatch","keywords":["aws-cloudwatch","cloud watch","compositealarm","dashboard"],"labels":["@aws-cdk/aws-cloudwatch"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-cloudwatch-actions","keywords":["aws-cloudwatch-actions","cloudwatch actions","applicationscalingaction","autoscalingaction","ec2action","snsaction"],"labels":["@aws-cdk/aws-cloudwatch-actions"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-codeartifact","keywords":["aws-codeartifact","code-artifact"],"labels":["@aws-cdk/aws-codeartifact"],"assignees":["njlynch"]}, @@ -120,12 +120,13 @@ jobs: {"area":"@aws-cdk/aws-glue","keywords":["aws-glue","glue"],"labels":["@aws-cdk/aws-glue"],"assignees":["kaizen3031593"]}, {"area":"@aws-cdk/aws-greengrass","keywords":["aws-greengrass","green-grass"],"labels":["@aws-cdk/aws-greengrass"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-greengrassv2","keywords":["(aws-greengrassv2)","(greengrassv2)"],"labels":["@aws-cdk/aws-greengrassv2"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-groundstation","keywords":["(aws-groundstation)","(groundstation)"],"labels":["@aws-cdk/aws-groundstation"],"assignees":["rix0rrr"]}, + {"area":"@aws-cdk/aws-groundstation","keywords":["(aws-groundstation)","(groundstation)"],"labels":["@aws-cdk/aws-groundstation"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-guardduty","keywords":["aws-guardduty","guard-duty"],"labels":["@aws-cdk/aws-guardduty"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/aws-iam","keywords":["aws-iam","iam","managedpolicy","policy","role"],"labels":["@aws-cdk/aws-iam"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/aws-imagebuilder","keywords":["aws-imagebuilder","imagebuilder"],"labels":["@aws-cdk/aws-imagebuilder"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-inspector","keywords":["aws-inspector","inspector"],"labels":["@aws-cdk/aws-inspector"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-iot","keywords":["internet-of-things","aws-iot","iot"],"labels":["@aws-cdk/aws-iot"],"assignees":["skinny85"]}, + {"area":"@aws-cdk/aws-iot-actions","keywords":["aws-iot-actions","iot-actions"],"labels":["@aws-cdk/aws-iot-actions"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-iot1click","keywords":["aws-iot1click","iot1click"],"labels":["@aws-cdk/aws-iot1click"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-iotanalytics","keywords":["aws-iotanalytics","iotanalytics"],"labels":["@aws-cdk/aws-iotanalytics"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-iotevents","keywords":["aws-iotevents","iotevents"],"labels":["@aws-cdk/aws-iotevents"],"assignees":["skinny85"]}, @@ -148,7 +149,7 @@ jobs: {"area":"@aws-cdk/aws-lambda-nodejs","keywords":["nodejsfunction","aws-lambda-nodejs","lambda-nodejs"],"labels":["@aws-cdk/aws-lambda-nodejs"],"assignees":["nija-at"]}, {"area":"@aws-cdk/aws-lambda-python","keywords":["aws-lambda-python","lambda-python","pythonfunction"],"labels":["@aws-cdk/aws-lambda-python"],"assignees":["nija-at"]}, {"area":"@aws-cdk/aws-licensemanager","keywords":["(aws-licensemanager)","(licensemanager)"],"labels":["@aws-cdk/aws-licensemanager"],"assignees":["njlynch"]}, - {"area":"@aws-cdk/aws-logs","keywords":["loggroup","aws-logs","logs","logretention"],"labels":["@aws-cdk/aws-logs"],"assignees":["rix0rrr"]}, + {"area":"@aws-cdk/aws-logs","keywords":["loggroup","aws-logs","logs","logretention"],"labels":["@aws-cdk/aws-logs"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-logs-destinations","keywords":["aws-logs-destinations","lambdadestination","kinesisdestination","logs-destinations"],"labels":["@aws-cdk/aws-logs-destinations"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/aws-lookoutmetrics","keywords":["(aws-lookoutmetrics)","(lookoutmetrics)"],"labels":["@aws-cdk/aws-lookoutmetrics"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-lookoutvision","keywords":["(aws-lookoutvision)","(lookoutvision)"],"labels":["@aws-cdk/aws-lookoutvision"],"assignees":["comcalvi"]}, diff --git a/.github/workflows/pr-labeler.yml b/.github/workflows/pr-labeler.yml new file mode 100644 index 0000000000000..b8a816623a9e0 --- /dev/null +++ b/.github/workflows/pr-labeler.yml @@ -0,0 +1,17 @@ +# Apply various labels on PRs + +name: pr-labeler +on: + pull_request: + types: [ opened ] + +jobs: + auto-approve: + if: github.event.pull_request.user.login == 'dependabot[bot]' || github.event.pull_request.user.login == 'dependabot-preview[bot]' + runs-on: ubuntu-latest + permissions: + pull-requests: write + steps: + - run: gh pr edit ${{ github.event.pull_request.number }} --add-label "pr/auto-approve" -R ${{ github.repository }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c9ab93b5e534..780107f78c21a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,55 @@ 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.131.0](https://github.com/aws/aws-cdk/compare/v1.130.0...v1.131.0) (2021-11-07) + + +### ⚠ BREAKING CHANGES TO EXPERIMENTAL FEATURES + +* **apigatewayv2-authorizers:** `userPoolClient` property in `UserPoolAuthorizerProps` +is now renamed to `userPoolClients`. + +### Features + +* **apigatewayv2-authorizers:** http api - allow multiple user pool clients per HttpUserPoolAuthorizer ([#16903](https://github.com/aws/aws-cdk/issues/16903)) ([747eb7c](https://github.com/aws/aws-cdk/commit/747eb7cf5dba4514241103ffebc49e03261d25a9)), closes [#15431](https://github.com/aws/aws-cdk/issues/15431) +* **certificatemanager:** requesting private certificates issued by Private Certificate Authority ([#16315](https://github.com/aws/aws-cdk/issues/16315)) ([e26f5be](https://github.com/aws/aws-cdk/commit/e26f5befc2adedeb524fd263424c7920989b2288)), closes [#10076](https://github.com/aws/aws-cdk/issues/10076) +* **cfnspec:** cloudformation spec v46.0.0 ([#17223](https://github.com/aws/aws-cdk/issues/17223)) ([d9f7b58](https://github.com/aws/aws-cdk/commit/d9f7b58a91a625ffd9bc366767794a3101b0afeb)) +* **cfnspec:** cloudformation spec v46.0.0 ([#17334](https://github.com/aws/aws-cdk/issues/17334)) ([e0f1180](https://github.com/aws/aws-cdk/commit/e0f118046c4a0350bdd614fbff4b96ba7772402e)) +* **cfnspec:** cloudformation spec v47.0.0 ([#17350](https://github.com/aws/aws-cdk/issues/17350)) ([ea71b4e](https://github.com/aws/aws-cdk/commit/ea71b4ed7466d8799bde4fdd5adfed9fc8febb9c)), closes [#17290](https://github.com/aws/aws-cdk/issues/17290) [#17223](https://github.com/aws/aws-cdk/issues/17223) +* **cfnspec:** cloudformation spec v47.0.0 ([#17353](https://github.com/aws/aws-cdk/issues/17353)) ([7886607](https://github.com/aws/aws-cdk/commit/7886607528b0cb005fa1176803b2a45d3e948f48)) +* **cli:** added `build` field to cdk.json ([#17176](https://github.com/aws/aws-cdk/issues/17176)) ([57ad1e0](https://github.com/aws/aws-cdk/commit/57ad1e087edef653d672c1426b920b12962f0f0f)) +* **cli:** introduce the 'watch' command ([#17240](https://github.com/aws/aws-cdk/issues/17240)) ([0adc8b7](https://github.com/aws/aws-cdk/commit/0adc8b7e13011956929fc945e083f75edec16698)) +* **codepipeline:** add construct for registering custom Actions ([#17041](https://github.com/aws/aws-cdk/issues/17041)) ([c66ac89](https://github.com/aws/aws-cdk/commit/c66ac89f43d3d2cee2b5842c54dc00e14ccdd2f4)), closes [#17039](https://github.com/aws/aws-cdk/issues/17039) +* **docdb:** add the ability to exclude characters when generating passwords ([#17262](https://github.com/aws/aws-cdk/issues/17262)) ([135f7d3](https://github.com/aws/aws-cdk/commit/135f7d33db5e96c3af4a8691c13b419e7b14ceae)), closes [#15732](https://github.com/aws/aws-cdk/issues/15732) +* **ec2:** add c6i instances ([#17237](https://github.com/aws/aws-cdk/issues/17237)) ([25cea18](https://github.com/aws/aws-cdk/commit/25cea1807539a8d45f3f4ff8b775b3417387d6fe)) +* **ecs-service-extensions:** Target tracking policies for Service Extensions ([#17101](https://github.com/aws/aws-cdk/issues/17101)) ([6420b18](https://github.com/aws/aws-cdk/commit/6420b1817d4319924d11cfccb8b6a29d4a2d5008)) +* **eks:** expose FargateCluster's defaultProfile ([#17130](https://github.com/aws/aws-cdk/issues/17130)) ([e461601](https://github.com/aws/aws-cdk/commit/e4616010c1915206758be3bf4cd6da9f14d2101a)), closes [#16149](https://github.com/aws/aws-cdk/issues/16149) +* **iot:** allow setting `description` and `enabled` of TopicRule ([#17225](https://github.com/aws/aws-cdk/issues/17225)) ([a9aae09](https://github.com/aws/aws-cdk/commit/a9aae097daad475dd57bbf4842956327a6d5a220)) +* **iot:** allow setting `errorAction` of TopicRule ([#17287](https://github.com/aws/aws-cdk/issues/17287)) ([e412308](https://github.com/aws/aws-cdk/commit/e412308bc81ede16b079077cfa4774ceaa2fadeb)) +* **iot-actions:** Add the action to put CloudWatch Logs ([#17228](https://github.com/aws/aws-cdk/issues/17228)) ([a7c869e](https://github.com/aws/aws-cdk/commit/a7c869e6d57932389df572cd7f104a4c9ea8f8a5)) +* **lambda-nodejs:** add sourcesContent in BundlingOptions ([#17280](https://github.com/aws/aws-cdk/issues/17280)) ([ea56e69](https://github.com/aws/aws-cdk/commit/ea56e6925422ebb987dbd87952511f23832ac7b6)), closes [#17256](https://github.com/aws/aws-cdk/issues/17256) +* **logs:** add support for cloudwatch logs resource policy ([#17015](https://github.com/aws/aws-cdk/issues/17015)) ([e9a461d](https://github.com/aws/aws-cdk/commit/e9a461d6dcbad933fcb9d671a8c5b5ad8f5ece8d)), closes [#5343](https://github.com/aws/aws-cdk/issues/5343) +* **servicecatalog:** allow creating a CFN Product Version with CDK code ([#17144](https://github.com/aws/aws-cdk/issues/17144)) ([f8d0ef5](https://github.com/aws/aws-cdk/commit/f8d0ef550df07e43aeab35dde4406c92f7551ed0)) +* **synthetics:** add static cron method to schedule class ([#17250](https://github.com/aws/aws-cdk/issues/17250)) ([1ab9b26](https://github.com/aws/aws-cdk/commit/1ab9b265e9899ffcd093b3600d658c8a6519cc69)), closes [#16402](https://github.com/aws/aws-cdk/issues/16402) + + +### Bug Fixes + +* **aws-eks:** proxy support and allow assigning a security group to all cluster handler functions ([#17200](https://github.com/aws/aws-cdk/issues/17200)) ([7bbd10d](https://github.com/aws/aws-cdk/commit/7bbd10deb322daf8ef1504ceb84ad3c895f291ae)), closes [#12469](https://github.com/aws/aws-cdk/issues/12469) +* **cli:** `wmic not found` on modern Windows systems ([#17070](https://github.com/aws/aws-cdk/issues/17070)) ([332ce4d](https://github.com/aws/aws-cdk/commit/332ce4d9ae995bd1336fef13e2c7f9fc0c12f34d)), closes [#16419](https://github.com/aws/aws-cdk/issues/16419) +* **cli:** cdk ls --long outputs less-friendly stack IDs for nested assemblies ([#17263](https://github.com/aws/aws-cdk/issues/17263)) ([864c50e](https://github.com/aws/aws-cdk/commit/864c50ed2f3ae133af0cffd17ed77a6cf32ac6f4)), closes [#14379](https://github.com/aws/aws-cdk/issues/14379) +* **cli:** no longer disable rollback by default for hotswap deployments ([#17317](https://github.com/aws/aws-cdk/issues/17317)) ([e32b616](https://github.com/aws/aws-cdk/commit/e32b61652b5d01c44b05c2ac6d5fb1e99b50e059)), closes [#17267](https://github.com/aws/aws-cdk/issues/17267) +* **cognito:** ambiguous error message when same trigger is added twice ([#16917](https://github.com/aws/aws-cdk/issues/16917)) ([4ae78b0](https://github.com/aws/aws-cdk/commit/4ae78b07af20ea3ef049079ac5b892f9ee8476e5)) +* **ec2:** functions addIngressRule and addEgressRule detect unresolved tokens as duplicates ([#17221](https://github.com/aws/aws-cdk/issues/17221)) ([d4952c3](https://github.com/aws/aws-cdk/commit/d4952c3cbe12e7c8c27e1bca7f9d8536d93fd3cb)), closes [#17201](https://github.com/aws/aws-cdk/issues/17201) +* **lambda-nodejs:** yarn berry goes into immutable mode in CI ([#17086](https://github.com/aws/aws-cdk/issues/17086)) ([cc8dd69](https://github.com/aws/aws-cdk/commit/cc8dd694e6746b9c6fc4663775aaa3b68d19ef61)), closes [#17082](https://github.com/aws/aws-cdk/issues/17082) +* **pipelines:** `additionalInputs` not working ([#17279](https://github.com/aws/aws-cdk/issues/17279)) ([9e81dc7](https://github.com/aws/aws-cdk/commit/9e81dc731993a55fbc05c642ce96151f12ed69da)), closes [#17224](https://github.com/aws/aws-cdk/issues/17224) +* **s3:** enforce that fromBucketAttributes supplies a valid bucket name ([#16915](https://github.com/aws/aws-cdk/issues/16915)) ([30ac0cc](https://github.com/aws/aws-cdk/commit/30ac0cc2d95ef3fd79d0658428975ea675b6916f)) + + +### Reverts + +* "chore: activate 'rosetta infuse' feature ([#17191](https://github.com/aws/aws-cdk/issues/17191))" ([#17329](https://github.com/aws/aws-cdk/issues/17329)) ([c8cd515](https://github.com/aws/aws-cdk/commit/c8cd515b3984ce0d8bfbe2d19cd56d299785e78b)) + ## [1.130.0](https://github.com/aws/aws-cdk/compare/v1.129.0...v1.130.0) (2021-10-29) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b6568c7be1263..dca9ebdce5f06 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -113,7 +113,7 @@ $ yarn build $ yarn test ``` -However, if you wish to build the the entire repository, the following command will achieve this. +However, if you wish to build the entire repository, the following command will achieve this. ```console cd @@ -978,3 +978,4 @@ $ node --inspect-brk /path/to/aws-cdk/node_modules/.bin/jest -i -t 'TESTNAME' * [Workshop](https://github.com/aws-samples/aws-cdk-intro-workshop): source for https://cdkworkshop.com * [Developer Guide](https://github.com/awsdocs/aws-cdk-guide): markdown source for developer guide * [jsii](https://github.com/aws/jsii): the technology we use for multi-language support. If you are looking to help us support new languages, start there. + diff --git a/build.sh b/build.sh index aae39e94ea730..64ecc043faf45 100755 --- a/build.sh +++ b/build.sh @@ -6,11 +6,10 @@ runtarget="build" run_tests="true" check_prereqs="true" check_compat="true" -extract_snippets="false" while [[ "${1:-}" != "" ]]; do case $1 in -h|--help) - echo "Usage: build.sh [--no-bail] [--force|-f] [--skip-test] [--skip-prereqs] [--skip-compat] [--extract]" + echo "Usage: build.sh [--no-bail] [--force|-f] [--skip-test] [--skip-prereqs] [--skip-compat]" exit 1 ;; --no-bail) @@ -28,9 +27,6 @@ while [[ "${1:-}" != "" ]]; do --skip-compat) check_compat="false" ;; - --extract) - extract_snippets="true" - ;; *) echo "Unrecognized parameter: $1" exit 1 @@ -81,9 +77,6 @@ trap "rm -rf $MERKLE_BUILD_CACHE" EXIT if [ "$run_tests" == "true" ]; then runtarget="$runtarget+test" fi -if [ "$extract_snippets" == "true" ]; then - runtarget="$runtarget+extract" -fi echo "=============================================================================================" echo "building..." diff --git a/buildspec-pr.yaml b/buildspec-pr.yaml index 647b78849b3e8..ade1f4a9be0c6 100644 --- a/buildspec-pr.yaml +++ b/buildspec-pr.yaml @@ -16,8 +16,14 @@ phases: # Packing the mono-libraries (monocdk & aws-cdk-lib) can cause # memory errors. Increasing this value allows our build to more consistently succeed - (command -v sysctl || yum install -y procps-ng) && /sbin/sysctl -w vm.max_map_count=2251954 + pre_build: + commands: + - /bin/bash ./scripts/cache-load.sh build: commands: - - /bin/bash ./build.sh --extract - - /bin/bash ./scripts/transform.sh --extract + - /bin/bash ./build.sh + - /bin/bash ./scripts/transform.sh + # After compilation, run Rosetta (using the cache if available). + # This will print errors, and fail the build if there are compilation errors in any packages marked as 'strict'. + - /bin/bash ./scripts/run-rosetta.sh - git diff-index --exit-code --ignore-space-at-eol --stat HEAD diff --git a/buildspec.yaml b/buildspec.yaml index 0fc990a17c805..94a75e2357f78 100644 --- a/buildspec.yaml +++ b/buildspec.yaml @@ -16,6 +16,9 @@ phases: # Packing the mono-libraries (monocdk & aws-cdk-lib) can cause # memory errors. Increasing this value allows our build to more consistently succeed - /sbin/sysctl -w vm.max_map_count=2251954 + pre_build: + commands: + - /bin/bash ./scripts/cache-load.sh build: commands: - 'if ${BUMP_CANDIDATE:-false}; then /bin/bash ./scripts/bump-candidate.sh; fi' @@ -25,6 +28,7 @@ phases: post_build: commands: - "[ -f .BUILD_COMPLETED ] && /bin/bash ./pack.sh" + - /bin/bash ./scripts/cache-store.sh artifacts: files: - "**/*" diff --git a/pack.sh b/pack.sh index 168a17f972406..81eecafabe187 100755 --- a/pack.sh +++ b/pack.sh @@ -39,11 +39,7 @@ function lerna_scopes() { # Compile examples with respect to "decdk" directory, as all packages will # be symlinked there so they can all be included. echo "Extracting code samples" >&2 -node --experimental-worker $(which $ROSETTA) \ - --compile \ - --output samples.tabl.json \ - --directory packages/decdk \ - $(cat $TMPDIR/jsii.txt) +scripts/run-rosetta.sh $TMPDIR/jsii.txt # Jsii packaging (all at once using jsii-pacmak) echo "Packaging jsii modules" >&2 diff --git a/package.json b/package.json index 7a521b7db98e1..e0f41dbbeabf1 100644 --- a/package.json +++ b/package.json @@ -20,13 +20,13 @@ "fs-extra": "^9.1.0", "graceful-fs": "^4.2.8", "jest-junit": "^12.3.0", - "jsii-diff": "^1.41.0", - "jsii-pacmak": "^1.41.0", - "jsii-reflect": "^1.41.0", - "jsii-rosetta": "^1.41.0", + "jsii-diff": "^1.42.0", + "jsii-pacmak": "^1.42.0", + "jsii-reflect": "^1.42.0", + "jsii-rosetta": "^1.42.0", "lerna": "^4.0.0", "patch-package": "^6.4.7", - "standard-version": "^9.3.1", + "standard-version": "^9.3.2", "typescript": "~3.9.10" }, "resolutions": { diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/README.md b/packages/@aws-cdk-containers/ecs-service-extensions/README.md index 0556debfc705f..b80f1539f4447 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/README.md +++ b/packages/@aws-cdk-containers/ecs-service-extensions/README.md @@ -154,43 +154,68 @@ const nameService = new Service(stack, 'name', { }); ``` +## Task Auto-Scaling + +You can configure the task count of a service to match demand. The recommended way of achieving this is to configure target tracking policies for your service which scales in and out in order to keep metrics around target values. + +You need to configure an auto scaling target for the service by setting the `minTaskCount` (defaults to 1) and `maxTaskCount` in the `Service` construct. Then you can specify target values for "CPU Utilization" or "Memory Utilization" across all tasks in your service. Note that the `desiredCount` value will be set to `undefined` if the auto scaling target is configured. + +If you want to configure auto-scaling policies based on resources like Application Load Balancer or SQS Queues, you can set the corresponding resource-specific fields in the extension. For example, you can enable target tracking scaling based on Application Load Balancer request count as follows: + +```ts +const stack = new cdk.Stack(); +const environment = new Environment(stack, 'production'); +const serviceDescription = new ServiceDescription(); + +serviceDescription.add(new Container({ + cpu: 256, + memoryMiB: 512, + trafficPort: 80, + image: ecs.ContainerImage.fromRegistry('my-alb'), +})); + +// Add the extension with target `requestsPerTarget` value set +serviceDescription.add(new HttpLoadBalancerExtension({ requestsPerTarget: 10 })); + +// Configure the auto scaling target +new Service(stack, 'my-service', { + environment, + serviceDescription, + desiredCount: 5, + // Task auto-scaling constuct for the service + autoScaleTaskCount: { + maxTaskCount: 10, + targetCpuUtilization: 70, + targetMemoryUtilization: 50, + }, +}); +``` + +You can also define your own service extensions for [other auto-scaling policies](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-auto-scaling.html) for your service by making use of the `scalableTaskCount` attribute of the `Service` class. + ## Creating your own custom `ServiceExtension` In addition to using the default service extensions that come with this module, you can choose to implement your own custom service extensions. The `ServiceExtension` class is an abstract class you can implement yourself. The following example implements a custom service extension that could be added to a service in order to -autoscale it based on CPU: +autoscale it based on scaling intervals of SQS Queue size: ```ts export class MyCustomAutoscaling extends ServiceExtension { constructor() { super('my-custom-autoscaling'); - } - - // This function modifies properties of the service prior - // to construct creation. - public modifyServiceProps(props: ServiceBuild) { - return { - ...props, - - // Initially launch 10 copies of the service - desiredCount: 10 - } as ServiceBuild; + // Scaling intervals for the step scaling policy + this.scalingSteps = [{ upper: 0, change: -1 }, { lower: 100, change: +1 }, { lower: 500, change: +5 }]; + this.sqsQueue = new sqs.Queue(this.scope, 'my-queue'); } // This hook utilizes the resulting service construct // once it is created public useService(service: ecs.Ec2Service | ecs.FargateService) { - const scalingTarget = service.autoScaleTaskCount({ - minCapacity: 5, // Min 5 tasks - maxCapacity: 20 // Max 20 tasks - }); - - scalingTarget.scaleOnCpuUtilization('TargetCpuUtilization50', { - targetUtilizationPercent: 50, - scaleInCooldown: cdk.Duration.seconds(60), - scaleOutCooldown: cdk.Duration.seconds(60), + this.parentService.scalableTaskCount.scaleOnMetric('QueueMessagesVisibleScaling', { + metric: this.sqsQueue.metricApproximateNumberOfMessagesVisible(), + scalingSteps: this.scalingSteps, }); } } 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 e0390c0ab617c..6db6a6c9616d4 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 @@ -8,6 +8,12 @@ import { ServiceExtension, ServiceBuild } from './extension-interfaces'; // eslint-disable-next-line no-duplicate-imports, import/order import { Construct } from '@aws-cdk/core'; +export interface HttpLoadBalancerProps { + /** + * The number of ALB requests per target. + */ + readonly requestsPerTarget?: number; +} /** * This extension add a public facing load balancer for sending traffic * to one or more replicas of the application container. @@ -15,9 +21,11 @@ import { Construct } from '@aws-cdk/core'; export class HttpLoadBalancerExtension extends ServiceExtension { private loadBalancer!: alb.IApplicationLoadBalancer; private listener!: alb.IApplicationListener; + private requestsPerTarget?: number; - constructor() { + constructor(props: HttpLoadBalancerProps = {}) { super('load-balancer'); + this.requestsPerTarget = props.requestsPerTarget; } // Before the service is created, go ahead and create the load balancer itself. @@ -55,10 +63,21 @@ export class HttpLoadBalancerExtension extends ServiceExtension { // After the service is created add the service to the load balancer's listener public useService(service: ecs.Ec2Service | ecs.FargateService) { - this.listener.addTargets(this.parentService.id, { + const targetGroup = this.listener.addTargets(this.parentService.id, { deregistrationDelay: cdk.Duration.seconds(10), port: 80, targets: [service], }); + + if (this.requestsPerTarget) { + if (!this.parentService.scalableTaskCount) { + throw Error(`Auto scaling target for the service '${this.parentService.id}' hasn't been configured. Please use Service construct to configure 'minTaskCount' and 'maxTaskCount'.`); + } + this.parentService.scalableTaskCount.scaleOnRequestCount(`${this.parentService.id}-target-request-count-${this.requestsPerTarget}`, { + requestsPerTarget: this.requestsPerTarget, + targetGroup, + }); + this.parentService.enableAutoScalingPolicy(); + } } } 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 4fdc8590c1dc0..957dcef280cd7 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/service.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/service.ts @@ -30,6 +30,43 @@ export interface ServiceProps { * @default - A task role is automatically created for you. */ readonly taskRole?: iam.IRole; + + /** + * The desired number of instantiations of the task definition to keep running on the service. + * + * @default - When creating the service, default is 1; when updating the service, default uses + * the current task number. + */ + readonly desiredCount?: number; + + /** + * The options for configuring the auto scaling target. + */ + readonly autoScaleTaskCount?: AutoScalingOptions; +} + +export interface AutoScalingOptions { + /** + * The minimum number of tasks when scaling in. + * + * @default - 1 + */ + readonly minTaskCount?: number; + + /** + * The maximum number of tasks when scaling out. + */ + readonly maxTaskCount: number; + + /** + * The target value for CPU utilization across all tasks in the service. + */ + readonly targetCpuUtilization?: number; + + /** + * The target value for memory utilization across all tasks in the service. + */ + readonly targetMemoryUtilization?: number; } /** @@ -75,6 +112,17 @@ export class Service extends Construct { */ public readonly environment: IEnvironment; + /** + * The scalable attribute representing task count. + */ + public readonly scalableTaskCount?: ecs.ScalableTaskCount; + + /** + * The flag to track if auto scaling policies have been configured + * for the service. + */ + private autoScalingPoliciesEnabled: boolean = false; + /** * The generated task definition for this service. It is only * generated after .prepare() has been executed. @@ -160,6 +208,9 @@ export class Service extends Construct { } } + // Set desiredCount to `undefined` if auto scaling is configured for the service + const desiredCount = props.autoScaleTaskCount ? undefined : (props.desiredCount || 1); + // Give each extension a chance to mutate the service props before // service creation let serviceProps = { @@ -167,7 +218,7 @@ export class Service extends Construct { taskDefinition: this.taskDefinition, minHealthyPercent: 100, maxHealthyPercent: 200, - desiredCount: 1, + desiredCount, } as ServiceBuild; for (const extensions in this.serviceDescription.extensions) { @@ -219,12 +270,41 @@ export class Service extends Construct { throw new Error(`Unknown capacity type for service ${this.id}`); } + // Create the auto scaling target and configure target tracking policies after the service is created + if (props.autoScaleTaskCount) { + this.scalableTaskCount = this.ecsService.autoScaleTaskCount({ + maxCapacity: props.autoScaleTaskCount.maxTaskCount, + minCapacity: props.autoScaleTaskCount.minTaskCount, + }); + + if (props.autoScaleTaskCount.targetCpuUtilization) { + const targetUtilizationPercent = props.autoScaleTaskCount.targetCpuUtilization; + this.scalableTaskCount.scaleOnCpuUtilization(`${this.id}-target-cpu-utilization-${targetUtilizationPercent}`, { + targetUtilizationPercent, + }); + this.enableAutoScalingPolicy(); + } + + if (props.autoScaleTaskCount.targetMemoryUtilization) { + const targetUtilizationPercent = props.autoScaleTaskCount.targetMemoryUtilization; + this.scalableTaskCount.scaleOnMemoryUtilization(`${this.id}-target-memory-utilization-${targetUtilizationPercent}`, { + targetUtilizationPercent, + }); + this.enableAutoScalingPolicy(); + } + } + // Now give all extensions a chance to use the service for (const extensions in this.serviceDescription.extensions) { if (this.serviceDescription.extensions[extensions]) { this.serviceDescription.extensions[extensions].useService(this.ecsService); } } + + // Error out if the auto scaling target is created but no scaling policies have been configured + if (this.scalableTaskCount && !this.autoScalingPoliciesEnabled) { + throw Error(`The auto scaling target for the service '${this.id}' has been created but no auto scaling policies have been configured.`); + } } /** @@ -266,4 +346,12 @@ export class Service extends Construct { return this.urls[urlName]; } + + /** + * This helper method is used to set the `autoScalingPoliciesEnabled` attribute + * whenever an auto scaling policy is configured for the service. + */ + public enableAutoScalingPolicy() { + this.autoScalingPoliciesEnabled = true; + } } diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/http-load-balancer.test.ts b/packages/@aws-cdk-containers/ecs-service-extensions/test/http-load-balancer.test.ts index 5e0d0e36ff554..e06c1632d93b5 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/http-load-balancer.test.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/http-load-balancer.test.ts @@ -72,4 +72,72 @@ describe('http load balancer', () => { }); + test('allows scaling on request count for the HTTP load balancer', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const environment = new Environment(stack, 'production'); + const serviceDescription = new ServiceDescription(); + + serviceDescription.add(new Container({ + cpu: 256, + memoryMiB: 512, + trafficPort: 80, + image: ecs.ContainerImage.fromRegistry('nathanpeck/name'), + })); + + serviceDescription.add(new HttpLoadBalancerExtension({ requestsPerTarget: 100 })); + + new Service(stack, 'my-service', { + environment, + serviceDescription, + autoScaleTaskCount: { + maxTaskCount: 5, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ApplicationAutoScaling::ScalableTarget', { + MaxCapacity: 5, + MinCapacity: 1, + }); + + expect(stack).toHaveResourceLike('AWS::ApplicationAutoScaling::ScalingPolicy', { + PolicyType: 'TargetTrackingScaling', + TargetTrackingScalingPolicyConfiguration: { + PredefinedMetricSpecification: { + PredefinedMetricType: 'ALBRequestCountPerTarget', + }, + TargetValue: 100, + }, + }); + }); + + test('should error when adding scaling policy if scaling target has not been configured', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const environment = new Environment(stack, 'production'); + const serviceDescription = new ServiceDescription(); + + serviceDescription.add(new Container({ + cpu: 256, + memoryMiB: 512, + trafficPort: 80, + image: ecs.ContainerImage.fromRegistry('nathanpeck/name'), + })); + + serviceDescription.add(new HttpLoadBalancerExtension({ requestsPerTarget: 100 })); + + // THEN + expect(() => { + new Service(stack, 'my-service', { + environment, + serviceDescription, + }); + }).toThrow(/Auto scaling target for the service 'my-service' hasn't been configured. Please use Service construct to configure 'minTaskCount' and 'maxTaskCount'./); + }); + }); \ No newline at end of file diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/service.test.ts b/packages/@aws-cdk-containers/ecs-service-extensions/test/service.test.ts index eb21eec01b5f5..65807231679b7 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/service.test.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/service.test.ts @@ -1,3 +1,4 @@ +import { ABSENT } 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'; @@ -102,4 +103,117 @@ describe('service', () => { }); + test('allows scaling on a target CPU utilization', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const environment = new Environment(stack, 'production'); + const serviceDescription = new ServiceDescription(); + serviceDescription.add(new Container({ + cpu: 256, + memoryMiB: 512, + trafficPort: 80, + image: ecs.ContainerImage.fromRegistry('nathanpeck/name'), + })); + + new Service(stack, 'my-service', { + environment, + serviceDescription, + desiredCount: 3, + autoScaleTaskCount: { + maxTaskCount: 5, + targetCpuUtilization: 70, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + DesiredCount: ABSENT, + }); + + expect(stack).toHaveResourceLike('AWS::ApplicationAutoScaling::ScalableTarget', { + MaxCapacity: 5, + MinCapacity: 1, + }); + + expect(stack).toHaveResource('AWS::ApplicationAutoScaling::ScalingPolicy', { + PolicyType: 'TargetTrackingScaling', + TargetTrackingScalingPolicyConfiguration: { + PredefinedMetricSpecification: { PredefinedMetricType: 'ECSServiceAverageCPUUtilization' }, + TargetValue: 70, + }, + }); + }); + + test('allows scaling on a target memory utilization', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const environment = new Environment(stack, 'production'); + const serviceDescription = new ServiceDescription(); + serviceDescription.add(new Container({ + cpu: 256, + memoryMiB: 512, + trafficPort: 80, + image: ecs.ContainerImage.fromRegistry('nathanpeck/name'), + })); + + new Service(stack, 'my-service', { + environment, + serviceDescription, + desiredCount: 3, + autoScaleTaskCount: { + maxTaskCount: 5, + targetMemoryUtilization: 70, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + DesiredCount: ABSENT, + }); + + expect(stack).toHaveResourceLike('AWS::ApplicationAutoScaling::ScalableTarget', { + MaxCapacity: 5, + MinCapacity: 1, + }); + + expect(stack).toHaveResource('AWS::ApplicationAutoScaling::ScalingPolicy', { + PolicyType: 'TargetTrackingScaling', + TargetTrackingScalingPolicyConfiguration: { + PredefinedMetricSpecification: { PredefinedMetricType: 'ECSServiceAverageMemoryUtilization' }, + TargetValue: 70, + }, + }); + }); + + test('should error when no auto scaling policies have been configured after creating the auto scaling target', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const environment = new Environment(stack, 'production'); + const serviceDescription = new ServiceDescription(); + + serviceDescription.add(new Container({ + cpu: 256, + memoryMiB: 512, + trafficPort: 80, + image: ecs.ContainerImage.fromRegistry('nathanpeck/name'), + })); + + // THEN + expect(() => { + new Service(stack, 'my-service', { + environment, + serviceDescription, + autoScaleTaskCount: { + maxTaskCount: 5, + }, + }); + }).toThrow(/The auto scaling target for the service 'my-service' has been created but no auto scaling policies have been configured./); + }); + }); \ No newline at end of file diff --git a/packages/@aws-cdk/app-delivery/package.json b/packages/@aws-cdk/app-delivery/package.json index ef9a52c744e36..fe89215e39094 100644 --- a/packages/@aws-cdk/app-delivery/package.json +++ b/packages/@aws-cdk/app-delivery/package.json @@ -66,7 +66,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "fast-check": "^2.18.0", + "fast-check": "^2.19.0", "jest": "^26.6.3" }, "repository": { diff --git a/packages/@aws-cdk/aws-amplify/test/integ.app.expected.json b/packages/@aws-cdk/aws-amplify/test/integ.app.expected.json index d7ddd233378e1..bd8f69d9f66d8 100644 --- a/packages/@aws-cdk/aws-amplify/test/integ.app.expected.json +++ b/packages/@aws-cdk/aws-amplify/test/integ.app.expected.json @@ -24,7 +24,9 @@ "GenerateStringKey": "password", "SecretStringTemplate": "{\"username\":\"aws\"}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "AppF1B96344": { "Type": "AWS::Amplify::App", diff --git a/packages/@aws-cdk/aws-apigateway/test/domains.test.ts b/packages/@aws-cdk/aws-apigateway/test/domains.test.ts index 7ad0f4224d70b..7b8817df48853 100644 --- a/packages/@aws-cdk/aws-apigateway/test/domains.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/domains.test.ts @@ -388,7 +388,7 @@ describe('domains', () => { test('accepts a mutual TLS configuration', () => { const stack = new Stack(); - const bucket = Bucket.fromBucketName(stack, 'testBucket', 'exampleBucket'); + const bucket = Bucket.fromBucketName(stack, 'testBucket', 'example-bucket'); new apigw.DomainName(stack, 'another-domain', { domainName: 'example.com', mtls: { @@ -402,14 +402,14 @@ describe('domains', () => { 'DomainName': 'example.com', 'EndpointConfiguration': { 'Types': ['REGIONAL'] }, 'RegionalCertificateArn': 'arn:aws:acm:us-east-1:1111111:certificate/11-3336f1-44483d-adc7-9cd375c5169d', - 'MutualTlsAuthentication': { 'TruststoreUri': 's3://exampleBucket/someca.pem' }, + 'MutualTlsAuthentication': { 'TruststoreUri': 's3://example-bucket/someca.pem' }, }); }); test('mTLS should allow versions to be set on the s3 bucket', () => { const stack = new Stack(); - const bucket = Bucket.fromBucketName(stack, 'testBucket', 'exampleBucket'); + const bucket = Bucket.fromBucketName(stack, 'testBucket', 'example-bucket'); new apigw.DomainName(stack, 'another-domain', { domainName: 'example.com', certificate: acm.Certificate.fromCertificateArn(stack, 'cert2', 'arn:aws:acm:us-east-1:1111111:certificate/11-3336f1-44483d-adc7-9cd375c5169d'), @@ -423,7 +423,7 @@ describe('domains', () => { 'DomainName': 'example.com', 'EndpointConfiguration': { 'Types': ['REGIONAL'] }, 'RegionalCertificateArn': 'arn:aws:acm:us-east-1:1111111:certificate/11-3336f1-44483d-adc7-9cd375c5169d', - 'MutualTlsAuthentication': { 'TruststoreUri': 's3://exampleBucket/someca.pem', 'TruststoreVersion': 'version' }, + 'MutualTlsAuthentication': { 'TruststoreUri': 's3://example-bucket/someca.pem', 'TruststoreVersion': 'version' }, }); }); diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/README.md b/packages/@aws-cdk/aws-apigatewayv2-authorizers/README.md index 7dd9c2f5e61bd..a7da95a29c682 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/README.md +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/README.md @@ -150,7 +150,7 @@ const userPoolClient = userPool.addClient('UserPoolClient'); const authorizer = new HttpUserPoolAuthorizer({ userPool, - userPoolClient, + userPoolClients: [userPoolClient], }); const api = new HttpApi(stack, 'HttpApi'); diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/lib/http/user-pool.ts b/packages/@aws-cdk/aws-apigatewayv2-authorizers/lib/http/user-pool.ts index 702a3a05576ec..21cef2e478756 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/lib/http/user-pool.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/lib/http/user-pool.ts @@ -7,9 +7,9 @@ import { Stack, Token } from '@aws-cdk/core'; */ export interface UserPoolAuthorizerProps { /** - * The user pool client that should be used to authorize requests with the user pool. + * The user pool clients that should be used to authorize requests with the user pool. */ - readonly userPoolClient: IUserPoolClient; + readonly userPoolClients: IUserPoolClient[]; /** * The associated user pool @@ -33,7 +33,7 @@ export interface UserPoolAuthorizerProps { * * @default ['$request.header.Authorization'] */ - readonly identitySource?: string[], + readonly identitySource?: string[]; } /** @@ -56,7 +56,7 @@ export class HttpUserPoolAuthorizer implements IHttpRouteAuthorizer { identitySource: this.props.identitySource ?? ['$request.header.Authorization'], type: HttpAuthorizerType.JWT, authorizerName: this.props.authorizerName, - jwtAudience: [this.props.userPoolClient.userPoolClientId], + jwtAudience: this.props.userPoolClients.map((c) => c.userPoolClientId), jwtIssuer: `https://cognito-idp.${region}.amazonaws.com/${this.props.userPool.userPoolId}`, }); } @@ -66,4 +66,4 @@ export class HttpUserPoolAuthorizer implements IHttpRouteAuthorizer { authorizationType: 'JWT', }; } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json b/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json index 13c9a7d48efd3..01d8903715957 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.84", + "@types/aws-lambda": "^8.10.85", "@types/jest": "^26.0.24" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.ts b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.ts index edf455f4a787c..3e607b4474365 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.ts @@ -25,7 +25,7 @@ const userPoolClient = userPool.addClient('my-client'); const authorizer = new HttpUserPoolAuthorizer({ userPool, - userPoolClient, + userPoolClients: [userPoolClient], }); const handler = new lambda.Function(stack, 'lambda', { 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 0e3c339e7f744..127b389b8b0f2 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 @@ -13,7 +13,7 @@ describe('HttpUserPoolAuthorizer', () => { const userPoolClient = userPool.addClient('UserPoolClient'); const authorizer = new HttpUserPoolAuthorizer({ userPool, - userPoolClient, + userPoolClients: [userPoolClient], }); // WHEN @@ -52,7 +52,7 @@ describe('HttpUserPoolAuthorizer', () => { const userPoolClient = userPool.addClient('UserPoolClient'); const authorizer = new HttpUserPoolAuthorizer({ userPool, - userPoolClient, + userPoolClients: [userPoolClient], }); // WHEN @@ -70,6 +70,46 @@ describe('HttpUserPoolAuthorizer', () => { // THEN Template.fromStack(stack).resourceCountIs('AWS::ApiGatewayV2::Authorizer', 1); }); + + test('multiple userPoolClients are attached', () => { + // GIVEN + const stack = new Stack(); + const api = new HttpApi(stack, 'HttpApi'); + const userPool = new UserPool(stack, 'UserPool'); + const userPoolClient1 = userPool.addClient('UserPoolClient1'); + const userPoolClient2 = userPool.addClient('UserPoolClient2'); + const authorizer = new HttpUserPoolAuthorizer({ + userPool, + userPoolClients: [userPoolClient1, userPoolClient2], + }); + + // WHEN + api.addRoutes({ + integration: new DummyRouteIntegration(), + path: '/books', + authorizer, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ApiGatewayV2::Authorizer', { + AuthorizerType: 'JWT', + IdentitySource: ['$request.header.Authorization'], + JwtConfiguration: { + Audience: [stack.resolve(userPoolClient1.userPoolClientId), stack.resolve(userPoolClient2.userPoolClientId)], + Issuer: { + 'Fn::Join': [ + '', + [ + 'https://cognito-idp.', + { Ref: 'AWS::Region' }, + '.amazonaws.com/', + stack.resolve(userPool.userPoolId), + ], + ], + }, + }, + }); + }); }); class DummyRouteIntegration implements IHttpRouteIntegration { diff --git a/packages/@aws-cdk/aws-applicationautoscaling/package.json b/packages/@aws-cdk/aws-applicationautoscaling/package.json index e0fb58dda98e7..64308f0005133 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/package.json +++ b/packages/@aws-cdk/aws-applicationautoscaling/package.json @@ -77,7 +77,7 @@ "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "fast-check": "^2.18.0", + "fast-check": "^2.19.0", "jest": "^26.6.3" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-autoscaling-common/package.json b/packages/@aws-cdk/aws-autoscaling-common/package.json index 2253a1669614f..f12569cbbc76d 100644 --- a/packages/@aws-cdk/aws-autoscaling-common/package.json +++ b/packages/@aws-cdk/aws-autoscaling-common/package.json @@ -69,7 +69,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "fast-check": "^2.18.0", + "fast-check": "^2.19.0", "jest": "^26.6.3" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-certificatemanager/README.md b/packages/@aws-cdk/aws-certificatemanager/README.md index 7068591d9c076..331d40ad27276 100644 --- a/packages/@aws-cdk/aws-certificatemanager/README.md +++ b/packages/@aws-cdk/aws-certificatemanager/README.md @@ -113,6 +113,21 @@ new acm.DnsValidatedCertificate(this, 'CrossRegionCertificate', { }); ``` +## Requesting private certificates + +AWS Certificate Manager can create [private certificates](https://docs.aws.amazon.com/acm/latest/userguide/gs-acm-request-private.html) issued by [Private Certificate Authority (PCA)](https://docs.aws.amazon.com/acm-pca/latest/userguide/PcaWelcome.html). Validation of private certificates is not necessary. + +```ts +import * as acmpca from '@aws-cdk/aws-acmpca'; + +new acm.PrivateCertificate(stack, 'PrivateCertificate', { + domainName: 'test.example.com', + subjectAlternativeNames: ['cool.example.com', 'test.example.net'], // optional + certificateAuthority: acmpca.CertificateAuthority.fromCertificateAuthorityArn(stack, 'CA', + 'arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/023077d8-2bfa-4eb0-8f22-05c96deade77'), +}); +``` + ## Importing If you want to import an existing certificate, you can do so from its ARN: 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 6c6198071796b..af5f69aa16046 100644 --- a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package.json +++ b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package.json @@ -29,7 +29,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.84", + "@types/aws-lambda": "^8.10.85", "@types/sinon": "^9.0.11", "@aws-cdk/cdk-build-tools": "0.0.0", "aws-sdk": "^2.596.0", @@ -43,7 +43,7 @@ "jest": "^26.6.3", "lambda-tester": "^3.6.0", "sinon": "^9.2.4", - "nock": "^13.1.3", + "nock": "^13.1.4", "ts-jest": "^26.5.6" } } diff --git a/packages/@aws-cdk/aws-certificatemanager/lib/index.ts b/packages/@aws-cdk/aws-certificatemanager/lib/index.ts index ee15ab71b8d4b..60be9ebed1c5c 100644 --- a/packages/@aws-cdk/aws-certificatemanager/lib/index.ts +++ b/packages/@aws-cdk/aws-certificatemanager/lib/index.ts @@ -1,5 +1,6 @@ export * from './certificate'; export * from './dns-validated-certificate'; +export * from './private-certificate'; export * from './util'; // AWS::CertificateManager CloudFormation Resources: diff --git a/packages/@aws-cdk/aws-certificatemanager/lib/private-certificate.ts b/packages/@aws-cdk/aws-certificatemanager/lib/private-certificate.ts new file mode 100644 index 0000000000000..366b3ea623ac6 --- /dev/null +++ b/packages/@aws-cdk/aws-certificatemanager/lib/private-certificate.ts @@ -0,0 +1,66 @@ +import * as acmpca from '@aws-cdk/aws-acmpca'; +import { Construct } from 'constructs'; +import { ICertificate } from './certificate'; +import { CertificateBase } from './certificate-base'; +import { CfnCertificate } from './certificatemanager.generated'; + +/** + * Properties for your private certificate + */ +export interface PrivateCertificateProps { + /** + * Fully-qualified domain name to request a private certificate for. + * + * May contain wildcards, such as ``*.domain.com``. + */ + readonly domainName: string; + + /** + * Alternative domain names on your private certificate. + * + * Use this to register alternative domain names that represent the same site. + * + * @default - No additional FQDNs will be included as alternative domain names. + */ + readonly subjectAlternativeNames?: string[]; + + /** + * Private certificate authority (CA) that will be used to issue the certificate. + */ + readonly certificateAuthority: acmpca.ICertificateAuthority; +} + +/** + * A private certificate managed by AWS Certificate Manager + * + * @resource AWS::CertificateManager::Certificate + */ +export class PrivateCertificate extends CertificateBase implements ICertificate { + /** + * Import a certificate + */ + public static fromCertificateArn(scope: Construct, id: string, certificateArn: string): ICertificate { + class Import extends CertificateBase { + public readonly certificateArn = certificateArn; + } + + return new Import(scope, id); + } + + /** + * The certificate's ARN + */ + public readonly certificateArn: string; + + constructor(scope: Construct, id: string, props: PrivateCertificateProps) { + super(scope, id); + + const cert = new CfnCertificate(this, 'Resource', { + domainName: props.domainName, + subjectAlternativeNames: props.subjectAlternativeNames, + certificateAuthorityArn: props.certificateAuthority.certificateAuthorityArn, + }); + + this.certificateArn = cert.ref; + } +} diff --git a/packages/@aws-cdk/aws-certificatemanager/package.json b/packages/@aws-cdk/aws-certificatemanager/package.json index 990c09fc3aa55..dae2a8a3a24dc 100644 --- a/packages/@aws-cdk/aws-certificatemanager/package.json +++ b/packages/@aws-cdk/aws-certificatemanager/package.json @@ -79,6 +79,7 @@ "@types/jest": "^26.0.24" }, "dependencies": { + "@aws-cdk/aws-acmpca": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", @@ -88,6 +89,7 @@ }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { + "@aws-cdk/aws-acmpca": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", @@ -101,7 +103,8 @@ "awslint": { "exclude": [ "props-physical-name:@aws-cdk/aws-certificatemanager.CertificateProps", - "props-physical-name:@aws-cdk/aws-certificatemanager.DnsValidatedCertificateProps" + "props-physical-name:@aws-cdk/aws-certificatemanager.DnsValidatedCertificateProps", + "props-physical-name:@aws-cdk/aws-certificatemanager.PrivateCertificateProps" ] }, "stability": "stable", diff --git a/packages/@aws-cdk/aws-certificatemanager/test/private-certificate.test.ts b/packages/@aws-cdk/aws-certificatemanager/test/private-certificate.test.ts new file mode 100644 index 0000000000000..e43a4ca005691 --- /dev/null +++ b/packages/@aws-cdk/aws-certificatemanager/test/private-certificate.test.ts @@ -0,0 +1,102 @@ +import '@aws-cdk/assert-internal/jest'; +import * as acmpca from '@aws-cdk/aws-acmpca'; +import { Duration, Lazy, Stack } from '@aws-cdk/core'; +import { PrivateCertificate } from '../lib'; + +test('private certificate authority', () => { + const stack = new Stack(); + + new PrivateCertificate(stack, 'Certificate', { + domainName: 'test.example.com', + certificateAuthority: acmpca.CertificateAuthority.fromCertificateAuthorityArn(stack, 'CA', + 'arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/023077d8-2bfa-4eb0-8f22-05c96deade77'), + }); + + expect(stack).toHaveResource('AWS::CertificateManager::Certificate', { + DomainName: 'test.example.com', + CertificateAuthorityArn: 'arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/023077d8-2bfa-4eb0-8f22-05c96deade77', + }); +}); + +test('private certificate authority with subjectAlternativeNames', () => { + const stack = new Stack(); + + new PrivateCertificate(stack, 'Certificate', { + domainName: 'test.example.com', + subjectAlternativeNames: ['extra.example.com'], + certificateAuthority: acmpca.CertificateAuthority.fromCertificateAuthorityArn(stack, 'CA', + 'arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/023077d8-2bfa-4eb0-8f22-05c96deade77'), + }); + + expect(stack).toHaveResource('AWS::CertificateManager::Certificate', { + DomainName: 'test.example.com', + SubjectAlternativeNames: ['extra.example.com'], + CertificateAuthorityArn: 'arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/023077d8-2bfa-4eb0-8f22-05c96deade77', + }); +}); + +test('private certificate authority with multiple subjectAlternativeNames', () => { + const stack = new Stack(); + + new PrivateCertificate(stack, 'Certificate', { + domainName: 'test.example.com', + subjectAlternativeNames: ['*.test.example.com', '*.foo.test.example.com', 'bar.test.example.com'], + certificateAuthority: acmpca.CertificateAuthority.fromCertificateAuthorityArn(stack, 'CA', + 'arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/023077d8-2bfa-4eb0-8f22-05c96deade77'), + }); + + expect(stack).toHaveResource('AWS::CertificateManager::Certificate', { + DomainName: 'test.example.com', + SubjectAlternativeNames: ['*.test.example.com', '*.foo.test.example.com', 'bar.test.example.com'], + CertificateAuthorityArn: 'arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/023077d8-2bfa-4eb0-8f22-05c96deade77', + }); +}); + +test('private certificate authority with tokens', () => { + const stack = new Stack(); + + const certificateAuthority = Lazy.string({ + produce: () => 'arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/023077d8-2bfa-4eb0-8f22-05c96deade77', + }); + + const domainName = Lazy.string({ + produce: () => 'test.example.com', + }); + + const domainNameAlternative = Lazy.string({ + produce: () => 'extra.example.com', + }); + + new PrivateCertificate(stack, 'Certificate', { + domainName, + subjectAlternativeNames: [domainNameAlternative], + certificateAuthority: acmpca.CertificateAuthority.fromCertificateAuthorityArn(stack, 'CA', certificateAuthority), + }); + + expect(stack).toHaveResource('AWS::CertificateManager::Certificate', { + DomainName: 'test.example.com', + SubjectAlternativeNames: ['extra.example.com'], + CertificateAuthorityArn: 'arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/023077d8-2bfa-4eb0-8f22-05c96deade77', + }); +}); + +test('metricDaysToExpiry', () => { + const stack = new Stack(); + + const certificate = new PrivateCertificate(stack, 'Certificate', { + domainName: 'test.example.com', + certificateAuthority: acmpca.CertificateAuthority.fromCertificateAuthorityArn(stack, 'CA', + 'arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/023077d8-2bfa-4eb0-8f22-05c96deade77'), + }); + + expect(stack.resolve(certificate.metricDaysToExpiry().toMetricConfig())).toEqual({ + metricStat: { + dimensions: [{ name: 'CertificateArn', value: stack.resolve(certificate.certificateArn) }], + metricName: 'DaysToExpiry', + namespace: 'AWS/CertificateManager', + period: Duration.days(1), + statistic: 'Minimum', + }, + renderingProperties: expect.anything(), + }); +}); diff --git a/packages/@aws-cdk/aws-cloudformation/package.json b/packages/@aws-cdk/aws-cloudformation/package.json index 3a8c455bf4557..39e73c2be2948 100644 --- a/packages/@aws-cdk/aws-cloudformation/package.json +++ b/packages/@aws-cdk/aws-cloudformation/package.json @@ -79,7 +79,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.84", + "@types/aws-lambda": "^8.10.85", "@types/jest": "^26.0.24", "jest": "^26.6.3" }, diff --git a/packages/@aws-cdk/aws-cloudtrail/test/cloudtrail.test.ts b/packages/@aws-cdk/aws-cloudtrail/test/cloudtrail.test.ts index c00f01d43acc4..89bd89d84c31c 100644 --- a/packages/@aws-cdk/aws-cloudtrail/test/cloudtrail.test.ts +++ b/packages/@aws-cdk/aws-cloudtrail/test/cloudtrail.test.ts @@ -131,13 +131,13 @@ describe('cloudtrail', () => { test('with imported s3 bucket', () => { // GIVEN const stack = getTestStack(); - const bucket = s3.Bucket.fromBucketName(stack, 'S3', 'SomeBucket'); + const bucket = s3.Bucket.fromBucketName(stack, 'S3', 'somebucket'); // WHEN new Trail(stack, 'Trail', { bucket }); expect(stack).toHaveResource('AWS::CloudTrail::Trail', { - S3BucketName: 'SomeBucket', + S3BucketName: 'somebucket', }); }); diff --git a/packages/@aws-cdk/aws-codebuild/README.md b/packages/@aws-cdk/aws-codebuild/README.md index 8a5fa30ac408b..29d06892bc682 100644 --- a/packages/@aws-cdk/aws-codebuild/README.md +++ b/packages/@aws-cdk/aws-codebuild/README.md @@ -184,23 +184,53 @@ You can save time when your project builds by using a cache. A cache can store r ### S3 Caching -With S3 caching, the cache is stored in an S3 bucket which is available from multiple hosts. +With S3 caching, the cache is stored in an S3 bucket which is available +regardless from what CodeBuild instance gets selected to run your CodeBuild job +on. When using S3 caching, you must also add in a `cache` section to your +buildspec which indicates the files to be cached: ```ts +declare const myCachingBucket: s3.Bucket; + new codebuild.Project(this, 'Project', { source: codebuild.Source.bitBucket({ owner: 'awslabs', repo: 'aws-cdk', }), - cache: codebuild.Cache.bucket(new s3.Bucket(this, 'Bucket')) + + cache: codebuild.Cache.bucket(myCachingBucket), + + // BuildSpec with a 'cache' section necessary for S3 caching. This can + // also come from 'buildspec.yml' in your source. + buildSpec: codebuild.BuildSpec.fromObject({ + version: '0.2', + phases: { + build: { + commands: ['...'], + }, + }, + cache: { + paths: [ + // The '**/*' is required to indicate all files in this directory + '/root/cachedir/**/*', + ], + }, + }), }); ``` +Note that two different CodeBuild Projects using the same S3 bucket will *not* +share their cache: each Project will get a unique file in the S3 bucket to store +the cache in. + ### Local Caching -With local caching, the cache is stored on the codebuild instance itself. This is simple, -cheap and fast, but CodeBuild cannot guarantee a reuse of instance and hence cannot -guarantee cache hits. For example, when a build starts and caches files locally, if two subsequent builds start at the same time afterwards only one of those builds would get the cache. Three different cache modes are supported, which can be turned on individually. +With local caching, the cache is stored on the codebuild instance itself. This +is simple, cheap and fast, but CodeBuild cannot guarantee a reuse of instance +and hence cannot guarantee cache hits. For example, when a build starts and +caches files locally, if two subsequent builds start at the same time afterwards +only one of those builds would get the cache. Three different cache modes are +supported, which can be turned on individually. * `LocalCacheMode.SOURCE` caches Git metadata for primary and secondary sources. * `LocalCacheMode.DOCKER_LAYER` caches existing Docker layers. @@ -214,6 +244,23 @@ new codebuild.Project(this, 'Project', { // Enable Docker AND custom caching cache: codebuild.Cache.local(codebuild.LocalCacheMode.DOCKER_LAYER, codebuild.LocalCacheMode.CUSTOM) + + // BuildSpec with a 'cache' section necessary for 'CUSTOM' caching. This can + // also come from 'buildspec.yml' in your source. + buildSpec: codebuild.BuildSpec.fromObject({ + version: '0.2', + phases: { + build: { + commands: ['...'], + }, + }, + cache: { + paths: [ + // The '**/*' is required to indicate all files in this directory + '/root/cachedir/**/*', + ], + }, + }), }); ``` diff --git a/packages/@aws-cdk/aws-codebuild/test/project.test.ts b/packages/@aws-cdk/aws-codebuild/test/project.test.ts index 08fbe3e8f8768..0041d1651ec9d 100644 --- a/packages/@aws-cdk/aws-codebuild/test/project.test.ts +++ b/packages/@aws-cdk/aws-codebuild/test/project.test.ts @@ -673,7 +673,7 @@ describe('Environment', () => { test('logs config - s3', () => { // GIVEN const stack = new cdk.Stack(); - const bucket = s3.Bucket.fromBucketName(stack, 'LogBucket', 'MyBucketName'); + const bucket = s3.Bucket.fromBucketName(stack, 'LogBucket', 'mybucketname'); // WHEN new codebuild.Project(stack, 'Project', { @@ -693,7 +693,7 @@ describe('Environment', () => { expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { LogsConfig: objectLike({ S3Logs: { - Location: 'MyBucketName/my-logs', + Location: 'mybucketname/my-logs', Status: 'ENABLED', }, }), @@ -703,7 +703,7 @@ describe('Environment', () => { test('logs config - cloudWatch and s3', () => { // GIVEN const stack = new cdk.Stack(); - const bucket = s3.Bucket.fromBucketName(stack, 'LogBucket2', 'MyBucketName'); + const bucket = s3.Bucket.fromBucketName(stack, 'LogBucket2', 'mybucketname'); const logGroup = logs.LogGroup.fromLogGroupName(stack, 'LogGroup2', 'MyLogGroupName'); // WHEN @@ -730,7 +730,7 @@ describe('Environment', () => { Status: 'ENABLED', }, S3Logs: { - Location: 'MyBucketName', + Location: 'mybucketname', Status: 'ENABLED', }, }), diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/index.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/index.ts index 254b2764f2684..e861161ab39c1 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/index.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/index.ts @@ -18,3 +18,4 @@ export * from './s3/source-action'; export * from './stepfunctions/invoke-action'; export * from './servicecatalog/deploy-action-beta1'; export * from './action'; + diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/jenkins/jenkins-provider.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/jenkins/jenkins-provider.ts index 923b1a1e39e7c..6e0d179859916 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/jenkins/jenkins-provider.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/jenkins/jenkins-provider.ts @@ -1,7 +1,6 @@ import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as cdk from '@aws-cdk/core'; import { Construct } from 'constructs'; -import { CustomActionRegistration } from '../custom-action-registration'; // 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 @@ -190,7 +189,7 @@ export class JenkinsProvider extends BaseJenkinsProvider { } private registerJenkinsCustomAction(id: string, category: codepipeline.ActionCategory) { - new CustomActionRegistration(this, id, { + new codepipeline.CustomActionRegistration(this, id, { category, artifactBounds: jenkinsArtifactsBounds, provider: this.providerName, diff --git a/packages/@aws-cdk/aws-codepipeline-actions/package.json b/packages/@aws-cdk/aws-codepipeline-actions/package.json index 6f08ecc470c28..bfc1de1719831 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/package.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/package.json @@ -76,7 +76,7 @@ "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "@types/lodash": "^4.14.175", + "@types/lodash": "^4.14.176", "jest": "^26.6.3", "lodash": "^4.17.21" }, diff --git a/packages/@aws-cdk/aws-codepipeline/README.md b/packages/@aws-cdk/aws-codepipeline/README.md index 23f86b9293e92..976c9932ca210 100644 --- a/packages/@aws-cdk/aws-codepipeline/README.md +++ b/packages/@aws-cdk/aws-codepipeline/README.md @@ -109,6 +109,40 @@ or you can use the `IStage.addAction()` method to mutate an existing Stage: sourceStage.addAction(someAction); ``` +## Custom Action Registration + +To make your own custom CodePipeline Action requires registering the action provider. Look to the `JenkinsProvider` in `@aws-cdk/aws-codepipeline-actions` for an implementation example. + +```ts +new codepipeline.CustomActionRegistration(this, 'GenericGitSourceProviderResource', { + category: codepipeline.ActionCategory.SOURCE, + artifactBounds: { minInputs: 0, maxInputs: 0, minOutputs: 1, maxOutputs: 1 }, + provider: 'GenericGitSource', + version: '1', + entityUrl: 'https://docs.aws.amazon.com/codepipeline/latest/userguide/actions-create-custom-action.html', + executionUrl: 'https://docs.aws.amazon.com/codepipeline/latest/userguide/actions-create-custom-action.html', + actionProperties: [ + { + name: 'Branch', + required: true, + key: false, + secret: false, + queryable: false, + description: 'Git branch to pull', + type: 'String', + }, + { + name: 'GitUrl', + required: true, + key: false, + secret: false, + queryable: false, + description: 'SSH git clone URL', + type: 'String', + }, + ] +``` + ## Cross-account CodePipelines > Cross-account Pipeline actions require that the Pipeline has *not* been diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/custom-action-registration.ts b/packages/@aws-cdk/aws-codepipeline/lib/custom-action-registration.ts similarity index 76% rename from packages/@aws-cdk/aws-codepipeline-actions/lib/custom-action-registration.ts rename to packages/@aws-cdk/aws-codepipeline/lib/custom-action-registration.ts index dad9e84a47094..f32a952a24d83 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/custom-action-registration.ts +++ b/packages/@aws-cdk/aws-codepipeline/lib/custom-action-registration.ts @@ -1,8 +1,10 @@ -import * as codepipeline from '@aws-cdk/aws-codepipeline'; +import { Construct } from 'constructs'; +import { ActionCategory, ActionArtifactBounds } from './action'; +import { CfnCustomActionType } from './codepipeline.generated'; // 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'; +import { Construct as CoreConstruct } from '@aws-cdk/core'; /** * The creation attributes used for defining a configuration property @@ -13,14 +15,14 @@ export interface CustomActionProperty { * The name of the property. * You use this name in the `configuration` attribute when defining your custom Action class. */ - name: string; + readonly name: string; /** * The description of the property. * * @default the description will be empty */ - description?: string; + readonly description?: string; /** * Whether this property is a key. @@ -28,7 +30,7 @@ export interface CustomActionProperty { * @default false * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codepipeline-customactiontype-configurationproperties.html#cfn-codepipeline-customactiontype-configurationproperties-key */ - key?: boolean; + readonly key?: boolean; /** * Whether this property is queryable. @@ -37,12 +39,12 @@ export interface CustomActionProperty { * @default false * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codepipeline-customactiontype-configurationproperties.html#cfn-codepipeline-customactiontype-configurationproperties-queryable */ - queryable?: boolean; + readonly queryable?: boolean; /** * Whether this property is required. */ - required: boolean; + readonly required: boolean; /** * Whether this property is secret, @@ -50,7 +52,7 @@ export interface CustomActionProperty { * * @default false */ - secret?: boolean; + readonly secret?: boolean; /** * The type of the property, @@ -58,7 +60,7 @@ export interface CustomActionProperty { * * @default 'String' */ - type?: string; + readonly type?: string; } /** @@ -68,41 +70,44 @@ export interface CustomActionRegistrationProps { /** * The category of the Action. */ - category: codepipeline.ActionCategory; + readonly category: ActionCategory; /** * The artifact bounds of the Action. */ - artifactBounds: codepipeline.ActionArtifactBounds; + readonly artifactBounds: ActionArtifactBounds; /** * The provider of the Action. + * @example 'MyCustomActionProvider' */ - provider: string; + readonly provider: string; /** * The version of your Action. * * @default '1' */ - version?: string; + readonly version?: string; /** * The URL shown for the entire Action in the Pipeline UI. + * @default none */ - entityUrl?: string; + readonly entityUrl?: string; /** * The URL shown for a particular execution of an Action in the Pipeline UI. + * @default none */ - executionUrl?: string; + readonly executionUrl?: string; /** * The properties used for customizing the instance of your Action. * * @default [] */ - actionProperties?: CustomActionProperty[]; + readonly actionProperties?: CustomActionProperty[]; } /** @@ -112,11 +117,11 @@ export interface CustomActionRegistrationProps { * representing your custom Action, extending the Action class, * and taking the `actionProperties` as properly typed, construction properties. */ -export class CustomActionRegistration extends Construct { - constructor(parent: Construct, id: string, props: CustomActionRegistrationProps) { - super(parent, id); +export class CustomActionRegistration extends CoreConstruct { + constructor(scope: Construct, id: string, props: CustomActionRegistrationProps) { + super(scope, id); - new codepipeline.CfnCustomActionType(this, 'Resource', { + new CfnCustomActionType(this, 'Resource', { category: props.category, inputArtifactDetails: { minimumCount: props.artifactBounds.minInputs, diff --git a/packages/@aws-cdk/aws-codepipeline/lib/index.ts b/packages/@aws-cdk/aws-codepipeline/lib/index.ts index c62d8dda6b33f..81b855f904184 100644 --- a/packages/@aws-cdk/aws-codepipeline/lib/index.ts +++ b/packages/@aws-cdk/aws-codepipeline/lib/index.ts @@ -1,6 +1,7 @@ export * from './action'; export * from './artifact'; export * from './pipeline'; +export * from './custom-action-registration'; // AWS::CodePipeline CloudFormation Resources: export * from './codepipeline.generated'; diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts index 6277ee0f467ee..adc3f51bf37a2 100644 --- a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts @@ -830,7 +830,7 @@ export class UserPool extends UserPoolBase { */ public addTrigger(operation: UserPoolOperation, fn: lambda.IFunction): void { if (operation.operationName in this.triggers) { - throw new Error(`A trigger for the operation ${operation} already exists.`); + throw new Error(`A trigger for the operation ${operation.operationName} already exists.`); } this.addLambdaPermission(fn, operation.operationName); 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 7b132803da2d6..5aa6c48ee99fc 100644 --- a/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts +++ b/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts @@ -403,7 +403,7 @@ describe('User Pool', () => { // WHEN userpool.addTrigger(UserPoolOperation.CREATE_AUTH_CHALLENGE, fn1); - expect(() => userpool.addTrigger(UserPoolOperation.CREATE_AUTH_CHALLENGE, fn2)).toThrow(/already exists/); + expect(() => userpool.addTrigger(UserPoolOperation.CREATE_AUTH_CHALLENGE, fn2)).toThrow(/createAuthChallenge already exists/); }); test('no username aliases specified', () => { diff --git a/packages/@aws-cdk/aws-docdb/README.md b/packages/@aws-cdk/aws-docdb/README.md index 6f7ed89e28e11..12f8e08a08387 100644 --- a/packages/@aws-cdk/aws-docdb/README.md +++ b/packages/@aws-cdk/aws-docdb/README.md @@ -21,6 +21,7 @@ your instances will be launched privately or publicly: const cluster = new DatabaseCluster(this, 'Database', { masterUser: { username: 'myuser' // NOTE: 'admin' is reserved by DocumentDB + excludeCharacters: '\"@/:', // optional, defaults to the set "\"@/" }, instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.LARGE), vpcSubnets: { diff --git a/packages/@aws-cdk/aws-docdb/lib/cluster.ts b/packages/@aws-cdk/aws-docdb/lib/cluster.ts index 56b5a724dd439..c2b4c7c9737a2 100644 --- a/packages/@aws-cdk/aws-docdb/lib/cluster.ts +++ b/packages/@aws-cdk/aws-docdb/lib/cluster.ts @@ -352,6 +352,7 @@ export class DatabaseCluster extends DatabaseClusterBase { secret = new DatabaseSecret(this, 'Secret', { username: props.masterUser.username, encryptionKey: props.masterUser.kmsKey, + excludeCharacters: props.masterUser.excludeCharacters, }); } diff --git a/packages/@aws-cdk/aws-docdb/lib/database-secret.ts b/packages/@aws-cdk/aws-docdb/lib/database-secret.ts index 605609b4b6ab2..8f1bca671da6d 100644 --- a/packages/@aws-cdk/aws-docdb/lib/database-secret.ts +++ b/packages/@aws-cdk/aws-docdb/lib/database-secret.ts @@ -32,6 +32,13 @@ export interface DatabaseSecretProps { * @default - no master secret information will be included */ readonly masterSecret?: ISecret; + + /** + * Characters to not include in the generated password. + * + * @default "\"@/" + */ + readonly excludeCharacters?: string; } /** @@ -61,7 +68,7 @@ export class DatabaseSecret extends Secret { masterarn: props.masterSecret?.secretArn, }), generateStringKey: 'password', - excludeCharacters: '"@/', + excludeCharacters: props.excludeCharacters ?? '"@/', }, }); } diff --git a/packages/@aws-cdk/aws-docdb/lib/props.ts b/packages/@aws-cdk/aws-docdb/lib/props.ts index 9cd24b1fce1bc..d02f8768973a9 100644 --- a/packages/@aws-cdk/aws-docdb/lib/props.ts +++ b/packages/@aws-cdk/aws-docdb/lib/props.ts @@ -53,6 +53,13 @@ export interface Login { * @default default master key */ readonly kmsKey?: kms.IKey; + + /** + * Specifies characters to not include in generated passwords. + * + * @default "\"@/" + */ + readonly excludeCharacters?: string; } /** diff --git a/packages/@aws-cdk/aws-docdb/test/cluster.test.ts b/packages/@aws-cdk/aws-docdb/test/cluster.test.ts index cb1f8653509df..6628520118c84 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, arrayWith } from '@aws-cdk/assert-internal'; +import { expect as expectCDK, haveResource, ResourcePart, arrayWith, haveResourceLike, objectLike } 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'; @@ -293,6 +293,29 @@ describe('DatabaseCluster', () => { })); }); + test('creates a secret with excludeCharacters', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + masterUser: { + username: 'admin', + excludeCharacters: '"@/()[]', + }, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + }); + + // THEN + expectCDK(stack).to(haveResourceLike('AWS::SecretsManager::Secret', { + GenerateSecretString: objectLike({ + ExcludeCharacters: '\"@/()[]', + }), + })); + }); + test('create an encrypted cluster with custom KMS key', () => { // GIVEN const stack = testStack(); diff --git a/packages/@aws-cdk/aws-docdb/test/integ.cluster-rotation.lit.expected.json b/packages/@aws-cdk/aws-docdb/test/integ.cluster-rotation.lit.expected.json index 6187414b9eb75..c063376359496 100644 --- a/packages/@aws-cdk/aws-docdb/test/integ.cluster-rotation.lit.expected.json +++ b/packages/@aws-cdk/aws-docdb/test/integ.cluster-rotation.lit.expected.json @@ -601,7 +601,9 @@ "PasswordLength": 41, "SecretStringTemplate": "{\"username\":\"docdb\"}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "DatabaseSecretAttachmentE5D1B020": { "Type": "AWS::SecretsManager::SecretTargetAttachment", diff --git a/packages/@aws-cdk/aws-docdb/test/integ.cluster.expected.json b/packages/@aws-cdk/aws-docdb/test/integ.cluster.expected.json index e8737956c6440..1b661827dd1ec 100644 --- a/packages/@aws-cdk/aws-docdb/test/integ.cluster.expected.json +++ b/packages/@aws-cdk/aws-docdb/test/integ.cluster.expected.json @@ -95,15 +95,15 @@ "VPCPublicSubnet1NATGatewayE0556630": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet1EIP6AD938E8", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, "Tags": [ { "Key": "Name", @@ -192,15 +192,15 @@ "VPCPublicSubnet2NATGateway3C070193": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet2EIP4947BC00", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" - }, "Tags": [ { "Key": "Name", @@ -506,4 +506,4 @@ "DeletionPolicy": "Delete" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package.json b/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package.json index 8e4e5cd1e6ff8..ee17747324574 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 @@ -39,6 +39,6 @@ "eslint-plugin-standard": "^4.1.0", "jest": "^26.6.3", "lambda-tester": "^3.6.0", - "nock": "^13.1.3" + "nock": "^13.1.4" } } diff --git a/packages/@aws-cdk/aws-dynamodb/README.md b/packages/@aws-cdk/aws-dynamodb/README.md index b07946c52d65f..b79b1e0efe465 100644 --- a/packages/@aws-cdk/aws-dynamodb/README.md +++ b/packages/@aws-cdk/aws-dynamodb/README.md @@ -14,10 +14,8 @@ Here is a minimal deployable DynamoDB table definition: ```ts -import * as dynamodb from '@aws-cdk/aws-dynamodb'; - const table = new dynamodb.Table(this, 'Table', { - partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING } + partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING }, }); ``` @@ -28,7 +26,8 @@ factory method. This method accepts table name or table ARN which describes the existing table: ```ts -const table = Table.fromTableArn(this, 'ImportedTable', 'arn:aws:dynamodb:us-east-1:111111111:table/my-table'); +declare const user: iam.User; +const table = dynamodb.Table.fromTableArn(this, 'ImportedTable', 'arn:aws:dynamodb:us-east-1:111111111:table/my-table'); // now you can just call methods on the table table.grantReadWriteData(user); ``` @@ -50,11 +49,9 @@ DynamoDB supports two billing modes: * PAY_PER_REQUEST - on-demand pricing and scaling. You only pay for what you use and there is no read and write capacity for the table or its global secondary indexes. ```ts -import * as dynamodb from '@aws-cdk/aws-dynamodb'; - const table = new dynamodb.Table(this, 'Table', { partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING }, - billingMode: dynamodb.BillingMode.PAY_PER_REQUEST + billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, }); ``` @@ -81,8 +78,6 @@ https://aws.amazon.com/blogs/database/how-to-use-aws-cloudformation-to-configure You can create DynamoDB Global Tables by setting the `replicationRegions` property on a `Table`: ```ts -import * as dynamodb from '@aws-cdk/aws-dynamodb'; - const globalTable = new dynamodb.Table(this, 'Table', { partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING }, replicationRegions: ['us-east-1', 'us-east-2', 'us-west-2'], @@ -100,7 +95,7 @@ you have to make sure write auto-scaling is enabled for that Table: const globalTable = new dynamodb.Table(this, 'Table', { partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING }, replicationRegions: ['us-east-1', 'us-east-2', 'us-west-2'], - billingMode: BillingMode.PROVISIONED, + billingMode: dynamodb.BillingMode.PROVISIONED, }); globalTable.autoScaleWriteCapacity({ @@ -131,11 +126,9 @@ All user data stored in Amazon DynamoDB is fully encrypted at rest. When creatin Creating a Table encrypted with a customer managed CMK: ```ts -import dynamodb = require('@aws-cdk/aws-dynamodb'); - -const table = new dynamodb.Table(stack, 'MyTable', { +const table = new dynamodb.Table(this, 'MyTable', { partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING }, - encryption: TableEncryption.CUSTOMER_MANAGED, + encryption: dynamodb.TableEncryption.CUSTOMER_MANAGED, }); // You can access the CMK that was added to the stack on your behalf by the Table construct via: @@ -145,15 +138,14 @@ const tableEncryptionKey = table.encryptionKey; You can also supply your own key: ```ts -import dynamodb = require('@aws-cdk/aws-dynamodb'); -import kms = require('@aws-cdk/aws-kms'); +import * as kms from '@aws-cdk/aws-kms'; -const encryptionKey = new kms.Key(stack, 'Key', { - enableKeyRotation: true +const encryptionKey = new kms.Key(this, 'Key', { + enableKeyRotation: true, }); -const table = new dynamodb.Table(stack, 'MyTable', { +const table = new dynamodb.Table(this, 'MyTable', { partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING }, - encryption: TableEncryption.CUSTOMER_MANAGED, + encryption: dynamodb.TableEncryption.CUSTOMER_MANAGED, encryptionKey, // This will be exposed as table.encryptionKey }); ``` @@ -161,11 +153,9 @@ const table = new dynamodb.Table(stack, 'MyTable', { In order to use the AWS managed CMK instead, change the code to: ```ts -import dynamodb = require('@aws-cdk/aws-dynamodb'); - -const table = new dynamodb.Table(stack, 'MyTable', { +const table = new dynamodb.Table(this, 'MyTable', { partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING }, - encryption: TableEncryption.AWS_MANAGED, + encryption: dynamodb.TableEncryption.AWS_MANAGED, }); // In this case, the CMK _cannot_ be accessed through table.encryptionKey. @@ -176,11 +166,13 @@ const table = new dynamodb.Table(stack, 'MyTable', { To get the partition key and sort key of the table or indexes you have configured: ```ts -const { partitionKey, sortKey } = table.schema(); +declare const table: dynamodb.Table; +const schema = table.schema(); +const partitionKey = schema.partitionKey; +const sortKey = schema.sortKey; // In case you want to get schema details for any secondary index - -const { partitionKey, sortKey } = table.schema(INDEX_NAME); +// const { partitionKey, sortKey } = table.schema(INDEX_NAME); ``` ## Kinesis Stream @@ -188,7 +180,6 @@ const { partitionKey, sortKey } = table.schema(INDEX_NAME); A Kinesis Data Stream can be configured on the DynamoDB table to capture item-level changes. ```ts -import * as dynamodb from '@aws-cdk/aws-dynamodb'; import * as kinesis from '@aws-cdk/aws-kinesis'; const stream = new kinesis.Stream(this, 'Stream'); diff --git a/packages/@aws-cdk/aws-dynamodb/package.json b/packages/@aws-cdk/aws-dynamodb/package.json index ba59f3f99b223..8fb374922fa25 100644 --- a/packages/@aws-cdk/aws-dynamodb/package.json +++ b/packages/@aws-cdk/aws-dynamodb/package.json @@ -77,7 +77,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.84", + "@types/aws-lambda": "^8.10.85", "@types/jest": "^26.0.24", "@types/sinon": "^9.0.11", "aws-sdk": "^2.848.0", diff --git a/packages/@aws-cdk/aws-dynamodb/rosetta/default.ts-fixture b/packages/@aws-cdk/aws-dynamodb/rosetta/default.ts-fixture new file mode 100644 index 0000000000000..1f9bb33819183 --- /dev/null +++ b/packages/@aws-cdk/aws-dynamodb/rosetta/default.ts-fixture @@ -0,0 +1,13 @@ +// Fixture with packages imported, but nothing else +import { Construct } from 'constructs'; +import { Duration, Stack } from '@aws-cdk/core'; +import dynamodb = require('@aws-cdk/aws-dynamodb'); +import iam = require('@aws-cdk/aws-iam'); + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + /// here + } +} diff --git a/packages/@aws-cdk/aws-ec2/lib/instance-types.ts b/packages/@aws-cdk/aws-ec2/lib/instance-types.ts index a2c5ccdadc760..1fc4e02f25daa 100644 --- a/packages/@aws-cdk/aws-ec2/lib/instance-types.ts +++ b/packages/@aws-cdk/aws-ec2/lib/instance-types.ts @@ -208,6 +208,16 @@ export enum InstanceClass { */ C5 = 'c5', + /** + * Compute optimized instances, 6th generation + */ + COMPUTE6_INTEL = 'c6i', + + /** + * Compute optimized instances, 6th generation + */ + C6I = 'c6i', + /** * Compute optimized instances with local NVME drive, 5th generation */ diff --git a/packages/@aws-cdk/aws-ec2/lib/security-group.ts b/packages/@aws-cdk/aws-ec2/lib/security-group.ts index 54695f2d17b71..692df3629ebbf 100644 --- a/packages/@aws-cdk/aws-ec2/lib/security-group.ts +++ b/packages/@aws-cdk/aws-ec2/lib/security-group.ts @@ -68,6 +68,8 @@ abstract class SecurityGroupBase extends Resource implements ISecurityGroup { public readonly connections: Connections = new Connections({ securityGroups: [this] }); public readonly defaultPort?: Port; + private peerAsTokenCount: number = 0; + constructor(scope: Construct, id: string, props?: ResourceProps) { super(scope, id, props); @@ -83,7 +85,7 @@ abstract class SecurityGroupBase extends Resource implements ISecurityGroup { description = `from ${peer.uniqueId}:${connection}`; } - const [scope, id] = determineRuleScope(this, peer, connection, 'from', remoteRule); + const [scope, id] = this.determineRuleScope(peer, connection, 'from', remoteRule); // Skip duplicates if (scope.node.tryFindChild(id) === undefined) { @@ -101,7 +103,7 @@ abstract class SecurityGroupBase extends Resource implements ISecurityGroup { description = `to ${peer.uniqueId}:${connection}`; } - const [scope, id] = determineRuleScope(this, peer, connection, 'to', remoteRule); + const [scope, id] = this.determineRuleScope(peer, connection, 'to', remoteRule); // Skip duplicates if (scope.node.tryFindChild(id) === undefined) { @@ -121,75 +123,82 @@ abstract class SecurityGroupBase extends Resource implements ISecurityGroup { public toEgressRuleConfig(): any { return { destinationSecurityGroupId: this.securityGroupId }; } -} -/** - * Determine where to parent a new ingress/egress rule - * - * A SecurityGroup rule is parented under the group it's related to, UNLESS - * we're in a cross-stack scenario with another Security Group. In that case, - * we respect the 'remoteRule' flag and will parent under the other security - * group. - * - * This is necessary to avoid cyclic dependencies between stacks, since both - * ingress and egress rules will reference both security groups, and a naive - * parenting will lead to the following situation: - * - * ╔════════════════════╗ ╔════════════════════╗ - * ║ ┌───────────┐ ║ ║ ┌───────────┐ ║ - * ║ │ GroupA │◀────╬─┐ ┌───╬───▶│ GroupB │ ║ - * ║ └───────────┘ ║ │ │ ║ └───────────┘ ║ - * ║ ▲ ║ │ │ ║ ▲ ║ - * ║ │ ║ │ │ ║ │ ║ - * ║ │ ║ │ │ ║ │ ║ - * ║ ┌───────────┐ ║ └───┼───╬────┌───────────┐ ║ - * ║ │ EgressA │─────╬─────┘ ║ │ IngressB │ ║ - * ║ └───────────┘ ║ ║ └───────────┘ ║ - * ║ ║ ║ ║ - * ╚════════════════════╝ ╚════════════════════╝ - * - * By having the ability to switch the parent, we avoid the cyclic reference by - * keeping all rules in a single stack. - * - * If this happens, we also have to change the construct ID, because - * otherwise we might have two objects with the same ID if we have - * multiple reversed security group relationships. - * - * ╔═══════════════════════════════════╗ - * ║┌───────────┐ ║ - * ║│ GroupB │ ║ - * ║└───────────┘ ║ - * ║ ▲ ║ - * ║ │ ┌───────────┐ ║ - * ║ ├────"from A"──│ IngressB │ ║ - * ║ │ └───────────┘ ║ - * ║ │ ┌───────────┐ ║ - * ║ ├─────"to B"───│ EgressA │ ║ - * ║ │ └───────────┘ ║ - * ║ │ ┌───────────┐ ║ - * ║ └─────"to B"───│ EgressC │ ║ <-- oops - * ║ └───────────┘ ║ - * ╚═══════════════════════════════════╝ - */ -function determineRuleScope( - group: SecurityGroupBase, - peer: IPeer, - connection: Port, - fromTo: 'from' | 'to', - remoteRule?: boolean): [SecurityGroupBase, string] { - - if (remoteRule && SecurityGroupBase.isSecurityGroup(peer) && differentStacks(group, peer)) { - // Reversed - const reversedFromTo = fromTo === 'from' ? 'to' : 'from'; - return [peer, `${group.uniqueId}:${connection} ${reversedFromTo}`]; - } else { - // Regular (do old ID escaping to in order to not disturb existing deployments) - return [group, `${fromTo} ${renderPeer(peer)}:${connection}`.replace('/', '_')]; + /** + * Determine where to parent a new ingress/egress rule + * + * A SecurityGroup rule is parented under the group it's related to, UNLESS + * we're in a cross-stack scenario with another Security Group. In that case, + * we respect the 'remoteRule' flag and will parent under the other security + * group. + * + * This is necessary to avoid cyclic dependencies between stacks, since both + * ingress and egress rules will reference both security groups, and a naive + * parenting will lead to the following situation: + * + * ╔════════════════════╗ ╔════════════════════╗ + * ║ ┌───────────┐ ║ ║ ┌───────────┐ ║ + * ║ │ GroupA │◀────╬─┐ ┌───╬───▶│ GroupB │ ║ + * ║ └───────────┘ ║ │ │ ║ └───────────┘ ║ + * ║ ▲ ║ │ │ ║ ▲ ║ + * ║ │ ║ │ │ ║ │ ║ + * ║ │ ║ │ │ ║ │ ║ + * ║ ┌───────────┐ ║ └───┼───╬────┌───────────┐ ║ + * ║ │ EgressA │─────╬─────┘ ║ │ IngressB │ ║ + * ║ └───────────┘ ║ ║ └───────────┘ ║ + * ║ ║ ║ ║ + * ╚════════════════════╝ ╚════════════════════╝ + * + * By having the ability to switch the parent, we avoid the cyclic reference by + * keeping all rules in a single stack. + * + * If this happens, we also have to change the construct ID, because + * otherwise we might have two objects with the same ID if we have + * multiple reversed security group relationships. + * + * ╔═══════════════════════════════════╗ + * ║┌───────────┐ ║ + * ║│ GroupB │ ║ + * ║└───────────┘ ║ + * ║ ▲ ║ + * ║ │ ┌───────────┐ ║ + * ║ ├────"from A"──│ IngressB │ ║ + * ║ │ └───────────┘ ║ + * ║ │ ┌───────────┐ ║ + * ║ ├─────"to B"───│ EgressA │ ║ + * ║ │ └───────────┘ ║ + * ║ │ ┌───────────┐ ║ + * ║ └─────"to B"───│ EgressC │ ║ <-- oops + * ║ └───────────┘ ║ + * ╚═══════════════════════════════════╝ + */ + + protected determineRuleScope( + peer: IPeer, + connection: Port, + fromTo: 'from' | 'to', + remoteRule?: boolean): [SecurityGroupBase, string] { + + if (remoteRule && SecurityGroupBase.isSecurityGroup(peer) && differentStacks(this, peer)) { + // Reversed + const reversedFromTo = fromTo === 'from' ? 'to' : 'from'; + return [peer, `${this.uniqueId}:${connection} ${reversedFromTo}`]; + } else { + // Regular (do old ID escaping to in order to not disturb existing deployments) + return [this, `${fromTo} ${this.renderPeer(peer)}:${connection}`.replace('/', '_')]; + } } -} -function renderPeer(peer: IPeer) { - return Token.isUnresolved(peer.uniqueId) ? '{IndirectPeer}' : peer.uniqueId; + private renderPeer(peer: IPeer) { + if (Token.isUnresolved(peer.uniqueId)) { + // Need to return a unique value each time a peer + // is an unresolved token, else the duplicate skipper + // in `sg.addXxxRule` can detect unique rules as duplicates + return this.peerAsTokenCount++ ? `'{IndirectPeer${this.peerAsTokenCount}}'` : '{IndirectPeer}'; + } else { + return peer.uniqueId; + } + } } function differentStacks(group1: SecurityGroupBase, group2: SecurityGroupBase) { @@ -565,13 +574,12 @@ export class SecurityGroup extends SecurityGroupBase { */ private removeNoTrafficRule() { if (this.disableInlineRules) { - const [scope, id] = determineRuleScope( - this, + const [scope, id] = this.determineRuleScope( NO_TRAFFIC_PEER, NO_TRAFFIC_PORT, 'to', - false); - + false, + ); scope.node.tryRemoveChild(id); } else { const i = this.directEgressRules.findIndex(r => egressRulesEqual(r, MATCH_NO_TRAFFIC)); diff --git a/packages/@aws-cdk/aws-ec2/package.json b/packages/@aws-cdk/aws-ec2/package.json index 6cf7d368e25a2..a82b70b68ab52 100644 --- a/packages/@aws-cdk/aws-ec2/package.json +++ b/packages/@aws-cdk/aws-ec2/package.json @@ -79,7 +79,7 @@ "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.84", + "@types/aws-lambda": "^8.10.85", "@types/jest": "^26.0.24", "jest": "^26.6.3" }, @@ -117,6 +117,7 @@ }, "awslint": { "exclude": [ + "resource-attribute:@aws-cdk/aws-ec2.NetworkAclEntry.networkAclEntryId", "resource-attribute:@aws-cdk/aws-ec2.ISecurityGroup.securityGroupVpcId", "no-unused-type:@aws-cdk/aws-ec2.ConnectionRule", "no-unused-type:@aws-cdk/aws-ec2.Protocol", @@ -131,6 +132,7 @@ "props-physical-name:@aws-cdk/aws-ec2.InterfaceVpcEndpointProps", "props-physical-name:@aws-cdk/aws-ec2.VpcEndpointServiceProps", "from-method:@aws-cdk/aws-ec2.Instance", + "from-method:@aws-cdk/aws-ec2.NetworkAclEntry", "from-method:@aws-cdk/aws-ec2.VpcEndpointService", "attribute-tag:@aws-cdk/aws-ec2.BastionHostLinux.instance", "attribute-tag:@aws-cdk/aws-ec2.Instance.instance", diff --git a/packages/@aws-cdk/aws-ec2/test/cfn-init-element.test.ts b/packages/@aws-cdk/aws-ec2/test/cfn-init-element.test.ts index 75896912f3661..8f1c4951d2bf3 100644 --- a/packages/@aws-cdk/aws-ec2/test/cfn-init-element.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/cfn-init-element.test.ts @@ -664,7 +664,7 @@ describe('InitSource', () => { test('fromS3Object uses object URL', () => { // GIVEN - const bucket = s3.Bucket.fromBucketName(stack, 'bucket', 'MyBucket'); + const bucket = s3.Bucket.fromBucketName(stack, 'bucket', 'mybucket'); const source = ec2.InitSource.fromS3Object('/tmp/foo', bucket, 'myKey'); // WHEN @@ -672,7 +672,7 @@ describe('InitSource', () => { // THEN expect(rendered).toEqual({ - '/tmp/foo': expect.stringContaining('/MyBucket/myKey'), + '/tmp/foo': expect.stringContaining('/mybucket/myKey'), }); }); 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 37d4fe2d72d28..2a9cce5e76719 100644 --- a/packages/@aws-cdk/aws-ec2/test/cfn-init.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/cfn-init.test.ts @@ -667,7 +667,7 @@ class SingletonLocationSythesizer extends DefaultStackSynthesizer { public addFileAsset(_asset: FileAssetSource): FileAssetLocation { const httpUrl = 'https://MyBucket.s3.amazonaws.com/MyAsset'; return { - bucketName: 'MyAssetBucket', + bucketName: 'myassetbucket', objectKey: 'MyAssetFile', httpUrl, s3ObjectUrl: httpUrl, 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 09ccc6cdc682e..70dbe64cef335 100644 --- a/packages/@aws-cdk/aws-ec2/test/security-group.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/security-group.test.ts @@ -208,6 +208,30 @@ describe('security group', () => { }); + test('can add multiple rules using tokens on same security group', () => { + // GIVEN + const stack = new Stack(undefined, 'TestStack', { env: { account: '12345678', region: 'dummy' } }); + const vpc = new Vpc(stack, 'VPC'); + const sg = new SecurityGroup(stack, 'SG', { vpc }); + + const p1 = Lazy.string({ produce: () => 'dummyid1' }); + const p2 = Lazy.string({ produce: () => 'dummyid2' }); + const peer1 = Peer.prefixList(p1); + const peer2 = Peer.prefixList(p2); + + // WHEN + sg.addIngressRule(peer1, Port.tcp(5432), 'Rule 1'); + sg.addIngressRule(peer2, Port.tcp(5432), 'Rule 2'); + + // THEN -- no crash + expect(stack).toHaveResourceLike('AWS::EC2::SecurityGroupIngress', { + Description: 'Rule 1', + }); + expect(stack).toHaveResourceLike('AWS::EC2::SecurityGroupIngress', { + Description: 'Rule 2', + }); + }); + test('if tokens are used in ports, `canInlineRule` should be false to avoid cycles', () => { // GIVEN const p1 = Lazy.number({ produce: () => 80 }); diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts index 19a2501355223..81f243f4a6fa6 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts @@ -86,7 +86,7 @@ export interface ApplicationLoadBalancedFargateServiceProps extends ApplicationL readonly platformVersion?: FargatePlatformVersion; /** - * The security groups to associate with the service. If you do not specify a security group, the default security group for the VPC is used. + * The security groups to associate with the service. If you do not specify a security group, a new security group is created. * * @default - A new security group is created. */ diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/queue-processing-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/queue-processing-fargate-service.ts index e6f8b89c736b3..033d19dc39612 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/queue-processing-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/queue-processing-fargate-service.ts @@ -77,7 +77,7 @@ export interface QueueProcessingFargateServiceProps extends QueueProcessingServi readonly taskSubnets?: ec2.SubnetSelection; /** - * The security groups to associate with the service. If you do not specify a security group, the default security group for the VPC is used. + * The security groups to associate with the service. If you do not specify a security group, a new security group is created. * * @default - A new security group is created. */ diff --git a/packages/@aws-cdk/aws-ecs/lib/ec2/ec2-service.ts b/packages/@aws-cdk/aws-ecs/lib/ec2/ec2-service.ts index df2ad7819543c..0a98809dff403 100644 --- a/packages/@aws-cdk/aws-ecs/lib/ec2/ec2-service.ts +++ b/packages/@aws-cdk/aws-ecs/lib/ec2/ec2-service.ts @@ -39,7 +39,7 @@ export interface Ec2ServiceProps extends BaseServiceOptions { readonly vpcSubnets?: ec2.SubnetSelection; /** - * The security groups to associate with the service. If you do not specify a security group, the default security group for the VPC is used. + * The security groups to associate with the service. If you do not specify a security group, a new security group is created. * * This property is only used for tasks that use the awsvpc network mode. * @@ -49,7 +49,7 @@ export interface Ec2ServiceProps extends BaseServiceOptions { readonly securityGroup?: ec2.ISecurityGroup; /** - * The security groups to associate with the service. If you do not specify a security group, the default security group for the VPC is used. + * The security groups to associate with the service. If you do not specify a security group, a new security group is created. * * This property is only used for tasks that use the awsvpc network mode. * diff --git a/packages/@aws-cdk/aws-ecs/lib/external/external-service.ts b/packages/@aws-cdk/aws-ecs/lib/external/external-service.ts index 741ba0a7b2b29..2c1c6c9f59534 100644 --- a/packages/@aws-cdk/aws-ecs/lib/external/external-service.ts +++ b/packages/@aws-cdk/aws-ecs/lib/external/external-service.ts @@ -21,7 +21,7 @@ export interface ExternalServiceProps extends BaseServiceOptions { readonly taskDefinition: TaskDefinition; /** - * The security groups to associate with the service. If you do not specify a security group, the default security group for the VPC is used. + * The security groups to associate with the service. If you do not specify a security group, a new security group is created. * * * @default - A new security group is created. diff --git a/packages/@aws-cdk/aws-ecs/lib/fargate/fargate-service.ts b/packages/@aws-cdk/aws-ecs/lib/fargate/fargate-service.ts index 7979b98f0b0fa..a996aca37cc23 100644 --- a/packages/@aws-cdk/aws-ecs/lib/fargate/fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs/lib/fargate/fargate-service.ts @@ -34,7 +34,7 @@ export interface FargateServiceProps extends BaseServiceOptions { readonly vpcSubnets?: ec2.SubnetSelection; /** - * The security groups to associate with the service. If you do not specify a security group, the default security group for the VPC is used. + * The security groups to associate with the service. If you do not specify a security group, a new security group is created. * * @default - A new security group is created. * @deprecated use securityGroups instead. @@ -42,7 +42,7 @@ export interface FargateServiceProps extends BaseServiceOptions { readonly securityGroup?: ec2.ISecurityGroup; /** - * The security groups to associate with the service. If you do not specify a security group, the default security group for the VPC is used. + * The security groups to associate with the service. If you do not specify a security group, a new security group is created. * * @default - A new security group is created. */ diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.secret-json-field.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.secret-json-field.expected.json index 6fe13e7abc27e..b14c1d7855e8c 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.secret-json-field.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.secret-json-field.expected.json @@ -7,7 +7,9 @@ "GenerateStringKey": "password", "SecretStringTemplate": "{\"username\":\"user\"}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "TaskDefTaskRole1EDB4A67": { "Type": "AWS::IAM::Role", diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/integ.secret.expected.json b/packages/@aws-cdk/aws-ecs/test/fargate/integ.secret.expected.json index 2ef36fdc4d94a..f86ae24841bbf 100644 --- a/packages/@aws-cdk/aws-ecs/test/fargate/integ.secret.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/fargate/integ.secret.expected.json @@ -7,7 +7,9 @@ "GenerateStringKey": "password", "SecretStringTemplate": "{\"username\":\"user\"}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "TaskDefTaskRole1EDB4A67": { "Type": "AWS::IAM::Role", diff --git a/packages/@aws-cdk/aws-eks/README.md b/packages/@aws-cdk/aws-eks/README.md index 3b04f5d9e7f61..e1d78b774450d 100644 --- a/packages/@aws-cdk/aws-eks/README.md +++ b/packages/@aws-cdk/aws-eks/README.md @@ -102,8 +102,8 @@ The following is a qualitative diagram of the various possible components involv ```text +-----------------------------------------------+ +-----------------+ - | EKS Cluster | kubectl | | - |-----------------------------------------------|<-------------+| Kubectl Handler | + | EKS Cluster | kubectl | | + | ----------- |<-------------+| Kubectl Handler | | | | | | | +-----------------+ | +--------------------+ +-----------------+ | @@ -342,6 +342,8 @@ const cluster = new eks.FargateCluster(this, 'MyCluster', { }); ``` +`FargateCluster` will create a default `FargateProfile` which can be accessed via the cluster's `defaultProfile` property. The created profile can also be customized by passing options as with `addFargateProfile`. + **NOTE**: Classic Load Balancers and Network Load Balancers are not supported on pods running on Fargate. For ingress, we recommend that you use the [ALB Ingress Controller](https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html) @@ -537,16 +539,21 @@ If the endpoint does not expose private access (via `EndpointAccess.PUBLIC`) **o #### Cluster Handler -The `ClusterHandler` is a Lambda function responsible to interact with the EKS API in order to control the cluster lifecycle. To provision this function inside the VPC, set the `placeClusterHandlerInVpc` property to `true`. This will place the function inside the private subnets of the VPC based on the selection strategy specified in the [`vpcSubnets`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-eks.Cluster.html#vpcsubnetsspan-classapi-icon-api-icon-experimental-titlethis-api-element-is-experimental-it-may-change-without-noticespan) property. +The `ClusterHandler` is a set of Lambda functions (`onEventHandler`, `isCompleteHandler`) responsible for interacting with the EKS API in order to control the cluster lifecycle. To provision these functions inside the VPC, set the `placeClusterHandlerInVpc` property to `true`. This will place the functions inside the private subnets of the VPC based on the selection strategy specified in the [`vpcSubnets`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-eks.Cluster.html#vpcsubnetsspan-classapi-icon-api-icon-experimental-titlethis-api-element-is-experimental-it-may-change-without-noticespan) property. -You can configure the environment of this function by specifying it at cluster instantiation. For example, this can be useful in order to configure an http proxy: +You can configure the environment of the Cluster Handler functions by specifying it at cluster instantiation. For example, this can be useful in order to configure an http proxy: ```ts const cluster = new eks.Cluster(this, 'hello-eks', { version: eks.KubernetesVersion.V1_21, clusterHandlerEnvironment: { - 'http_proxy': 'http://proxy.myproxy.com' - } + https_proxy: 'http://proxy.myproxy.com' + }, + /** + * If the proxy is not open publicly, you can pass a security group to the + * Cluster Handler Lambdas so that it can reach the proxy. + */ + clusterHandlerSecurityGroup: proxyInstanceSecurityGroup }); ``` diff --git a/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/common.ts b/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/common.ts index 8f563de833bf6..21cf958df5a68 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/common.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/common.ts @@ -41,12 +41,6 @@ export abstract class ResourceHandler { } public onEvent() { - // eslint-disable-next-line @typescript-eslint/no-require-imports, import/no-extraneous-dependencies - const ProxyAgent: any = require('proxy-agent'); - aws.config.update({ - httpOptions: { agent: new ProxyAgent() }, - }); - switch (this.requestType) { case 'Create': return this.onCreate(); case 'Update': return this.onUpdate(); diff --git a/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/index.ts b/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/index.ts index e7fc357846259..258f5d8b04545 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/index.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/index.ts @@ -8,7 +8,13 @@ import { EksClient } from './common'; import * as consts from './consts'; import { FargateProfileResourceHandler } from './fargate'; +// eslint-disable-next-line @typescript-eslint/no-require-imports, import/no-extraneous-dependencies +const ProxyAgent = require('proxy-agent'); + aws.config.logger = console; +aws.config.update({ + httpOptions: { agent: new ProxyAgent() }, +}); let eks: aws.EKS | undefined; diff --git a/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts b/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts index f425b0a1eaba6..9bb65be4f56b2 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts @@ -36,11 +36,18 @@ export interface ClusterResourceProviderProps { readonly environment?: { [key: string]: string }; /** - * An AWS Lambda layer that includes the NPM dependency `proxy-agent`. - * - * If not defined, a default layer will be used. - */ + * An AWS Lambda layer that includes the NPM dependency `proxy-agent`. + * + * If not defined, a default layer will be used. + */ readonly onEventLayer?: lambda.ILayerVersion; + + /** + * The security group to associate with the functions. + * + * @default - No security group. + */ + readonly securityGroup?: ec2.ISecurityGroup; } /** @@ -66,6 +73,9 @@ export class ClusterResourceProvider extends NestedStack { private constructor(scope: Construct, id: string, props: ClusterResourceProviderProps) { super(scope as CoreConstruct, id); + // The NPM dependency proxy-agent is required in order to support proxy routing with the AWS JS SDK. + const nodeProxyAgentLayer = new NodeProxyAgentLayer(this, 'NodeProxyAgentLayer'); + const onEvent = new lambda.Function(this, 'OnEventHandler', { code: lambda.Code.fromAsset(HANDLER_DIR), description: 'onEvent handler for EKS cluster resource provider', @@ -75,24 +85,22 @@ export class ClusterResourceProvider extends NestedStack { timeout: Duration.minutes(1), vpc: props.subnets ? props.vpc : undefined, vpcSubnets: props.subnets ? { subnets: props.subnets } : undefined, + securityGroups: props.securityGroup ? [props.securityGroup] : undefined, + // Allow user to override the layer. + layers: props.onEventLayer ? [props.onEventLayer] : [nodeProxyAgentLayer], }); - // Allow user to customize the layer - if (!props.onEventLayer) { - // `NodeProxyAgentLayer` provides `proxy-agent` which is needed to configure `aws-sdk-js` with a user provided proxy. - onEvent.addLayers(new NodeProxyAgentLayer(this, 'NodeProxyAgentLayer')); - } else { - onEvent.addLayers(props.onEventLayer); - } - const isComplete = new lambda.Function(this, 'IsCompleteHandler', { code: lambda.Code.fromAsset(HANDLER_DIR), description: 'isComplete handler for EKS cluster resource provider', runtime: HANDLER_RUNTIME, + environment: props.environment, handler: 'index.isComplete', timeout: Duration.minutes(1), vpc: props.subnets ? props.vpc : undefined, vpcSubnets: props.subnets ? { subnets: props.subnets } : undefined, + securityGroups: props.securityGroup ? [props.securityGroup] : undefined, + layers: [nodeProxyAgentLayer], }); this.provider = new cr.Provider(this, 'Provider', { @@ -102,6 +110,7 @@ export class ClusterResourceProvider extends NestedStack { queryInterval: Duration.minutes(1), vpc: props.subnets ? props.vpc : undefined, vpcSubnets: props.subnets ? { subnets: props.subnets } : undefined, + securityGroups: props.securityGroup ? [props.securityGroup] : undefined, }); props.adminRole.grant(onEvent.role!, 'sts:AssumeRole'); diff --git a/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts b/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts index 88f3cd0138344..ed0852338a527 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts @@ -27,6 +27,7 @@ export interface ClusterResourceProps { readonly subnets?: ec2.ISubnet[]; readonly secretsEncryptionKey?: kms.IKey; readonly onEventLayer?: lambda.ILayerVersion; + readonly clusterHandlerSecurityGroup?: ec2.ISecurityGroup; } /** @@ -66,6 +67,7 @@ export class ClusterResource extends CoreConstruct { vpc: props.vpc, environment: props.environment, onEventLayer: props.onEventLayer, + securityGroup: props.clusterHandlerSecurityGroup, }); const resource = new CustomResource(this, 'Resource', { diff --git a/packages/@aws-cdk/aws-eks/lib/cluster.ts b/packages/@aws-cdk/aws-eks/lib/cluster.ts index c1d00a9dcd767..2c762ab666327 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster.ts @@ -130,10 +130,21 @@ export interface ICluster extends IResource, ec2.IConnectable { readonly kubectlMemory?: Size; /** - * An AWS Lambda layer that includes the NPM dependency `proxy-agent`. - * - * If not defined, a default layer will be used. - */ + * A security group to associate with the Cluster Handler's Lambdas. + * The Cluster Handler's Lambdas are responsible for calling AWS's EKS API. + * + * Requires `placeClusterHandlerInVpc` to be set to true. + * + * @default - No security group. + * @attribute + */ + readonly clusterHandlerSecurityGroup?: ec2.ISecurityGroup; + + /** + * An AWS Lambda layer that includes the NPM dependency `proxy-agent`. + * + * If not defined, a default layer will be used. + */ readonly onEventLayer?: lambda.ILayerVersion; /** @@ -309,6 +320,14 @@ export interface ClusterAttributes { */ readonly kubectlMemory?: Size; + /** + * A security group id to associate with the Cluster Handler's Lambdas. + * The Cluster Handler's Lambdas are responsible for calling AWS's EKS API. + * + * @default - No security group. + */ + readonly clusterHandlerSecurityGroupId?: string; + /** * An AWS Lambda Layer which includes the NPM dependency `proxy-agent`. This layer * is used by the onEvent handler to route AWS SDK requests through a proxy. @@ -452,13 +471,6 @@ export interface ClusterOptions extends CommonClusterOptions { */ readonly kubectlEnvironment?: { [key: string]: string }; - /** - * Custom environment variables when interacting with the EKS endpoint to manage the cluster lifecycle. - * - * @default - No environment variables. - */ - readonly clusterHandlerEnvironment?: { [key: string]: string }; - /** * An AWS Lambda Layer which includes `kubectl`, Helm and the AWS CLI. * @@ -491,26 +503,40 @@ export interface ClusterOptions extends CommonClusterOptions { readonly kubectlMemory?: Size; /** - * An AWS Lambda Layer which includes the NPM dependency `proxy-agent`. + * Custom environment variables when interacting with the EKS endpoint to manage the cluster lifecycle. + * + * @default - No environment variables. + */ + readonly clusterHandlerEnvironment?: { [key: string]: string }; + + /** + * A security group to associate with the Cluster Handler's Lambdas. + * The Cluster Handler's Lambdas are responsible for calling AWS's EKS API. + * + * Requires `placeClusterHandlerInVpc` to be set to true. + * + * @default - No security group. + */ + readonly clusterHandlerSecurityGroup?: ec2.ISecurityGroup; + + /** + * An AWS Lambda Layer which includes the NPM dependency `proxy-agent`. This layer + * is used by the onEvent handler to route AWS SDK requests through a proxy. * * By default, the provider will use the layer included in the * "aws-lambda-layer-node-proxy-agent" SAR application which is available in all * commercial regions. * - * To deploy the layer locally, visit - * https://github.com/aws-samples/aws-lambda-layer-node-proxy-agent/blob/master/cdk/README.md - * for instructions on how to prepare the .zip file and then define it in your - * app as follows: + * To deploy the layer locally define it in your app as follows: * * ```ts - * const layer = new lambda.LayerVersion(this, 'node-proxy-agent-layer', { + * const layer = new lambda.LayerVersion(this, 'proxy-agent-layer', { * code: lambda.Code.fromAsset(`${__dirname}/layer.zip`)), - * compatibleRuntimes: [lambda.Runtime.NODEJS_14_X] + * compatibleRuntimes: [lambda.Runtime.NODEJS_12_X] * }) * ``` * - * @default - the layer provided by the `aws-lambda-layer-node-proxy-agent` SAR app. - * @see https://github.com/aws-samples/aws-lambda-layer-node-proxy-agent + * @default - a layer bundled with this module. */ readonly onEventLayer?: lambda.ILayerVersion; @@ -749,6 +775,7 @@ abstract class ClusterBase extends Resource implements ICluster { public abstract readonly kubectlSecurityGroup?: ec2.ISecurityGroup; public abstract readonly kubectlPrivateSubnets?: ec2.ISubnet[]; public abstract readonly kubectlMemory?: Size; + public abstract readonly clusterHandlerSecurityGroup?: ec2.ISecurityGroup; public abstract readonly prune: boolean; public abstract readonly openIdConnectProvider: iam.IOpenIdConnectProvider; public abstract readonly awsAuth: AwsAuth; @@ -902,7 +929,7 @@ abstract class ClusterBase extends Resource implements ICluster { // cluster or if `mapRole` is set to false. By default this should happen. let mapRole = options.mapRole ?? true; if (mapRole && !(this instanceof Cluster)) { - // do the mapping... + // do the mapping... Annotations.of(autoScalingGroup).addWarning('Auto-mapping aws-auth role for imported cluster is not supported, please map role manually'); mapRole = false; } @@ -1099,11 +1126,21 @@ export class Cluster extends ClusterBase { */ public readonly kubectlMemory?: Size; + /** + * A security group to associate with the Cluster Handler's Lambdas. + * The Cluster Handler's Lambdas are responsible for calling AWS's EKS API. + * + * Requires `placeClusterHandlerInVpc` to be set to true. + * + * @default - No security group. + */ + public readonly clusterHandlerSecurityGroup?: ec2.ISecurityGroup; + /** * The AWS Lambda layer that contains the NPM dependency `proxy-agent`. If * undefined, a SAR app that contains this layer will be used. */ - public readonly onEventLayer?: lambda.ILayerVersion; + readonly onEventLayer?: lambda.ILayerVersion; /** * Determines if Kubernetes resources can be pruned automatically. @@ -1188,9 +1225,11 @@ export class Cluster extends ClusterBase { this.endpointAccess = props.endpointAccess ?? EndpointAccess.PUBLIC_AND_PRIVATE; this.kubectlEnvironment = props.kubectlEnvironment; this.kubectlLayer = props.kubectlLayer; - this.onEventLayer = props.onEventLayer; this.kubectlMemory = props.kubectlMemory; + this.onEventLayer = props.onEventLayer; + this.clusterHandlerSecurityGroup = props.clusterHandlerSecurityGroup; + const privateSubnets = this.selectPrivateSubnets().slice(0, 16); const publicAccessDisabled = !this.endpointAccess._config.publicAccess; const publicAccessRestricted = !publicAccessDisabled @@ -1215,6 +1254,10 @@ export class Cluster extends ClusterBase { throw new Error('Cannot place cluster handler in the VPC since no private subnets could be selected'); } + if (props.clusterHandlerSecurityGroup && !placeClusterHandlerInVpc) { + throw new Error('Cannot specify clusterHandlerSecurityGroup without placeClusterHandlerInVpc set to true'); + } + const resource = this._clusterResource = new ClusterResource(this, 'Resource', { name: this.physicalName, environment: props.clusterHandlerEnvironment, @@ -1241,6 +1284,7 @@ export class Cluster extends ClusterBase { secretsEncryptionKey: props.secretsEncryptionKey, vpc: this.vpc, subnets: placeClusterHandlerInVpc ? privateSubnets : undefined, + clusterHandlerSecurityGroup: this.clusterHandlerSecurityGroup, onEventLayer: this.onEventLayer, }); @@ -1827,8 +1871,9 @@ class ImportedCluster extends ClusterBase { public readonly kubectlSecurityGroup?: ec2.ISecurityGroup | undefined; public readonly kubectlPrivateSubnets?: ec2.ISubnet[] | undefined; public readonly kubectlLayer?: lambda.ILayerVersion; - public readonly onEventLayer?: lambda.ILayerVersion; public readonly kubectlMemory?: Size; + public readonly clusterHandlerSecurityGroup?: ec2.ISecurityGroup | undefined; + public readonly onEventLayer?: lambda.ILayerVersion; public readonly prune: boolean; // so that `clusterSecurityGroup` on `ICluster` can be configured without optionality, avoiding users from having @@ -1845,8 +1890,9 @@ class ImportedCluster extends ClusterBase { this.kubectlEnvironment = props.kubectlEnvironment; this.kubectlPrivateSubnets = props.kubectlPrivateSubnetIds ? props.kubectlPrivateSubnetIds.map((subnetid, index) => ec2.Subnet.fromSubnetId(this, `KubectlSubnet${index}`, subnetid)) : undefined; this.kubectlLayer = props.kubectlLayer; - this.onEventLayer = props.onEventLayer; this.kubectlMemory = props.kubectlMemory; + this.clusterHandlerSecurityGroup = props.clusterHandlerSecurityGroupId ? ec2.SecurityGroup.fromSecurityGroupId(this, 'ClusterHandlerSecurityGroup', props.clusterHandlerSecurityGroupId) : undefined; + this.onEventLayer = props.onEventLayer; this.prune = props.prune ?? true; let i = 1; diff --git a/packages/@aws-cdk/aws-eks/lib/fargate-cluster.ts b/packages/@aws-cdk/aws-eks/lib/fargate-cluster.ts index 11036875a9d30..022d6bc6ecdbf 100644 --- a/packages/@aws-cdk/aws-eks/lib/fargate-cluster.ts +++ b/packages/@aws-cdk/aws-eks/lib/fargate-cluster.ts @@ -1,6 +1,6 @@ import { Construct } from 'constructs'; import { Cluster, ClusterOptions, CoreDnsComputeType } from './cluster'; -import { FargateProfileOptions } from './fargate-profile'; +import { FargateProfile, FargateProfileOptions } from './fargate-profile'; /** * Configuration props for EKS Fargate. @@ -23,6 +23,11 @@ export interface FargateClusterProps extends ClusterOptions { * `addFargateProfile`. */ export class FargateCluster extends Cluster { + /** + * Fargate Profile that was created with the cluster. + */ + public readonly defaultProfile: FargateProfile; + constructor(scope: Construct, id: string, props: FargateClusterProps) { super(scope, id, { ...props, @@ -31,7 +36,7 @@ export class FargateCluster extends Cluster { version: props.version, }); - this.addFargateProfile( + this.defaultProfile = this.addFargateProfile( props.defaultProfile?.fargateProfileName ?? (props.defaultProfile ? 'custom' : 'default'), props.defaultProfile ?? { selectors: [ diff --git a/packages/@aws-cdk/aws-eks/package.json b/packages/@aws-cdk/aws-eks/package.json index 7864034ff146b..35db07123cae8 100644 --- a/packages/@aws-cdk/aws-eks/package.json +++ b/packages/@aws-cdk/aws-eks/package.json @@ -77,7 +77,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.84", + "@types/aws-lambda": "^8.10.85", "@types/jest": "^26.0.24", "@types/sinon": "^9.0.11", "@types/yaml": "1.9.6", @@ -93,7 +93,6 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", - "@aws-cdk/aws-lambda-nodejs": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", @@ -113,7 +112,6 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", - "@aws-cdk/aws-lambda-nodejs": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", diff --git a/packages/@aws-cdk/aws-eks/test/cluster.test.ts b/packages/@aws-cdk/aws-eks/test/cluster.test.ts index 295092509ffd2..63a17d9c5d64d 100644 --- a/packages/@aws-cdk/aws-eks/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-eks/test/cluster.test.ts @@ -38,6 +38,25 @@ describe('cluster', () => { expect(template.Resources.OnEventHandler42BEBAE0.Properties.Environment).toEqual({ Variables: { foo: 'bar' } }); }); + test('can specify security group to cluster resource handler', () => { + const { stack, vpc } = testFixture(); + const securityGroup = new ec2.SecurityGroup(stack, 'ProxyInstanceSG', { + vpc, + allowAllOutbound: false, + }); + + new eks.Cluster(stack, 'Cluster', { + version: CLUSTER_VERSION, + placeClusterHandlerInVpc: true, + clusterHandlerSecurityGroup: securityGroup, + }); + + const nested = stack.node.tryFindChild('@aws-cdk/aws-eks.ClusterResourceProvider') as cdk.NestedStack; + + const template = SynthUtils.toCloudFormation(nested); + expect(template.Resources.OnEventHandler42BEBAE0.Properties.VpcConfig.SecurityGroupIds).toEqual([{ Ref: 'referencetoStackProxyInstanceSG80B79D87GroupId' }]); + }); + test('throws when trying to place cluster handlers in a vpc with no private subnets', () => { const { stack } = testFixture(); @@ -55,6 +74,21 @@ describe('cluster', () => { }); + test('throws when provided `clusterHandlerSecurityGroup` without `placeClusterHandlerInVpc: true`', () => { + const { stack, vpc } = testFixture(); + const securityGroup = new ec2.SecurityGroup(stack, 'ProxyInstanceSG', { + vpc, + allowAllOutbound: false, + }); + + expect(() => { + new eks.Cluster(stack, 'Cluster', { + version: CLUSTER_VERSION, + clusterHandlerSecurityGroup: securityGroup, + }); + }).toThrow(/Cannot specify clusterHandlerSecurityGroup without placeClusterHandlerInVpc set to true/); + }); + describe('imported Vpc from unparseable list tokens', () => { let stack: cdk.Stack; let vpc: ec2.IVpc; 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 index fc046ff8065b2..1883358d70fe7 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch-vpc.expected.json +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch-vpc.expected.json @@ -95,15 +95,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "Tags": [ { "Key": "Name", @@ -192,15 +192,15 @@ "VpcPublicSubnet2NATGateway9182C01D": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, - "SubnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "Tags": [ { "Key": "Name", @@ -289,15 +289,15 @@ "VpcPublicSubnet3NATGateway7640CD1D": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet3SubnetBE12F0B6" + }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet3EIP3A666A23", "AllocationId" ] }, - "SubnetId": { - "Ref": "VpcPublicSubnet3SubnetBE12F0B6" - }, "Tags": [ { "Key": "Name", 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 33066ad9091b6..8cbc696c94e14 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 @@ -359,7 +359,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersf4b39c228007db80daf4497318957f3b455415dce70fdbb7aeb6151a0b6da924S3BucketA716C641" + "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E" }, "S3Key": { "Fn::Join": [ @@ -372,7 +372,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersf4b39c228007db80daf4497318957f3b455415dce70fdbb7aeb6151a0b6da924S3VersionKey2B40A946" + "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" } ] } @@ -385,7 +385,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersf4b39c228007db80daf4497318957f3b455415dce70fdbb7aeb6151a0b6da924S3VersionKey2B40A946" + "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" } ] } @@ -412,17 +412,17 @@ } }, "Parameters": { - "AssetParametersf4b39c228007db80daf4497318957f3b455415dce70fdbb7aeb6151a0b6da924S3BucketA716C641": { + "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E": { "Type": "String", - "Description": "S3 bucket for asset \"f4b39c228007db80daf4497318957f3b455415dce70fdbb7aeb6151a0b6da924\"" + "Description": "S3 bucket for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" }, - "AssetParametersf4b39c228007db80daf4497318957f3b455415dce70fdbb7aeb6151a0b6da924S3VersionKey2B40A946": { + "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632": { "Type": "String", - "Description": "S3 key for asset version \"f4b39c228007db80daf4497318957f3b455415dce70fdbb7aeb6151a0b6da924\"" + "Description": "S3 key for asset version \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" }, - "AssetParametersf4b39c228007db80daf4497318957f3b455415dce70fdbb7aeb6151a0b6da924ArtifactHash2B031F57": { + "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2ArtifactHash4BE92B79": { "Type": "String", - "Description": "Artifact hash for asset \"f4b39c228007db80daf4497318957f3b455415dce70fdbb7aeb6151a0b6da924\"" + "Description": "Artifact hash for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" } } } \ No newline at end of file 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 e976e19e502a2..3734722a35ca7 100644 --- a/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.expected.json +++ b/packages/@aws-cdk/aws-elasticsearch/test/integ.elasticsearch.expected.json @@ -296,7 +296,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersf2b7671fc0b80f63e3c94441727cbff799bb0f4991339d990d7b4c419e1ab3ddS3Bucket292EB571" + "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E" }, "S3Key": { "Fn::Join": [ @@ -309,7 +309,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersf2b7671fc0b80f63e3c94441727cbff799bb0f4991339d990d7b4c419e1ab3ddS3VersionKeyCE9A5F79" + "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" } ] } @@ -322,7 +322,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersf2b7671fc0b80f63e3c94441727cbff799bb0f4991339d990d7b4c419e1ab3ddS3VersionKeyCE9A5F79" + "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" } ] } @@ -608,17 +608,17 @@ } }, "Parameters": { - "AssetParametersf2b7671fc0b80f63e3c94441727cbff799bb0f4991339d990d7b4c419e1ab3ddS3Bucket292EB571": { + "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E": { "Type": "String", - "Description": "S3 bucket for asset \"f2b7671fc0b80f63e3c94441727cbff799bb0f4991339d990d7b4c419e1ab3dd\"" + "Description": "S3 bucket for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" }, - "AssetParametersf2b7671fc0b80f63e3c94441727cbff799bb0f4991339d990d7b4c419e1ab3ddS3VersionKeyCE9A5F79": { + "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632": { "Type": "String", - "Description": "S3 key for asset version \"f2b7671fc0b80f63e3c94441727cbff799bb0f4991339d990d7b4c419e1ab3dd\"" + "Description": "S3 key for asset version \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" }, - "AssetParametersf2b7671fc0b80f63e3c94441727cbff799bb0f4991339d990d7b4c419e1ab3ddArtifactHash86854188": { + "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2ArtifactHash4BE92B79": { "Type": "String", - "Description": "Artifact hash for asset \"f2b7671fc0b80f63e3c94441727cbff799bb0f4991339d990d7b4c419e1ab3dd\"" + "Description": "Artifact hash for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" } } } \ No newline at end of file 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 7ff999080fed6..d74ea6423a7bd 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 @@ -8,7 +8,9 @@ "GenerateStringKey": "password", "SecretStringTemplate": "{\"username\":\"admin\"}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "Domain66AC69E0": { "Type": "AWS::Elasticsearch::Domain", @@ -191,7 +193,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3BucketD609D0D9" + "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E" }, "S3Key": { "Fn::Join": [ @@ -204,7 +206,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3VersionKey77CF589B" + "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" } ] } @@ -217,7 +219,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3VersionKey77CF589B" + "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" } ] } @@ -243,17 +245,17 @@ } }, "Parameters": { - "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3BucketD609D0D9": { + "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E": { "Type": "String", - "Description": "S3 bucket for asset \"4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02c\"" + "Description": "S3 bucket for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" }, - "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3VersionKey77CF589B": { + "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632": { "Type": "String", - "Description": "S3 key for asset version \"4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02c\"" + "Description": "S3 key for asset version \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" }, - "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cArtifactHash86CFA15D": { + "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2ArtifactHash4BE92B79": { "Type": "String", - "Description": "Artifact hash for asset \"4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02c\"" + "Description": "Artifact hash for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-glue/test/code.test.ts b/packages/@aws-cdk/aws-glue/test/code.test.ts index 061f6d26c351f..8049bc1b29c6a 100644 --- a/packages/@aws-cdk/aws-glue/test/code.test.ts +++ b/packages/@aws-cdk/aws-glue/test/code.test.ts @@ -17,7 +17,7 @@ describe('Code', () => { let bucket: s3.IBucket; test('with valid bucket name and key and bound by job sets the right path and grants the job permissions to read from it', () => { - bucket = s3.Bucket.fromBucketName(stack, 'Bucket', 'bucketName'); + bucket = s3.Bucket.fromBucketName(stack, 'Bucket', 'bucketname'); script = glue.Code.fromBucket(bucket, key); new glue.Job(stack, 'Job1', { executable: glue.JobExecutable.pythonShell({ @@ -29,7 +29,7 @@ describe('Code', () => { Template.fromStack(stack).hasResourceProperties('AWS::Glue::Job', { Command: { - ScriptLocation: 's3://bucketName/script', + ScriptLocation: 's3://bucketname/script', }, }); @@ -53,7 +53,7 @@ describe('Code', () => { { Ref: 'AWS::Partition', }, - ':s3:::bucketName', + ':s3:::bucketname', ], ], }, @@ -65,7 +65,7 @@ describe('Code', () => { { Ref: 'AWS::Partition', }, - ':s3:::bucketName/script', + ':s3:::bucketname/script', ], ], }, diff --git a/packages/@aws-cdk/aws-glue/test/job-executable.test.ts b/packages/@aws-cdk/aws-glue/test/job-executable.test.ts index 481bd16dc8944..5fcf3b1487764 100644 --- a/packages/@aws-cdk/aws-glue/test/job-executable.test.ts +++ b/packages/@aws-cdk/aws-glue/test/job-executable.test.ts @@ -31,7 +31,7 @@ describe('JobExecutable', () => { beforeEach(() => { stack = new cdk.Stack(); - bucket = s3.Bucket.fromBucketName(stack, 'Bucket', 'bucketName'); + bucket = s3.Bucket.fromBucketName(stack, 'Bucket', 'bucketname'); script = glue.Code.fromBucket(bucket, 'script.py'); }); diff --git a/packages/@aws-cdk/aws-glue/test/job.test.ts b/packages/@aws-cdk/aws-glue/test/job.test.ts index 625e4743570fd..c338b4d09cb42 100644 --- a/packages/@aws-cdk/aws-glue/test/job.test.ts +++ b/packages/@aws-cdk/aws-glue/test/job.test.ts @@ -55,7 +55,7 @@ describe('Job', () => { describe('new', () => { const className = 'com.amazon.test.ClassName'; - const codeBucketName = 'bucketName'; + const codeBucketName = 'bucketname'; const codeBucketAccessStatement = { Action: [ 's3:GetObject*', @@ -166,7 +166,7 @@ describe('Job', () => { Template.fromStack(stack).hasResourceProperties('AWS::Glue::Job', { Command: { Name: 'glueetl', - ScriptLocation: 's3://bucketName/script', + ScriptLocation: 's3://bucketname/script', }, Role: { 'Fn::GetAtt': [ @@ -383,7 +383,7 @@ describe('Job', () => { }); describe('with bucket provided', () => { - const sparkUIBucketName = 'sparkBucketName'; + const sparkUIBucketName = 'sparkbucketname'; let sparkUIBucket: s3.IBucket; beforeEach(() => { @@ -420,7 +420,7 @@ describe('Job', () => { { Ref: 'AWS::Partition', }, - ':s3:::sparkBucketName', + ':s3:::sparkbucketname', ], ], }, @@ -432,7 +432,7 @@ describe('Job', () => { { Ref: 'AWS::Partition', }, - ':s3:::sparkBucketName/*', + ':s3:::sparkbucketname/*', ], ], }, @@ -460,7 +460,7 @@ describe('Job', () => { }); describe('with bucket and path provided', () => { - const sparkUIBucketName = 'sparkBucketName'; + const sparkUIBucketName = 'sparkbucketname'; const prefix = 'some/path/'; let sparkUIBucket: s3.IBucket; @@ -516,7 +516,7 @@ describe('Job', () => { Template.fromStack(stack).hasResourceProperties('AWS::Glue::Job', { Command: { Name: 'glueetl', - ScriptLocation: 's3://bucketName/script', + ScriptLocation: 's3://bucketname/script', }, Role: { 'Fn::GetAtt': [ @@ -614,7 +614,7 @@ describe('Job', () => { GlueVersion: '2.0', Command: { Name: 'glueetl', - ScriptLocation: 's3://bucketName/script', + ScriptLocation: 's3://bucketname/script', PythonVersion: '3', }, Role: { @@ -625,9 +625,9 @@ describe('Job', () => { }, DefaultArguments: { '--job-language': 'python', - '--extra-jars': 's3://bucketName/file1.jar,s3://bucketName/file2.jar', - '--extra-py-files': 's3://bucketName/file1.py,s3://bucketName/file2.py', - '--extra-files': 's3://bucketName/file1.txt,s3://bucketName/file2.txt', + '--extra-jars': 's3://bucketname/file1.jar,s3://bucketname/file2.jar', + '--extra-py-files': 's3://bucketname/file1.py,s3://bucketname/file2.py', + '--extra-files': 's3://bucketname/file1.txt,s3://bucketname/file2.txt', '--user-jars-first': 'true', }, }); @@ -649,7 +649,7 @@ describe('Job', () => { GlueVersion: '2.0', Command: { Name: 'gluestreaming', - ScriptLocation: 's3://bucketName/script', + ScriptLocation: 's3://bucketname/script', }, Role: { 'Fn::GetAtt': [ @@ -660,8 +660,8 @@ describe('Job', () => { DefaultArguments: { '--job-language': 'scala', '--class': 'com.amazon.test.ClassName', - '--extra-jars': 's3://bucketName/file1.jar,s3://bucketName/file2.jar', - '--extra-files': 's3://bucketName/file1.txt,s3://bucketName/file2.txt', + '--extra-jars': 's3://bucketname/file1.jar,s3://bucketname/file2.jar', + '--extra-files': 's3://bucketname/file1.txt,s3://bucketname/file2.txt', '--user-jars-first': 'true', }, }); diff --git a/packages/@aws-cdk/aws-iam/package.json b/packages/@aws-cdk/aws-iam/package.json index 0e951bb0cdf2c..338e97338adfa 100644 --- a/packages/@aws-cdk/aws-iam/package.json +++ b/packages/@aws-cdk/aws-iam/package.json @@ -77,7 +77,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.84", + "@types/aws-lambda": "^8.10.85", "@types/jest": "^26.0.24", "@types/sinon": "^9.0.11", "jest": "^26.6.3", diff --git a/packages/@aws-cdk/aws-iot-actions/README.md b/packages/@aws-cdk/aws-iot-actions/README.md index 67d9b2924dd53..b18182a80a9ad 100644 --- a/packages/@aws-cdk/aws-iot-actions/README.md +++ b/packages/@aws-cdk/aws-iot-actions/README.md @@ -48,3 +48,21 @@ new iot.TopicRule(this, 'TopicRule', { actions: [new actions.LambdaFunctionAction(func)], }); ``` + +## Put logs to CloudWatch Logs + +The code snippet below creates an AWS IoT Rule that put logs to CloudWatch Logs +when it is triggered. + +```ts +import * as iot from '@aws-cdk/aws-iot'; +import * as actions from '@aws-cdk/aws-iot-actions'; +import * as logs from '@aws-cdk/aws-logs'; + +const logGroup = new logs.LogGroup(this, 'MyLogGroup'); + +new iot.TopicRule(this, 'TopicRule', { + sql: iot.IotSql.fromStringAsVer20160323("SELECT topic(2) as device_id FROM 'device/+/data'"), + actions: [new actions.CloudWatchLogsAction(logGroup)], +}); +``` diff --git a/packages/@aws-cdk/aws-iot-actions/lib/cloudwatch-logs-action.ts b/packages/@aws-cdk/aws-iot-actions/lib/cloudwatch-logs-action.ts new file mode 100644 index 0000000000000..dda14de887774 --- /dev/null +++ b/packages/@aws-cdk/aws-iot-actions/lib/cloudwatch-logs-action.ts @@ -0,0 +1,49 @@ +import * as iam from '@aws-cdk/aws-iam'; +import * as iot from '@aws-cdk/aws-iot'; +import * as logs from '@aws-cdk/aws-logs'; +import { singletonActionRole } from './private/role'; + +/** + * Configuration properties of an action for CloudWatch Logs. + */ +export interface CloudWatchLogsActionProps { + /** + * The IAM role that allows access to the CloudWatch log group. + * + * @default a new role will be created + */ + readonly role?: iam.IRole; +} + +/** + * The action to send data to Amazon CloudWatch Logs + */ +export class CloudWatchLogsAction implements iot.IAction { + private readonly role?: iam.IRole; + + /** + * @param logGroup The CloudWatch log group to which the action sends data + * @param props Optional properties to not use default + */ + constructor( + private readonly logGroup: logs.ILogGroup, + props: CloudWatchLogsActionProps = {}, + ) { + this.role = props.role; + } + + bind(rule: iot.ITopicRule): iot.ActionConfig { + const role = this.role ?? singletonActionRole(rule); + this.logGroup.grantWrite(role); + this.logGroup.grant(role, 'logs:DescribeLogStreams'); + + return { + configuration: { + cloudwatchLogs: { + logGroupName: this.logGroup.logGroupName, + roleArn: role.roleArn, + }, + }, + }; + } +} diff --git a/packages/@aws-cdk/aws-iot-actions/lib/index.ts b/packages/@aws-cdk/aws-iot-actions/lib/index.ts index 751863744ffe2..ef917fd0e2181 100644 --- a/packages/@aws-cdk/aws-iot-actions/lib/index.ts +++ b/packages/@aws-cdk/aws-iot-actions/lib/index.ts @@ -1 +1,2 @@ +export * from './cloudwatch-logs-action'; export * from './lambda-function-action'; diff --git a/packages/@aws-cdk/aws-iot-actions/lib/private/role.ts b/packages/@aws-cdk/aws-iot-actions/lib/private/role.ts new file mode 100644 index 0000000000000..78c72b914f56b --- /dev/null +++ b/packages/@aws-cdk/aws-iot-actions/lib/private/role.ts @@ -0,0 +1,27 @@ +import * as iam from '@aws-cdk/aws-iam'; +import { IConstruct, PhysicalName } 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'; + +/** + * Obtain the Role for the TopicRule + * + * If a role already exists, it will be returned. This ensures that if a rule have multiple + * actions, they will share a role. + * @internal + */ +export function singletonActionRole(scope: IConstruct): iam.IRole { + const id = 'TopicRuleActionRole'; + const existing = scope.node.tryFindChild(id) as iam.IRole; + if (existing) { + return existing; + }; + + const role = new iam.Role(scope as Construct, id, { + roleName: PhysicalName.GENERATE_IF_NEEDED, + assumedBy: new iam.ServicePrincipal('iot.amazonaws.com'), + }); + return role; +} diff --git a/packages/@aws-cdk/aws-iot-actions/package.json b/packages/@aws-cdk/aws-iot-actions/package.json index 3b66b73a1562e..d60ae4c5e1376 100644 --- a/packages/@aws-cdk/aws-iot-actions/package.json +++ b/packages/@aws-cdk/aws-iot-actions/package.json @@ -82,6 +82,7 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-iot": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, @@ -90,6 +91,7 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-iot": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, diff --git a/packages/@aws-cdk/aws-iot-actions/test/cloudwatch-logs/cloudwatch-logs-action.test.ts b/packages/@aws-cdk/aws-iot-actions/test/cloudwatch-logs/cloudwatch-logs-action.test.ts new file mode 100644 index 0000000000000..4e25f43367c31 --- /dev/null +++ b/packages/@aws-cdk/aws-iot-actions/test/cloudwatch-logs/cloudwatch-logs-action.test.ts @@ -0,0 +1,199 @@ +import { Template } from '@aws-cdk/assertions'; +import * as iam from '@aws-cdk/aws-iam'; +import * as iot from '@aws-cdk/aws-iot'; +import * as logs from '@aws-cdk/aws-logs'; +import * as cdk from '@aws-cdk/core'; +import * as actions from '../../lib'; + +test('Default cloudwatch logs action', () => { + // GIVEN + const stack = new cdk.Stack(); + const topicRule = new iot.TopicRule(stack, 'MyTopicRule', { + sql: iot.IotSql.fromStringAsVer20160323("SELECT topic(2) as device_id FROM 'device/+/data'"), + }); + const logGroup = new logs.LogGroup(stack, 'MyLogGroup'); + + // WHEN + topicRule.addAction( + new actions.CloudWatchLogsAction(logGroup), + ); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IoT::TopicRule', { + TopicRulePayload: { + Actions: [ + { + CloudwatchLogs: { + LogGroupName: { Ref: 'MyLogGroup5C0DAD85' }, + RoleArn: { + 'Fn::GetAtt': [ + 'MyTopicRuleTopicRuleActionRoleCE2D05DA', + 'Arn', + ], + }, + }, + }, + ], + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { + AssumeRolePolicyDocument: { + Statement: [ + { + Action: 'sts:AssumeRole', + Effect: 'Allow', + Principal: { + Service: 'iot.amazonaws.com', + }, + }, + ], + Version: '2012-10-17', + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: ['logs:CreateLogStream', 'logs:PutLogEvents'], + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': ['MyLogGroup5C0DAD85', 'Arn'], + }, + }, + { + Action: 'logs:DescribeLogStreams', + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': ['MyLogGroup5C0DAD85', 'Arn'], + }, + }, + ], + Version: '2012-10-17', + }, + PolicyName: 'MyTopicRuleTopicRuleActionRoleDefaultPolicy54A701F7', + Roles: [ + { Ref: 'MyTopicRuleTopicRuleActionRoleCE2D05DA' }, + ], + }); +}); + +test('can set role', () => { + // GIVEN + const stack = new cdk.Stack(); + const topicRule = new iot.TopicRule(stack, 'MyTopicRule', { + sql: iot.IotSql.fromStringAsVer20160323("SELECT topic(2) as device_id FROM 'device/+/data'"), + }); + const logGroup = new logs.LogGroup(stack, 'MyLogGroup'); + const role = iam.Role.fromRoleArn(stack, 'MyRole', 'arn:aws:iam::123456789012:role/ForTest'); + + // WHEN + topicRule.addAction( + new actions.CloudWatchLogsAction(logGroup, { + role, + }), + ); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IoT::TopicRule', { + TopicRulePayload: { + Actions: [ + { + CloudwatchLogs: { + LogGroupName: { Ref: 'MyLogGroup5C0DAD85' }, + RoleArn: 'arn:aws:iam::123456789012:role/ForTest', + }, + }, + ], + }, + }); +}); + +test('The specified role is added a policy needed for sending data to logs', () => { + // GIVEN + const stack = new cdk.Stack(); + const topicRule = new iot.TopicRule(stack, 'MyTopicRule', { + sql: iot.IotSql.fromStringAsVer20160323("SELECT topic(2) as device_id FROM 'device/+/data'"), + }); + const logGroup = new logs.LogGroup(stack, 'MyLogGroup'); + const role = iam.Role.fromRoleArn(stack, 'MyRole', 'arn:aws:iam::123456789012:role/ForTest'); + + // WHEN + topicRule.addAction( + new actions.CloudWatchLogsAction(logGroup, { + role, + }), + ); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: ['logs:CreateLogStream', 'logs:PutLogEvents'], + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': ['MyLogGroup5C0DAD85', 'Arn'], + }, + }, + { + Action: 'logs:DescribeLogStreams', + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': ['MyLogGroup5C0DAD85', 'Arn'], + }, + }, + ], + Version: '2012-10-17', + }, + PolicyName: 'MyRolePolicy64AB00A5', + Roles: ['ForTest'], + }); +}); + + +test('When multiple actions are omitted role property, the actions use same one role', () => { + // GIVEN + // GIVEN + const stack = new cdk.Stack(); + const topicRule = new iot.TopicRule(stack, 'MyTopicRule', { + sql: iot.IotSql.fromStringAsVer20160323("SELECT topic(2) as device_id FROM 'device/+/data'"), + }); + const logGroup1 = new logs.LogGroup(stack, 'MyLogGroup1'); + const logGroup2 = new logs.LogGroup(stack, 'MyLogGroup2'); + + // WHEN + topicRule.addAction(new actions.CloudWatchLogsAction(logGroup1)); + topicRule.addAction(new actions.CloudWatchLogsAction(logGroup2)); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IoT::TopicRule', { + TopicRulePayload: { + Actions: [ + { + CloudwatchLogs: { + LogGroupName: { Ref: 'MyLogGroup14A6E382A' }, + RoleArn: { + 'Fn::GetAtt': [ + 'MyTopicRuleTopicRuleActionRoleCE2D05DA', + 'Arn', + ], + }, + }, + }, + { + CloudwatchLogs: { + LogGroupName: { Ref: 'MyLogGroup279D6359D' }, + RoleArn: { + 'Fn::GetAtt': [ + 'MyTopicRuleTopicRuleActionRoleCE2D05DA', + 'Arn', + ], + }, + }, + }, + ], + }, + }); +}); diff --git a/packages/@aws-cdk/aws-iot-actions/test/cloudwatch-logs/integ.cloudwatch-logs-action.expected.json b/packages/@aws-cdk/aws-iot-actions/test/cloudwatch-logs/integ.cloudwatch-logs-action.expected.json new file mode 100644 index 0000000000000..7d1748a084c77 --- /dev/null +++ b/packages/@aws-cdk/aws-iot-actions/test/cloudwatch-logs/integ.cloudwatch-logs-action.expected.json @@ -0,0 +1,92 @@ +{ + "Resources": { + "TopicRule40A4EA44": { + "Type": "AWS::IoT::TopicRule", + "Properties": { + "TopicRulePayload": { + "Actions": [ + { + "CloudwatchLogs": { + "LogGroupName": { + "Ref": "MyLogGroup5C0DAD85" + }, + "RoleArn": { + "Fn::GetAtt": [ + "TopicRuleTopicRuleActionRole246C4F77", + "Arn" + ] + } + } + } + ], + "AwsIotSqlVersion": "2016-03-23", + "Sql": "SELECT topic(2) as device_id FROM 'device/+/data'" + } + } + }, + "TopicRuleTopicRuleActionRole246C4F77": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "iot.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "TopicRuleTopicRuleActionRoleDefaultPolicy99ADD687": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "MyLogGroup5C0DAD85", + "Arn" + ] + } + }, + { + "Action": "logs:DescribeLogStreams", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "MyLogGroup5C0DAD85", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "TopicRuleTopicRuleActionRoleDefaultPolicy99ADD687", + "Roles": [ + { + "Ref": "TopicRuleTopicRuleActionRole246C4F77" + } + ] + } + }, + "MyLogGroup5C0DAD85": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "RetentionInDays": 731 + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iot-actions/test/cloudwatch-logs/integ.cloudwatch-logs-action.ts b/packages/@aws-cdk/aws-iot-actions/test/cloudwatch-logs/integ.cloudwatch-logs-action.ts new file mode 100644 index 0000000000000..802f485b77e37 --- /dev/null +++ b/packages/@aws-cdk/aws-iot-actions/test/cloudwatch-logs/integ.cloudwatch-logs-action.ts @@ -0,0 +1,25 @@ +/// !cdk-integ pragma:ignore-assets +import * as iot from '@aws-cdk/aws-iot'; +import * as logs from '@aws-cdk/aws-logs'; +import * as cdk from '@aws-cdk/core'; +import * as actions from '../../lib'; + +const app = new cdk.App(); + +class TestStack extends cdk.Stack { + constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { + super(scope, id, props); + + const topicRule = new iot.TopicRule(this, 'TopicRule', { + sql: iot.IotSql.fromStringAsVer20160323("SELECT topic(2) as device_id FROM 'device/+/data'"), + }); + + const logGroup = new logs.LogGroup(this, 'MyLogGroup', { + removalPolicy: cdk.RemovalPolicy.DESTROY, + }); + topicRule.addAction(new actions.CloudWatchLogsAction(logGroup)); + } +} + +new TestStack(app, 'test-stack'); +app.synth(); diff --git a/packages/@aws-cdk/aws-iot/README.md b/packages/@aws-cdk/aws-iot/README.md index 6a9640629891a..402036b531dfc 100644 --- a/packages/@aws-cdk/aws-iot/README.md +++ b/packages/@aws-cdk/aws-iot/README.md @@ -59,6 +59,8 @@ const func = new lambda.Function(this, 'MyFunction', { }); new iot.TopicRule(this, 'TopicRule', { + topicRuleName: 'MyTopicRule', // optional + description: 'invokes the lambda finction', // optional sql: iot.IotSql.fromStringAsVer20160323("SELECT topic(2) as device_id, timestamp() as timestamp FROM 'device/+/data'"), actions: [new actions.LambdaFunctionAction(func)], }); @@ -72,3 +74,30 @@ const topicRule = new iot.TopicRule(this, 'TopicRule', { }); topicRule.addAction(new actions.LambdaFunctionAction(func)) ``` + +You can also supply `errorAction` as following, +and the IoT Rule will trigger it if a rule's action is unable to perform: + +```ts +import * as iot from '@aws-cdk/aws-iot'; +import * as actions from '@aws-cdk/aws-iot-actions'; +import * as logs from '@aws-cdk/aws-logs'; + +const logGroup = new logs.LogGroup(this, 'MyLogGroup'); + +new iot.TopicRule(this, 'TopicRule', { + sql: iot.IotSql.fromStringAsVer20160323("SELECT topic(2) as device_id, timestamp() as timestamp FROM 'device/+/data'"), + errorAction: new actions.CloudWatchLogsAction(logGroup), +}); +``` + +If you wanna make the topic rule disable, add property `enabled: false` as following: + +```ts +new iot.TopicRule(this, 'TopicRule', { + sql: iot.IotSql.fromStringAsVer20160323("SELECT topic(2) as device_id, timestamp() as timestamp FROM 'device/+/data'"), + enabled: false, +}); +``` + +See also [@aws-cdk/aws-iot-actions](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-iot-actions-readme.html) for other actions. diff --git a/packages/@aws-cdk/aws-iot/lib/topic-rule.ts b/packages/@aws-cdk/aws-iot/lib/topic-rule.ts index a8cd21fe2bd96..89f40c3797d97 100644 --- a/packages/@aws-cdk/aws-iot/lib/topic-rule.ts +++ b/packages/@aws-cdk/aws-iot/lib/topic-rule.ts @@ -41,6 +41,27 @@ export interface TopicRuleProps { */ readonly actions?: IAction[]; + /** + * A textual description of the topic rule. + * + * @default None + */ + readonly description?: string; + + /** + * The action AWS IoT performs when it is unable to perform a rule's action. + * + * @default - no action will be performed + */ + readonly errorAction?: IAction; + + /** + * Specifies whether the rule is enabled. + * + * @default true + */ + readonly enabled?: boolean + /** * A simplified SQL syntax to filter messages received on an MQTT topic and push the data elsewhere. * @@ -102,6 +123,9 @@ export class TopicRule extends Resource implements ITopicRule { topicRulePayload: { actions: Lazy.any({ produce: () => this.actions }), awsIotSqlVersion: sqlConfig.awsIotSqlVersion, + description: props.description, + errorAction: props.errorAction?.bind(this).configuration, + ruleDisabled: props.enabled === undefined ? undefined : !props.enabled, sql: sqlConfig.sql, }, }); diff --git a/packages/@aws-cdk/aws-iot/test/topic-rule.test.ts b/packages/@aws-cdk/aws-iot/test/topic-rule.test.ts index 66246e860dddb..5f84201a37e5d 100644 --- a/packages/@aws-cdk/aws-iot/test/topic-rule.test.ts +++ b/packages/@aws-cdk/aws-iot/test/topic-rule.test.ts @@ -71,6 +71,36 @@ test('can set physical name', () => { }); }); +test('can set description', () => { + const stack = new cdk.Stack(); + + new iot.TopicRule(stack, 'MyTopicRule', { + description: 'test-description', + sql: iot.IotSql.fromStringAsVer20151008("SELECT topic(2) as device_id, temperature FROM 'device/+/data'"), + }); + + Template.fromStack(stack).hasResourceProperties('AWS::IoT::TopicRule', { + TopicRulePayload: { + Description: 'test-description', + }, + }); +}); + +test('can set ruleDisabled', () => { + const stack = new cdk.Stack(); + + new iot.TopicRule(stack, 'MyTopicRule', { + enabled: false, + sql: iot.IotSql.fromStringAsVer20151008("SELECT topic(2) as device_id, temperature FROM 'device/+/data'"), + }); + + Template.fromStack(stack).hasResourceProperties('AWS::IoT::TopicRule', { + TopicRulePayload: { + RuleDisabled: true, + }, + }); +}); + test.each([ ['fromStringAsVer20151008', iot.IotSql.fromStringAsVer20151008, '2015-10-08'], ['fromStringAsVer20160323', iot.IotSql.fromStringAsVer20160323, '2016-03-23'], @@ -203,6 +233,31 @@ test('cannot add an action that have multiple keys', () => { }).toThrow('An action property cannot have multiple keys, received: http,lambda'); }); +test('can set errorAction', () => { + const stack = new cdk.Stack(); + + const action: iot.IAction = { + bind: () => ({ + configuration: { + http: { url: 'http://example.com' }, + }, + }), + }; + + new iot.TopicRule(stack, 'MyTopicRule', { + errorAction: action, + sql: iot.IotSql.fromStringAsVer20151008("SELECT topic(2) as device_id, temperature FROM 'device/+/data'"), + }); + + Template.fromStack(stack).hasResourceProperties('AWS::IoT::TopicRule', { + TopicRulePayload: { + ErrorAction: { + Http: { Url: 'http://example.com' }, + }, + }, + }); +}); + test('can import a TopicRule by ARN', () => { const stack = new cdk.Stack(); diff --git a/packages/@aws-cdk/aws-lambda-go/lib/Dockerfile b/packages/@aws-cdk/aws-lambda-go/lib/Dockerfile index ffa102c84803c..e832110399bea 100644 --- a/packages/@aws-cdk/aws-lambda-go/lib/Dockerfile +++ b/packages/@aws-cdk/aws-lambda-go/lib/Dockerfile @@ -1,13 +1,15 @@ # 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 +ARG IMAGE=public.ecr.aws/sam/build-go1.x FROM $IMAGE # set the GOCACHE +ENV GOPATH=/go ENV GOCACHE=$GOPATH/.cache/go-build ENV GOPROXY=direct # Ensure all users can write to GOPATH -RUN chmod -R 777 $GOPATH +RUN mkdir $GOPATH && \ + chmod -R 777 $GOPATH CMD [ "go" ] diff --git a/packages/@aws-cdk/aws-lambda-go/test/docker.test.ts b/packages/@aws-cdk/aws-lambda-go/test/docker.test.ts index d619d9f0fb91d..cd335d834358f 100644 --- a/packages/@aws-cdk/aws-lambda-go/test/docker.test.ts +++ b/packages/@aws-cdk/aws-lambda-go/test/docker.test.ts @@ -2,7 +2,7 @@ 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')]); + spawnSync('docker', ['build', '-t', 'golang', path.join(__dirname, '../lib')]); }); test('golang is available', async () => { 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 index 9ae6cc08830e8..9ad2aa2afce94 100644 --- a/packages/@aws-cdk/aws-lambda-go/test/integ.function.expected.json +++ b/packages/@aws-cdk/aws-lambda-go/test/integ.function.expected.json @@ -36,7 +36,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1S3Bucket62A8237E" + "Ref": "AssetParameterse04b349f3d0535498861679603e52edaa01d01ee442f4f665c16e22e5bc81820S3Bucket854EE9A9" }, "S3Key": { "Fn::Join": [ @@ -49,7 +49,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1S3VersionKey1C4F3B50" + "Ref": "AssetParameterse04b349f3d0535498861679603e52edaa01d01ee442f4f665c16e22e5bc81820S3VersionKey2AD7C6E5" } ] } @@ -62,7 +62,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1S3VersionKey1C4F3B50" + "Ref": "AssetParameterse04b349f3d0535498861679603e52edaa01d01ee442f4f665c16e22e5bc81820S3VersionKey2AD7C6E5" } ] } @@ -87,17 +87,17 @@ } }, "Parameters": { - "AssetParameters4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1S3Bucket62A8237E": { + "AssetParameterse04b349f3d0535498861679603e52edaa01d01ee442f4f665c16e22e5bc81820S3Bucket854EE9A9": { "Type": "String", - "Description": "S3 bucket for asset \"4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1\"" + "Description": "S3 bucket for asset \"e04b349f3d0535498861679603e52edaa01d01ee442f4f665c16e22e5bc81820\"" }, - "AssetParameters4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1S3VersionKey1C4F3B50": { + "AssetParameterse04b349f3d0535498861679603e52edaa01d01ee442f4f665c16e22e5bc81820S3VersionKey2AD7C6E5": { "Type": "String", - "Description": "S3 key for asset version \"4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1\"" + "Description": "S3 key for asset version \"e04b349f3d0535498861679603e52edaa01d01ee442f4f665c16e22e5bc81820\"" }, - "AssetParameters4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1ArtifactHashBE683488": { + "AssetParameterse04b349f3d0535498861679603e52edaa01d01ee442f4f665c16e22e5bc81820ArtifactHash245320AE": { "Type": "String", - "Description": "Artifact hash for asset \"4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1\"" + "Description": "Artifact hash for asset \"e04b349f3d0535498861679603e52edaa01d01ee442f4f665c16e22e5bc81820\"" } } } \ 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 index 093597339e8b5..84a30bff352e3 100644 --- a/packages/@aws-cdk/aws-lambda-go/test/integ.function.ts +++ b/packages/@aws-cdk/aws-lambda-go/test/integ.function.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import { App, DockerImage, Stack, StackProps } from '@aws-cdk/core'; +import { App, Stack, StackProps } from '@aws-cdk/core'; import { Construct } from 'constructs'; import * as lambda from '../lib'; @@ -15,11 +15,6 @@ class TestStack extends Stack { 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"'], }, diff --git a/packages/@aws-cdk/aws-lambda-nodejs/README.md b/packages/@aws-cdk/aws-lambda-nodejs/README.md index 9bf47f0631d57..1d3eaa66a2a4a 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/README.md +++ b/packages/@aws-cdk/aws-lambda-nodejs/README.md @@ -174,6 +174,7 @@ new lambda.NodejsFunction(this, 'my-handler', { minify: true, // minify code, defaults to false sourceMap: true, // include source map, defaults to false sourceMapMode: SourceMapMode.INLINE, // defaults to SourceMapMode.DEFAULT + sourcesContent: false, // do not include original source into source map, defaults to true target: 'es2020', // target environment for the generated JavaScript code loader: { // Use the 'dataurl' loader for '.png' files '.png': 'dataurl', diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts index 3bd05a7ccb39d..5b7c6ce416b2c 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts @@ -182,6 +182,7 @@ export class Bundling implements cdk.BundlingOptions { const sourceMapEnabled = this.props.sourceMapMode ?? this.props.sourceMap; const sourceMapMode = this.props.sourceMapMode ?? SourceMapMode.DEFAULT; const sourceMapValue = sourceMapMode === SourceMapMode.DEFAULT ? '' : `=${this.props.sourceMapMode}`; + const sourcesContent = this.props.sourcesContent ?? true; const esbuildCommand: string[] = [ options.esbuildRunner, @@ -191,6 +192,7 @@ export class Bundling implements cdk.BundlingOptions { `--outfile="${pathJoin(options.outputDir, 'index.js')}"`, ...this.props.minify ? ['--minify'] : [], ...sourceMapEnabled ? [`--sourcemap${sourceMapValue}`] : [], + ...sourcesContent ? [] : [`--sources-content=${sourcesContent}`], ...this.externals.map(external => `--external:${external}`), ...loaders.map(([ext, name]) => `--loader:${ext}=${name}`), ...defines.map(([key, value]) => `--define:${key}=${JSON.stringify(value)}`), diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/package-manager.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/package-manager.ts index 0f18c92cbde20..f0206bbd19a99 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/package-manager.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/package-manager.ts @@ -20,7 +20,7 @@ export class PackageManager { public static YARN = new PackageManager({ lockFile: 'yarn.lock', - installCommand: ['yarn', 'install'], + installCommand: ['yarn', 'install', '--no-immutable'], runCommand: ['yarn', 'run'], }); diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts index 55606f66b2507..87d3de0eec1fc 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts @@ -26,6 +26,15 @@ export interface BundlingOptions { */ readonly sourceMapMode?: SourceMapMode; + /** + * Whether to include original source code in source maps when bundling. + * + * @see https://esbuild.github.io/api/#sources-content + * + * @default true + */ + readonly sourcesContent?: boolean; + /** * Target environment for the generated JavaScript code. * diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/util.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/util.ts index 5ead91793e93b..af24d3b4ae371 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/util.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/util.ts @@ -64,7 +64,7 @@ export function exec(cmd: string, args: string[], options?: SpawnSyncOptions) { 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}`); + throw new Error(`${cmd} ${args.join(' ')} ${options?.cwd ? `run in directory ${options.cwd}` : ''} exited with status ${proc.status}`); } return proc; diff --git a/packages/@aws-cdk/aws-lambda-nodejs/package.json b/packages/@aws-cdk/aws-lambda-nodejs/package.json index 185aeed69b3ec..fc627ab9e0227 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/package.json +++ b/packages/@aws-cdk/aws-lambda-nodejs/package.json @@ -71,7 +71,7 @@ "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "delay": "5.0.0", - "esbuild": "^0.13.5" + "esbuild": "^0.13.12" }, "dependencies": { "@aws-cdk/aws-lambda": "0.0.0", 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 f4e974c08fdce..e79ddc2aca150 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts @@ -188,6 +188,7 @@ test('esbuild bundling with esbuild options', () => { architecture: Architecture.X86_64, minify: true, sourceMap: true, + sourcesContent: false, target: 'es2020', loader: { '.png': 'dataurl', @@ -218,7 +219,7 @@ test('esbuild bundling with esbuild options', () => { [ 'esbuild --bundle "/asset-input/lib/handler.ts"', '--target=es2020 --platform=node --outfile="/asset-output/index.js"', - '--minify --sourcemap --external:aws-sdk --loader:.png=dataurl', + '--minify --sourcemap --sources-content=false --external:aws-sdk --loader:.png=dataurl', defineInstructions, '--log-level=silent --keep-names --tsconfig=/asset-input/lib/custom-tsconfig.ts', '--metafile=/asset-output/index.meta.json --banner:js="/* comments */" --footer:js="/* comments */"', @@ -341,7 +342,7 @@ test('Detects yarn.lock', () => { assetHashType: AssetHashType.OUTPUT, bundling: expect.objectContaining({ command: expect.arrayContaining([ - expect.stringMatching(/yarn\.lock.+yarn install/), + expect.stringMatching(/yarn\.lock.+yarn install --no-immutable/), ]), }), }); @@ -656,4 +657,4 @@ test('esbuild bundling with pre compilations and undefined tsconfig ( Should thr }); }).toThrow('Cannot find a tsconfig.json, please specify the prop: tsconfig'); -}); \ No newline at end of file +}); diff --git a/packages/@aws-cdk/aws-lambda/package.json b/packages/@aws-cdk/aws-lambda/package.json index f139f180e7420..1a4baf8ea0d80 100644 --- a/packages/@aws-cdk/aws-lambda/package.json +++ b/packages/@aws-cdk/aws-lambda/package.json @@ -82,9 +82,9 @@ "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cfnspec": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.84", + "@types/aws-lambda": "^8.10.85", "@types/jest": "^26.0.24", - "@types/lodash": "^4.14.175", + "@types/lodash": "^4.14.176", "jest": "^26.6.3", "lodash": "^4.17.21" }, diff --git a/packages/@aws-cdk/aws-logs/README.md b/packages/@aws-cdk/aws-logs/README.md index 1fcd323ca621c..631bc382365e0 100644 --- a/packages/@aws-cdk/aws-logs/README.md +++ b/packages/@aws-cdk/aws-logs/README.md @@ -48,6 +48,44 @@ By default, the log group will be created in the same region as the stack. The ` log groups in other regions. This is typically useful when controlling retention for log groups auto-created by global services that publish their log group to a specific region, such as AWS Chatbot creating a log group in `us-east-1`. +## Resource Policy + +CloudWatch Resource Policies allow other AWS services or IAM Principals to put log events into the log groups. +A resource policy is automatically created when `addToResourcePolicy` is called on the LogGroup for the first time. + +`ResourcePolicy` can also be created manually. + +```ts +const logGroup = new LogGroup(this, 'LogGroup'); +const resourcePolicy = new ResourcePolicy(this, 'ResourcePolicy'); +resourcePolicy.document.addStatements(new iam.PolicyStatement({ + actions: ['logs:CreateLogStream', 'logs:PutLogEvents'], + principals: [new iam.ServicePrincipal('es.amazonaws.com')], + resources: [logGroup.logGroupArn], +})); +``` + +Or more conveniently, write permissions to the log group can be granted as follows which gives same result as in the above example. + +```ts +const logGroup = new LogGroup(this, 'LogGroup'); +logGroup.grantWrite(iam.ServicePrincipal('es.amazonaws.com')); +``` + +Optionally name and policy statements can also be passed on `ResourcePolicy` construction. + +```ts +const policyStatement = new new iam.PolicyStatement({ + resources: ["*"], + actions: ['logs:PutLogEvents'], + principals: [new iam.ArnPrincipal('arn:aws:iam::123456789012:user/user-name')], +}); +const resourcePolicy = new ResourcePolicy(this, 'ResourcePolicy', { + policyName: 'myResourcePolicy', + policyStatements: [policyStatement], +}); +``` + ## Encrypting Log Groups By default, log group data is always encrypted in CloudWatch Logs. You have the @@ -182,7 +220,6 @@ line. all of the terms in any of the groups (specified as arrays) matches. This is an OR match. - Examples: ```ts @@ -231,7 +268,6 @@ and then descending into it, such as `$.field` or `$.list[0].field`. given JSON patterns match. This makes an OR combination of the given patterns. - Example: ```ts diff --git a/packages/@aws-cdk/aws-logs/lib/log-group.ts b/packages/@aws-cdk/aws-logs/lib/log-group.ts index 4c74dbf02f3ee..c701f4b5e4c9f 100644 --- a/packages/@aws-cdk/aws-logs/lib/log-group.ts +++ b/packages/@aws-cdk/aws-logs/lib/log-group.ts @@ -1,15 +1,16 @@ 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 { IResource, RemovalPolicy, Resource, Stack, Token } from '@aws-cdk/core'; +import { RemovalPolicy, Resource, Stack, Token } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { LogStream } from './log-stream'; import { CfnLogGroup } from './logs.generated'; import { MetricFilter } from './metric-filter'; import { FilterPattern, IFilterPattern } from './pattern'; +import { ResourcePolicy } from './policy'; import { ILogSubscriptionDestination, SubscriptionFilter } from './subscription-filter'; -export interface ILogGroup extends IResource { +export interface ILogGroup extends iam.IResourceWithPolicy { /** * The ARN of this log group, with ':*' appended * @@ -93,6 +94,9 @@ abstract class LogGroupBase extends Resource implements ILogGroup { */ public abstract readonly logGroupName: string; + + private policy?: ResourcePolicy; + /** * Create a new Log Stream for this Log Group * @@ -169,13 +173,13 @@ abstract class LogGroupBase extends Resource implements ILogGroup { * Give the indicated permissions on this log group and all streams */ public grant(grantee: iam.IGrantable, ...actions: string[]) { - return iam.Grant.addToPrincipal({ + return iam.Grant.addToPrincipalOrResource({ grantee, actions, // A LogGroup ARN out of CloudFormation already includes a ':*' at the end to include the log streams under the group. // See https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-logs-loggroup.html#w2ab1c21c10c63c43c11 resourceArns: [this.logGroupArn], - scope: this, + resource: this, }); } @@ -186,6 +190,19 @@ abstract class LogGroupBase extends Resource implements ILogGroup { public logGroupPhysicalName(): string { return this.physicalName; } + + /** + * Adds a statement to the resource policy associated with this log group. + * A resource policy will be automatically created upon the first call to `addToResourcePolicy`. + * @param statement The policy statement to add + */ + public addToResourcePolicy(statement: iam.PolicyStatement): iam.AddToResourcePolicyResult { + if (!this.policy) { + this.policy = new ResourcePolicy(this, 'Policy'); + } + this.policy.document.addStatements(statement); + return { statementAdded: true, policyDependable: this.policy }; + } } /** diff --git a/packages/@aws-cdk/aws-logs/lib/policy.ts b/packages/@aws-cdk/aws-logs/lib/policy.ts new file mode 100644 index 0000000000000..974f517d48b25 --- /dev/null +++ b/packages/@aws-cdk/aws-logs/lib/policy.ts @@ -0,0 +1,47 @@ +import { PolicyDocument, PolicyStatement } from '@aws-cdk/aws-iam'; +import { Resource, Lazy, Names } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import { CfnResourcePolicy } from './logs.generated'; + +/** + * Properties to define Cloudwatch log group resource policy + */ +export interface ResourcePolicyProps { + /** + * Name of the log group resource policy + * @default - Uses a unique id based on the construct path + */ + readonly policyName?: string; + + /** + * Initial statements to add to the resource policy + * + * @default - No statements + */ + readonly policyStatements?: PolicyStatement[]; +} + +/** + * Creates Cloudwatch log group resource policies + */ +export class ResourcePolicy extends Resource { + /** + * The IAM policy document for this resource policy. + */ + public readonly document = new PolicyDocument(); + + constructor(scope: Construct, id: string, props?: ResourcePolicyProps) { + super(scope, id); + new CfnResourcePolicy(this, 'Resource', { + policyName: Lazy.string({ + produce: () => props?.policyName ?? Names.uniqueId(this), + }), + policyDocument: Lazy.string({ + produce: () => JSON.stringify(this.document), + }), + }); + if (props?.policyStatements) { + this.document.addStatements(...props.policyStatements); + } + } +} diff --git a/packages/@aws-cdk/aws-logs/package.json b/packages/@aws-cdk/aws-logs/package.json index a21e787888c1c..fa78fe76b2c9f 100644 --- a/packages/@aws-cdk/aws-logs/package.json +++ b/packages/@aws-cdk/aws-logs/package.json @@ -77,13 +77,13 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.84", + "@types/aws-lambda": "^8.10.85", "@types/jest": "^26.0.24", "@types/sinon": "^9.0.11", "aws-sdk": "^2.848.0", "aws-sdk-mock": "^5.4.0", "jest": "^26.6.3", - "nock": "^13.1.3", + "nock": "^13.1.4", "sinon": "^9.2.4" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-logs/test/loggroup.test.ts b/packages/@aws-cdk/aws-logs/test/loggroup.test.ts index 72b3c390a2f96..d7fa5cb600b76 100644 --- a/packages/@aws-cdk/aws-logs/test/loggroup.test.ts +++ b/packages/@aws-cdk/aws-logs/test/loggroup.test.ts @@ -335,6 +335,57 @@ describe('log group', () => { }); + test('grant to service principal', () => { + // GIVEN + const stack = new Stack(); + const lg = new LogGroup(stack, 'LogGroup'); + const sp = new iam.ServicePrincipal('es.amazonaws.com'); + + // WHEN + lg.grantWrite(sp); + + // THEN + expect(stack).toHaveResource('AWS::Logs::ResourcePolicy', { + PolicyDocument: { + 'Fn::Join': [ + '', + [ + '{"Statement":[{"Action":["logs:CreateLogStream","logs:PutLogEvents"],"Effect":"Allow","Principal":{"Service":"es.amazonaws.com"},"Resource":"', + { + 'Fn::GetAtt': [ + 'LogGroupF5B46931', + 'Arn', + ], + }, + '"}],"Version":"2012-10-17"}', + ], + ], + }, + PolicyName: 'LogGroupPolicy643B329C', + }); + + }); + + + test('can add a policy to the log group', () => { + // GIVEN + const stack = new Stack(); + const lg = new LogGroup(stack, 'LogGroup'); + + // WHEN + lg.addToResourcePolicy(new iam.PolicyStatement({ + resources: ['*'], + actions: ['logs:PutLogEvents'], + principals: [new iam.ArnPrincipal('arn:aws:iam::123456789012:user/user-name')], + })); + + // THEN + expect(stack).toHaveResource('AWS::Logs::ResourcePolicy', { + PolicyDocument: '{"Statement":[{"Action":"logs:PutLogEvents","Effect":"Allow","Principal":{"AWS":"arn:aws:iam::123456789012:user/user-name"},"Resource":"*"}],"Version":"2012-10-17"}', + PolicyName: 'LogGroupPolicy643B329C', + }); + }); + test('correctly returns physical name of the log group', () => { // GIVEN const stack = new Stack(); diff --git a/packages/@aws-cdk/aws-opensearchservice/test/integ.opensearch.custom-kms-key.expected.json b/packages/@aws-cdk/aws-opensearchservice/test/integ.opensearch.custom-kms-key.expected.json index 5a2791399497d..63a1cb0c236d5 100644 --- a/packages/@aws-cdk/aws-opensearchservice/test/integ.opensearch.custom-kms-key.expected.json +++ b/packages/@aws-cdk/aws-opensearchservice/test/integ.opensearch.custom-kms-key.expected.json @@ -232,7 +232,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters5d4cb1694db181d27240b1dabc7e4d79a7e1051022a41b773652782433c07f7dS3BucketF2AC65B6" + "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E" }, "S3Key": { "Fn::Join": [ @@ -245,7 +245,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters5d4cb1694db181d27240b1dabc7e4d79a7e1051022a41b773652782433c07f7dS3VersionKey8025D5E5" + "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" } ] } @@ -258,7 +258,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters5d4cb1694db181d27240b1dabc7e4d79a7e1051022a41b773652782433c07f7dS3VersionKey8025D5E5" + "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" } ] } @@ -285,17 +285,17 @@ } }, "Parameters": { - "AssetParameters5d4cb1694db181d27240b1dabc7e4d79a7e1051022a41b773652782433c07f7dS3BucketF2AC65B6": { + "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E": { "Type": "String", - "Description": "S3 bucket for asset \"5d4cb1694db181d27240b1dabc7e4d79a7e1051022a41b773652782433c07f7d\"" + "Description": "S3 bucket for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" }, - "AssetParameters5d4cb1694db181d27240b1dabc7e4d79a7e1051022a41b773652782433c07f7dS3VersionKey8025D5E5": { + "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632": { "Type": "String", - "Description": "S3 key for asset version \"5d4cb1694db181d27240b1dabc7e4d79a7e1051022a41b773652782433c07f7d\"" + "Description": "S3 key for asset version \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" }, - "AssetParameters5d4cb1694db181d27240b1dabc7e4d79a7e1051022a41b773652782433c07f7dArtifactHash30B93F3B": { + "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2ArtifactHash4BE92B79": { "Type": "String", - "Description": "Artifact hash for asset \"5d4cb1694db181d27240b1dabc7e4d79a7e1051022a41b773652782433c07f7d\"" + "Description": "Artifact hash for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-opensearchservice/test/integ.opensearch.expected.json b/packages/@aws-cdk/aws-opensearchservice/test/integ.opensearch.expected.json index f317e3a7eb835..da98a9b24ab35 100644 --- a/packages/@aws-cdk/aws-opensearchservice/test/integ.opensearch.expected.json +++ b/packages/@aws-cdk/aws-opensearchservice/test/integ.opensearch.expected.json @@ -296,7 +296,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters0036020ad5459434aa7b01d7769825c4b189b2a7722cc47c4a1bc6dbd9ccf85eS3BucketF2C16119" + "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E" }, "S3Key": { "Fn::Join": [ @@ -309,7 +309,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters0036020ad5459434aa7b01d7769825c4b189b2a7722cc47c4a1bc6dbd9ccf85eS3VersionKey60E022E2" + "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" } ] } @@ -322,7 +322,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters0036020ad5459434aa7b01d7769825c4b189b2a7722cc47c4a1bc6dbd9ccf85eS3VersionKey60E022E2" + "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" } ] } @@ -608,17 +608,17 @@ } }, "Parameters": { - "AssetParameters0036020ad5459434aa7b01d7769825c4b189b2a7722cc47c4a1bc6dbd9ccf85eS3BucketF2C16119": { + "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E": { "Type": "String", - "Description": "S3 bucket for asset \"0036020ad5459434aa7b01d7769825c4b189b2a7722cc47c4a1bc6dbd9ccf85e\"" + "Description": "S3 bucket for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" }, - "AssetParameters0036020ad5459434aa7b01d7769825c4b189b2a7722cc47c4a1bc6dbd9ccf85eS3VersionKey60E022E2": { + "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632": { "Type": "String", - "Description": "S3 key for asset version \"0036020ad5459434aa7b01d7769825c4b189b2a7722cc47c4a1bc6dbd9ccf85e\"" + "Description": "S3 key for asset version \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" }, - "AssetParameters0036020ad5459434aa7b01d7769825c4b189b2a7722cc47c4a1bc6dbd9ccf85eArtifactHash4E1710B0": { + "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2ArtifactHash4BE92B79": { "Type": "String", - "Description": "Artifact hash for asset \"0036020ad5459434aa7b01d7769825c4b189b2a7722cc47c4a1bc6dbd9ccf85e\"" + "Description": "Artifact hash for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-opensearchservice/test/integ.opensearch.unsignedbasicauth.expected.json b/packages/@aws-cdk/aws-opensearchservice/test/integ.opensearch.unsignedbasicauth.expected.json index c2e8d28a0d35f..b1a9048f14dc1 100644 --- a/packages/@aws-cdk/aws-opensearchservice/test/integ.opensearch.unsignedbasicauth.expected.json +++ b/packages/@aws-cdk/aws-opensearchservice/test/integ.opensearch.unsignedbasicauth.expected.json @@ -8,7 +8,9 @@ "GenerateStringKey": "password", "SecretStringTemplate": "{\"username\":\"admin\"}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "Domain66AC69E0": { "Type": "AWS::OpenSearchService::Domain", @@ -191,7 +193,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters5d4cb1694db181d27240b1dabc7e4d79a7e1051022a41b773652782433c07f7dS3BucketF2AC65B6" + "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E" }, "S3Key": { "Fn::Join": [ @@ -204,7 +206,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters5d4cb1694db181d27240b1dabc7e4d79a7e1051022a41b773652782433c07f7dS3VersionKey8025D5E5" + "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" } ] } @@ -217,7 +219,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters5d4cb1694db181d27240b1dabc7e4d79a7e1051022a41b773652782433c07f7dS3VersionKey8025D5E5" + "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" } ] } @@ -243,17 +245,17 @@ } }, "Parameters": { - "AssetParameters5d4cb1694db181d27240b1dabc7e4d79a7e1051022a41b773652782433c07f7dS3BucketF2AC65B6": { + "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E": { "Type": "String", - "Description": "S3 bucket for asset \"5d4cb1694db181d27240b1dabc7e4d79a7e1051022a41b773652782433c07f7d\"" + "Description": "S3 bucket for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" }, - "AssetParameters5d4cb1694db181d27240b1dabc7e4d79a7e1051022a41b773652782433c07f7dS3VersionKey8025D5E5": { + "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632": { "Type": "String", - "Description": "S3 key for asset version \"5d4cb1694db181d27240b1dabc7e4d79a7e1051022a41b773652782433c07f7d\"" + "Description": "S3 key for asset version \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" }, - "AssetParameters5d4cb1694db181d27240b1dabc7e4d79a7e1051022a41b773652782433c07f7dArtifactHash30B93F3B": { + "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2ArtifactHash4BE92B79": { "Type": "String", - "Description": "Artifact hash for asset \"5d4cb1694db181d27240b1dabc7e4d79a7e1051022a41b773652782433c07f7d\"" + "Description": "Artifact hash for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-panorama/.eslintrc.js b/packages/@aws-cdk/aws-panorama/.eslintrc.js new file mode 100644 index 0000000000000..2658ee8727166 --- /dev/null +++ b/packages/@aws-cdk/aws-panorama/.eslintrc.js @@ -0,0 +1,3 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-panorama/.gitignore b/packages/@aws-cdk/aws-panorama/.gitignore new file mode 100644 index 0000000000000..62ebc95d75ce6 --- /dev/null +++ b/packages/@aws-cdk/aws-panorama/.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-panorama/.npmignore b/packages/@aws-cdk/aws-panorama/.npmignore new file mode 100644 index 0000000000000..f931fede67c44 --- /dev/null +++ b/packages/@aws-cdk/aws-panorama/.npmignore @@ -0,0 +1,29 @@ +# 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/ +!*.lit.ts diff --git a/packages/@aws-cdk/aws-panorama/LICENSE b/packages/@aws-cdk/aws-panorama/LICENSE new file mode 100644 index 0000000000000..28e4bdcec77ec --- /dev/null +++ b/packages/@aws-cdk/aws-panorama/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-panorama/NOTICE b/packages/@aws-cdk/aws-panorama/NOTICE new file mode 100644 index 0000000000000..5fc3826926b5b --- /dev/null +++ b/packages/@aws-cdk/aws-panorama/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-panorama/README.md b/packages/@aws-cdk/aws-panorama/README.md new file mode 100644 index 0000000000000..334264b4ea581 --- /dev/null +++ b/packages/@aws-cdk/aws-panorama/README.md @@ -0,0 +1,20 @@ +# AWS::Panorama 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 aws-panorama = require('@aws-cdk/aws-panorama'); +``` diff --git a/packages/@aws-cdk/aws-panorama/jest.config.js b/packages/@aws-cdk/aws-panorama/jest.config.js new file mode 100644 index 0000000000000..3a2fd93a1228a --- /dev/null +++ b/packages/@aws-cdk/aws-panorama/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-panorama/lib/index.ts b/packages/@aws-cdk/aws-panorama/lib/index.ts new file mode 100644 index 0000000000000..1ef8b1378379a --- /dev/null +++ b/packages/@aws-cdk/aws-panorama/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::Panorama CloudFormation Resources: +export * from './panorama.generated'; diff --git a/packages/@aws-cdk/aws-panorama/package.json b/packages/@aws-cdk/aws-panorama/package.json new file mode 100644 index 0000000000000..08af6d8c5a82d --- /dev/null +++ b/packages/@aws-cdk/aws-panorama/package.json @@ -0,0 +1,105 @@ +{ + "name": "@aws-cdk/aws-panorama", + "version": "0.0.0", + "description": "The CDK Construct Library for AWS::Panorama", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "projectReferences": true, + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.Panorama", + "packageId": "Amazon.CDK.AWS.Panorama", + "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.panorama", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "panorama" + } + }, + "python": { + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 1" + ], + "distName": "aws-cdk.aws-panorama", + "module": "aws_cdk.aws_panorama" + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-panorama" + }, + "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", + "build+extract": "yarn build && yarn rosetta:extract", + "build+test+extract": "yarn build+test && yarn rosetta:extract" + }, + "cdk-build": { + "cloudformation": "AWS::Panorama", + "jest": true, + "env": { + "AWSLINT_BASE_CONSTRUCT": "true" + } + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::Panorama", + "aws-panorama" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.22" + }, + "dependencies": { + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" + }, + "peerDependencies": { + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" + }, + "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-panorama/test/aws-panorama.test.ts b/packages/@aws-cdk/aws-panorama/test/aws-panorama.test.ts new file mode 100644 index 0000000000000..465c7bdea0693 --- /dev/null +++ b/packages/@aws-cdk/aws-panorama/test/aws-panorama.test.ts @@ -0,0 +1,6 @@ +import '@aws-cdk/assertions'; +import {} from '../lib'; + +test('No tests are specified for this package', () => { + expect(true).toBe(true); +}); diff --git a/packages/@aws-cdk/aws-rds/README.md b/packages/@aws-cdk/aws-rds/README.md index cad785735dfb6..9f350d3dd1f5b 100644 --- a/packages/@aws-cdk/aws-rds/README.md +++ b/packages/@aws-cdk/aws-rds/README.md @@ -12,7 +12,7 @@ -```ts +```ts nofixture import * as rds from '@aws-cdk/aws-rds'; ``` @@ -23,6 +23,7 @@ always launch a database in a VPC. Use the `vpcSubnets` attribute to control whe your instances will be launched privately or publicly: ```ts +declare const vpc: ec2.Vpc; const cluster = new rds.DatabaseCluster(this, 'Database', { engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_2_08_1 }), credentials: rds.Credentials.fromGeneratedSecret('clusteradmin'), // Optional - will default to 'admin' username and generated password @@ -52,7 +53,8 @@ Your cluster will be empty by default. To add a default database upon constructi Use `DatabaseClusterFromSnapshot` to create a cluster from a snapshot: ```ts -new rds.DatabaseClusterFromSnapshot(stack, 'Database', { +declare const vpc: ec2.Vpc; +new rds.DatabaseClusterFromSnapshot(this, 'Database', { engine: rds.DatabaseClusterEngine.aurora({ version: rds.AuroraEngineVersion.VER_1_22_2 }), instanceProps: { vpc, @@ -68,6 +70,7 @@ always launch a database in a VPC. Use the `vpcSubnets` attribute to control whe your instances will be launched privately or publicly: ```ts +declare const vpc: ec2.Vpc; const instance = new rds.DatabaseInstance(this, 'Instance', { engine: rds.DatabaseInstanceEngine.oracleSe2({ version: rds.OracleEngineVersion.VER_19_0_0_0_2020_04_R1 }), // optional, defaults to m5.large @@ -75,7 +78,7 @@ const instance = new rds.DatabaseInstance(this, 'Instance', { credentials: rds.Credentials.fromGeneratedSecret('syscdk'), // Optional - will default to 'admin' username and generated password vpc, vpcSubnets: { - subnetType: ec2.SubnetType.PRIVATE + subnetType: ec2.SubnetType.PRIVATE, } }); ``` @@ -95,6 +98,7 @@ This is the upper limit to which RDS can automatically scale the storage. More i Example for max storage configuration: ```ts +declare const vpc: ec2.Vpc; const instance = new rds.DatabaseInstance(this, 'Instance', { engine: rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_12_3 }), // optional, defaults to m5.large @@ -108,7 +112,8 @@ Use `DatabaseInstanceFromSnapshot` and `DatabaseInstanceReadReplica` to create a a source database respectively: ```ts -new rds.DatabaseInstanceFromSnapshot(stack, 'Instance', { +declare const vpc: ec2.Vpc; +new rds.DatabaseInstanceFromSnapshot(this, 'Instance', { snapshotIdentifier: 'my-snapshot', engine: rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_12_3 }), // optional, defaults to m5.large @@ -116,7 +121,8 @@ new rds.DatabaseInstanceFromSnapshot(stack, 'Instance', { vpc, }); -new rds.DatabaseInstanceReadReplica(stack, 'ReadReplica', { +declare const sourceInstance: rds.DatabaseInstance; +new rds.DatabaseInstanceReadReplica(this, 'ReadReplica', { sourceDatabaseInstance: sourceInstance, instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.LARGE), vpc, @@ -136,8 +142,9 @@ The default value depends on `vpcSubnets`. It will be `true` if `vpcSubnets` is `subnetType: SubnetType.PUBLIC`, `false` otherwise. ```ts +declare const vpc: ec2.Vpc; // Setting public accessibility for DB instance -new rds.DatabaseInstance(stack, 'Instance', { +new rds.DatabaseInstance(this, 'Instance', { engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19, }), @@ -149,15 +156,14 @@ new rds.DatabaseInstance(stack, 'Instance', { }); // Setting public accessibility for DB cluster -new rds.DatabaseCluster(stack, 'DatabaseCluster', { - engine: DatabaseClusterEngine.AURORA, +new rds.DatabaseCluster(this, 'DatabaseCluster', { + engine: rds.DatabaseClusterEngine.AURORA, instanceProps: { vpc, vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE, }, publiclyAccessible: true, - copyTagsToSnapshot: true, // whether to save the cluster tags when creating the snapshot. Default is 'true' }, }); ``` @@ -168,6 +174,8 @@ To define Amazon CloudWatch event rules for database instances, use the `onEvent method: ```ts +declare const instance: rds.DatabaseInstance; +declare const fn: lambda.Function; const rule = instance.onEvent('InstanceEvent', { target: new targets.LambdaFunction(fn) }); ``` @@ -179,6 +187,7 @@ An alternative username (and password) may be specified for the admin user inste The following examples use a `DatabaseInstance`, but the same usage is applicable to `DatabaseCluster`. ```ts +declare const vpc: ec2.Vpc; const engine = rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_12_3 }); new rds.DatabaseInstance(this, 'InstanceWithUsername', { engine, @@ -203,7 +212,9 @@ new rds.DatabaseInstance(this, 'InstanceWithSecretLogin', { Secrets generated by `fromGeneratedSecret()` can be customized: ```ts -const myKey = kms.Key(this, 'MyKey'); +declare const vpc: ec2.Vpc; +const engine = rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_12_3 }); +const myKey = new kms.Key(this, 'MyKey'); new rds.DatabaseInstance(this, 'InstanceWithCustomizedSecret', { engine, @@ -211,7 +222,7 @@ new rds.DatabaseInstance(this, 'InstanceWithCustomizedSecret', { credentials: rds.Credentials.fromGeneratedSecret('postgres', { secretName: 'my-cool-name', encryptionKey: myKey, - excludeCharacters: ['!&*^#@()'], + excludeCharacters: '!&*^#@()', replicaRegions: [{ region: 'eu-west-1' }, { region: 'eu-west-2' }], }), }); @@ -223,19 +234,22 @@ To control who can access the cluster or instance, use the `.connections` attrib a default port, so you don't need to specify the port: ```ts -cluster.connections.allowFromAnyIpv4('Open to the world'); +declare const cluster: rds.DatabaseCluster; +cluster.connections.allowFromAnyIpv4(ec2.Port.allTraffic(), 'Open to the world'); ``` The endpoints to access your database cluster will be available as the `.clusterEndpoint` and `.readerEndpoint` attributes: ```ts +declare const cluster: rds.DatabaseCluster; const writeAddress = cluster.clusterEndpoint.socketAddress; // "HOSTNAME:PORT" ``` For an instance database: ```ts +declare const instance: rds.DatabaseInstance; const address = instance.instanceEndpoint.socketAddress; // "HOSTNAME:PORT" ``` @@ -244,6 +258,9 @@ const address = instance.instanceEndpoint.socketAddress; // "HOSTNAME:PORT" When the master password is generated and stored in AWS Secrets Manager, it can be rotated automatically: ```ts +import * as cdk from '@aws-cdk/core'; + +declare const instance: rds.DatabaseInstance; instance.addRotationSingleUser({ automaticallyAfter: cdk.Duration.days(7), // defaults to 30 days excludeCharacters: '!@#$%^&*', // defaults to the set " %+~`#$&*()|[]{}:;<>?!'/@\"\\" @@ -255,6 +272,8 @@ instance.addRotationSingleUser({ The multi user rotation scheme is also available: ```ts +declare const instance: rds.DatabaseInstance; +declare const myImportedSecret: rds.DatabaseSecret; instance.addRotationMultiUser('MyUser', { secret: myImportedSecret, // This secret must have the `masterarn` key }); @@ -263,6 +282,7 @@ instance.addRotationMultiUser('MyUser', { It's also possible to create user credentials together with the instance/cluster and add rotation: ```ts +declare const instance: rds.DatabaseInstance; const myUserSecret = new rds.DatabaseSecret(this, 'MyUserSecret', { username: 'myuser', secretName: 'my-user-secret', // optional, defaults to a CloudFormation-generated name @@ -279,6 +299,21 @@ instance.addRotationMultiUser('MyUser', { // Add rotation using the multi user s **Note**: This user must be created manually in the database using the master credentials. The rotation will start as soon as this user exists. +Access to the Secrets Manager API is required for the secret rotation. This can be achieved either with +internet connectivity (through NAT) or with a VPC interface endpoint. By default, the rotation Lambda function +is deployed in the same subnets as the instance/cluster. If access to the Secrets Manager API is not possible from +those subnets or using the default API endpoint, use the `vpcSubnets` and/or `endpoint` options: + +```ts +declare const instance: rds.DatabaseInstance; +declare const myEndpoint: ec2.InterfaceVpcEndpoint; + +instance.addRotationSingleUser({ + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_NAT }, // Place rotation Lambda in private subnets + endpoint: myEndpoint, // Use VPC interface endpoint +}); +``` + See also [@aws-cdk/aws-secretsmanager](https://github.com/aws/aws-cdk/blob/master/packages/%40aws-cdk/aws-secretsmanager/README.md) for credentials rotation of existing clusters/instances. ## IAM Authentication @@ -290,30 +325,32 @@ and a list of supported versions and limitations. The following example shows enabling IAM authentication for a database instance and granting connection access to an IAM role. ```ts -const instance = new rds.DatabaseInstance(stack, 'Instance', { +declare const vpc: ec2.Vpc; +const instance = new rds.DatabaseInstance(this, 'Instance', { engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19 }), vpc, iamAuthentication: true, // Optional - will be automatically set if you call grantConnect(). }); -const role = new Role(stack, 'DBRole', { assumedBy: new AccountPrincipal(stack.account) }); +const role = new iam.Role(this, 'DBRole', { assumedBy: new iam.AccountPrincipal(this.account) }); instance.grantConnect(role); // Grant the role connection access to the DB. ``` The following example shows granting connection access for RDS Proxy to an IAM role. ```ts -const cluster = new rds.DatabaseCluster(stack, 'Database', { +declare const vpc: ec2.Vpc; +const cluster = new rds.DatabaseCluster(this, 'Database', { engine: rds.DatabaseClusterEngine.AURORA, instanceProps: { vpc }, }); -const proxy = new rds.DatabaseProxy(stack, 'Proxy', { +const proxy = new rds.DatabaseProxy(this, 'Proxy', { proxyTarget: rds.ProxyTarget.fromCluster(cluster), secrets: [cluster.secret!], vpc, }); -const role = new Role(stack, 'DBProxyRole', { assumedBy: new AccountPrincipal(stack.account) }); +const role = new iam.Role(this, 'DBProxyRole', { assumedBy: new iam.AccountPrincipal(this.account) }); proxy.grantConnect(role, 'admin'); // Grant the role connection access to the DB Proxy for database user 'admin'. ``` @@ -330,13 +367,14 @@ The following example shows enabling domain support for a database instance and Directory Services. ```ts -const role = new iam.Role(stack, 'RDSDirectoryServicesRole', { +declare const vpc: ec2.Vpc; +const role = new iam.Role(this, 'RDSDirectoryServicesRole', { assumedBy: new iam.ServicePrincipal('rds.amazonaws.com'), managedPolicies: [ iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonRDSDirectoryServiceAccess'), ], }); -const instance = new rds.DatabaseInstance(stack, 'Instance', { +const instance = new rds.DatabaseInstance(this, 'Instance', { engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19 }), vpc, domain: 'd-????????', // The ID of the domain for the instance to join. @@ -356,13 +394,15 @@ Database instances and clusters both expose metrics (`cloudwatch.Metric`): ```ts // The number of database connections in use (average over 5 minutes) +declare const instance: rds.DatabaseInstance; const dbConnections = instance.metricDatabaseConnections(); // Average CPU utilization over 5 minutes +declare const cluster: rds.DatabaseCluster; const cpuUtilization = cluster.metricCPUUtilization(); // The average amount of time taken per disk I/O operation (average over 1 minute) -const readLatency = instance.metric('ReadLatency', { statistic: 'Average', periodSec: 60 }); +const readLatency = instance.metric('ReadLatency', { statistic: 'Average', period: Duration.seconds(60) }); ``` ## Enabling S3 integration @@ -388,10 +428,14 @@ The following snippet sets up a database cluster with different S3 buckets where ```ts import * as s3 from '@aws-cdk/aws-s3'; +declare const vpc: ec2.Vpc; const importBucket = new s3.Bucket(this, 'importbucket'); const exportBucket = new s3.Bucket(this, 'exportbucket'); new rds.DatabaseCluster(this, 'dbcluster', { - // ... + engine: rds.DatabaseClusterEngine.AURORA, + instanceProps: { + vpc, + }, s3ImportBuckets: [importBucket], s3ExportBuckets: [exportBucket], }); @@ -405,18 +449,13 @@ connections to the database and improve scalability of the application. Learn mo The following code configures an RDS Proxy for a `DatabaseInstance`. ```ts -import * as cdk from '@aws-cdk/core'; -import * as ec2 from '@aws-cdk/aws-ec2'; -import * as rds from '@aws-cdk/aws-rds'; -import * as secrets from '@aws-cdk/aws-secretsmanager'; - -const vpc: ec2.IVpc = ...; -const securityGroup: ec2.ISecurityGroup = ...; -const secrets: secrets.ISecret[] = [...]; -const dbInstance: rds.IDatabaseInstance = ...; +declare const vpc: ec2.Vpc; +declare const securityGroup: ec2.SecurityGroup; +declare const secrets: secretsmanager.Secret[]; +declare const dbInstance: rds.DatabaseInstance; const proxy = dbInstance.addProxy('proxy', { - connectionBorrowTimeout: cdk.Duration.seconds(30), + borrowTimeout: Duration.seconds(30), maxConnectionsPercent: 50, secrets, vpc, @@ -430,12 +469,18 @@ store the data in highly durable storage, and manage the data with the CloudWatc instances and clusters; the types of logs available depend on the database type and engine being used. ```ts +import * as logs from '@aws-cdk/aws-logs'; +declare const myLogsPublishingRole: iam.Role; +declare const vpc: ec2.Vpc; + // Exporting logs from a cluster const cluster = new rds.DatabaseCluster(this, 'Database', { engine: rds.DatabaseClusterEngine.aurora({ version: rds.AuroraEngineVersion.VER_1_17_9, // different version class for each engine type + }), + instanceProps: { + vpc, }, - // ... cloudwatchLogsExports: ['error', 'general', 'slowquery', 'audit'], // Export all available MySQL-based logs cloudwatchLogsRetention: logs.RetentionDays.THREE_MONTHS, // Optional - default is to never expire logs cloudwatchLogsRetentionRole: myLogsPublishingRole, // Optional - a role will be created if not provided @@ -447,7 +492,7 @@ const instance = new rds.DatabaseInstance(this, 'Instance', { engine: rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_12_3, }), - // ... + vpc, cloudwatchLogsExports: ['postgresql'], // Export the PostgreSQL logs // ... }); @@ -460,9 +505,10 @@ Amazon RDS uses option groups to enable and configure these features. An option that are available for a particular Amazon RDS DB instance. ```ts -const vpc: ec2.IVpc = ...; -const securityGroup: ec2.ISecurityGroup = ...; -new rds.OptionGroup(stack, 'Options', { +declare const vpc: ec2.Vpc; +declare const securityGroup: ec2.SecurityGroup; + +new rds.OptionGroup(this, 'Options', { engine: rds.DatabaseInstanceEngine.oracleSe2({ version: rds.OracleEngineVersion.VER_19, }), @@ -489,10 +535,7 @@ Aurora Serverless clusters can specify scaling properties which will be used to automatically scale the database cluster seamlessly based on the workload. ```ts -import * as ec2 from '@aws-cdk/aws-ec2'; -import * as rds from '@aws-cdk/aws-rds'; - -const vpc = new ec2.Vpc(this, 'myrdsvpc'); +declare const vpc: ec2.Vpc; const cluster = new rds.ServerlessCluster(this, 'AnotherCluster', { engine: rds.DatabaseClusterEngine.AURORA_POSTGRESQL, @@ -532,11 +575,7 @@ You can access your Aurora Serverless DB cluster using the built-in Data API. Th The following example shows granting Data API access to a Lamba function. ```ts -import * as ec2 from '@aws-cdk/aws-ec2'; -import * as lambda from '@aws-cdk/aws-lambda'; -import * as rds from '@aws-cdk/aws-rds'; - -const vpc = new ec2.Vpc(this, 'MyVPC'); +declare const vpc: ec2.Vpc; const cluster = new rds.ServerlessCluster(this, 'AnotherCluster', { engine: rds.DatabaseClusterEngine.AURORA_MYSQL, @@ -544,16 +583,17 @@ const cluster = new rds.ServerlessCluster(this, 'AnotherCluster', { enableDataApi: true, // Optional - will be automatically set if you call grantDataApiAccess() }); +declare const code: lambda.Code; const fn = new lambda.Function(this, 'MyFunction', { runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', - code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), + code, environment: { CLUSTER_ARN: cluster.clusterArn, - SECRET_ARN: cluster.secret.secretArn, + SECRET_ARN: cluster.secret!.secretArn, }, }); -cluster.grantDataApiAccess(fn) +cluster.grantDataApiAccess(fn); ``` **Note**: To invoke the Data API, the resource will need to read the secret associated with the cluster. diff --git a/packages/@aws-cdk/aws-rds/lib/cluster-engine.ts b/packages/@aws-cdk/aws-rds/lib/cluster-engine.ts index 606fddd75edbf..cde235257ff8e 100644 --- a/packages/@aws-cdk/aws-rds/lib/cluster-engine.ts +++ b/packages/@aws-cdk/aws-rds/lib/cluster-engine.ts @@ -451,6 +451,8 @@ export class AuroraPostgresEngineVersion { public static readonly VER_10_14 = AuroraPostgresEngineVersion.of('10.14', '10', { s3Import: true, s3Export: true }); /** Version "10.16". */ public static readonly VER_10_16 = AuroraPostgresEngineVersion.of('10.16', '10', { s3Import: true, s3Export: true }); + /** Version "10.18". */ + public static readonly VER_10_18 = AuroraPostgresEngineVersion.of('10.18', '10', { s3Import: true, s3Export: true }); /** Version "11.4". */ public static readonly VER_11_4 = AuroraPostgresEngineVersion.of('11.4', '11', { s3Import: true }); /** Version "11.6". */ @@ -463,12 +465,18 @@ export class AuroraPostgresEngineVersion { public static readonly VER_11_9 = AuroraPostgresEngineVersion.of('11.9', '11', { s3Import: true, s3Export: true }); /** Version "11.11". */ public static readonly VER_11_11 = AuroraPostgresEngineVersion.of('11.11', '11', { s3Import: true, s3Export: true }); + /** Version "11.13". */ + public static readonly VER_11_13 = AuroraPostgresEngineVersion.of('11.13', '11', { s3Import: true, s3Export: true }); /** Version "12.4". */ public static readonly VER_12_4 = AuroraPostgresEngineVersion.of('12.4', '12', { s3Import: true, s3Export: true }); /** Version "12.6". */ public static readonly VER_12_6 = AuroraPostgresEngineVersion.of('12.6', '12', { s3Import: true, s3Export: true }); + /** Version "12.8". */ + public static readonly VER_12_8 = AuroraPostgresEngineVersion.of('12.8', '12', { s3Import: true, s3Export: true }); /** Version "13.3". */ public static readonly VER_13_3 = AuroraPostgresEngineVersion.of('13.3', '13', { s3Import: true, s3Export: true }); + /** Version "13.4". */ + public static readonly VER_13_4 = AuroraPostgresEngineVersion.of('13.4', '13', { s3Import: true, s3Export: true }); /** * Create a new AuroraPostgresEngineVersion with an arbitrary version. diff --git a/packages/@aws-cdk/aws-rds/lib/instance-engine.ts b/packages/@aws-cdk/aws-rds/lib/instance-engine.ts index dfea03877a0d2..05d045e56c8f3 100644 --- a/packages/@aws-cdk/aws-rds/lib/instance-engine.ts +++ b/packages/@aws-cdk/aws-rds/lib/instance-engine.ts @@ -497,6 +497,8 @@ export class MysqlEngineVersion { public static readonly VER_8_0_23 = MysqlEngineVersion.of('8.0.23', '8.0'); /** Version "8.0.25". */ public static readonly VER_8_0_25 = MysqlEngineVersion.of('8.0.25', '8.0'); + /** Version "8.0.26". */ + public static readonly VER_8_0_26 = MysqlEngineVersion.of('8.0.26', '8.0'); /** * Create a new MysqlEngineVersion with an arbitrary version. diff --git a/packages/@aws-cdk/aws-rds/lib/props.ts b/packages/@aws-cdk/aws-rds/lib/props.ts index e9ed3c126cd65..50577cf4dde29 100644 --- a/packages/@aws-cdk/aws-rds/lib/props.ts +++ b/packages/@aws-cdk/aws-rds/lib/props.ts @@ -468,6 +468,25 @@ interface CommonRotationUserOptions { * @default " %+~`#$&*()|[]{}:;<>?!'/@\"\\" */ readonly excludeCharacters?: string; + + /** + * Where to place the rotation Lambda function + * + * @default - same placement as instance or cluster + */ + readonly vpcSubnets?: ec2.SubnetSelection; + + /** + * The VPC interface endpoint to use for the Secrets Manager API + * + * If you enable private DNS hostnames for your VPC private endpoint (the default), you don't + * need to specify an endpoint. The standard Secrets Manager DNS hostname the Secrets Manager + * CLI and SDKs use by default (https://secretsmanager..amazonaws.com) automatically + * resolves to your VPC endpoint. + * + * @default https://secretsmanager..amazonaws.com + */ + readonly endpoint?: ec2.IInterfaceVpcEndpoint; } /** diff --git a/packages/@aws-cdk/aws-rds/rosetta/default.ts-fixture b/packages/@aws-cdk/aws-rds/rosetta/default.ts-fixture new file mode 100644 index 0000000000000..7e78fde1372a1 --- /dev/null +++ b/packages/@aws-cdk/aws-rds/rosetta/default.ts-fixture @@ -0,0 +1,18 @@ +// Fixture with packages imported, but nothing else +import { Duration, SecretValue, Stack } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import ec2 = require('@aws-cdk/aws-ec2'); +import rds = require('@aws-cdk/aws-rds'); +import targets = require('@aws-cdk/aws-events-targets'); +import lambda = require('@aws-cdk/aws-lambda'); +import kms = require('@aws-cdk/aws-kms'); +import iam = require('@aws-cdk/aws-iam'); +import secretsmanager = require('@aws-cdk/aws-secretsmanager'); + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + /// here + } +} diff --git a/packages/@aws-cdk/aws-rds/test/cluster.test.ts b/packages/@aws-cdk/aws-rds/test/cluster.test.ts index 5adc3d4906643..35fe439c57857 100644 --- a/packages/@aws-cdk/aws-rds/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-rds/test/cluster.test.ts @@ -722,6 +722,197 @@ describe('cluster', () => { }); + test('addRotationSingleUser()', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA_MYSQL, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + }, + }); + + // WHEN + cluster.addRotationSingleUser(); + + expect(stack).toHaveResource('AWS::SecretsManager::RotationSchedule', { + SecretId: { + Ref: 'DatabaseSecretAttachmentE5D1B020', + }, + RotationLambdaARN: { + 'Fn::GetAtt': [ + 'DatabaseRotationSingleUser65F55654', + 'Outputs.RotationLambdaARN', + ], + }, + RotationRules: { + AutomaticallyAfterDays: 30, + }, + }); + }); + + test('addRotationMultiUser()', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA_MYSQL, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + }, + }); + + const userSecret = new DatabaseSecret(stack, 'UserSecret', { username: 'user' }); + cluster.addRotationMultiUser('user', { secret: userSecret.attach(cluster) }); + + expect(stack).toHaveResource('AWS::SecretsManager::RotationSchedule', { + SecretId: { + Ref: 'UserSecretAttachment16ACBE6D', + }, + RotationLambdaARN: { + 'Fn::GetAtt': [ + 'DatabaseuserECD1FB0C', + 'Outputs.RotationLambdaARN', + ], + }, + RotationRules: { + AutomaticallyAfterDays: 30, + }, + }); + + expect(stack).toHaveResourceLike('AWS::Serverless::Application', { + Parameters: { + masterSecretArn: { + Ref: 'DatabaseSecretAttachmentE5D1B020', + }, + }, + }); + }); + + test('addRotationSingleUser() with options', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpcWithIsolated = new ec2.Vpc(stack, 'Vpc', { + subnetConfiguration: [ + { name: 'public', subnetType: ec2.SubnetType.PUBLIC }, + { name: 'private', subnetType: ec2.SubnetType.PRIVATE_WITH_NAT }, + { name: 'isolated', subnetType: ec2.SubnetType.PRIVATE_ISOLATED }, + ], + }); + + // WHEN + // DB in isolated subnet (no internet connectivity) + const cluster = new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA_MYSQL, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc: vpcWithIsolated, + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED }, + }, + }); + + // Rotation in private subnet (internet via NAT) + cluster.addRotationSingleUser({ + automaticallyAfter: cdk.Duration.days(15), + excludeCharacters: '°_@', + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_NAT }, + }); + + // THEN + expect(stack).toHaveResource('AWS::SecretsManager::RotationSchedule', { + RotationRules: { + AutomaticallyAfterDays: 15, + }, + }); + + expect(stack).toHaveResource('AWS::Serverless::Application', { + Parameters: { + endpoint: { + 'Fn::Join': ['', [ + 'https://secretsmanager.', + { Ref: 'AWS::Region' }, + '.', + { Ref: 'AWS::URLSuffix' }, + ]], + }, + functionName: 'DatabaseRotationSingleUser458A45BE', + vpcSubnetIds: { + 'Fn::Join': ['', [ + { Ref: 'VpcprivateSubnet1SubnetCEAD3716' }, + ',', + { Ref: 'VpcprivateSubnet2Subnet2DE7549C' }, + ]], + }, + vpcSecurityGroupIds: { + 'Fn::GetAtt': [ + 'DatabaseRotationSingleUserSecurityGroupAC6E0E73', + 'GroupId', + ], + }, + excludeCharacters: '°_@', + }, + }); + }); + + + test('addRotationSingleUser() with VPC interface endpoint', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpcIsolatedOnly = new ec2.Vpc(stack, 'Vpc', { natGateways: 0 }); + + const endpoint = new ec2.InterfaceVpcEndpoint(stack, 'Endpoint', { + service: ec2.InterfaceVpcEndpointAwsService.SECRETS_MANAGER, + vpc: vpcIsolatedOnly, + subnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED }, + }); + + // DB in isolated subnet (no internet connectivity) + const cluster = new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA_MYSQL, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc: vpcIsolatedOnly, + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED }, + }, + }); + + // Rotation in isolated subnet with access to Secrets Manager API via endpoint + cluster.addRotationSingleUser({ endpoint }); + + expect(stack).toHaveResource('AWS::Serverless::Application', { + Parameters: { + endpoint: { + 'Fn::Join': ['', [ + 'https://', + { Ref: 'EndpointEEF1FD8F' }, + '.secretsmanager.', + { Ref: 'AWS::Region' }, + '.', + { Ref: 'AWS::URLSuffix' }, + ]], + }, + functionName: 'DatabaseRotationSingleUser458A45BE', + vpcSubnetIds: { + 'Fn::Join': ['', [ + { Ref: 'VpcIsolatedSubnet1SubnetE48C5737' }, + ',', + { Ref: 'VpcIsolatedSubnet2Subnet16364B91' }, + ]], + }, + vpcSecurityGroupIds: { + 'Fn::GetAtt': [ + 'DatabaseRotationSingleUserSecurityGroupAC6E0E73', + 'GroupId', + ], + }, + excludeCharacters: " %+~`#$&*()|[]{}:;<>?!'/@\"\\", + }, + }); + }); + test('throws when trying to add rotation to a cluster without secret', () => { // GIVEN const stack = new cdk.Stack(); diff --git a/packages/@aws-cdk/aws-rds/test/instance.test.ts b/packages/@aws-cdk/aws-rds/test/instance.test.ts index 7364599e4ed25..9f94607eda8ad 100644 --- a/packages/@aws-cdk/aws-rds/test/instance.test.ts +++ b/packages/@aws-cdk/aws-rds/test/instance.test.ts @@ -738,6 +738,184 @@ describe('instance', () => { }); + test('addRotationSingleUser()', () => { + // GIVEN + const instance = new rds.DatabaseInstance(stack, 'Database', { + engine: rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_10 }), + vpc, + }); + + // WHEN + instance.addRotationSingleUser(); + + // THEN + expect(stack).toHaveResource('AWS::SecretsManager::RotationSchedule', { + SecretId: { + Ref: 'DatabaseSecretAttachmentE5D1B020', + }, + RotationLambdaARN: { + 'Fn::GetAtt': [ + 'DatabaseRotationSingleUser65F55654', + 'Outputs.RotationLambdaARN', + ], + }, + RotationRules: { + AutomaticallyAfterDays: 30, + }, + }); + }); + + test('addRotationMultiUser()', () => { + // GIVEN + const instance = new rds.DatabaseInstance(stack, 'Database', { + engine: rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_10 }), + vpc, + }); + + // WHEN + const userSecret = new rds.DatabaseSecret(stack, 'UserSecret', { username: 'user' }); + instance.addRotationMultiUser('user', { secret: userSecret.attach(instance) }); + + // THEN + expect(stack).toHaveResource('AWS::SecretsManager::RotationSchedule', { + SecretId: { + Ref: 'UserSecretAttachment16ACBE6D', + }, + RotationLambdaARN: { + 'Fn::GetAtt': [ + 'DatabaseuserECD1FB0C', + 'Outputs.RotationLambdaARN', + ], + }, + RotationRules: { + AutomaticallyAfterDays: 30, + }, + }); + + expect(stack).toHaveResourceLike('AWS::Serverless::Application', { + Parameters: { + masterSecretArn: { + Ref: 'DatabaseSecretAttachmentE5D1B020', + }, + }, + }); + }); + + test('addRotationSingleUser() with options', () => { + // GIVEN + const vpcWithIsolated = new ec2.Vpc(stack, 'Vpc', { + subnetConfiguration: [ + { name: 'public', subnetType: ec2.SubnetType.PUBLIC }, + { name: 'private', subnetType: ec2.SubnetType.PRIVATE_WITH_NAT }, + { name: 'isolated', subnetType: ec2.SubnetType.PRIVATE_ISOLATED }, + ], + }); + + // WHEN + // DB in isolated subnet (no internet connectivity) + const instance = new rds.DatabaseInstance(stack, 'Database', { + engine: rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_10 }), + vpc: vpcWithIsolated, + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED }, + }); + + // Rotation in private subnet (internet via NAT) + instance.addRotationSingleUser({ + automaticallyAfter: cdk.Duration.days(15), + excludeCharacters: '°_@', + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_NAT }, + }); + + // THEN + expect(stack).toHaveResource('AWS::SecretsManager::RotationSchedule', { + RotationRules: { + AutomaticallyAfterDays: 15, + }, + }); + + expect(stack).toHaveResource('AWS::Serverless::Application', { + Parameters: { + endpoint: { + 'Fn::Join': ['', [ + 'https://secretsmanager.', + { Ref: 'AWS::Region' }, + '.', + { Ref: 'AWS::URLSuffix' }, + ]], + }, + functionName: 'DatabaseRotationSingleUser458A45BE', + vpcSubnetIds: { + 'Fn::Join': ['', [ + { Ref: 'VpcprivateSubnet1SubnetCEAD3716' }, + ',', + { Ref: 'VpcprivateSubnet2Subnet2DE7549C' }, + ]], + }, + vpcSecurityGroupIds: { + 'Fn::GetAtt': [ + 'DatabaseRotationSingleUserSecurityGroupAC6E0E73', + 'GroupId', + ], + }, + excludeCharacters: '°_@', + }, + }); + }); + + + test('addRotationSingleUser() with VPC interface endpoint', () => { + // GIVEN + const vpcIsolatedOnly = new ec2.Vpc(stack, 'Vpc', { natGateways: 0 }); + + const endpoint = new ec2.InterfaceVpcEndpoint(stack, 'Endpoint', { + service: ec2.InterfaceVpcEndpointAwsService.SECRETS_MANAGER, + vpc: vpcIsolatedOnly, + subnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED }, + }); + + // WHEN + // DB in isolated subnet (no internet connectivity) + const instance = new rds.DatabaseInstance(stack, 'Database', { + engine: rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_10 }), + vpc: vpcIsolatedOnly, + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED }, + }); + + // Rotation in isolated subnet with access to Secrets Manager API via endpoint + instance.addRotationSingleUser({ endpoint }); + + // THEN + expect(stack).toHaveResource('AWS::Serverless::Application', { + Parameters: { + endpoint: { + 'Fn::Join': ['', [ + 'https://', + { Ref: 'EndpointEEF1FD8F' }, + '.secretsmanager.', + { Ref: 'AWS::Region' }, + '.', + { Ref: 'AWS::URLSuffix' }, + ]], + }, + functionName: 'DatabaseRotationSingleUser458A45BE', + vpcSubnetIds: { + 'Fn::Join': ['', [ + { Ref: 'VpcIsolatedSubnet1SubnetE48C5737' }, + ',', + { Ref: 'VpcIsolatedSubnet2Subnet16364B91' }, + ]], + }, + vpcSecurityGroupIds: { + 'Fn::GetAtt': [ + 'DatabaseRotationSingleUserSecurityGroupAC6E0E73', + 'GroupId', + ], + }, + excludeCharacters: " %+~`#$&*()|[]{}:;<>?!'/@\"\\", + }, + }); + }); + test('throws when trying to add rotation to an instance without secret', () => { const instance = new rds.DatabaseInstance(stack, 'Database', { engine: rds.DatabaseInstanceEngine.SQL_SERVER_EE, diff --git a/packages/@aws-cdk/aws-rds/test/integ.cluster-rotation.lit.expected.json b/packages/@aws-cdk/aws-rds/test/integ.cluster-rotation.lit.expected.json index 91b189023f587..19fbeabb515b1 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.cluster-rotation.lit.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.cluster-rotation.lit.expected.json @@ -599,7 +599,9 @@ "PasswordLength": 30, "SecretStringTemplate": "{\"username\":\"admin\"}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "DatabaseSecretAttachmentE5D1B020": { "Type": "AWS::SecretsManager::SecretTargetAttachment", diff --git a/packages/@aws-cdk/aws-rds/test/integ.instance-from-generated-password.expected.json b/packages/@aws-cdk/aws-rds/test/integ.instance-from-generated-password.expected.json index ca2ee08c781ad..219202e5fa587 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.instance-from-generated-password.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.instance-from-generated-password.expected.json @@ -95,15 +95,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "Tags": [ { "Key": "Name", @@ -192,15 +192,15 @@ "VpcPublicSubnet2NATGateway9182C01D": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, - "SubnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "Tags": [ { "Key": "Name", @@ -289,15 +289,15 @@ "VpcPublicSubnet3NATGateway7640CD1D": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet3SubnetBE12F0B6" + }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet3EIP3A666A23", "AllocationId" ] }, - "SubnetId": { - "Ref": "VpcPublicSubnet3SubnetBE12F0B6" - }, "Tags": [ { "Key": "Name", @@ -567,7 +567,9 @@ "PasswordLength": 30, "SecretStringTemplate": "{\"username\":\"admin\"}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "InstanceSecretAttachment83BEE581": { "Type": "AWS::SecretsManager::SecretTargetAttachment", diff --git a/packages/@aws-cdk/aws-rds/test/integ.instance-s3-postgres.expected.json b/packages/@aws-cdk/aws-rds/test/integ.instance-s3-postgres.expected.json index 2a55df00bab2c..c623afaf92464 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.instance-s3-postgres.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.instance-s3-postgres.expected.json @@ -512,7 +512,9 @@ "PasswordLength": 30, "SecretStringTemplate": "{\"username\":\"postgres\"}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "InstanceSecretAttachment83BEE581": { "Type": "AWS::SecretsManager::SecretTargetAttachment", diff --git a/packages/@aws-cdk/aws-rds/test/integ.instance-s3.expected.json b/packages/@aws-cdk/aws-rds/test/integ.instance-s3.expected.json index 2b144dedcc3aa..5b851784caef0 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.instance-s3.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.instance-s3.expected.json @@ -95,15 +95,15 @@ "VPCPublicSubnet1NATGatewayE0556630": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet1EIP6AD938E8", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, "Tags": [ { "Key": "Name", @@ -192,15 +192,15 @@ "VPCPublicSubnet2NATGateway3C070193": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet2EIP4947BC00", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" - }, "Tags": [ { "Key": "Name", @@ -535,7 +535,9 @@ "PasswordLength": 30, "SecretStringTemplate": "{\"username\":\"admin\"}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "DatabaseSecretAttachmentE5D1B020": { "Type": "AWS::SecretsManager::SecretTargetAttachment", @@ -570,7 +572,7 @@ "Ref": "DatabaseSubnetGroup7D60F180" }, "Engine": "sqlserver-se", - "EngineVersion": "14.00.3192.2.v1", + "EngineVersion": "14.00", "LicenseModel": "license-included", "MasterUsername": { "Fn::Join": [ diff --git a/packages/@aws-cdk/aws-rds/test/integ.instance-s3.ts b/packages/@aws-cdk/aws-rds/test/integ.instance-s3.ts index 876ac2251e8fc..317e3c74abb57 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.instance-s3.ts +++ b/packages/@aws-cdk/aws-rds/test/integ.instance-s3.ts @@ -12,7 +12,7 @@ const importBucket = new s3.Bucket(stack, 'ImportBucket', { removalPolicy: cdk.R const exportBucket = new s3.Bucket(stack, 'ExportBucket', { removalPolicy: cdk.RemovalPolicy.DESTROY }); new DatabaseInstance(stack, 'Database', { - engine: DatabaseInstanceEngine.sqlServerSe({ version: SqlServerEngineVersion.VER_14_00_3192_2_V1 }), + engine: DatabaseInstanceEngine.sqlServerSe({ version: SqlServerEngineVersion.VER_14 }), vpc, licenseModel: LicenseModel.LICENSE_INCLUDED, s3ImportBuckets: [importBucket], diff --git a/packages/@aws-cdk/aws-rds/test/integ.instance.lit.expected.json b/packages/@aws-cdk/aws-rds/test/integ.instance.lit.expected.json index 5214516968486..7b4328ccc3341 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.instance.lit.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.instance.lit.expected.json @@ -96,15 +96,15 @@ "VPCPublicSubnet1NATGatewayE0556630": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet1EIP6AD938E8", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, "Tags": [ { "Key": "Name", @@ -193,15 +193,15 @@ "VPCPublicSubnet2NATGateway3C070193": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet2EIP4947BC00", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" - }, "Tags": [ { "Key": "Name", @@ -554,7 +554,9 @@ "PasswordLength": 30, "SecretStringTemplate": "{\"username\":\"syscdk\"}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "InstanceSecretAttachment83BEE581": { "Type": "AWS::SecretsManager::SecretTargetAttachment", @@ -1006,7 +1008,7 @@ "Runtime": "nodejs14.x", "Code": { "S3Bucket": { - "Ref": "AssetParameters884431e2bc651d2b61bd699a29dc9684b0f66911f06bd3ed0635f854bf18e147S3BucketAE1150B3" + "Ref": "AssetParametersdd4b26cf376ea5894e31041be239fc518713becdafb8f2894b069a53984fafe9S3BucketE7DA8D4B" }, "S3Key": { "Fn::Join": [ @@ -1019,7 +1021,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters884431e2bc651d2b61bd699a29dc9684b0f66911f06bd3ed0635f854bf18e147S3VersionKeyC76660C1" + "Ref": "AssetParametersdd4b26cf376ea5894e31041be239fc518713becdafb8f2894b069a53984fafe9S3VersionKey534293E7" } ] } @@ -1032,7 +1034,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters884431e2bc651d2b61bd699a29dc9684b0f66911f06bd3ed0635f854bf18e147S3VersionKeyC76660C1" + "Ref": "AssetParametersdd4b26cf376ea5894e31041be239fc518713becdafb8f2894b069a53984fafe9S3VersionKey534293E7" } ] } @@ -1118,27 +1120,13 @@ ] }, "Handler": "index.handler", - "Runtime": "nodejs10.x" + "Runtime": "nodejs12.x" }, "DependsOn": [ "FunctionServiceRole675BB04A" ] } }, - "Parameters": { - "AssetParameters884431e2bc651d2b61bd699a29dc9684b0f66911f06bd3ed0635f854bf18e147S3BucketAE1150B3": { - "Type": "String", - "Description": "S3 bucket for asset \"884431e2bc651d2b61bd699a29dc9684b0f66911f06bd3ed0635f854bf18e147\"" - }, - "AssetParameters884431e2bc651d2b61bd699a29dc9684b0f66911f06bd3ed0635f854bf18e147S3VersionKeyC76660C1": { - "Type": "String", - "Description": "S3 key for asset version \"884431e2bc651d2b61bd699a29dc9684b0f66911f06bd3ed0635f854bf18e147\"" - }, - "AssetParameters884431e2bc651d2b61bd699a29dc9684b0f66911f06bd3ed0635f854bf18e147ArtifactHash717FC602": { - "Type": "String", - "Description": "Artifact hash for asset \"884431e2bc651d2b61bd699a29dc9684b0f66911f06bd3ed0635f854bf18e147\"" - } - }, "Mappings": { "InstanceRotationSingleUserSARMappingFEA0C86E": { "aws": { @@ -1150,5 +1138,19 @@ "semanticVersion": "1.1.37" } } + }, + "Parameters": { + "AssetParametersdd4b26cf376ea5894e31041be239fc518713becdafb8f2894b069a53984fafe9S3BucketE7DA8D4B": { + "Type": "String", + "Description": "S3 bucket for asset \"dd4b26cf376ea5894e31041be239fc518713becdafb8f2894b069a53984fafe9\"" + }, + "AssetParametersdd4b26cf376ea5894e31041be239fc518713becdafb8f2894b069a53984fafe9S3VersionKey534293E7": { + "Type": "String", + "Description": "S3 key for asset version \"dd4b26cf376ea5894e31041be239fc518713becdafb8f2894b069a53984fafe9\"" + }, + "AssetParametersdd4b26cf376ea5894e31041be239fc518713becdafb8f2894b069a53984fafe9ArtifactHash3CB520C3": { + "Type": "String", + "Description": "Artifact hash for asset \"dd4b26cf376ea5894e31041be239fc518713becdafb8f2894b069a53984fafe9\"" + } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/test/integ.instance.lit.ts b/packages/@aws-cdk/aws-rds/test/integ.instance.lit.ts index eafe7a2953735..3e869950a0a46 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.instance.lit.ts +++ b/packages/@aws-cdk/aws-rds/test/integ.instance.lit.ts @@ -85,7 +85,7 @@ class DatabaseInstanceStack extends cdk.Stack { const fn = new lambda.Function(this, 'Function', { code: lambda.Code.fromInline('exports.handler = (event) => console.log(event);'), handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, + runtime: lambda.Runtime.NODEJS_12_X, }); const availabilityRule = instance.onEvent('Availability', { target: new targets.LambdaFunction(fn) }); diff --git a/packages/@aws-cdk/aws-rds/test/integ.proxy.expected.json b/packages/@aws-cdk/aws-rds/test/integ.proxy.expected.json index a18c5f5843512..8ec23ce0fe7db 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.proxy.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.proxy.expected.json @@ -95,15 +95,15 @@ "vpcPublicSubnet1NATGateway9C16659E": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "vpcPublicSubnet1Subnet2E65531E" + }, "AllocationId": { "Fn::GetAtt": [ "vpcPublicSubnet1EIPDA49DCBE", "AllocationId" ] }, - "SubnetId": { - "Ref": "vpcPublicSubnet1Subnet2E65531E" - }, "Tags": [ { "Key": "Name", @@ -192,15 +192,15 @@ "vpcPublicSubnet2NATGateway9B8AE11A": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "vpcPublicSubnet2Subnet009B674F" + }, "AllocationId": { "Fn::GetAtt": [ "vpcPublicSubnet2EIP9B3743B1", "AllocationId" ] }, - "SubnetId": { - "Ref": "vpcPublicSubnet2Subnet009B674F" - }, "Tags": [ { "Key": "Name", @@ -436,7 +436,9 @@ "PasswordLength": 30, "SecretStringTemplate": "{\"username\":\"master\"}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "dbInstanceSecretAttachment88CFBDAE": { "Type": "AWS::SecretsManager::SecretTargetAttachment", diff --git a/packages/@aws-cdk/aws-rekognition/.eslintrc.js b/packages/@aws-cdk/aws-rekognition/.eslintrc.js new file mode 100644 index 0000000000000..2658ee8727166 --- /dev/null +++ b/packages/@aws-cdk/aws-rekognition/.eslintrc.js @@ -0,0 +1,3 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-rekognition/.gitignore b/packages/@aws-cdk/aws-rekognition/.gitignore new file mode 100644 index 0000000000000..62ebc95d75ce6 --- /dev/null +++ b/packages/@aws-cdk/aws-rekognition/.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-rekognition/.npmignore b/packages/@aws-cdk/aws-rekognition/.npmignore new file mode 100644 index 0000000000000..f931fede67c44 --- /dev/null +++ b/packages/@aws-cdk/aws-rekognition/.npmignore @@ -0,0 +1,29 @@ +# 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/ +!*.lit.ts diff --git a/packages/@aws-cdk/aws-rekognition/LICENSE b/packages/@aws-cdk/aws-rekognition/LICENSE new file mode 100644 index 0000000000000..28e4bdcec77ec --- /dev/null +++ b/packages/@aws-cdk/aws-rekognition/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-rekognition/NOTICE b/packages/@aws-cdk/aws-rekognition/NOTICE new file mode 100644 index 0000000000000..5fc3826926b5b --- /dev/null +++ b/packages/@aws-cdk/aws-rekognition/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-rekognition/README.md b/packages/@aws-cdk/aws-rekognition/README.md new file mode 100644 index 0000000000000..9e158afddf5de --- /dev/null +++ b/packages/@aws-cdk/aws-rekognition/README.md @@ -0,0 +1,20 @@ +# AWS::Rekognition 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 aws-rekognition = require('@aws-cdk/aws-rekognition'); +``` diff --git a/packages/@aws-cdk/aws-rekognition/jest.config.js b/packages/@aws-cdk/aws-rekognition/jest.config.js new file mode 100644 index 0000000000000..3a2fd93a1228a --- /dev/null +++ b/packages/@aws-cdk/aws-rekognition/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-rekognition/lib/index.ts b/packages/@aws-cdk/aws-rekognition/lib/index.ts new file mode 100644 index 0000000000000..a0fee8d99d632 --- /dev/null +++ b/packages/@aws-cdk/aws-rekognition/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::Rekognition CloudFormation Resources: +export * from './rekognition.generated'; diff --git a/packages/@aws-cdk/aws-rekognition/package.json b/packages/@aws-cdk/aws-rekognition/package.json new file mode 100644 index 0000000000000..0639bc97ec905 --- /dev/null +++ b/packages/@aws-cdk/aws-rekognition/package.json @@ -0,0 +1,105 @@ +{ + "name": "@aws-cdk/aws-rekognition", + "version": "0.0.0", + "description": "The CDK Construct Library for AWS::Rekognition", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "projectReferences": true, + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.Rekognition", + "packageId": "Amazon.CDK.AWS.Rekognition", + "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.rekognition", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "rekognition" + } + }, + "python": { + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 1" + ], + "distName": "aws-cdk.aws-rekognition", + "module": "aws_cdk.aws_rekognition" + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-rekognition" + }, + "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", + "build+extract": "yarn build && yarn rosetta:extract", + "build+test+extract": "yarn build+test && yarn rosetta:extract" + }, + "cdk-build": { + "cloudformation": "AWS::Rekognition", + "jest": true, + "env": { + "AWSLINT_BASE_CONSTRUCT": "true" + } + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::Rekognition", + "aws-rekognition" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.22" + }, + "dependencies": { + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" + }, + "peerDependencies": { + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" + }, + "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-rekognition/test/aws-rekognition.test.ts b/packages/@aws-cdk/aws-rekognition/test/aws-rekognition.test.ts new file mode 100644 index 0000000000000..465c7bdea0693 --- /dev/null +++ b/packages/@aws-cdk/aws-rekognition/test/aws-rekognition.test.ts @@ -0,0 +1,6 @@ +import '@aws-cdk/assertions'; +import {} from '../lib'; + +test('No tests are specified for this package', () => { + expect(true).toBe(true); +}); diff --git a/packages/@aws-cdk/aws-route53-targets/jest.config.js b/packages/@aws-cdk/aws-route53-targets/jest.config.js index 3a2fd93a1228a..53d601eeeff94 100644 --- a/packages/@aws-cdk/aws-route53-targets/jest.config.js +++ b/packages/@aws-cdk/aws-route53-targets/jest.config.js @@ -1,2 +1,10 @@ const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); -module.exports = baseConfig; +module.exports = { + ...baseConfig, + coverageThreshold: { + global: { + branches: 70, + statements: 80, + } + } +}; diff --git a/packages/@aws-cdk/aws-route53/package.json b/packages/@aws-cdk/aws-route53/package.json index 2fc93edef1b21..9354619e6db4e 100644 --- a/packages/@aws-cdk/aws-route53/package.json +++ b/packages/@aws-cdk/aws-route53/package.json @@ -77,7 +77,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.84", + "@types/aws-lambda": "^8.10.85", "@types/jest": "^26.0.24", "aws-sdk": "^2.848.0", "jest": "^26.6.3" 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 43922fb54cc5d..2bfe968f99279 100644 --- a/packages/@aws-cdk/aws-s3-notifications/test/notifications.test.ts +++ b/packages/@aws-cdk/aws-s3-notifications/test/notifications.test.ts @@ -336,7 +336,7 @@ describe('CloudWatch Events', () => { test('onCloudTrailPutObject contains the Bucket ARN itself when path is undefined', () => { const stack = new cdk.Stack(); const bucket = s3.Bucket.fromBucketAttributes(stack, 'Bucket', { - bucketName: 'MyBucket', + bucketName: 'mybucket', }); bucket.onCloudTrailPutObject('PutRule', { target: { @@ -363,7 +363,7 @@ describe('CloudWatch Events', () => { { 'Ref': 'AWS::Partition', }, - ':s3:::MyBucket', + ':s3:::mybucket', ], ], }, @@ -378,7 +378,7 @@ describe('CloudWatch Events', () => { test("onCloudTrailPutObject contains the path when it's provided", () => { const stack = new cdk.Stack(); const bucket = s3.Bucket.fromBucketAttributes(stack, 'Bucket', { - bucketName: 'MyBucket', + bucketName: 'mybucket', }); bucket.onCloudTrailPutObject('PutRule', { target: { @@ -406,7 +406,7 @@ describe('CloudWatch Events', () => { { 'Ref': 'AWS::Partition', }, - ':s3:::MyBucket/my/path.zip', + ':s3:::mybucket/my/path.zip', ], ], }, @@ -421,7 +421,7 @@ describe('CloudWatch Events', () => { test('onCloudTrailWriteObject matches on events CompleteMultipartUpload, CopyObject, and PutObject', () => { const stack = new cdk.Stack(); const bucket = s3.Bucket.fromBucketAttributes(stack, 'Bucket', { - bucketName: 'MyBucket', + bucketName: 'mybucket', }); bucket.onCloudTrailWriteObject('OnCloudTrailWriteObjectRule', { target: { @@ -449,7 +449,7 @@ describe('CloudWatch Events', () => { test('onCloudTrailWriteObject matches on the requestParameter bucketName when the path is not provided', () => { const stack = new cdk.Stack(); const bucket = s3.Bucket.fromBucketAttributes(stack, 'Bucket', { - bucketName: 'MyBucket', + bucketName: 'mybucket', }); bucket.onCloudTrailWriteObject('OnCloudTrailWriteObjectRule', { target: { @@ -476,7 +476,7 @@ describe('CloudWatch Events', () => { test('onCloudTrailWriteObject matches on the requestParameters bucketName and key when the path is provided', () => { const stack = new cdk.Stack(); const bucket = s3.Bucket.fromBucketAttributes(stack, 'Bucket', { - bucketName: 'MyBucket', + bucketName: 'mybucket', }); bucket.onCloudTrailWriteObject('OnCloudTrailWriteObjectRule', { target: { diff --git a/packages/@aws-cdk/aws-s3/lib/bucket.ts b/packages/@aws-cdk/aws-s3/lib/bucket.ts index 67037f874bc3e..157aa31a3ed5f 100644 --- a/packages/@aws-cdk/aws-s3/lib/bucket.ts +++ b/packages/@aws-cdk/aws-s3/lib/bucket.ts @@ -1396,6 +1396,7 @@ export class Bucket extends BucketBase { if (!bucketName) { throw new Error('Bucket name is required'); } + Bucket.validateBucketName(bucketName); const newUrlFormat = attrs.bucketWebsiteNewUrlFormat === undefined ? false @@ -1434,6 +1435,52 @@ export class Bucket extends BucketBase { }); } + /** + * Thrown an exception if the given bucket name is not valid. + * + * @param physicalName name of the bucket. + */ + public static validateBucketName(physicalName: string): void { + const bucketName = physicalName; + if (!bucketName || Token.isUnresolved(bucketName)) { + // the name is a late-bound value, not a defined string, + // so skip validation + return; + } + + const errors: string[] = []; + + // Rules codified from https://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html + if (bucketName.length < 3 || bucketName.length > 63) { + errors.push('Bucket name must be at least 3 and no more than 63 characters'); + } + const charsetMatch = bucketName.match(/[^a-z0-9.-]/); + if (charsetMatch) { + errors.push('Bucket name must only contain lowercase characters and the symbols, period (.) and dash (-) ' + + `(offset: ${charsetMatch.index})`); + } + if (!/[a-z0-9]/.test(bucketName.charAt(0))) { + errors.push('Bucket name must start and end with a lowercase character or number ' + + '(offset: 0)'); + } + if (!/[a-z0-9]/.test(bucketName.charAt(bucketName.length - 1))) { + errors.push('Bucket name must start and end with a lowercase character or number ' + + `(offset: ${bucketName.length - 1})`); + } + const consecSymbolMatch = bucketName.match(/\.-|-\.|\.\./); + if (consecSymbolMatch) { + errors.push('Bucket name must not have dash next to period, or period next to dash, or consecutive periods ' + + `(offset: ${consecSymbolMatch.index})`); + } + if (/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(bucketName)) { + errors.push('Bucket name must not resemble an IP address'); + } + + if (errors.length > 0) { + throw new Error(`Invalid S3 bucket name (value: ${bucketName})${EOL}${errors.join(EOL)}`); + } + } + public readonly bucketArn: string; public readonly bucketName: string; public readonly bucketDomainName: string; @@ -1462,7 +1509,7 @@ export class Bucket extends BucketBase { const { bucketEncryption, encryptionKey } = this.parseEncryption(props); - this.validateBucketName(this.physicalName); + Bucket.validateBucketName(this.physicalName); const websiteConfiguration = this.renderWebsiteConfiguration(props); this.isWebsite = (websiteConfiguration !== undefined); @@ -1600,47 +1647,6 @@ export class Bucket extends BucketBase { this.addToResourcePolicy(statement); } - private validateBucketName(physicalName: string): void { - const bucketName = physicalName; - if (!bucketName || Token.isUnresolved(bucketName)) { - // the name is a late-bound value, not a defined string, - // so skip validation - return; - } - - const errors: string[] = []; - - // Rules codified from https://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html - if (bucketName.length < 3 || bucketName.length > 63) { - errors.push('Bucket name must be at least 3 and no more than 63 characters'); - } - const charsetMatch = bucketName.match(/[^a-z0-9.-]/); - if (charsetMatch) { - errors.push('Bucket name must only contain lowercase characters and the symbols, period (.) and dash (-) ' - + `(offset: ${charsetMatch.index})`); - } - if (!/[a-z0-9]/.test(bucketName.charAt(0))) { - errors.push('Bucket name must start and end with a lowercase character or number ' - + '(offset: 0)'); - } - if (!/[a-z0-9]/.test(bucketName.charAt(bucketName.length - 1))) { - errors.push('Bucket name must start and end with a lowercase character or number ' - + `(offset: ${bucketName.length - 1})`); - } - const consecSymbolMatch = bucketName.match(/\.-|-\.|\.\./); - if (consecSymbolMatch) { - errors.push('Bucket name must not have dash next to period, or period next to dash, or consecutive periods ' - + `(offset: ${consecSymbolMatch.index})`); - } - if (/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(bucketName)) { - errors.push('Bucket name must not resemble an IP address'); - } - - if (errors.length > 0) { - throw new Error(`Invalid S3 bucket name (value: ${bucketName})${EOL}${errors.join(EOL)}`); - } - } - /** * Set up key properties and return the Bucket encryption property from the * user's configuration. diff --git a/packages/@aws-cdk/aws-s3/package.json b/packages/@aws-cdk/aws-s3/package.json index 3117d2919f6a6..afb95aeaa0d2e 100644 --- a/packages/@aws-cdk/aws-s3/package.json +++ b/packages/@aws-cdk/aws-s3/package.json @@ -77,7 +77,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.84", + "@types/aws-lambda": "^8.10.85", "@types/jest": "^26.0.24", "jest": "^26.6.3" }, diff --git a/packages/@aws-cdk/aws-s3/test/bucket.test.ts b/packages/@aws-cdk/aws-s3/test/bucket.test.ts index 3ef166722c1b6..67d263aa60ea5 100644 --- a/packages/@aws-cdk/aws-s3/test/bucket.test.ts +++ b/packages/@aws-cdk/aws-s3/test/bucket.test.ts @@ -3,9 +3,9 @@ import { EOL } from 'os'; 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 { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as s3 from '../lib'; // to make it easy to copy & paste from output: @@ -103,8 +103,6 @@ describe('bucket', () => { expect(() => new s3.Bucket(stack, 'MyBucket2', { bucketName: '124.pp--33', })).not.toThrow(); - - }); test('bucket validation skips tokenized values', () => { @@ -746,14 +744,24 @@ describe('bucket', () => { }); const bucket = s3.Bucket.fromBucketAttributes(stack, 'ImportedBucket', { - bucketName: 'myBucket', + bucketName: 'mybucket', region: 'eu-west-1', }); - expect(bucket.bucketRegionalDomainName).toEqual(`myBucket.s3.eu-west-1.${stack.urlSuffix}`); - expect(bucket.bucketWebsiteDomainName).toEqual(`myBucket.s3-website-eu-west-1.${stack.urlSuffix}`); + expect(bucket.bucketRegionalDomainName).toEqual(`mybucket.s3.eu-west-1.${stack.urlSuffix}`); + expect(bucket.bucketWebsiteDomainName).toEqual(`mybucket.s3-website-eu-west-1.${stack.urlSuffix}`); + + }); + + test('import needs to specify a valid bucket name', () => { + const stack = new cdk.Stack(undefined, undefined, { + env: { region: 'us-east-1' }, + }); + expect(() => s3.Bucket.fromBucketAttributes(stack, 'MyBucket3', { + bucketName: 'arn:aws:s3:::example-com', + })).toThrow(); }); }); @@ -2129,11 +2137,11 @@ describe('bucket', () => { const stack = new cdk.Stack(); // WHEN - const bucket = s3.Bucket.fromBucketArn(stack, 'my-bucket', 'arn:aws:s3:::my_corporate_bucket'); + const bucket = s3.Bucket.fromBucketArn(stack, 'my-bucket', 'arn:aws:s3:::my-corporate-bucket'); // THEN - expect(bucket.bucketName).toEqual('my_corporate_bucket'); - expect(bucket.bucketArn).toEqual('arn:aws:s3:::my_corporate_bucket'); + expect(bucket.bucketName).toEqual('my-corporate-bucket'); + expect(bucket.bucketArn).toEqual('arn:aws:s3:::my-corporate-bucket'); }); diff --git a/packages/@aws-cdk/aws-secretsmanager/lib/secret-rotation.ts b/packages/@aws-cdk/aws-secretsmanager/lib/secret-rotation.ts index fb52821c88729..7311288279a51 100644 --- a/packages/@aws-cdk/aws-secretsmanager/lib/secret-rotation.ts +++ b/packages/@aws-cdk/aws-secretsmanager/lib/secret-rotation.ts @@ -245,6 +245,18 @@ export interface SecretRotationProps { * @default - no additional characters are explicitly excluded */ readonly excludeCharacters?: string; + + /** + * The VPC interface endpoint to use for the Secrets Manager API + * + * If you enable private DNS hostnames for your VPC private endpoint (the default), you don't + * need to specify an endpoint. The standard Secrets Manager DNS hostname the Secrets Manager + * CLI and SDKs use by default (https://secretsmanager..amazonaws.com) automatically + * resolves to your VPC endpoint. + * + * @default https://secretsmanager..amazonaws.com + */ + readonly endpoint?: ec2.IInterfaceVpcEndpoint; } /** @@ -272,7 +284,7 @@ export class SecretRotation extends CoreConstruct { props.target.connections.allowDefaultPortFrom(securityGroup); const parameters: { [key: string]: string } = { - endpoint: `https://secretsmanager.${Stack.of(this).region}.${Stack.of(this).urlSuffix}`, + endpoint: `https://${props.endpoint ? `${props.endpoint.vpcEndpointId}.` : ''}secretsmanager.${Stack.of(this).region}.${Stack.of(this).urlSuffix}`, functionName: rotationFunctionName, vpcSubnetIds: props.vpc.selectSubnets(props.vpcSubnets).subnetIds.join(','), vpcSecurityGroupIds: securityGroup.securityGroupId, diff --git a/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts b/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts index 119b02ccc507d..70144db7d2dbd 100644 --- a/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts +++ b/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts @@ -467,9 +467,9 @@ export class Secret extends SecretBase { replicaRegions: Lazy.any({ produce: () => this.replicaRegions }, { omitEmptyArray: true }), }); - if (props.removalPolicy) { - resource.applyRemovalPolicy(props.removalPolicy); - } + resource.applyRemovalPolicy(props.removalPolicy, { + default: RemovalPolicy.DESTROY, + }); this.secretArn = this.getResourceArnAttribute(resource.ref, { service: 'secretsmanager', diff --git a/packages/@aws-cdk/aws-secretsmanager/test/integ.hosted-rotation.expected.json b/packages/@aws-cdk/aws-secretsmanager/test/integ.hosted-rotation.expected.json index be2f63be0aa79..19c9a9d4c7f1e 100644 --- a/packages/@aws-cdk/aws-secretsmanager/test/integ.hosted-rotation.expected.json +++ b/packages/@aws-cdk/aws-secretsmanager/test/integ.hosted-rotation.expected.json @@ -5,7 +5,9 @@ "Type": "AWS::SecretsManager::Secret", "Properties": { "GenerateSecretString": {} - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "SecretSchedule18F2CB66": { "Type": "AWS::SecretsManager::RotationSchedule", diff --git a/packages/@aws-cdk/aws-secretsmanager/test/integ.lambda-rotation.expected.json b/packages/@aws-cdk/aws-secretsmanager/test/integ.lambda-rotation.expected.json index 12ea99df10a85..f1d540cbd42a7 100644 --- a/packages/@aws-cdk/aws-secretsmanager/test/integ.lambda-rotation.expected.json +++ b/packages/@aws-cdk/aws-secretsmanager/test/integ.lambda-rotation.expected.json @@ -165,7 +165,9 @@ "Arn" ] } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "SecretSchedule18F2CB66": { "Type": "AWS::SecretsManager::RotationSchedule", diff --git a/packages/@aws-cdk/aws-secretsmanager/test/integ.replica.expected.json b/packages/@aws-cdk/aws-secretsmanager/test/integ.replica.expected.json index 99fd65c02e2b4..6483de751a884 100644 --- a/packages/@aws-cdk/aws-secretsmanager/test/integ.replica.expected.json +++ b/packages/@aws-cdk/aws-secretsmanager/test/integ.replica.expected.json @@ -9,7 +9,9 @@ "Region": "eu-central-1" } ] - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-secretsmanager/test/integ.secret-name-parsed.expected.json b/packages/@aws-cdk/aws-secretsmanager/test/integ.secret-name-parsed.expected.json index b1b91a239d649..01e9e10d4eed9 100644 --- a/packages/@aws-cdk/aws-secretsmanager/test/integ.secret-name-parsed.expected.json +++ b/packages/@aws-cdk/aws-secretsmanager/test/integ.secret-name-parsed.expected.json @@ -4,27 +4,35 @@ "Type": "AWS::SecretsManager::Secret", "Properties": { "GenerateSecretString": {} - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "NamedSecret7CD5422D": { "Type": "AWS::SecretsManager::Secret", "Properties": { "GenerateSecretString": {}, "Name": "namedSecret" - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "NamedSecretWithHyphen6DC9716A": { "Type": "AWS::SecretsManager::Secret", "Properties": { "GenerateSecretString": {}, "Name": "named-secret-1" - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "AReallyLongLogicalIThatWillBeTrimmedBeforeItsUsedInTheName83476586": { "Type": "AWS::SecretsManager::Secret", "Properties": { "GenerateSecretString": {} - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "CustomIntegVerificationSecretNameMatchesCustomResourceProviderRole4A6F8B2A": { "Type": "AWS::IAM::Role", diff --git a/packages/@aws-cdk/aws-secretsmanager/test/integ.secret.lit.expected.json b/packages/@aws-cdk/aws-secretsmanager/test/integ.secret.lit.expected.json index 5411df31be1ba..7a69272a9550f 100644 --- a/packages/@aws-cdk/aws-secretsmanager/test/integ.secret.lit.expected.json +++ b/packages/@aws-cdk/aws-secretsmanager/test/integ.secret.lit.expected.json @@ -62,7 +62,9 @@ "Type": "AWS::SecretsManager::Secret", "Properties": { "GenerateSecretString": {} - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "User00B015A1": { "Type": "AWS::IAM::User", @@ -90,7 +92,9 @@ "GenerateStringKey": "password", "SecretStringTemplate": "{\"username\":\"user\"}" } - } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" }, "OtherUser6093621C": { "Type": "AWS::IAM::User", @@ -124,4 +128,4 @@ } } } -} +} \ No newline at end of file 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 55c7388393619..974aa0c611c4d 100644 --- a/packages/@aws-cdk/aws-secretsmanager/test/secret-rotation.test.ts +++ b/packages/@aws-cdk/aws-secretsmanager/test/secret-rotation.test.ts @@ -345,3 +345,37 @@ test('rotation function name does not exceed 64 chars', () => { }, }); }); + + +test('with interface vpc endpoint', () => { + // GIVEN + const endpoint = new ec2.InterfaceVpcEndpoint(stack, 'SecretsManagerEndpoint', { + service: ec2.InterfaceVpcEndpointAwsService.SECRETS_MANAGER, + vpc, + }); + + // WHEN + new secretsmanager.SecretRotation(stack, 'SecretRotation', { + application: secretsmanager.SecretRotationApplication.MYSQL_ROTATION_SINGLE_USER, + secret, + target, + vpc, + endpoint, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::Serverless::Application', { + Parameters: { + endpoint: { + 'Fn::Join': ['', [ + 'https://', + { Ref: 'SecretsManagerEndpoint5E83C66B' }, + '.secretsmanager.', + { Ref: 'AWS::Region' }, + '.', + { Ref: 'AWS::URLSuffix' }, + ]], + }, + }, + }); +}); diff --git a/packages/@aws-cdk/aws-servicecatalog/README.md b/packages/@aws-cdk/aws-servicecatalog/README.md index 4bb6885c601eb..2d7694d3e84b6 100644 --- a/packages/@aws-cdk/aws-servicecatalog/README.md +++ b/packages/@aws-cdk/aws-servicecatalog/README.md @@ -30,6 +30,8 @@ enables organizations to create and manage catalogs of products for their end us - [Granting access to a portfolio](#granting-access-to-a-portfolio) - [Sharing a portfolio with another AWS account](#sharing-a-portfolio-with-another-aws-account) - [Product](#product) + - [Creating a product from a local asset](#creating-a-product-from-local-asset) + - [Creating a product from a stack](#creating-a-product-from-a-stack) - [Adding a product to a portfolio](#adding-a-product-to-a-portfolio) - [TagOptions](#tag-options) - [Constraints](#constraints) @@ -125,10 +127,12 @@ const product = new servicecatalog.CloudFormationProduct(this, 'MyFirstProduct', cloudFormationTemplate: servicecatalog.CloudFormationTemplate.fromUrl( 'https://raw.githubusercontent.com/awslabs/aws-cloudformation-templates/master/aws/services/ServiceCatalog/Product.yaml'), }, - ] + ], }); ``` +### Creating a product from a local asset + A `CloudFormationProduct` can also be created using a Cloudformation template from an Asset. Assets are files that are uploaded to an S3 Bucket before deployment. `CloudFormationTemplate.fromAsset` can be utilized to create a Product by passing the path to a local template file on your disk: @@ -149,7 +153,38 @@ const product = new servicecatalog.CloudFormationProduct(this, 'MyFirstProduct', productVersionName: "v2", cloudFormationTemplate: servicecatalog.CloudFormationTemplate.fromAsset(path.join(__dirname, 'development-environment.template.json')), }, - ] + ], +}); +``` + +### Creating a product from a stack + +You can define a service catalog `CloudFormationProduct` entirely within CDK using a service catalog `ProductStack`. +A separate child stack for your product is created and you can add resources like you would for any other CDK stack, +such as an S3 Bucket, IAM roles, and EC2 instances. This stack is passed in as a product version to your +product. This will not create a separate stack during deployment. + +```ts +import * as s3 from '@aws-cdk/aws-s3'; +import * as cdk from '@aws-cdk/core'; + +class S3BucketProduct extends servicecatalog.ProductStack { + constructor(scope: cdk.Construct, id: string) { + super(scope, id); + + new s3.Bucket(this, 'BucketProduct'); + } +} + +const product = new servicecatalog.CloudFormationProduct(this, 'MyFirstProduct', { + productName: "My Product", + owner: "Product Owner", + productVersions: [ + { + productVersionName: "v1", + cloudFormationTemplate: servicecatalog.CloudFormationTemplate.fromProductStack(new S3BucketProduct(this, 'S3BucketProduct')), + }, + ], }); ``` diff --git a/packages/@aws-cdk/aws-servicecatalog/lib/cloudformation-template.ts b/packages/@aws-cdk/aws-servicecatalog/lib/cloudformation-template.ts index be0cb9adf2022..4086db6655fda 100644 --- a/packages/@aws-cdk/aws-servicecatalog/lib/cloudformation-template.ts +++ b/packages/@aws-cdk/aws-servicecatalog/lib/cloudformation-template.ts @@ -1,5 +1,6 @@ import * as s3_assets from '@aws-cdk/aws-s3-assets'; import { hashValues } from './private/util'; +import { ProductStack } from './product-stack'; // 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 @@ -26,6 +27,13 @@ export abstract class CloudFormationTemplate { return new CloudFormationAssetTemplate(path, options); } + /** + * Creates a product with the resources defined in the given product stack. + */ + public static fromProductStack(productStack: ProductStack): CloudFormationTemplate { + return new CloudFormationProductStackTemplate(productStack); + } + /** * Called when the product is initialized to allow this object to bind * to the stack, add resources and have fun. @@ -88,3 +96,21 @@ class CloudFormationAssetTemplate extends CloudFormationTemplate { }; } } + +/** + * Template from a CDK defined product stack. + */ +class CloudFormationProductStackTemplate extends CloudFormationTemplate { + /** + * @param stack A service catalog product stack. + */ + constructor(public readonly productStack: ProductStack) { + super(); + } + + public bind(_scope: Construct): CloudFormationTemplateConfig { + return { + httpUrl: this.productStack._getTemplateUrl(), + }; + } +} diff --git a/packages/@aws-cdk/aws-servicecatalog/lib/index.ts b/packages/@aws-cdk/aws-servicecatalog/lib/index.ts index 8a7b0f0ff9ac6..cc26e880fdd2e 100644 --- a/packages/@aws-cdk/aws-servicecatalog/lib/index.ts +++ b/packages/@aws-cdk/aws-servicecatalog/lib/index.ts @@ -3,6 +3,7 @@ export * from './constraints'; export * from './cloudformation-template'; export * from './portfolio'; export * from './product'; +export * from './product-stack'; export * from './tag-options'; // AWS::ServiceCatalog CloudFormation Resources: diff --git a/packages/@aws-cdk/aws-servicecatalog/lib/private/product-stack-synthesizer.ts b/packages/@aws-cdk/aws-servicecatalog/lib/private/product-stack-synthesizer.ts new file mode 100644 index 0000000000000..4840a7e756fe5 --- /dev/null +++ b/packages/@aws-cdk/aws-servicecatalog/lib/private/product-stack-synthesizer.ts @@ -0,0 +1,34 @@ +import * as cdk from '@aws-cdk/core'; + +/** + * Deployment environment for an AWS Service Catalog product stack. + * + * Interoperates with the StackSynthesizer of the parent stack. + */ +export class ProductStackSynthesizer extends cdk.StackSynthesizer { + private stack?: cdk.Stack; + + public bind(stack: cdk.Stack): void { + if (this.stack !== undefined) { + throw new Error('A Stack Synthesizer can only be bound once, create a new instance to use with a different Stack'); + } + this.stack = stack; + } + + public addFileAsset(_asset: cdk.FileAssetSource): cdk.FileAssetLocation { + throw new Error('Service Catalog Product Stacks cannot use Assets'); + } + + public addDockerImageAsset(_asset: cdk.DockerImageAssetSource): cdk.DockerImageAssetLocation { + throw new Error('Service Catalog Product Stacks cannot use Assets'); + } + + public synthesize(session: cdk.ISynthesisSession): void { + if (!this.stack) { + throw new Error('You must call bindStack() first'); + } + // Synthesize the template, but don't emit as a cloud assembly artifact. + // It will be registered as an S3 asset of its parent instead. + this.synthesizeStackTemplate(this.stack, session); + } +} diff --git a/packages/@aws-cdk/aws-servicecatalog/lib/product-stack.ts b/packages/@aws-cdk/aws-servicecatalog/lib/product-stack.ts new file mode 100644 index 0000000000000..b96224a8b2c60 --- /dev/null +++ b/packages/@aws-cdk/aws-servicecatalog/lib/product-stack.ts @@ -0,0 +1,77 @@ +import * as crypto from 'crypto'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as cdk from '@aws-cdk/core'; +import { ProductStackSynthesizer } from './private/product-stack-synthesizer'; + +// 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 'constructs'; + +/** + * A Service Catalog product stack, which is similar in form to a Cloudformation nested stack. + * You can add the resources to this stack that you want to define for your service catalog product. + * + * This stack will not be treated as an independent deployment + * artifact (won't be listed in "cdk list" or deployable through "cdk deploy"), + * but rather only synthesized as a template and uploaded as an asset to S3. + * + */ +export class ProductStack extends cdk.Stack { + public readonly templateFile: string; + private _templateUrl?: string; + private _parentStack: cdk.Stack; + + constructor(scope: Construct, id: string) { + super(scope, id, { + synthesizer: new ProductStackSynthesizer(), + }); + + this._parentStack = findParentStack(scope); + + // this is the file name of the synthesized template file within the cloud assembly + this.templateFile = `${cdk.Names.uniqueId(this)}.product.template.json`; + } + + /** + * Fetch the template URL. + * + * @internal + */ + public _getTemplateUrl(): string { + return cdk.Lazy.uncachedString({ produce: () => this._templateUrl }); + } + + /** + * Synthesize the product stack template, overrides the `super` class method. + * + * Defines an asset at the parent stack which represents the template of this + * product stack. + * + * @internal + */ + public _synthesizeTemplate(session: cdk.ISynthesisSession): void { + const cfn = JSON.stringify(this._toCloudFormation(), undefined, 2); + const templateHash = crypto.createHash('sha256').update(cfn).digest('hex'); + + this._templateUrl = this._parentStack.synthesizer.addFileAsset({ + packaging: cdk.FileAssetPackaging.FILE, + sourceHash: templateHash, + fileName: this.templateFile, + }).httpUrl; + + fs.writeFileSync(path.join(session.assembly.outdir, this.templateFile), cfn); + } +} + +/** + * Validates the scope for a product stack, which must be defined within the scope of another `Stack`. + */ +function findParentStack(scope: Construct): cdk.Stack { + try { + const parentStack = cdk.Stack.of(scope); + return parentStack as cdk.Stack; + } catch (e) { + throw new Error('Product stacks must be defined within scope of another non-product stack'); + } +} diff --git a/packages/@aws-cdk/aws-servicecatalog/package.json b/packages/@aws-cdk/aws-servicecatalog/package.json index de3bfcfb667a5..3d96fbe55edcc 100644 --- a/packages/@aws-cdk/aws-servicecatalog/package.json +++ b/packages/@aws-cdk/aws-servicecatalog/package.json @@ -104,7 +104,8 @@ "resource-attribute:@aws-cdk/aws-servicecatalog.CloudFormationProduct.cloudFormationProductProvisioningArtifactNames", "props-physical-name:@aws-cdk/aws-servicecatalog.CloudFormationProductProps", "resource-attribute:@aws-cdk/aws-servicecatalog.Portfolio.portfolioName", - "props-physical-name:@aws-cdk/aws-servicecatalog.PortfolioProps" + "props-physical-name:@aws-cdk/aws-servicecatalog.PortfolioProps", + "props-physical-name:@aws-cdk/aws-servicecatalog.ProductStack" ] }, "maturity": "experimental", diff --git a/packages/@aws-cdk/aws-servicecatalog/rosetta/basic-portfolio.ts-fixture b/packages/@aws-cdk/aws-servicecatalog/rosetta/basic-portfolio.ts-fixture index d8925e6645aa7..3029872ea1f0d 100644 --- a/packages/@aws-cdk/aws-servicecatalog/rosetta/basic-portfolio.ts-fixture +++ b/packages/@aws-cdk/aws-servicecatalog/rosetta/basic-portfolio.ts-fixture @@ -1,9 +1,9 @@ // Fixture with packages imported, but nothing else -import { Construct, Stack } from '@aws-cdk/core'; +import * as cdk from '@aws-cdk/core'; import * as servicecatalog from '@aws-cdk/aws-servicecatalog'; -class Fixture extends Stack { - constructor(scope: Construct, id: string) { +class Fixture extends cdk.Stack { + constructor(scope: cdk.Construct, id: string) { super(scope, id); const portfolio = new servicecatalog.Portfolio(this, "MyFirstPortfolio", { diff --git a/packages/@aws-cdk/aws-servicecatalog/test/integ.product.expected.json b/packages/@aws-cdk/aws-servicecatalog/test/integ.product.expected.json index 786fdcad0f8fc..f54d640e1d0ca 100644 --- a/packages/@aws-cdk/aws-servicecatalog/test/integ.product.expected.json +++ b/packages/@aws-cdk/aws-servicecatalog/test/integ.product.expected.json @@ -113,6 +113,108 @@ ] } } + }, + { + "DisableTemplateValidation": false, + "Info": { + "LoadTemplateFromURL": { + "Fn::Join": [ + "", + [ + "https://s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "AssetParametersdd2d087eeb6ede1d2a9166639ccbde7bd1b10eef9ba2b4cb3d9855faa4fe8c1fS3BucketB4751C98" + }, + "/", + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersdd2d087eeb6ede1d2a9166639ccbde7bd1b10eef9ba2b4cb3d9855faa4fe8c1fS3VersionKeyEB38C6F9" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersdd2d087eeb6ede1d2a9166639ccbde7bd1b10eef9ba2b4cb3d9855faa4fe8c1fS3VersionKeyEB38C6F9" + } + ] + } + ] + } + ] + ] + } + } + }, + { + "DisableTemplateValidation": false, + "Info": { + "LoadTemplateFromURL": { + "Fn::Join": [ + "", + [ + "https://s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "AssetParametersdd2d087eeb6ede1d2a9166639ccbde7bd1b10eef9ba2b4cb3d9855faa4fe8c1fS3BucketB4751C98" + }, + "/", + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersdd2d087eeb6ede1d2a9166639ccbde7bd1b10eef9ba2b4cb3d9855faa4fe8c1fS3VersionKeyEB38C6F9" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersdd2d087eeb6ede1d2a9166639ccbde7bd1b10eef9ba2b4cb3d9855faa4fe8c1fS3VersionKeyEB38C6F9" + } + ] + } + ] + } + ] + ] + } + } } ] } @@ -142,6 +244,18 @@ "AssetParameters6412a5f4524c6b41d26fbeee226c68c2dad735393940a51008d77e6f8b1038f5ArtifactHashDC26AFAC": { "Type": "String", "Description": "Artifact hash for asset \"6412a5f4524c6b41d26fbeee226c68c2dad735393940a51008d77e6f8b1038f5\"" + }, + "AssetParametersdd2d087eeb6ede1d2a9166639ccbde7bd1b10eef9ba2b4cb3d9855faa4fe8c1fS3BucketB4751C98": { + "Type": "String", + "Description": "S3 bucket for asset \"dd2d087eeb6ede1d2a9166639ccbde7bd1b10eef9ba2b4cb3d9855faa4fe8c1f\"" + }, + "AssetParametersdd2d087eeb6ede1d2a9166639ccbde7bd1b10eef9ba2b4cb3d9855faa4fe8c1fS3VersionKeyEB38C6F9": { + "Type": "String", + "Description": "S3 key for asset version \"dd2d087eeb6ede1d2a9166639ccbde7bd1b10eef9ba2b4cb3d9855faa4fe8c1f\"" + }, + "AssetParametersdd2d087eeb6ede1d2a9166639ccbde7bd1b10eef9ba2b4cb3d9855faa4fe8c1fArtifactHash5C1F9228": { + "Type": "String", + "Description": "Artifact hash for asset \"dd2d087eeb6ede1d2a9166639ccbde7bd1b10eef9ba2b4cb3d9855faa4fe8c1f\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-servicecatalog/test/integ.product.ts b/packages/@aws-cdk/aws-servicecatalog/test/integ.product.ts index 5c4192cc9b25c..7a88c98a466d1 100644 --- a/packages/@aws-cdk/aws-servicecatalog/test/integ.product.ts +++ b/packages/@aws-cdk/aws-servicecatalog/test/integ.product.ts @@ -1,10 +1,19 @@ import * as path from 'path'; +import * as sns from '@aws-cdk/aws-sns'; import * as cdk from '@aws-cdk/core'; import * as servicecatalog from '../lib'; const app = new cdk.App(); const stack = new cdk.Stack(app, 'integ-servicecatalog-product'); +class TestProductStack extends servicecatalog.ProductStack { + constructor(scope: any, id: string) { + super(scope, id); + + new sns.Topic(this, 'TopicProduct'); + } +} + new servicecatalog.CloudFormationProduct(stack, 'TestProduct', { productName: 'testProduct', owner: 'testOwner', @@ -20,6 +29,12 @@ new servicecatalog.CloudFormationProduct(stack, 'TestProduct', { { cloudFormationTemplate: servicecatalog.CloudFormationTemplate.fromAsset(path.join(__dirname, 'product2.template.json')), }, + { + cloudFormationTemplate: servicecatalog.CloudFormationTemplate.fromProductStack(new TestProductStack(stack, 'SNSTopicProduct1')), + }, + { + cloudFormationTemplate: servicecatalog.CloudFormationTemplate.fromProductStack(new TestProductStack(stack, 'SNSTopicProduct2')), + }, ], }); diff --git a/packages/@aws-cdk/aws-servicecatalog/test/product-stack.test.ts b/packages/@aws-cdk/aws-servicecatalog/test/product-stack.test.ts new file mode 100644 index 0000000000000..e024421d724dc --- /dev/null +++ b/packages/@aws-cdk/aws-servicecatalog/test/product-stack.test.ts @@ -0,0 +1,88 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import * as s3_assets from '@aws-cdk/aws-s3-assets'; +import * as sns from '@aws-cdk/aws-sns'; +import * as cdk from '@aws-cdk/core'; +import * as servicecatalog from '../lib'; + +/* eslint-disable quote-props */ +describe('ProductStack', () => { + test('fails to add asset to a product stack', () => { + // GIVEN + const app = new cdk.App(); + const mainStack = new cdk.Stack(app, 'MyStack'); + const productStack = new servicecatalog.ProductStack(mainStack, 'MyProductStack'); + + // THEN + expect(() => { + new s3_assets.Asset(productStack, 'testAsset', { + path: path.join(__dirname, 'product1.template.json'), + }); + }).toThrow(/Service Catalog Product Stacks cannot use Assets/); + }), + + test('fails if defined at root', () => { + // GIVEN + const app = new cdk.App(); + + // THEN + expect(() => { + new servicecatalog.ProductStack(app, 'ProductStack'); + }).toThrow(/must be defined within scope of another non-product stack/); + }), + + test('fails if defined without a parent stack', () => { + // GIVEN + const app = new cdk.App(); + const group = new cdk.Construct(app, 'group'); + + // THEN + expect(() => { + new servicecatalog.ProductStack(group, 'ProductStack'); + }).toThrow(/must be defined within scope of another non-product stack/); + }), + + test('can be defined as a direct child or an indirect child of a Stack', () => { + // GIVEN + const parent = new cdk.Stack(); + + // THEN + expect(() => { + new servicecatalog.ProductStack(parent, 'direct'); + }).not.toThrow(); + }); + + test('product stack is not synthesized as a stack artifact into the assembly', () => { + // GIVEN + const app = new cdk.App(); + const parentStack = new cdk.Stack(app, 'ParentStack'); + new servicecatalog.ProductStack(parentStack, 'ProductStack'); + + // WHEN + const assembly = app.synth(); + + // THEN + expect(assembly.artifacts.length).toEqual(2); + }); + + test('the template of the product stack is synthesized into the cloud assembly', () => { + // GIVEN + const app = new cdk.App(); + const parent = new cdk.Stack(app, 'ParentStack'); + const productStack = new servicecatalog.ProductStack(parent, 'ProductStack'); + new sns.Topic(productStack, 'SNSTopicProduct'); + + // WHEN + const assembly = app.synth(); + + // THEN + const template = JSON.parse(fs.readFileSync(path.join(assembly.directory, productStack.templateFile), 'utf-8')); + expect(template).toEqual({ + Resources: { + SNSTopicProduct20605D98: { + Type: 'AWS::SNS::Topic', + }, + }, + }); + }); +}); diff --git a/packages/@aws-cdk/aws-servicecatalog/test/product.test.ts b/packages/@aws-cdk/aws-servicecatalog/test/product.test.ts index f3e485b30e951..f399a79dcdb83 100644 --- a/packages/@aws-cdk/aws-servicecatalog/test/product.test.ts +++ b/packages/@aws-cdk/aws-servicecatalog/test/product.test.ts @@ -1,5 +1,6 @@ import * as path from 'path'; import { Match, Template } from '@aws-cdk/assertions'; +import * as sns from '@aws-cdk/aws-sns'; import * as cdk from '@aws-cdk/core'; import * as servicecatalog from '../lib'; @@ -101,6 +102,93 @@ describe('Product', () => { expect(synthesized.assets.length).toEqual(2); }), + test('product test from product stack', () => { + const productStack = new servicecatalog.ProductStack(stack, 'ProductStack'); + + new sns.Topic(productStack, 'SNSTopicProductStack'); + + new servicecatalog.CloudFormationProduct(stack, 'MyProduct', { + productName: 'testProduct', + owner: 'testOwner', + productVersions: [ + { + productVersionName: 'v1', + cloudFormationTemplate: servicecatalog.CloudFormationTemplate.fromProductStack(productStack), + }, + ], + }); + + const assembly = app.synth(); + expect(assembly.artifacts.length).toEqual(2); + expect(assembly.stacks[0].assets.length).toBe(1); + expect(assembly.stacks[0].assets[0].path).toEqual('ProductStack.product.template.json'); + }), + + test('multiple product versions from product stack', () => { + const productStackVersion1 = new servicecatalog.ProductStack(stack, 'ProductStackV1'); + const productStackVersion2 = new servicecatalog.ProductStack(stack, 'ProductStackV2'); + + new sns.Topic(productStackVersion1, 'SNSTopicProductStack1'); + + new sns.Topic(productStackVersion2, 'SNSTopicProductStack2', { + displayName: 'a test', + }); + + new servicecatalog.CloudFormationProduct(stack, 'MyProduct', { + productName: 'testProduct', + owner: 'testOwner', + productVersions: [ + { + productVersionName: 'v1', + cloudFormationTemplate: servicecatalog.CloudFormationTemplate.fromProductStack(productStackVersion1), + }, + { + productVersionName: 'v2', + cloudFormationTemplate: servicecatalog.CloudFormationTemplate.fromProductStack(productStackVersion2), + }, + ], + }); + + const assembly = app.synth(); + + expect(assembly.stacks[0].assets.length).toBe(2); + expect(assembly.stacks[0].assets[0].path).toEqual('ProductStackV1.product.template.json'); + expect(assembly.stacks[0].assets[1].path).toEqual('ProductStackV2.product.template.json'); + }), + + test('identical product versions from product stack creates one asset', () => { + class TestProductStack extends servicecatalog.ProductStack { + constructor(scope: any, id: string) { + super(scope, id); + + new sns.Topic(this, 'TopicProduct'); + } + } + + new servicecatalog.CloudFormationProduct(stack, 'MyProduct', { + productName: 'testProduct', + owner: 'testOwner', + productVersions: [ + { + productVersionName: 'v1', + cloudFormationTemplate: servicecatalog.CloudFormationTemplate.fromProductStack(new TestProductStack(stack, 'v1')), + }, + { + productVersionName: 'v2', + cloudFormationTemplate: servicecatalog.CloudFormationTemplate.fromProductStack(new TestProductStack(stack, 'v2')), + }, + { + productVersionName: 'v3', + cloudFormationTemplate: servicecatalog.CloudFormationTemplate.fromProductStack(new TestProductStack(stack, 'v3')), + }, + ], + }); + + const assembly = app.synth(); + + expect(assembly.stacks[0].assets.length).toBe(1); + }), + test('product test from multiple sources', () => { new servicecatalog.CloudFormationProduct(stack, 'MyProduct', { productName: 'testProduct', diff --git a/packages/@aws-cdk/aws-ses/package.json b/packages/@aws-cdk/aws-ses/package.json index a2a797e38b8cb..492108f1f04d9 100644 --- a/packages/@aws-cdk/aws-ses/package.json +++ b/packages/@aws-cdk/aws-ses/package.json @@ -77,7 +77,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.84", + "@types/aws-lambda": "^8.10.85", "@types/jest": "^26.0.24", "jest": "^26.6.3" }, diff --git a/packages/@aws-cdk/aws-sns-subscriptions/README.md b/packages/@aws-cdk/aws-sns-subscriptions/README.md index ca06d08689736..048ca4dd9fdda 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/README.md +++ b/packages/@aws-cdk/aws-sns-subscriptions/README.md @@ -27,8 +27,6 @@ Subscriptions to Amazon SQS and AWS Lambda can be added on topics across regions Create an Amazon SNS Topic to add subscriptions. ```ts -import * as sns from '@aws-cdk/aws-sns'; - const myTopic = new sns.Topic(this, 'MyTopic'); ``` @@ -37,7 +35,7 @@ const myTopic = new sns.Topic(this, 'MyTopic'); Add an HTTP or HTTPS Subscription to your topic: ```ts -import * as subscriptions from '@aws-cdk/aws-sns-subscriptions'; +const myTopic = new sns.Topic(this, 'MyTopic'); myTopic.addSubscription(new subscriptions.UrlSubscription('https://foobar.com/')); ``` @@ -48,8 +46,10 @@ parameter](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parame following code defines a CloudFormation parameter and uses it in a URL subscription. ```ts +const myTopic = new sns.Topic(this, 'MyTopic'); const url = new CfnParameter(this, 'url-param'); -myTopic.addSubscription(new subscriptions.UrlSubscription(url.valueAsString())); + +myTopic.addSubscription(new subscriptions.UrlSubscription(url.valueAsString)); ``` ### Amazon SQS @@ -57,12 +57,10 @@ myTopic.addSubscription(new subscriptions.UrlSubscription(url.valueAsString())); Subscribe a queue to your topic: ```ts -import * as sqs from '@aws-cdk/aws-sqs'; -import * as subscriptions from '@aws-cdk/aws-sns-subscriptions'; - const myQueue = new sqs.Queue(this, 'MyQueue'); +const myTopic = new sns.Topic(this, 'MyTopic'); -myTopic.addSubscription(new subscriptions.SqsSubscription(queue)); +myTopic.addSubscription(new subscriptions.SqsSubscription(myQueue)); ``` KMS key permissions will automatically be granted to SNS when a subscription is made to @@ -77,14 +75,9 @@ Subscribe an AWS Lambda function to your topic: ```ts import * as lambda from '@aws-cdk/aws-lambda'; -import * as subscriptions from '@aws-cdk/aws-sns-subscriptions'; - -const myFunction = new lambda.Function(this, 'Echo', { - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_12_X, - code: lambda.Code.fromInline(`exports.handler = ${handler.toString()}`) -}); +const myTopic = new sns.Topic(this, 'myTopic'); +declare const myFunction: lambda.Function; myTopic.addSubscription(new subscriptions.LambdaSubscription(myFunction)); ``` @@ -93,8 +86,7 @@ myTopic.addSubscription(new subscriptions.LambdaSubscription(myFunction)); Subscribe an email address to your topic: ```ts -import * as subscriptions from '@aws-cdk/aws-sns-subscriptions'; - +const myTopic = new sns.Topic(this, 'MyTopic'); myTopic.addSubscription(new subscriptions.EmailSubscription('foo@bar.com')); ``` @@ -104,8 +96,10 @@ parameter](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parame following code defines a CloudFormation parameter and uses it in an email subscription. ```ts +const myTopic = new sns.Topic(this, 'Topic'); const emailAddress = new CfnParameter(this, 'email-param'); -myTopic.addSubscription(new subscriptions.EmailSubscription(emailAddress.valueAsString())); + +myTopic.addSubscription(new subscriptions.EmailSubscription(emailAddress.valueAsString)); ``` Note that email subscriptions require confirmation by visiting the link sent to the @@ -116,7 +110,7 @@ email address. Subscribe an sms number to your topic: ```ts -import * as subscriptions from '@aws-cdk/aws-sns-subscriptions'; +const myTopic = new sns.Topic(this, 'Topic'); myTopic.addSubscription(new subscriptions.SmsSubscription('+15551231234')); ``` @@ -127,6 +121,8 @@ parameter](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parame following code defines a CloudFormation parameter and uses it in an sms subscription. ```ts +const myTopic = new sns.Topic(this, 'Topic'); const smsNumber = new CfnParameter(this, 'sms-param'); -myTopic.addSubscription(new subscriptions.SmsSubscription(smsNumber.valueAsString())); + +myTopic.addSubscription(new subscriptions.SmsSubscription(smsNumber.valueAsString)); ``` diff --git a/packages/@aws-cdk/aws-sns-subscriptions/rosetta/default.ts-fixture b/packages/@aws-cdk/aws-sns-subscriptions/rosetta/default.ts-fixture new file mode 100644 index 0000000000000..8fd7cde78ac48 --- /dev/null +++ b/packages/@aws-cdk/aws-sns-subscriptions/rosetta/default.ts-fixture @@ -0,0 +1,15 @@ +// Fixture with packages imported, but nothing else +import { Construct } from 'constructs'; +import { CfnParameter, Duration, Stack } from '@aws-cdk/core'; +import * as sns from '@aws-cdk/aws-sns'; +import * as sqs from '@aws-cdk/aws-sqs'; +import * as subscriptions from '@aws-cdk/aws-sns-subscriptions'; +import * as iam from '@aws-cdk/aws-iam'; + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + /// here + } +} diff --git a/packages/@aws-cdk/aws-sns/README.md b/packages/@aws-cdk/aws-sns/README.md index 23ee15e4af508..72678ff0f8a3d 100644 --- a/packages/@aws-cdk/aws-sns/README.md +++ b/packages/@aws-cdk/aws-sns/README.md @@ -14,23 +14,19 @@ Add an SNS Topic to your stack: ```ts -import * as sns from '@aws-cdk/aws-sns'; - const topic = new sns.Topic(this, 'Topic', { - displayName: 'Customer subscription topic' + displayName: 'Customer subscription topic', }); ``` Add a FIFO SNS topic with content-based de-duplication to your stack: ```ts -import * as sns from '@aws-cdk/aws-sns'; - const topic = new sns.Topic(this, 'Topic', { - contentBasedDeduplication: true, - displayName: 'Customer subscription topic', - fifo: true, - topicName: 'customerTopic', + contentBasedDeduplication: true, + displayName: 'Customer subscription topic', + fifo: true, + topicName: 'customerTopic', }); ``` @@ -46,17 +42,18 @@ default implementations of which can be found in the Add an HTTPS Subscription to your topic: ```ts -import * as subs from '@aws-cdk/aws-sns-subscriptions'; - const myTopic = new sns.Topic(this, 'MyTopic'); -myTopic.addSubscription(new subs.UrlSubscription('https://foobar.com/')); +myTopic.addSubscription(new subscriptions.UrlSubscription('https://foobar.com/')); ``` Subscribe a queue to the topic: ```ts -myTopic.addSubscription(new subs.SqsSubscription(queue)); +declare const queue: sqs.Queue; +const myTopic = new sns.Topic(this, 'MyTopic'); + +myTopic.addSubscription(new subscriptions.SqsSubscription(queue)); ``` Note that subscriptions of queues in different accounts need to be manually confirmed by @@ -69,44 +66,48 @@ A filter policy can be specified when subscribing an endpoint to a topic. Example with a Lambda subscription: ```ts +import * as lambda from '@aws-cdk/aws-lambda'; + const myTopic = new sns.Topic(this, 'MyTopic'); -const fn = new lambda.Function(this, 'Function', ...); +declare const fn: lambda.Function; // Lambda should receive only message matching the following conditions on attributes: // color: 'red' or 'orange' or begins with 'bl' // size: anything but 'small' or 'medium' // price: between 100 and 200 or greater than 300 // store: attribute must be present -topic.addSubscription(new subs.LambdaSubscription(fn, { - filterPolicy: { - color: sns.SubscriptionFilter.stringFilter({ - allowlist: ['red', 'orange'], - matchPrefixes: ['bl'] - }), - size: sns.SubscriptionFilter.stringFilter({ - denylist: ['small', 'medium'], - }), - price: sns.SubscriptionFilter.numericFilter({ - between: { start: 100, stop: 200 }, - greaterThan: 300 - }), - store: sns.SubscriptionFilter.existsFilter(), - } +myTopic.addSubscription(new subscriptions.LambdaSubscription(fn, { + filterPolicy: { + color: sns.SubscriptionFilter.stringFilter({ + allowlist: ['red', 'orange'], + matchPrefixes: ['bl'], + }), + size: sns.SubscriptionFilter.stringFilter({ + denylist: ['small', 'medium'], + }), + price: sns.SubscriptionFilter.numericFilter({ + between: { start: 100, stop: 200 }, + greaterThan: 300, + }), + store: sns.SubscriptionFilter.existsFilter(), + }, })); ``` ### Example of Firehose Subscription -```typescript - import { Subscription, SubscriptionProtocol, Topic } from '@aws-cdk/aws-sns'; - import { DeliveryStream } from '@aws-cdk/aws-kinesisfirehose'; - const topic = new Topic(stack, 'Topic'); - const stream = new DeliveryStream(stack, 'DeliveryStream', ...) - new Subscription(stack, 'Subscription', { - endpoint: stream.deliveryStreamArn, - protocol: SubscriptionProtocol.FIREHOSE, - subscriptionRoleArn: "SAMPLE_ARN", //role with permissions to send messages to a firehose delivery stream - }) +```ts +import { DeliveryStream } from '@aws-cdk/aws-kinesisfirehose'; + +const topic = new sns.Topic(this, 'Topic'); +declare const stream: DeliveryStream; + +new sns.Subscription(this, 'Subscription', { + topic, + endpoint: stream.deliveryStreamArn, + protocol: sns.SubscriptionProtocol.FIREHOSE, + subscriptionRoleArn: "SAMPLE_ARN", //role with permissions to send messages to a firehose delivery stream +}); ``` ## DLQ setup for SNS Subscription @@ -117,17 +118,17 @@ See the [SNS DLQ configuration docs](https://docs.aws.amazon.com/sns/latest/dg/s Example of usage with user provided DLQ. ```ts -const topic = new sns.Topic(stack, 'Topic'); -const dlQueue = new Queue(stack, 'DeadLetterQueue', { - queueName: 'MySubscription_DLQ', - retentionPeriod: cdk.Duration.days(14), +const topic = new sns.Topic(this, 'Topic'); +const dlQueue = new sqs.Queue(this, 'DeadLetterQueue', { + queueName: 'MySubscription_DLQ', + retentionPeriod: Duration.days(14), }); -new sns.Subscription(stack, 'Subscription', { - endpoint: 'endpoint', - protocol: sns.SubscriptionProtocol.LAMBDA, - topic, - deadLetterQueue: dlQueue, +new sns.Subscription(this, 'Subscription', { + endpoint: 'endpoint', + protocol: sns.SubscriptionProtocol.LAMBDA, + topic, + deadLetterQueue: dlQueue, }); ``` @@ -138,9 +139,15 @@ SNS topics can be used as targets for CloudWatch event rules. Use the `@aws-cdk/aws-events-targets.SnsTopic`: ```ts +import * as codecommit from '@aws-cdk/aws-codecommit'; import * as targets from '@aws-cdk/aws-events-targets'; -codeCommitRepository.onCommit(new targets.SnsTopic(myTopic)); +declare const repo: codecommit.Repository; +const myTopic = new sns.Topic(this, 'Topic'); + +repo.onCommit('OnCommit', { + target: new targets.SnsTopic(myTopic), +}); ``` This will result in adding a target to the event rule and will also modify the @@ -153,8 +160,8 @@ one doesn't already exist. Using `addToResourcePolicy` is the simplest way to add policies, but a `TopicPolicy` can also be created manually. ```ts -const topic = new sns.Topic(stack, 'Topic'); -const topicPolicy = new sns.TopicPolicy(stack, 'TopicPolicy', { +const topic = new sns.Topic(this, 'Topic'); +const topicPolicy = new sns.TopicPolicy(this, 'TopicPolicy', { topics: [topic], }); @@ -168,14 +175,14 @@ topicPolicy.document.addStatements(new iam.PolicyStatement({ A policy document can also be passed on `TopicPolicy` construction ```ts -const topic = new sns.Topic(stack, 'Topic'); +const topic = new sns.Topic(this, 'Topic'); const policyDocument = new iam.PolicyDocument({ assignSids: true, statements: [ new iam.PolicyStatement({ actions: ["sns:Subscribe"], principals: [new iam.AnyPrincipal()], - resources: [topic.topicArn] + resources: [topic.topicArn], }), ], }); diff --git a/packages/@aws-cdk/aws-sns/rosetta/default.ts-fixture b/packages/@aws-cdk/aws-sns/rosetta/default.ts-fixture new file mode 100644 index 0000000000000..72fda381ecb7a --- /dev/null +++ b/packages/@aws-cdk/aws-sns/rosetta/default.ts-fixture @@ -0,0 +1,15 @@ +// Fixture with packages imported, but nothing else +import { Construct } from 'constructs'; +import { Duration, Stack } from '@aws-cdk/core'; +import * as sns from '@aws-cdk/aws-sns'; +import * as sqs from '@aws-cdk/aws-sqs'; +import * as subscriptions from '@aws-cdk/aws-sns-subscriptions'; +import * as iam from '@aws-cdk/aws-iam'; + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + /// here + } +} diff --git a/packages/@aws-cdk/aws-sqs/README.md b/packages/@aws-cdk/aws-sqs/README.md index c824f9410e8ad..11dbb164e5c56 100644 --- a/packages/@aws-cdk/aws-sqs/README.md +++ b/packages/@aws-cdk/aws-sqs/README.md @@ -22,7 +22,7 @@ without losing messages or requiring other services to be available. Import to your project: -```ts +```ts nofixture import * as sqs from '@aws-cdk/aws-sqs'; ``` @@ -44,15 +44,15 @@ can manage yourself. ```ts // Use managed key new sqs.Queue(this, 'Queue', { - encryption: QueueEncryption.KMS_MANAGED, + encryption: sqs.QueueEncryption.KMS_MANAGED, }); // Use custom key const myKey = new kms.Key(this, 'Key'); new sqs.Queue(this, 'Queue', { - encryption: QueueEncryption.KMS, - encryptionMasterKey: myKey + encryption: sqs.QueueEncryption.KMS, + encryptionMasterKey: myKey, }); ``` diff --git a/packages/@aws-cdk/aws-sqs/rosetta/default.ts-fixture b/packages/@aws-cdk/aws-sqs/rosetta/default.ts-fixture new file mode 100644 index 0000000000000..968d51c8ae916 --- /dev/null +++ b/packages/@aws-cdk/aws-sqs/rosetta/default.ts-fixture @@ -0,0 +1,13 @@ +// Fixture with packages imported, but nothing else +import { Construct } from 'constructs'; +import { Stack } from '@aws-cdk/core'; +import sqs = require('@aws-cdk/aws-sqs'); +import kms = require('@aws-cdk/aws-kms'); + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + /// here + } +} diff --git a/packages/@aws-cdk/aws-ssm/README.md b/packages/@aws-cdk/aws-ssm/README.md index 54e7acab8cec0..23fea31765525 100644 --- a/packages/@aws-cdk/aws-ssm/README.md +++ b/packages/@aws-cdk/aws-ssm/README.md @@ -23,7 +23,7 @@ $ npm i @aws-cdk/aws-ssm Import it into your code: -```ts +```ts nofixture import * as ssm from '@aws-cdk/aws-ssm'; ``` @@ -43,7 +43,7 @@ to provision secrets automatically, use Secrets Manager Secrets (see the `@aws-cdk/aws-secretsmanager` package). ```ts -new ssm.StringParameter(stack, 'Parameter', { +new ssm.StringParameter(this, 'Parameter', { allowedPattern: '.*', description: 'The value Foo', parameterName: 'FooParameter', diff --git a/packages/@aws-cdk/aws-ssm/rosetta/default.ts-fixture b/packages/@aws-cdk/aws-ssm/rosetta/default.ts-fixture new file mode 100644 index 0000000000000..66143d00d0bff --- /dev/null +++ b/packages/@aws-cdk/aws-ssm/rosetta/default.ts-fixture @@ -0,0 +1,12 @@ +// Fixture with packages imported, but nothing else +import { Construct } from 'constructs'; +import { Stack } from '@aws-cdk/core'; +import * as ssm from '@aws-cdk/aws-ssm'; + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + /// here + } +} diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/README.md b/packages/@aws-cdk/aws-stepfunctions-tasks/README.md index cedf89eefe07c..2f5d463067a35 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/README.md +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/README.md @@ -348,7 +348,7 @@ action name does not match with the API service/action name: ```ts const listBuckets = new tasks.CallAwsService(this, 'ListBuckets', { service: 's3', - action: 'ListBuckets', + action: 'listBuckets', iamResources: ['*'], iamAction: 's3:ListAllMyBuckets', }); diff --git a/packages/@aws-cdk/aws-synthetics/README.md b/packages/@aws-cdk/aws-synthetics/README.md index 7f7665e02238c..cdb5aaa6dff47 100644 --- a/packages/@aws-cdk/aws-synthetics/README.md +++ b/packages/@aws-cdk/aws-synthetics/README.md @@ -97,13 +97,15 @@ object to the `schedule` property. Configure a run rate of up to 60 minutes with `Schedule.rate`: ```ts -Schedule.rate(Duration.minutes(5)), // Runs every 5 minutes. +const schedule = synthetics.Schedule.rate(Duration.minutes(5)); // Runs every 5 minutes. ``` -You can also specify a [cron expression](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_cron.html) via `Schedule.expression`: +You can also specify a [cron expression](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_cron.html) with `Schedule.cron`: ```ts -Schedule.expression('cron(0 0,8,16 * * ? *)'), // Run at 12am, 8am, 4pm UTC every day +const schedule = synthetics.Schedule.cron({ + hour: '0,8,16', // Run at 12am, 8am, 4pm UTC every day +}); ``` If you want the canary to run just once upon deployment, you can use `Schedule.once()`. @@ -181,8 +183,10 @@ You can configure a CloudWatch Alarm on a canary metric. Metrics are emitted by Create an alarm that tracks the canary metric: -```ts fixture=canary +```ts import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; + +declare const canary: synthetics.Canary; new cloudwatch.Alarm(this, 'CanaryAlarm', { metric: canary.metricSuccessPercent(), evaluationPeriods: 2, @@ -190,7 +194,3 @@ new cloudwatch.Alarm(this, 'CanaryAlarm', { comparisonOperator: cloudwatch.ComparisonOperator.LESS_THAN_THRESHOLD, }); ``` - -### Future Work - -- Add blueprints to the Test class [#9613](https://github.com/aws/aws-cdk/issues/9613#issue-677134857). diff --git a/packages/@aws-cdk/aws-synthetics/lib/schedule.ts b/packages/@aws-cdk/aws-synthetics/lib/schedule.ts index 3bd92c81b4d0b..248b44e4c59cb 100644 --- a/packages/@aws-cdk/aws-synthetics/lib/schedule.ts +++ b/packages/@aws-cdk/aws-synthetics/lib/schedule.ts @@ -42,9 +42,81 @@ export class Schedule { return new Schedule(`rate(${minutes} minutes)`); } + /** + * Create a schedule from a set of cron fields + */ + public static cron(options: CronOptions): Schedule { + if (options.weekDay !== undefined && options.day !== undefined) { + throw new Error('Cannot supply both \'day\' and \'weekDay\', use at most one'); + } + + const minute = fallback(options.minute, '*'); + const hour = fallback(options.hour, '*'); + const month = fallback(options.month, '*'); + + // Weekday defaults to '?' if not supplied. If it is supplied, day must become '?' + const day = fallback(options.day, options.weekDay !== undefined ? '?' : '*'); + const weekDay = fallback(options.weekDay, '?'); + + // '*' is only allowed in the year field + const year = '*'; + + return new Schedule(`cron(${minute} ${hour} ${day} ${month} ${weekDay} ${year})`); + } + private constructor( /** * The Schedule expression */ public readonly expressionString: string) {} } + + +/** + * Options to configure a cron expression + * + * All fields are strings so you can use complex expressions. Absence of + * a field implies '*' or '?', whichever one is appropriate. + * + * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_cron.html + */ +export interface CronOptions { + /** + * The minute to run this rule at + * + * @default - Every minute + */ + readonly minute?: string; + + /** + * The hour to run this rule at + * + * @default - Every hour + */ + readonly hour?: string; + + /** + * The day of the month to run this rule at + * + * @default - Every day of the month + */ + readonly day?: string; + + /** + * The month to run this rule at + * + * @default - Every month + */ + readonly month?: string; + + /** + * The day of the week to run this rule at + * + * @default - Any day of the week + */ + readonly weekDay?: string; +} + +function fallback(x: string | undefined, def: string): string { + return x ?? def; +} diff --git a/packages/@aws-cdk/aws-synthetics/rosetta/canary.ts-fixture b/packages/@aws-cdk/aws-synthetics/rosetta/canary.ts-fixture deleted file mode 100644 index d1950f9d9bcbe..0000000000000 --- a/packages/@aws-cdk/aws-synthetics/rosetta/canary.ts-fixture +++ /dev/null @@ -1,21 +0,0 @@ -// Fixture with a canary already created, named `canary` -import { Construct, Duration, Stack } from '@aws-cdk/core'; -import * as synthetics from '@aws-cdk/aws-synthetics'; -import * as path from 'path'; - -class Fixture extends Stack { - constructor(scope: Construct, id: string) { - super(scope, id); - - const canary = new synthetics.Canary(this, 'MyCanary', { - schedule: synthetics.Schedule.rate(Duration.minutes(5)), - test: synthetics.Test.custom({ - code: synthetics.Code.fromAsset(path.join(__dirname, 'canary')), - handler: 'index.handler', - }), - runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_1, - }); - - /// here - } -} diff --git a/packages/@aws-cdk/aws-synthetics/rosetta/default.ts-fixture b/packages/@aws-cdk/aws-synthetics/rosetta/default.ts-fixture index 0af6c54c30689..a0a9d5c2a596e 100644 --- a/packages/@aws-cdk/aws-synthetics/rosetta/default.ts-fixture +++ b/packages/@aws-cdk/aws-synthetics/rosetta/default.ts-fixture @@ -1,5 +1,6 @@ // Fixture with packages imported, but nothing else -import { Construct, Duration, Stack } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import { Duration, Stack } from '@aws-cdk/core'; import * as synthetics from '@aws-cdk/aws-synthetics'; import * as path from 'path'; diff --git a/packages/@aws-cdk/aws-synthetics/test/canary.test.ts b/packages/@aws-cdk/aws-synthetics/test/canary.test.ts index 27491d01b2850..83ba173562834 100644 --- a/packages/@aws-cdk/aws-synthetics/test/canary.test.ts +++ b/packages/@aws-cdk/aws-synthetics/test/canary.test.ts @@ -292,6 +292,27 @@ test('Schedule can be set to 1 minute', () => { }); }); +test('Schedule can be set with Cron', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + new synthetics.Canary(stack, 'Canary', { + schedule: synthetics.Schedule.cron({ minute: '30' }), + test: synthetics.Test.custom({ + handler: 'index.handler', + code: synthetics.Code.fromInline('/* Synthetics handler code */'), + }), + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_3, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Synthetics::Canary', { + Schedule: Match.objectLike({ Expression: 'cron(30 * * * ? *)' }), + }); +}); + + test('Schedule can be set with Expression', () => { // GIVEN const stack = new Stack(); diff --git a/packages/@aws-cdk/aws-synthetics/test/schedule.test.ts b/packages/@aws-cdk/aws-synthetics/test/schedule.test.ts new file mode 100644 index 0000000000000..664f27774b61f --- /dev/null +++ b/packages/@aws-cdk/aws-synthetics/test/schedule.test.ts @@ -0,0 +1,26 @@ +import * as synthetics from '../lib'; + +describe('cron', () => { + test('day and weekDay are mutex: given week day', () => { + expect(synthetics.Schedule.cron({ + weekDay: 'MON-FRI', + }).expressionString).toEqual('cron(* * ? * MON-FRI *)'); + }); + + test('day and weekDay are mutex: given month day', () => { + expect(synthetics.Schedule.cron({ + day: '1', + }).expressionString).toEqual('cron(* * 1 * ? *)'); + }); + + test('day and weekDay are mutex: given neither', () => { + expect(synthetics.Schedule.cron({}).expressionString).toEqual('cron(* * * * ? *)'); + }); + + test('day and weekDay are mutex: throw if given both', () => { + expect(() => synthetics.Schedule.cron({ + day: '1', + weekDay: 'MON', + })).toThrow('Cannot supply both \'day\' and \'weekDay\', use at most one'); + }); +}); diff --git a/packages/@aws-cdk/aws-wisdom/.eslintrc.js b/packages/@aws-cdk/aws-wisdom/.eslintrc.js new file mode 100644 index 0000000000000..2658ee8727166 --- /dev/null +++ b/packages/@aws-cdk/aws-wisdom/.eslintrc.js @@ -0,0 +1,3 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-wisdom/.gitignore b/packages/@aws-cdk/aws-wisdom/.gitignore new file mode 100644 index 0000000000000..62ebc95d75ce6 --- /dev/null +++ b/packages/@aws-cdk/aws-wisdom/.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-wisdom/.npmignore b/packages/@aws-cdk/aws-wisdom/.npmignore new file mode 100644 index 0000000000000..f931fede67c44 --- /dev/null +++ b/packages/@aws-cdk/aws-wisdom/.npmignore @@ -0,0 +1,29 @@ +# 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/ +!*.lit.ts diff --git a/packages/@aws-cdk/aws-wisdom/LICENSE b/packages/@aws-cdk/aws-wisdom/LICENSE new file mode 100644 index 0000000000000..28e4bdcec77ec --- /dev/null +++ b/packages/@aws-cdk/aws-wisdom/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-wisdom/NOTICE b/packages/@aws-cdk/aws-wisdom/NOTICE new file mode 100644 index 0000000000000..5fc3826926b5b --- /dev/null +++ b/packages/@aws-cdk/aws-wisdom/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-wisdom/README.md b/packages/@aws-cdk/aws-wisdom/README.md new file mode 100644 index 0000000000000..d942b3358d363 --- /dev/null +++ b/packages/@aws-cdk/aws-wisdom/README.md @@ -0,0 +1,20 @@ +# AWS::Wisdom 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 aws-wisdom = require('@aws-cdk/aws-wisdom'); +``` diff --git a/packages/@aws-cdk/aws-wisdom/jest.config.js b/packages/@aws-cdk/aws-wisdom/jest.config.js new file mode 100644 index 0000000000000..3a2fd93a1228a --- /dev/null +++ b/packages/@aws-cdk/aws-wisdom/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-wisdom/lib/index.ts b/packages/@aws-cdk/aws-wisdom/lib/index.ts new file mode 100644 index 0000000000000..368aee100e245 --- /dev/null +++ b/packages/@aws-cdk/aws-wisdom/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::Wisdom CloudFormation Resources: +export * from './wisdom.generated'; diff --git a/packages/@aws-cdk/aws-wisdom/package.json b/packages/@aws-cdk/aws-wisdom/package.json new file mode 100644 index 0000000000000..44465292a4350 --- /dev/null +++ b/packages/@aws-cdk/aws-wisdom/package.json @@ -0,0 +1,105 @@ +{ + "name": "@aws-cdk/aws-wisdom", + "version": "0.0.0", + "description": "The CDK Construct Library for AWS::Wisdom", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "projectReferences": true, + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.Wisdom", + "packageId": "Amazon.CDK.AWS.Wisdom", + "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.wisdom", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "wisdom" + } + }, + "python": { + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 1" + ], + "distName": "aws-cdk.aws-wisdom", + "module": "aws_cdk.aws_wisdom" + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-wisdom" + }, + "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", + "build+extract": "yarn build && yarn rosetta:extract", + "build+test+extract": "yarn build+test && yarn rosetta:extract" + }, + "cdk-build": { + "cloudformation": "AWS::Wisdom", + "jest": true, + "env": { + "AWSLINT_BASE_CONSTRUCT": "true" + } + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::Wisdom", + "aws-wisdom" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.22" + }, + "dependencies": { + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" + }, + "peerDependencies": { + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" + }, + "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-wisdom/test/aws-wisdom.test.ts b/packages/@aws-cdk/aws-wisdom/test/aws-wisdom.test.ts new file mode 100644 index 0000000000000..465c7bdea0693 --- /dev/null +++ b/packages/@aws-cdk/aws-wisdom/test/aws-wisdom.test.ts @@ -0,0 +1,6 @@ +import '@aws-cdk/assertions'; +import {} from '../lib'; + +test('No tests are specified for this package', () => { + expect(true).toBe(true); +}); diff --git a/packages/@aws-cdk/cfnspec/CHANGELOG.md b/packages/@aws-cdk/cfnspec/CHANGELOG.md index 19c814c818182..913546215a38d 100644 --- a/packages/@aws-cdk/cfnspec/CHANGELOG.md +++ b/packages/@aws-cdk/cfnspec/CHANGELOG.md @@ -1,3 +1,521 @@ +# CloudFormation Resource Specification v47.0.0 + +## New Resource Types + +* AWS::CloudFront::ResponseHeadersPolicy +* AWS::DataSync::LocationHDFS +* AWS::IoT::Logging +* AWS::IoT::ResourceSpecificLogging +* AWS::Pinpoint::InAppTemplate +* AWS::Redshift::EndpointAccess +* AWS::Redshift::EndpointAuthorization +* AWS::Redshift::EventSubscription +* AWS::Redshift::ScheduledAction + +## Attribute Changes + +* AWS::EC2::InternetGateway InternetGatewayId (__added__) +* AWS::EC2::NetworkInterface Id (__added__) +* AWS::EC2::NetworkInterface SecondaryPrivateIpAddresses.DuplicatesAllowed (__added__) +* AWS::EC2::NetworkInterface Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkinterface.html +* AWS::IoTAnalytics::Channel Id (__added__) +* AWS::IoTAnalytics::Dataset Id (__added__) +* AWS::IoTAnalytics::Datastore Id (__added__) +* AWS::IoTAnalytics::Pipeline Id (__added__) + +## Property Changes + +* AWS::DMS::Endpoint RedisSettings (__added__) +* AWS::EC2::NetworkInterface Description.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html#cfn-awsec2networkinterface-description + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkinterface.html#cfn-ec2-networkinterface-description +* AWS::EC2::NetworkInterface GroupSet.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html#cfn-awsec2networkinterface-groupset + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkinterface.html#cfn-ec2-networkinterface-groupset +* AWS::EC2::NetworkInterface GroupSet.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::EC2::NetworkInterface InterfaceType.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html#cfn-ec2-networkinterface-interfacetype + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkinterface.html#cfn-ec2-networkinterface-interfacetype +* AWS::EC2::NetworkInterface Ipv6AddressCount.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html#cfn-ec2-networkinterface-ipv6addresscount + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkinterface.html#cfn-ec2-networkinterface-ipv6addresscount +* AWS::EC2::NetworkInterface Ipv6Addresses.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html#cfn-ec2-networkinterface-ipv6addresses + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkinterface.html#cfn-ec2-networkinterface-ipv6addresses +* AWS::EC2::NetworkInterface PrivateIpAddress.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html#cfn-awsec2networkinterface-privateipaddress + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkinterface.html#cfn-ec2-networkinterface-privateipaddress +* AWS::EC2::NetworkInterface PrivateIpAddresses.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html#cfn-awsec2networkinterface-privateipaddresses + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkinterface.html#cfn-ec2-networkinterface-privateipaddresses +* AWS::EC2::NetworkInterface PrivateIpAddresses.DuplicatesAllowed (__changed__) + * Old: false + * New: true +* AWS::EC2::NetworkInterface PrivateIpAddresses.UpdateType (__changed__) + * Old: Conditional + * New: Mutable +* AWS::EC2::NetworkInterface SecondaryPrivateIpAddressCount.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html#cfn-awsec2networkinterface-secondaryprivateipcount + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkinterface.html#cfn-ec2-networkinterface-secondaryprivateipaddresscount +* AWS::EC2::NetworkInterface SourceDestCheck.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html#cfn-awsec2networkinterface-sourcedestcheck + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkinterface.html#cfn-ec2-networkinterface-sourcedestcheck +* AWS::EC2::NetworkInterface SubnetId.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html#cfn-awsec2networkinterface-subnetid + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkinterface.html#cfn-ec2-networkinterface-subnetid +* AWS::EC2::NetworkInterface Tags.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html#cfn-awsec2networkinterface-tags + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkinterface.html#cfn-ec2-networkinterface-tags +* AWS::EC2::TransitGatewayPeeringAttachment Options (__added__) +* AWS::EC2::VPCEndpointService PayerResponsibility (__added__) +* AWS::EKS::Cluster Logging (__added__) +* AWS::EKS::Cluster Tags (__added__) +* AWS::EKS::Cluster ResourcesVpcConfig.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::IoTAnalytics::Channel ChannelName.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Channel Tags.DuplicatesAllowed (__added__) +* AWS::IoTAnalytics::Dataset Actions.DuplicatesAllowed (__added__) +* AWS::IoTAnalytics::Dataset ContentDeliveryRules.DuplicatesAllowed (__added__) +* AWS::IoTAnalytics::Dataset DatasetName.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Dataset LateDataRules.DuplicatesAllowed (__added__) +* AWS::IoTAnalytics::Dataset Tags.DuplicatesAllowed (__added__) +* AWS::IoTAnalytics::Dataset Triggers.DuplicatesAllowed (__added__) +* AWS::IoTAnalytics::Datastore Tags.DuplicatesAllowed (__added__) +* AWS::IoTAnalytics::Pipeline PipelineActivities.DuplicatesAllowed (__added__) +* AWS::IoTAnalytics::Pipeline PipelineName.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Pipeline Tags.DuplicatesAllowed (__added__) +* AWS::S3ObjectLambda::AccessPoint Name.Required (__changed__) + * Old: true + * New: false +* AWS::SageMaker::Endpoint RetainDeploymentConfig (__added__) + +## Property Type Changes + +* AWS::EKS::Cluster.Provider (__removed__) +* AWS::DMS::Endpoint.RedisSettings (__added__) +* AWS::EC2::EC2Fleet.CapacityRebalance (__added__) +* AWS::EC2::EC2Fleet.MaintenanceStrategies (__added__) +* AWS::EC2::TransitGatewayPeeringAttachment.TransitGatewayPeeringAttachmentOptions (__added__) +* AWS::EKS::Cluster.ClusterLogging (__added__) +* AWS::EKS::Cluster.Logging (__added__) +* AWS::EKS::Cluster.LoggingTypeConfig (__added__) +* AWS::NetworkFirewall::FirewallPolicy.StatefulEngineOptions (__added__) +* AWS::NetworkFirewall::RuleGroup.StatefulRuleOptions (__added__) +* AWS::DMS::Endpoint.KafkaSettings IncludeControlDetails (__added__) +* AWS::DMS::Endpoint.KafkaSettings IncludeNullAndEmpty (__added__) +* AWS::DMS::Endpoint.KafkaSettings IncludeTableAlterOperations (__added__) +* AWS::DMS::Endpoint.KafkaSettings IncludeTransactionDetails (__added__) +* AWS::DMS::Endpoint.KafkaSettings NoHexPrefix (__added__) +* AWS::DMS::Endpoint.KafkaSettings PartitionIncludeSchemaTable (__added__) +* AWS::DMS::Endpoint.KafkaSettings SaslPassword (__added__) +* AWS::DMS::Endpoint.KafkaSettings SaslUserName (__added__) +* AWS::DMS::Endpoint.KafkaSettings SecurityProtocol (__added__) +* AWS::DMS::Endpoint.KafkaSettings SslCaCertificateArn (__added__) +* AWS::DMS::Endpoint.KafkaSettings SslClientCertificateArn (__added__) +* AWS::DMS::Endpoint.KafkaSettings SslClientKeyArn (__added__) +* AWS::DMS::Endpoint.KafkaSettings SslClientKeyPassword (__added__) +* AWS::DMS::Endpoint.KinesisSettings IncludeControlDetails (__added__) +* AWS::DMS::Endpoint.KinesisSettings IncludeNullAndEmpty (__added__) +* AWS::DMS::Endpoint.KinesisSettings IncludeTableAlterOperations (__added__) +* AWS::DMS::Endpoint.KinesisSettings IncludeTransactionDetails (__added__) +* AWS::DMS::Endpoint.KinesisSettings NoHexPrefix (__added__) +* AWS::DMS::Endpoint.KinesisSettings PartitionIncludeSchemaTable (__added__) +* AWS::EC2::EC2Fleet.SpotOptionsRequest MaintenanceStrategies.PrimitiveType (__deleted__) +* AWS::EC2::EC2Fleet.SpotOptionsRequest MaintenanceStrategies.Type (__added__) +* AWS::EC2::NetworkInterface.PrivateIpAddressSpecification Primary.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-network-interface-privateipspec.html#cfn-ec2-networkinterface-privateipspecification-primary + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-networkinterface-privateipaddressspecification.html#cfn-ec2-networkinterface-privateipaddressspecification-primary +* AWS::EC2::NetworkInterface.PrivateIpAddressSpecification PrivateIpAddress.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-network-interface-privateipspec.html#cfn-ec2-networkinterface-privateipspecification-privateipaddress + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-networkinterface-privateipaddressspecification.html#cfn-ec2-networkinterface-privateipaddressspecification-privateipaddress +* AWS::EKS::Cluster.EncryptionConfig Provider.Type (__deleted__) +* AWS::EKS::Cluster.EncryptionConfig Provider.PrimitiveType (__added__) +* AWS::EKS::Cluster.EncryptionConfig Provider.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::EKS::Cluster.EncryptionConfig Resources.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::EKS::Cluster.KubernetesNetworkConfig ServiceIpv4Cidr.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::EKS::Cluster.ResourcesVpcConfig EndpointPrivateAccess (__added__) +* AWS::EKS::Cluster.ResourcesVpcConfig EndpointPublicAccess (__added__) +* AWS::EKS::Cluster.ResourcesVpcConfig PublicAccessCidrs (__added__) +* AWS::EKS::Cluster.ResourcesVpcConfig SecurityGroupIds.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::EKS::Cluster.ResourcesVpcConfig SubnetIds.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::IoTAnalytics::Dataset.ContainerAction Variables.DuplicatesAllowed (__added__) +* AWS::IoTAnalytics::Dataset.DatasetContentVersionValue DatasetName.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-dataset-variable-datasetcontentversionvalue.html#cfn-iotanalytics-dataset-variable-datasetcontentversionvalue-datasetname + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-dataset-datasetcontentversionvalue.html#cfn-iotanalytics-dataset-datasetcontentversionvalue-datasetname +* AWS::IoTAnalytics::Dataset.DatasetContentVersionValue DatasetName.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Dataset.OutputFileUriValue FileName.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-dataset-variable-outputfileurivalue.html#cfn-iotanalytics-dataset-variable-outputfileurivalue-filename + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-dataset-outputfileurivalue.html#cfn-iotanalytics-dataset-outputfileurivalue-filename +* AWS::IoTAnalytics::Dataset.OutputFileUriValue FileName.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Dataset.QueryAction Filters.DuplicatesAllowed (__added__) +* AWS::IoTAnalytics::Dataset.Schedule ScheduleExpression.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-dataset-trigger-schedule.html#cfn-iotanalytics-dataset-trigger-schedule-scheduleexpression + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-dataset-schedule.html#cfn-iotanalytics-dataset-schedule-scheduleexpression +* AWS::IoTAnalytics::Datastore.DatastorePartitions Partitions.DuplicatesAllowed (__added__) +* AWS::IoTAnalytics::Datastore.IotSiteWiseMultiLayerStorage CustomerManagedS3Storage.Required (__changed__) + * Old: true + * New: false +* AWS::IoTAnalytics::Datastore.SchemaDefinition Columns.DuplicatesAllowed (__added__) +* AWS::IoTAnalytics::Pipeline.AddAttributes Attributes.PrimitiveType (__deleted__) +* AWS::IoTAnalytics::Pipeline.AddAttributes Attributes.PrimitiveItemType (__added__) +* AWS::IoTAnalytics::Pipeline.AddAttributes Attributes.Type (__added__) +* AWS::IoTAnalytics::Pipeline.AddAttributes Attributes.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Pipeline.AddAttributes Name.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Pipeline.Channel ChannelName.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Pipeline.Channel Name.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Pipeline.Datastore DatastoreName.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Pipeline.Datastore Name.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Pipeline.DeviceRegistryEnrich Attribute.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Pipeline.DeviceRegistryEnrich Name.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Pipeline.DeviceRegistryEnrich RoleArn.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Pipeline.DeviceRegistryEnrich ThingName.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Pipeline.DeviceShadowEnrich Attribute.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Pipeline.DeviceShadowEnrich Name.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Pipeline.DeviceShadowEnrich RoleArn.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Pipeline.DeviceShadowEnrich ThingName.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Pipeline.Filter Filter.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Pipeline.Filter Name.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Pipeline.Lambda BatchSize.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Pipeline.Lambda LambdaName.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Pipeline.Lambda Name.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Pipeline.Math Attribute.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Pipeline.Math Math.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Pipeline.Math Name.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Pipeline.RemoveAttributes Attributes.DuplicatesAllowed (__added__) +* AWS::IoTAnalytics::Pipeline.RemoveAttributes Attributes.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Pipeline.RemoveAttributes Name.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Pipeline.SelectAttributes Attributes.DuplicatesAllowed (__added__) +* AWS::IoTAnalytics::Pipeline.SelectAttributes Attributes.Required (__changed__) + * Old: false + * New: true +* AWS::IoTAnalytics::Pipeline.SelectAttributes Name.Required (__changed__) + * Old: false + * New: true +* AWS::NetworkFirewall::FirewallPolicy.FirewallPolicy StatefulDefaultActions (__added__) +* AWS::NetworkFirewall::FirewallPolicy.FirewallPolicy StatefulEngineOptions (__added__) +* AWS::NetworkFirewall::FirewallPolicy.StatefulRuleGroupReference Priority (__added__) +* AWS::NetworkFirewall::RuleGroup.RuleGroup StatefulRuleOptions (__added__) +* AWS::SageMaker::Endpoint.TrafficRoutingConfig LinearStepSize (__added__) + + +# CloudFormation Resource Specification v46.0.0 + +## New Resource Types + +* AWS::Connect::HoursOfOperation +* AWS::Connect::User +* AWS::Connect::UserHierarchyGroup +* AWS::EC2::CapacityReservationFleet +* AWS::IoT::JobTemplate +* AWS::Lightsail::Database +* AWS::Lightsail::StaticIp +* AWS::Panorama::ApplicationInstance +* AWS::Panorama::Package +* AWS::Panorama::PackageVersion +* AWS::Rekognition::Project +* AWS::Route53Resolver::ResolverConfig +* AWS::Wisdom::Assistant +* AWS::Wisdom::AssistantAssociation +* AWS::Wisdom::KnowledgeBase + +## Attribute Changes + +* AWS::ApiGateway::Authorizer AuthorizerId (__added__) +* AWS::AutoScaling::LifecycleHook Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-as-lifecyclehook.html + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-lifecyclehook.html +* AWS::EC2::NetworkAcl Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-acl.html + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkacl.html +* AWS::EC2::NetworkAcl Id (__added__) +* AWS::EC2::NetworkAclEntry Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-acl-entry.html + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkaclentry.html +* AWS::EC2::NetworkAclEntry Id (__added__) +* AWS::EC2::RouteTable Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-route-table.html + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-routetable.html +* AWS::EC2::RouteTable RouteTableId (__added__) +* AWS::Lightsail::Instance KeyPairName (__deleted__) +* AWS::Lightsail::Instance UserData (__deleted__) +* AWS::Route53Resolver::ResolverRule TargetIps.PrimitiveType (__deleted__) +* AWS::Route53Resolver::ResolverRule TargetIps.DuplicatesAllowed (__added__) +* AWS::Route53Resolver::ResolverRule TargetIps.ItemType (__added__) +* AWS::Route53Resolver::ResolverRule TargetIps.Type (__added__) +* AWS::StepFunctions::Activity Arn (__added__) + +## Property Changes + +* AWS::ApiGateway::Authorizer Name.Required (__changed__) + * Old: false + * New: true +* AWS::ApiGateway::VpcLink Tags (__added__) +* AWS::AutoScaling::AutoScalingGroup DesiredCapacityType (__added__) +* AWS::AutoScaling::LifecycleHook AutoScalingGroupName.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-as-lifecyclehook.html#cfn-as-lifecyclehook-autoscalinggroupname + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-lifecyclehook.html#cfn-autoscaling-lifecyclehook-autoscalinggroupname +* AWS::AutoScaling::LifecycleHook DefaultResult.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-as-lifecyclehook.html#cfn-as-lifecyclehook-defaultresult + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-lifecyclehook.html#cfn-autoscaling-lifecyclehook-defaultresult +* AWS::AutoScaling::LifecycleHook HeartbeatTimeout.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-as-lifecyclehook.html#cfn-as-lifecyclehook-heartbeattimeout + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-lifecyclehook.html#cfn-autoscaling-lifecyclehook-heartbeattimeout +* AWS::AutoScaling::LifecycleHook LifecycleHookName.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-as-lifecyclehook.html#cfn-autoscaling-lifecyclehook-lifecyclehookname + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-lifecyclehook.html#cfn-autoscaling-lifecyclehook-lifecyclehookname +* AWS::AutoScaling::LifecycleHook LifecycleTransition.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-as-lifecyclehook.html#cfn-as-lifecyclehook-lifecycletransition + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-lifecyclehook.html#cfn-autoscaling-lifecyclehook-lifecycletransition +* AWS::AutoScaling::LifecycleHook NotificationMetadata.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-as-lifecyclehook.html#cfn-as-lifecyclehook-notificationmetadata + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-lifecyclehook.html#cfn-autoscaling-lifecyclehook-notificationmetadata +* AWS::AutoScaling::LifecycleHook NotificationTargetARN.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-as-lifecyclehook.html#cfn-as-lifecyclehook-notificationtargetarn + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-lifecyclehook.html#cfn-autoscaling-lifecyclehook-notificationtargetarn +* AWS::AutoScaling::LifecycleHook RoleARN.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-as-lifecyclehook.html#cfn-as-lifecyclehook-rolearn + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-lifecyclehook.html#cfn-autoscaling-lifecyclehook-rolearn +* AWS::Batch::ComputeEnvironment UnmanagedvCpus (__added__) +* AWS::Batch::JobDefinition SchedulingPriority (__added__) +* AWS::Batch::JobQueue SchedulingPolicyArn (__added__) +* AWS::Budgets::BudgetsAction Subscribers.Required (__changed__) + * Old: false + * New: true +* AWS::Cassandra::Table DefaultTimeToLive (__added__) +* AWS::CodeStarNotifications::NotificationRule CreatedBy (__added__) +* AWS::CodeStarNotifications::NotificationRule EventTypeId (__added__) +* AWS::CodeStarNotifications::NotificationRule TargetAddress (__added__) +* AWS::EC2::NetworkAcl Tags.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-acl.html#cfn-ec2-networkacl-tags + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkacl.html#cfn-ec2-networkacl-tags +* AWS::EC2::NetworkAcl VpcId.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-acl.html#cfn-ec2-networkacl-vpcid + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkacl.html#cfn-ec2-networkacl-vpcid +* AWS::EC2::NetworkAclEntry CidrBlock.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-acl-entry.html#cfn-ec2-networkaclentry-cidrblock + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkaclentry.html#cfn-ec2-networkaclentry-cidrblock +* AWS::EC2::NetworkAclEntry Egress.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-acl-entry.html#cfn-ec2-networkaclentry-egress + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkaclentry.html#cfn-ec2-networkaclentry-egress +* AWS::EC2::NetworkAclEntry Icmp.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-acl-entry.html#cfn-ec2-networkaclentry-icmp + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkaclentry.html#cfn-ec2-networkaclentry-icmp +* AWS::EC2::NetworkAclEntry Ipv6CidrBlock.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-acl-entry.html#cfn-ec2-networkaclentry-ipv6cidrblock + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkaclentry.html#cfn-ec2-networkaclentry-ipv6cidrblock +* AWS::EC2::NetworkAclEntry NetworkAclId.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-acl-entry.html#cfn-ec2-networkaclentry-networkaclid + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkaclentry.html#cfn-ec2-networkaclentry-networkaclid +* AWS::EC2::NetworkAclEntry PortRange.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-acl-entry.html#cfn-ec2-networkaclentry-portrange + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkaclentry.html#cfn-ec2-networkaclentry-portrange +* AWS::EC2::NetworkAclEntry Protocol.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-acl-entry.html#cfn-ec2-networkaclentry-protocol + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkaclentry.html#cfn-ec2-networkaclentry-protocol +* AWS::EC2::NetworkAclEntry RuleAction.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-acl-entry.html#cfn-ec2-networkaclentry-ruleaction + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkaclentry.html#cfn-ec2-networkaclentry-ruleaction +* AWS::EC2::NetworkAclEntry RuleNumber.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-acl-entry.html#cfn-ec2-networkaclentry-rulenumber + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkaclentry.html#cfn-ec2-networkaclentry-rulenumber +* AWS::EC2::RouteTable Tags.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-route-table.html#cfn-ec2-routetable-tags + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-routetable.html#cfn-ec2-routetable-tags +* AWS::EC2::RouteTable VpcId.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-route-table.html#cfn-ec2-routetable-vpcid + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-routetable.html#cfn-ec2-routetable-vpcid +* AWS::ECS::TaskDefinition RuntimePlatform (__added__) +* AWS::FMS::Policy ResourcesCleanUp (__added__) +* AWS::Glue::Registry Tags.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::Glue::Schema Tags.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::ImageBuilder::InfrastructureConfiguration InstanceMetadataOptions (__added__) +* AWS::Lightsail::Instance KeyPairName (__added__) +* AWS::Lightsail::Instance UserData (__added__) +* AWS::Location::Tracker PositionFiltering (__added__) +* AWS::MWAA::Environment Tags.Type (__deleted__) +* AWS::MWAA::Environment Tags.PrimitiveType (__added__) +* AWS::MemoryDB::Cluster ACLName.Required (__changed__) + * Old: false + * New: true +* AWS::MemoryDB::Cluster NodeType.Required (__changed__) + * Old: false + * New: true +* AWS::MemoryDB::ParameterGroup Family.Required (__changed__) + * Old: false + * New: true +* AWS::MemoryDB::SubnetGroup SubnetIds.Required (__changed__) + * Old: false + * New: true +* AWS::Pinpoint::Campaign Priority (__added__) +* AWS::QuickSight::Analysis SourceEntity.Required (__changed__) + * Old: false + * New: true +* AWS::QuickSight::Dashboard SourceEntity.Required (__changed__) + * Old: false + * New: true +* AWS::QuickSight::Template SourceEntity.Required (__changed__) + * Old: false + * New: true +* AWS::Route53RecoveryControl::Cluster Tags (__added__) +* AWS::Route53RecoveryControl::ControlPanel Tags (__added__) +* AWS::Route53RecoveryControl::SafetyRule Tags (__added__) +* AWS::Route53Resolver::ResolverRule Tags.DuplicatesAllowed (__added__) +* AWS::Route53Resolver::ResolverRule TargetIps.DuplicatesAllowed (__added__) +* AWS::SageMaker::NotebookInstance PlatformIdentifier (__added__) +* AWS::StepFunctions::Activity Tags.DuplicatesAllowed (__added__) +* AWS::Synthetics::Canary ArtifactConfig (__added__) + +## Property Type Changes + +* AWS::MWAA::Environment.TagMap (__removed__) +* AWS::AppFlow::ConnectorProfile.OAuthProperties (__added__) +* AWS::AppFlow::ConnectorProfile.SAPODataConnectorProfileCredentials (__added__) +* AWS::AppFlow::ConnectorProfile.SAPODataConnectorProfileProperties (__added__) +* AWS::AppFlow::Flow.S3InputFormatConfig (__added__) +* AWS::AppFlow::Flow.SAPODataSourceProperties (__added__) +* AWS::AutoScaling::AutoScalingGroup.AcceleratorCountRequest (__added__) +* AWS::AutoScaling::AutoScalingGroup.AcceleratorTotalMemoryMiBRequest (__added__) +* AWS::AutoScaling::AutoScalingGroup.BaselineEbsBandwidthMbpsRequest (__added__) +* AWS::AutoScaling::AutoScalingGroup.InstanceRequirements (__added__) +* AWS::AutoScaling::AutoScalingGroup.MemoryGiBPerVCpuRequest (__added__) +* AWS::AutoScaling::AutoScalingGroup.MemoryMiBRequest (__added__) +* AWS::AutoScaling::AutoScalingGroup.NetworkInterfaceCountRequest (__added__) +* AWS::AutoScaling::AutoScalingGroup.TotalLocalStorageGBRequest (__added__) +* AWS::AutoScaling::AutoScalingGroup.VCpuCountRequest (__added__) +* AWS::EC2::EC2Fleet.AcceleratorCountRequest (__added__) +* AWS::EC2::EC2Fleet.AcceleratorTotalMemoryMiBRequest (__added__) +* AWS::EC2::EC2Fleet.BaselineEbsBandwidthMbpsRequest (__added__) +* AWS::EC2::EC2Fleet.InstanceRequirementsRequest (__added__) +* AWS::EC2::EC2Fleet.MemoryGiBPerVCpuRequest (__added__) +* AWS::EC2::EC2Fleet.MemoryMiBRequest (__added__) +* AWS::EC2::EC2Fleet.NetworkInterfaceCountRequest (__added__) +* AWS::EC2::EC2Fleet.TotalLocalStorageGBRequest (__added__) +* AWS::EC2::EC2Fleet.VCpuCountRangeRequest (__added__) +* AWS::EC2::SpotFleet.AcceleratorCountRequest (__added__) +* AWS::EC2::SpotFleet.AcceleratorTotalMemoryMiBRequest (__added__) +* AWS::EC2::SpotFleet.BaselineEbsBandwidthMbpsRequest (__added__) +* AWS::EC2::SpotFleet.InstanceRequirementsRequest (__added__) +* AWS::EC2::SpotFleet.MemoryGiBPerVCpuRequest (__added__) +* AWS::EC2::SpotFleet.MemoryMiBRequest (__added__) +* AWS::EC2::SpotFleet.NetworkInterfaceCountRequest (__added__) +* AWS::EC2::SpotFleet.TotalLocalStorageGBRequest (__added__) +* AWS::EC2::SpotFleet.VCpuCountRangeRequest (__added__) +* AWS::ECS::TaskDefinition.RuntimePlatform (__added__) +* AWS::ImageBuilder::InfrastructureConfiguration.InstanceMetadataOptions (__added__) +* AWS::Pinpoint::Campaign.CampaignInAppMessage (__added__) +* AWS::Pinpoint::Campaign.DefaultButtonConfiguration (__added__) +* AWS::Pinpoint::Campaign.InAppMessageBodyConfig (__added__) +* AWS::Pinpoint::Campaign.InAppMessageButton (__added__) +* AWS::Pinpoint::Campaign.InAppMessageContent (__added__) +* AWS::Pinpoint::Campaign.InAppMessageHeaderConfig (__added__) +* AWS::Pinpoint::Campaign.OverrideButtonConfiguration (__added__) +* AWS::QuickSight::DataSource.AmazonOpenSearchParameters (__added__) +* AWS::Synthetics::Canary.ArtifactConfig (__added__) +* AWS::Synthetics::Canary.S3Encryption (__added__) +* AWS::AppFlow::ConnectorProfile.ConnectorProfileCredentials SAPOData (__added__) +* AWS::AppFlow::ConnectorProfile.ConnectorProfileProperties SAPOData (__added__) +* AWS::AppFlow::Flow.ConnectorOperator SAPOData (__added__) +* AWS::AppFlow::Flow.S3SourceProperties S3InputFormatConfig (__added__) +* AWS::AppFlow::Flow.SourceConnectorProperties SAPOData (__added__) +* AWS::AutoScaling::AutoScalingGroup.LaunchTemplateOverrides InstanceRequirements (__added__) +* AWS::Backup::BackupSelection.BackupSelectionResourceType Conditions (__added__) +* AWS::Backup::BackupSelection.BackupSelectionResourceType NotResources (__added__) +* AWS::CodeBuild::Project.ProjectBuildBatchConfig BatchReportMode (__added__) +* AWS::EC2::EC2Fleet.FleetLaunchTemplateOverridesRequest InstanceRequirements (__added__) +* AWS::EC2::EC2Fleet.SpotOptionsRequest MaintenanceStrategies (__added__) +* AWS::EC2::EC2Fleet.TargetCapacitySpecificationRequest TargetCapacityUnitType (__added__) +* AWS::EC2::SpotFleet.LaunchTemplateOverrides InstanceRequirements (__added__) +* AWS::EC2::SpotFleet.SpotCapacityRebalance TerminationDelay (__added__) +* AWS::EC2::SpotFleet.SpotFleetLaunchSpecification InstanceRequirements (__added__) +* AWS::EC2::SpotFleet.SpotFleetLaunchSpecification InstanceType.Required (__changed__) + * Old: true + * New: false +* AWS::EC2::SpotFleet.SpotFleetRequestConfigData TargetCapacityUnitType (__added__) +* AWS::ImageBuilder::ContainerRecipe.EbsInstanceBlockDeviceSpecification Throughput (__added__) +* AWS::ImageBuilder::ImageRecipe.EbsInstanceBlockDeviceSpecification Throughput (__added__) +* AWS::Lightsail::Instance.Networking MonthlyTransfer.Type (__added__) +* AWS::Pinpoint::Campaign.Limits Session (__added__) +* AWS::Pinpoint::Campaign.MessageConfiguration InAppMessage (__added__) +* AWS::QuickSight::DataSource.DataSourceParameters AmazonOpenSearchParameters (__added__) + + # CloudFormation Resource Specification v43.0.0 ## New Resource Types diff --git a/packages/@aws-cdk/cfnspec/cfn.version b/packages/@aws-cdk/cfnspec/cfn.version index f3986a67888db..645a41f3b46f7 100644 --- a/packages/@aws-cdk/cfnspec/cfn.version +++ b/packages/@aws-cdk/cfnspec/cfn.version @@ -1 +1 @@ -43.0.0 +47.0.0 diff --git a/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json b/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json index b5b29349fe4e4..5d8a7aab62e63 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json +++ b/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json @@ -2557,6 +2557,12 @@ "Type": "RedshiftConnectorProfileCredentials", "UpdateType": "Mutable" }, + "SAPOData": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-connectorprofile-connectorprofilecredentials.html#cfn-appflow-connectorprofile-connectorprofilecredentials-sapodata", + "Required": false, + "Type": "SAPODataConnectorProfileCredentials", + "UpdateType": "Mutable" + }, "Salesforce": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-connectorprofile-connectorprofilecredentials.html#cfn-appflow-connectorprofile-connectorprofilecredentials-salesforce", "Required": false, @@ -2640,6 +2646,12 @@ "Type": "RedshiftConnectorProfileProperties", "UpdateType": "Mutable" }, + "SAPOData": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-connectorprofile-connectorprofileproperties.html#cfn-appflow-connectorprofile-connectorprofileproperties-sapodata", + "Required": false, + "Type": "SAPODataConnectorProfileProperties", + "UpdateType": "Mutable" + }, "Salesforce": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-connectorprofile-connectorprofileproperties.html#cfn-appflow-connectorprofile-connectorprofileproperties-salesforce", "Required": false, @@ -2843,6 +2855,31 @@ } } }, + "AWS::AppFlow::ConnectorProfile.OAuthProperties": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-connectorprofile-oauthproperties.html", + "Properties": { + "AuthCodeUrl": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-connectorprofile-oauthproperties.html#cfn-appflow-connectorprofile-oauthproperties-authcodeurl", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "OAuthScopes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-connectorprofile-oauthproperties.html#cfn-appflow-connectorprofile-oauthproperties-oauthscopes", + "DuplicatesAllowed": false, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "TokenUrl": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-connectorprofile-oauthproperties.html#cfn-appflow-connectorprofile-oauthproperties-tokenurl", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::AppFlow::ConnectorProfile.RedshiftConnectorProfileCredentials": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-connectorprofile-redshiftconnectorprofilecredentials.html", "Properties": { @@ -2889,6 +2926,70 @@ } } }, + "AWS::AppFlow::ConnectorProfile.SAPODataConnectorProfileCredentials": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-connectorprofile-sapodataconnectorprofilecredentials.html", + "Properties": { + "BasicAuthCredentials": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-connectorprofile-sapodataconnectorprofilecredentials.html#cfn-appflow-connectorprofile-sapodataconnectorprofilecredentials-basicauthcredentials", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Mutable" + }, + "OAuthCredentials": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-connectorprofile-sapodataconnectorprofilecredentials.html#cfn-appflow-connectorprofile-sapodataconnectorprofilecredentials-oauthcredentials", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::AppFlow::ConnectorProfile.SAPODataConnectorProfileProperties": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-connectorprofile-sapodataconnectorprofileproperties.html", + "Properties": { + "ApplicationHostUrl": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-connectorprofile-sapodataconnectorprofileproperties.html#cfn-appflow-connectorprofile-sapodataconnectorprofileproperties-applicationhosturl", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ApplicationServicePath": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-connectorprofile-sapodataconnectorprofileproperties.html#cfn-appflow-connectorprofile-sapodataconnectorprofileproperties-applicationservicepath", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ClientNumber": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-connectorprofile-sapodataconnectorprofileproperties.html#cfn-appflow-connectorprofile-sapodataconnectorprofileproperties-clientnumber", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "LogonLanguage": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-connectorprofile-sapodataconnectorprofileproperties.html#cfn-appflow-connectorprofile-sapodataconnectorprofileproperties-logonlanguage", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "OAuthProperties": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-connectorprofile-sapodataconnectorprofileproperties.html#cfn-appflow-connectorprofile-sapodataconnectorprofileproperties-oauthproperties", + "Required": false, + "Type": "OAuthProperties", + "UpdateType": "Mutable" + }, + "PortNumber": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-connectorprofile-sapodataconnectorprofileproperties.html#cfn-appflow-connectorprofile-sapodataconnectorprofileproperties-portnumber", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "PrivateLinkServiceName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-connectorprofile-sapodataconnectorprofileproperties.html#cfn-appflow-connectorprofile-sapodataconnectorprofileproperties-privatelinkservicename", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::AppFlow::ConnectorProfile.SalesforceConnectorProfileCredentials": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-connectorprofile-salesforceconnectorprofilecredentials.html", "Properties": { @@ -3224,6 +3325,12 @@ "Required": false, "UpdateType": "Mutable" }, + "SAPOData": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-connectoroperator.html#cfn-appflow-flow-connectoroperator-sapodata", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "Salesforce": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-connectoroperator.html#cfn-appflow-flow-connectoroperator-salesforce", "PrimitiveType": "String", @@ -3530,6 +3637,17 @@ } } }, + "AWS::AppFlow::Flow.S3InputFormatConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-s3inputformatconfig.html", + "Properties": { + "S3InputFileType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-s3inputformatconfig.html#cfn-appflow-flow-s3inputformatconfig-s3inputfiletype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::AppFlow::Flow.S3OutputFormatConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-s3outputformatconfig.html", "Properties": { @@ -3567,6 +3685,23 @@ "PrimitiveType": "String", "Required": true, "UpdateType": "Mutable" + }, + "S3InputFormatConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-s3sourceproperties.html#cfn-appflow-flow-s3sourceproperties-s3inputformatconfig", + "Required": false, + "Type": "S3InputFormatConfig", + "UpdateType": "Mutable" + } + } + }, + "AWS::AppFlow::Flow.SAPODataSourceProperties": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-sapodatasourceproperties.html", + "Properties": { + "ObjectPath": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-sapodatasourceproperties.html#cfn-appflow-flow-sapodatasourceproperties-objectpath", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" } } }, @@ -3771,6 +3906,12 @@ "Type": "S3SourceProperties", "UpdateType": "Mutable" }, + "SAPOData": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-sourceconnectorproperties.html#cfn-appflow-flow-sourceconnectorproperties-sapodata", + "Required": false, + "Type": "SAPODataSourceProperties", + "UpdateType": "Mutable" + }, "Salesforce": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-sourceconnectorproperties.html#cfn-appflow-flow-sourceconnectorproperties-salesforce", "Required": false, @@ -8309,6 +8450,202 @@ } } }, + "AWS::AutoScaling::AutoScalingGroup.AcceleratorCountRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-acceleratorcountrequest.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-acceleratorcountrequest.html#cfn-autoscaling-autoscalinggroup-acceleratorcountrequest-max", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-acceleratorcountrequest.html#cfn-autoscaling-autoscalinggroup-acceleratorcountrequest-min", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::AutoScaling::AutoScalingGroup.AcceleratorTotalMemoryMiBRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-acceleratortotalmemorymibrequest.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-acceleratortotalmemorymibrequest.html#cfn-autoscaling-autoscalinggroup-acceleratortotalmemorymibrequest-max", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-acceleratortotalmemorymibrequest.html#cfn-autoscaling-autoscalinggroup-acceleratortotalmemorymibrequest-min", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::AutoScaling::AutoScalingGroup.BaselineEbsBandwidthMbpsRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-baselineebsbandwidthmbpsrequest.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-baselineebsbandwidthmbpsrequest.html#cfn-autoscaling-autoscalinggroup-baselineebsbandwidthmbpsrequest-max", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-baselineebsbandwidthmbpsrequest.html#cfn-autoscaling-autoscalinggroup-baselineebsbandwidthmbpsrequest-min", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::AutoScaling::AutoScalingGroup.InstanceRequirements": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-as-mixedinstancespolicy-instancerequirements.html", + "Properties": { + "AcceleratorCount": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-as-mixedinstancespolicy-instancerequirements.html#cfn-autoscaling-autoscalinggroup-instancerequirements-acceleratorcount", + "Required": false, + "Type": "AcceleratorCountRequest", + "UpdateType": "Mutable" + }, + "AcceleratorManufacturers": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-as-mixedinstancespolicy-instancerequirements.html#cfn-autoscaling-autoscalinggroup-instancerequirements-acceleratormanufacturers", + "DuplicatesAllowed": false, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "AcceleratorNames": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-as-mixedinstancespolicy-instancerequirements.html#cfn-autoscaling-autoscalinggroup-instancerequirements-acceleratornames", + "DuplicatesAllowed": false, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "AcceleratorTotalMemoryMiB": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-as-mixedinstancespolicy-instancerequirements.html#cfn-autoscaling-autoscalinggroup-instancerequirements-acceleratortotalmemorymib", + "Required": false, + "Type": "AcceleratorTotalMemoryMiBRequest", + "UpdateType": "Mutable" + }, + "AcceleratorTypes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-as-mixedinstancespolicy-instancerequirements.html#cfn-autoscaling-autoscalinggroup-instancerequirements-acceleratortypes", + "DuplicatesAllowed": false, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "BareMetal": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-as-mixedinstancespolicy-instancerequirements.html#cfn-autoscaling-autoscalinggroup-instancerequirements-baremetal", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "BaselineEbsBandwidthMbps": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-as-mixedinstancespolicy-instancerequirements.html#cfn-autoscaling-autoscalinggroup-instancerequirements-baselineebsbandwidthmbps", + "Required": false, + "Type": "BaselineEbsBandwidthMbpsRequest", + "UpdateType": "Mutable" + }, + "BurstablePerformance": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-as-mixedinstancespolicy-instancerequirements.html#cfn-autoscaling-autoscalinggroup-instancerequirements-burstableperformance", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "CpuManufacturers": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-as-mixedinstancespolicy-instancerequirements.html#cfn-autoscaling-autoscalinggroup-instancerequirements-cpumanufacturers", + "DuplicatesAllowed": false, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "ExcludedInstanceTypes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-as-mixedinstancespolicy-instancerequirements.html#cfn-autoscaling-autoscalinggroup-instancerequirements-excludedinstancetypes", + "DuplicatesAllowed": false, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "InstanceGenerations": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-as-mixedinstancespolicy-instancerequirements.html#cfn-autoscaling-autoscalinggroup-instancerequirements-instancegenerations", + "DuplicatesAllowed": false, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "LocalStorage": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-as-mixedinstancespolicy-instancerequirements.html#cfn-autoscaling-autoscalinggroup-instancerequirements-localstorage", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "LocalStorageTypes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-as-mixedinstancespolicy-instancerequirements.html#cfn-autoscaling-autoscalinggroup-instancerequirements-localstoragetypes", + "DuplicatesAllowed": false, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "MemoryGiBPerVCpu": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-as-mixedinstancespolicy-instancerequirements.html#cfn-autoscaling-autoscalinggroup-instancerequirements-memorygibpervcpu", + "Required": false, + "Type": "MemoryGiBPerVCpuRequest", + "UpdateType": "Mutable" + }, + "MemoryMiB": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-as-mixedinstancespolicy-instancerequirements.html#cfn-autoscaling-autoscalinggroup-instancerequirements-memorymib", + "Required": false, + "Type": "MemoryMiBRequest", + "UpdateType": "Mutable" + }, + "NetworkInterfaceCount": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-as-mixedinstancespolicy-instancerequirements.html#cfn-autoscaling-autoscalinggroup-instancerequirements-networkinterfacecount", + "Required": false, + "Type": "NetworkInterfaceCountRequest", + "UpdateType": "Mutable" + }, + "OnDemandMaxPricePercentageOverLowestPrice": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-as-mixedinstancespolicy-instancerequirements.html#cfn-autoscaling-autoscalinggroup-instancerequirements-ondemandmaxpricepercentageoverlowestprice", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "RequireHibernateSupport": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-as-mixedinstancespolicy-instancerequirements.html#cfn-autoscaling-autoscalinggroup-instancerequirements-requirehibernatesupport", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "SpotMaxPricePercentageOverLowestPrice": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-as-mixedinstancespolicy-instancerequirements.html#cfn-autoscaling-autoscalinggroup-instancerequirements-spotmaxpricepercentageoverlowestprice", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "TotalLocalStorageGB": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-as-mixedinstancespolicy-instancerequirements.html#cfn-autoscaling-autoscalinggroup-instancerequirements-totallocalstoragegb", + "Required": false, + "Type": "TotalLocalStorageGBRequest", + "UpdateType": "Mutable" + }, + "VCpuCount": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-as-mixedinstancespolicy-instancerequirements.html#cfn-autoscaling-autoscalinggroup-instancerequirements-vcpucount", + "Required": false, + "Type": "VCpuCountRequest", + "UpdateType": "Mutable" + } + } + }, "AWS::AutoScaling::AutoScalingGroup.InstancesDistribution": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-as-mixedinstancespolicy-instancesdistribution.html", "Properties": { @@ -8372,6 +8709,12 @@ "AWS::AutoScaling::AutoScalingGroup.LaunchTemplateOverrides": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-as-mixedinstancespolicy-launchtemplateoverrides.html", "Properties": { + "InstanceRequirements": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-as-mixedinstancespolicy-launchtemplateoverrides.html#cfn-as-mixedinstancespolicy-instancerequirements", + "Required": false, + "Type": "InstanceRequirements", + "UpdateType": "Mutable" + }, "InstanceType": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-as-mixedinstancespolicy-launchtemplateoverrides.html#cfn-autoscaling-autoscalinggroup-launchtemplateoverrides-instancetype", "PrimitiveType": "String", @@ -8462,6 +8805,40 @@ } } }, + "AWS::AutoScaling::AutoScalingGroup.MemoryGiBPerVCpuRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-memorygibpervcpurequest.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-memorygibpervcpurequest.html#cfn-autoscaling-autoscalinggroup-memorygibpervcpurequest-max", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-memorygibpervcpurequest.html#cfn-autoscaling-autoscalinggroup-memorygibpervcpurequest-min", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::AutoScaling::AutoScalingGroup.MemoryMiBRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-memorymibrequest.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-memorymibrequest.html#cfn-autoscaling-autoscalinggroup-memorymibrequest-max", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-memorymibrequest.html#cfn-autoscaling-autoscalinggroup-memorymibrequest-min", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::AutoScaling::AutoScalingGroup.MetricsCollection": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-metricscollection.html", "Properties": { @@ -8498,6 +8875,23 @@ } } }, + "AWS::AutoScaling::AutoScalingGroup.NetworkInterfaceCountRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-networkinterfacecountrequest.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-networkinterfacecountrequest.html#cfn-autoscaling-autoscalinggroup-networkinterfacecountrequest-max", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-networkinterfacecountrequest.html#cfn-autoscaling-autoscalinggroup-networkinterfacecountrequest-min", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::AutoScaling::AutoScalingGroup.NotificationConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-notificationconfigurations.html", "Properties": { @@ -8540,6 +8934,40 @@ } } }, + "AWS::AutoScaling::AutoScalingGroup.TotalLocalStorageGBRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-totallocalstoragegbrequest.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-totallocalstoragegbrequest.html#cfn-autoscaling-autoscalinggroup-totallocalstoragegbrequest-max", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-totallocalstoragegbrequest.html#cfn-autoscaling-autoscalinggroup-totallocalstoragegbrequest-min", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::AutoScaling::AutoScalingGroup.VCpuCountRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-vcpucountrequest.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-vcpucountrequest.html#cfn-autoscaling-autoscalinggroup-vcpucountrequest-max", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-vcpucountrequest.html#cfn-autoscaling-autoscalinggroup-vcpucountrequest-min", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::AutoScaling::LaunchConfiguration.BlockDevice": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig-blockdev-template.html", "Properties": { @@ -9318,6 +9746,12 @@ "AWS::Backup::BackupSelection.BackupSelectionResourceType": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-backupselection-backupselectionresourcetype.html", "Properties": { + "Conditions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-backupselection-backupselectionresourcetype.html#cfn-backup-backupselection-backupselectionresourcetype-conditions", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Immutable" + }, "IamRoleArn": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-backupselection-backupselectionresourcetype.html#cfn-backup-backupselection-backupselectionresourcetype-iamrolearn", "PrimitiveType": "String", @@ -9332,6 +9766,14 @@ "Type": "List", "UpdateType": "Immutable" }, + "NotResources": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-backupselection-backupselectionresourcetype.html#cfn-backup-backupselection-backupselectionresourcetype-notresources", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "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, @@ -12095,6 +12537,333 @@ } } }, + "AWS::CloudFront::ResponseHeadersPolicy.AccessControlAllowHeaders": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-accesscontrolallowheaders.html", + "Properties": { + "Items": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-accesscontrolallowheaders.html#cfn-cloudfront-responseheaderspolicy-accesscontrolallowheaders-items", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::ResponseHeadersPolicy.AccessControlAllowMethods": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-accesscontrolallowmethods.html", + "Properties": { + "Items": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-accesscontrolallowmethods.html#cfn-cloudfront-responseheaderspolicy-accesscontrolallowmethods-items", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::ResponseHeadersPolicy.AccessControlAllowOrigins": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-accesscontrolalloworigins.html", + "Properties": { + "Items": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-accesscontrolalloworigins.html#cfn-cloudfront-responseheaderspolicy-accesscontrolalloworigins-items", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::ResponseHeadersPolicy.AccessControlExposeHeaders": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-accesscontrolexposeheaders.html", + "Properties": { + "Items": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-accesscontrolexposeheaders.html#cfn-cloudfront-responseheaderspolicy-accesscontrolexposeheaders-items", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::ResponseHeadersPolicy.ContentSecurityPolicy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-contentsecuritypolicy.html", + "Properties": { + "ContentSecurityPolicy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-contentsecuritypolicy.html#cfn-cloudfront-responseheaderspolicy-contentsecuritypolicy-contentsecuritypolicy", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Override": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-contentsecuritypolicy.html#cfn-cloudfront-responseheaderspolicy-contentsecuritypolicy-override", + "PrimitiveType": "Boolean", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::ResponseHeadersPolicy.ContentTypeOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-contenttypeoptions.html", + "Properties": { + "Override": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-contenttypeoptions.html#cfn-cloudfront-responseheaderspolicy-contenttypeoptions-override", + "PrimitiveType": "Boolean", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::ResponseHeadersPolicy.CorsConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-corsconfig.html", + "Properties": { + "AccessControlAllowCredentials": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-corsconfig.html#cfn-cloudfront-responseheaderspolicy-corsconfig-accesscontrolallowcredentials", + "PrimitiveType": "Boolean", + "Required": true, + "UpdateType": "Mutable" + }, + "AccessControlAllowHeaders": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-corsconfig.html#cfn-cloudfront-responseheaderspolicy-corsconfig-accesscontrolallowheaders", + "Required": true, + "Type": "AccessControlAllowHeaders", + "UpdateType": "Mutable" + }, + "AccessControlAllowMethods": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-corsconfig.html#cfn-cloudfront-responseheaderspolicy-corsconfig-accesscontrolallowmethods", + "Required": true, + "Type": "AccessControlAllowMethods", + "UpdateType": "Mutable" + }, + "AccessControlAllowOrigins": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-corsconfig.html#cfn-cloudfront-responseheaderspolicy-corsconfig-accesscontrolalloworigins", + "Required": true, + "Type": "AccessControlAllowOrigins", + "UpdateType": "Mutable" + }, + "AccessControlExposeHeaders": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-corsconfig.html#cfn-cloudfront-responseheaderspolicy-corsconfig-accesscontrolexposeheaders", + "Required": false, + "Type": "AccessControlExposeHeaders", + "UpdateType": "Mutable" + }, + "AccessControlMaxAgeSec": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-corsconfig.html#cfn-cloudfront-responseheaderspolicy-corsconfig-accesscontrolmaxagesec", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "OriginOverride": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-corsconfig.html#cfn-cloudfront-responseheaderspolicy-corsconfig-originoverride", + "PrimitiveType": "Boolean", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::ResponseHeadersPolicy.CustomHeader": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-customheader.html", + "Properties": { + "Header": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-customheader.html#cfn-cloudfront-responseheaderspolicy-customheader-header", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Override": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-customheader.html#cfn-cloudfront-responseheaderspolicy-customheader-override", + "PrimitiveType": "Boolean", + "Required": true, + "UpdateType": "Mutable" + }, + "Value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-customheader.html#cfn-cloudfront-responseheaderspolicy-customheader-value", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::ResponseHeadersPolicy.CustomHeadersConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-customheadersconfig.html", + "Properties": { + "Items": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-customheadersconfig.html#cfn-cloudfront-responseheaderspolicy-customheadersconfig-items", + "DuplicatesAllowed": true, + "ItemType": "CustomHeader", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::ResponseHeadersPolicy.FrameOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-frameoptions.html", + "Properties": { + "FrameOption": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-frameoptions.html#cfn-cloudfront-responseheaderspolicy-frameoptions-frameoption", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Override": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-frameoptions.html#cfn-cloudfront-responseheaderspolicy-frameoptions-override", + "PrimitiveType": "Boolean", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::ResponseHeadersPolicy.ReferrerPolicy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-referrerpolicy.html", + "Properties": { + "Override": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-referrerpolicy.html#cfn-cloudfront-responseheaderspolicy-referrerpolicy-override", + "PrimitiveType": "Boolean", + "Required": true, + "UpdateType": "Mutable" + }, + "ReferrerPolicy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-referrerpolicy.html#cfn-cloudfront-responseheaderspolicy-referrerpolicy-referrerpolicy", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::ResponseHeadersPolicy.ResponseHeadersPolicyConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-responseheaderspolicyconfig.html", + "Properties": { + "Comment": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-responseheaderspolicyconfig.html#cfn-cloudfront-responseheaderspolicy-responseheaderspolicyconfig-comment", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "CorsConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-responseheaderspolicyconfig.html#cfn-cloudfront-responseheaderspolicy-responseheaderspolicyconfig-corsconfig", + "Required": false, + "Type": "CorsConfig", + "UpdateType": "Mutable" + }, + "CustomHeadersConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-responseheaderspolicyconfig.html#cfn-cloudfront-responseheaderspolicy-responseheaderspolicyconfig-customheadersconfig", + "Required": false, + "Type": "CustomHeadersConfig", + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-responseheaderspolicyconfig.html#cfn-cloudfront-responseheaderspolicy-responseheaderspolicyconfig-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "SecurityHeadersConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-responseheaderspolicyconfig.html#cfn-cloudfront-responseheaderspolicy-responseheaderspolicyconfig-securityheadersconfig", + "Required": false, + "Type": "SecurityHeadersConfig", + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::ResponseHeadersPolicy.SecurityHeadersConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-securityheadersconfig.html", + "Properties": { + "ContentSecurityPolicy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-securityheadersconfig.html#cfn-cloudfront-responseheaderspolicy-securityheadersconfig-contentsecuritypolicy", + "Required": false, + "Type": "ContentSecurityPolicy", + "UpdateType": "Mutable" + }, + "ContentTypeOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-securityheadersconfig.html#cfn-cloudfront-responseheaderspolicy-securityheadersconfig-contenttypeoptions", + "Required": false, + "Type": "ContentTypeOptions", + "UpdateType": "Mutable" + }, + "FrameOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-securityheadersconfig.html#cfn-cloudfront-responseheaderspolicy-securityheadersconfig-frameoptions", + "Required": false, + "Type": "FrameOptions", + "UpdateType": "Mutable" + }, + "ReferrerPolicy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-securityheadersconfig.html#cfn-cloudfront-responseheaderspolicy-securityheadersconfig-referrerpolicy", + "Required": false, + "Type": "ReferrerPolicy", + "UpdateType": "Mutable" + }, + "StrictTransportSecurity": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-securityheadersconfig.html#cfn-cloudfront-responseheaderspolicy-securityheadersconfig-stricttransportsecurity", + "Required": false, + "Type": "StrictTransportSecurity", + "UpdateType": "Mutable" + }, + "XSSProtection": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-securityheadersconfig.html#cfn-cloudfront-responseheaderspolicy-securityheadersconfig-xssprotection", + "Required": false, + "Type": "XSSProtection", + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::ResponseHeadersPolicy.StrictTransportSecurity": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-stricttransportsecurity.html", + "Properties": { + "AccessControlMaxAgeSec": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-stricttransportsecurity.html#cfn-cloudfront-responseheaderspolicy-stricttransportsecurity-accesscontrolmaxagesec", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + }, + "IncludeSubdomains": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-stricttransportsecurity.html#cfn-cloudfront-responseheaderspolicy-stricttransportsecurity-includesubdomains", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "Override": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-stricttransportsecurity.html#cfn-cloudfront-responseheaderspolicy-stricttransportsecurity-override", + "PrimitiveType": "Boolean", + "Required": true, + "UpdateType": "Mutable" + }, + "Preload": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-stricttransportsecurity.html#cfn-cloudfront-responseheaderspolicy-stricttransportsecurity-preload", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::ResponseHeadersPolicy.XSSProtection": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-xssprotection.html", + "Properties": { + "ModeBlock": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-xssprotection.html#cfn-cloudfront-responseheaderspolicy-xssprotection-modeblock", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "Override": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-xssprotection.html#cfn-cloudfront-responseheaderspolicy-xssprotection-override", + "PrimitiveType": "Boolean", + "Required": true, + "UpdateType": "Mutable" + }, + "Protection": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-xssprotection.html#cfn-cloudfront-responseheaderspolicy-xssprotection-protection", + "PrimitiveType": "Boolean", + "Required": true, + "UpdateType": "Mutable" + }, + "ReportUri": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-responseheaderspolicy-xssprotection.html#cfn-cloudfront-responseheaderspolicy-xssprotection-reporturi", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::CloudFront::StreamingDistribution.Logging": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-streamingdistribution-logging.html", "Properties": { @@ -12684,6 +13453,12 @@ "AWS::CodeBuild::Project.ProjectBuildBatchConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-projectbuildbatchconfig.html", "Properties": { + "BatchReportMode": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-projectbuildbatchconfig.html#cfn-codebuild-project-projectbuildbatchconfig-batchreportmode", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "CombineArtifacts": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-projectbuildbatchconfig.html#cfn-codebuild-project-projectbuildbatchconfig-combineartifacts", "PrimitiveType": "Boolean", @@ -15284,6 +16059,46 @@ } } }, + "AWS::Connect::HoursOfOperation.HoursOfOperationConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-connect-hoursofoperation-hoursofoperationconfig.html", + "Properties": { + "Day": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-connect-hoursofoperation-hoursofoperationconfig.html#cfn-connect-hoursofoperation-hoursofoperationconfig-day", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "EndTime": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-connect-hoursofoperation-hoursofoperationconfig.html#cfn-connect-hoursofoperation-hoursofoperationconfig-endtime", + "Required": true, + "Type": "HoursOfOperationTimeSlice", + "UpdateType": "Mutable" + }, + "StartTime": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-connect-hoursofoperation-hoursofoperationconfig.html#cfn-connect-hoursofoperation-hoursofoperationconfig-starttime", + "Required": true, + "Type": "HoursOfOperationTimeSlice", + "UpdateType": "Mutable" + } + } + }, + "AWS::Connect::HoursOfOperation.HoursOfOperationTimeSlice": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-connect-hoursofoperation-hoursofoperationtimeslice.html", + "Properties": { + "Hours": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-connect-hoursofoperation-hoursofoperationtimeslice.html#cfn-connect-hoursofoperation-hoursofoperationtimeslice-hours", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + }, + "Minutes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-connect-hoursofoperation-hoursofoperationtimeslice.html#cfn-connect-hoursofoperation-hoursofoperationtimeslice-minutes", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::Connect::QuickConnect.PhoneNumberQuickConnectConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-connect-quickconnect-phonenumberquickconnectconfig.html", "Properties": { @@ -15358,6 +16173,58 @@ } } }, + "AWS::Connect::User.UserIdentityInfo": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-connect-user-useridentityinfo.html", + "Properties": { + "Email": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-connect-user-useridentityinfo.html#cfn-connect-user-useridentityinfo-email", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "FirstName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-connect-user-useridentityinfo.html#cfn-connect-user-useridentityinfo-firstname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "LastName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-connect-user-useridentityinfo.html#cfn-connect-user-useridentityinfo-lastname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Connect::User.UserPhoneConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-connect-user-userphoneconfig.html", + "Properties": { + "AfterContactWorkTimeLimit": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-connect-user-userphoneconfig.html#cfn-connect-user-userphoneconfig-aftercontactworktimelimit", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "AutoAccept": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-connect-user-userphoneconfig.html#cfn-connect-user-userphoneconfig-autoaccept", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "DeskPhoneNumber": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-connect-user-userphoneconfig.html#cfn-connect-user-userphoneconfig-deskphonenumber", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "PhoneType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-connect-user-userphoneconfig.html#cfn-connect-user-userphoneconfig-phonetype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::CustomerProfiles::Integration.ConnectorOperator": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-customerprofiles-integration-connectoroperator.html", "Properties": { @@ -16343,6 +17210,84 @@ "Required": false, "UpdateType": "Mutable" }, + "IncludeControlDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kafkasettings.html#cfn-dms-endpoint-kafkasettings-includecontroldetails", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "IncludeNullAndEmpty": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kafkasettings.html#cfn-dms-endpoint-kafkasettings-includenullandempty", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "IncludeTableAlterOperations": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kafkasettings.html#cfn-dms-endpoint-kafkasettings-includetablealteroperations", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "IncludeTransactionDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kafkasettings.html#cfn-dms-endpoint-kafkasettings-includetransactiondetails", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "NoHexPrefix": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kafkasettings.html#cfn-dms-endpoint-kafkasettings-nohexprefix", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "PartitionIncludeSchemaTable": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kafkasettings.html#cfn-dms-endpoint-kafkasettings-partitionincludeschematable", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "SaslPassword": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kafkasettings.html#cfn-dms-endpoint-kafkasettings-saslpassword", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SaslUserName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kafkasettings.html#cfn-dms-endpoint-kafkasettings-saslusername", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SecurityProtocol": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kafkasettings.html#cfn-dms-endpoint-kafkasettings-securityprotocol", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SslCaCertificateArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kafkasettings.html#cfn-dms-endpoint-kafkasettings-sslcacertificatearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SslClientCertificateArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kafkasettings.html#cfn-dms-endpoint-kafkasettings-sslclientcertificatearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SslClientKeyArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kafkasettings.html#cfn-dms-endpoint-kafkasettings-sslclientkeyarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SslClientKeyPassword": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kafkasettings.html#cfn-dms-endpoint-kafkasettings-sslclientkeypassword", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "Topic": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kafkasettings.html#cfn-dms-endpoint-kafkasettings-topic", "PrimitiveType": "String", @@ -16354,12 +17299,48 @@ "AWS::DMS::Endpoint.KinesisSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kinesissettings.html", "Properties": { + "IncludeControlDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kinesissettings.html#cfn-dms-endpoint-kinesissettings-includecontroldetails", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "IncludeNullAndEmpty": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kinesissettings.html#cfn-dms-endpoint-kinesissettings-includenullandempty", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "IncludeTableAlterOperations": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kinesissettings.html#cfn-dms-endpoint-kinesissettings-includetablealteroperations", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "IncludeTransactionDetails": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kinesissettings.html#cfn-dms-endpoint-kinesissettings-includetransactiondetails", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, "MessageFormat": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kinesissettings.html#cfn-dms-endpoint-kinesissettings-messageformat", "PrimitiveType": "String", "Required": false, "UpdateType": "Mutable" }, + "NoHexPrefix": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kinesissettings.html#cfn-dms-endpoint-kinesissettings-nohexprefix", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "PartitionIncludeSchemaTable": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kinesissettings.html#cfn-dms-endpoint-kinesissettings-partitionincludeschematable", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, "ServiceAccessRoleArn": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kinesissettings.html#cfn-dms-endpoint-kinesissettings-serviceaccessrolearn", "PrimitiveType": "String", @@ -16584,6 +17565,53 @@ } } }, + "AWS::DMS::Endpoint.RedisSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-redissettings.html", + "Properties": { + "AuthPassword": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-redissettings.html#cfn-dms-endpoint-redissettings-authpassword", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "AuthType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-redissettings.html#cfn-dms-endpoint-redissettings-authtype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "AuthUserName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-redissettings.html#cfn-dms-endpoint-redissettings-authusername", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Port": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-redissettings.html#cfn-dms-endpoint-redissettings-port", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + }, + "ServerName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-redissettings.html#cfn-dms-endpoint-redissettings-servername", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SslCaCertificateArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-redissettings.html#cfn-dms-endpoint-redissettings-sslcacertificatearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SslSecurityProtocol": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-redissettings.html#cfn-dms-endpoint-redissettings-sslsecurityprotocol", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::DMS::Endpoint.RedshiftSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-redshiftsettings.html", "Properties": { @@ -18206,6 +19234,40 @@ } } }, + "AWS::DataSync::LocationHDFS.NameNode": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-datasync-locationhdfs-namenode.html", + "Properties": { + "Hostname": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-datasync-locationhdfs-namenode.html#cfn-datasync-locationhdfs-namenode-hostname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Port": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-datasync-locationhdfs-namenode.html#cfn-datasync-locationhdfs-namenode-port", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::DataSync::LocationHDFS.QopConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-datasync-locationhdfs-qopconfiguration.html", + "Properties": { + "DataTransferProtection": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-datasync-locationhdfs-qopconfiguration.html#cfn-datasync-locationhdfs-qopconfiguration-datatransferprotection", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "RpcProtection": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-datasync-locationhdfs-qopconfiguration.html#cfn-datasync-locationhdfs-qopconfiguration-rpcprotection", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::DataSync::LocationNFS.MountOptions": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-datasync-locationnfs-mountoptions.html", "Properties": { @@ -19032,6 +20094,72 @@ } } }, + "AWS::EC2::CapacityReservationFleet.InstanceTypeSpecification": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-capacityreservationfleet-instancetypespecification.html", + "Properties": { + "AvailabilityZone": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-capacityreservationfleet-instancetypespecification.html#cfn-ec2-capacityreservationfleet-instancetypespecification-availabilityzone", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "AvailabilityZoneId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-capacityreservationfleet-instancetypespecification.html#cfn-ec2-capacityreservationfleet-instancetypespecification-availabilityzoneid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "EbsOptimized": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-capacityreservationfleet-instancetypespecification.html#cfn-ec2-capacityreservationfleet-instancetypespecification-ebsoptimized", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Immutable" + }, + "InstancePlatform": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-capacityreservationfleet-instancetypespecification.html#cfn-ec2-capacityreservationfleet-instancetypespecification-instanceplatform", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "InstanceType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-capacityreservationfleet-instancetypespecification.html#cfn-ec2-capacityreservationfleet-instancetypespecification-instancetype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Priority": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-capacityreservationfleet-instancetypespecification.html#cfn-ec2-capacityreservationfleet-instancetypespecification-priority", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + }, + "Weight": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-capacityreservationfleet-instancetypespecification.html#cfn-ec2-capacityreservationfleet-instancetypespecification-weight", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::EC2::CapacityReservationFleet.TagSpecification": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-capacityreservationfleet-tagspecification.html", + "Properties": { + "ResourceType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-capacityreservationfleet-tagspecification.html#cfn-ec2-capacityreservationfleet-tagspecification-resourcetype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-capacityreservationfleet-tagspecification.html#cfn-ec2-capacityreservationfleet-tagspecification-tags", + "DuplicatesAllowed": true, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + } + } + }, "AWS::EC2::ClientVpnEndpoint.CertificateAuthenticationRequest": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-clientvpnendpoint-certificateauthenticationrequest.html", "Properties": { @@ -19158,6 +20286,74 @@ } } }, + "AWS::EC2::EC2Fleet.AcceleratorCountRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-acceleratorcountrequest.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-acceleratorcountrequest.html#cfn-ec2-ec2fleet-acceleratorcountrequest-max", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-acceleratorcountrequest.html#cfn-ec2-ec2fleet-acceleratorcountrequest-min", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::EC2::EC2Fleet.AcceleratorTotalMemoryMiBRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-acceleratortotalmemorymibrequest.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-acceleratortotalmemorymibrequest.html#cfn-ec2-ec2fleet-acceleratortotalmemorymibrequest-max", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-acceleratortotalmemorymibrequest.html#cfn-ec2-ec2fleet-acceleratortotalmemorymibrequest-min", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::EC2::EC2Fleet.BaselineEbsBandwidthMbpsRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-baselineebsbandwidthmbpsrequest.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-baselineebsbandwidthmbpsrequest.html#cfn-ec2-ec2fleet-baselineebsbandwidthmbpsrequest-max", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-baselineebsbandwidthmbpsrequest.html#cfn-ec2-ec2fleet-baselineebsbandwidthmbpsrequest-min", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::EC2::EC2Fleet.CapacityRebalance": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-capacityrebalance.html", + "Properties": { + "ReplacementStrategy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-capacityrebalance.html#cfn-ec2-ec2fleet-capacityrebalance-replacementstrategy", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "TerminationDelay": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-capacityrebalance.html#cfn-ec2-ec2fleet-capacityrebalance-terminationdelay", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + } + } + }, "AWS::EC2::EC2Fleet.CapacityReservationOptionsRequest": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-capacityreservationoptionsrequest.html", "Properties": { @@ -19197,6 +20393,12 @@ "Required": false, "UpdateType": "Immutable" }, + "InstanceRequirements": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-fleetlaunchtemplateoverridesrequest.html#cfn-ec2-ec2fleet-fleetlaunchtemplateoverridesrequest-instancerequirements", + "Required": false, + "Type": "InstanceRequirementsRequest", + "UpdateType": "Immutable" + }, "InstanceType": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-fleetlaunchtemplateoverridesrequest.html#cfn-ec2-ec2fleet-fleetlaunchtemplateoverridesrequest-instancetype", "PrimitiveType": "String", @@ -19258,6 +20460,213 @@ } } }, + "AWS::EC2::EC2Fleet.InstanceRequirementsRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-instancerequirementsrequest.html", + "Properties": { + "AcceleratorCount": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-instancerequirementsrequest.html#cfn-ec2-ec2fleet-instancerequirementsrequest-acceleratorcount", + "Required": false, + "Type": "AcceleratorCountRequest", + "UpdateType": "Immutable" + }, + "AcceleratorManufacturers": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-instancerequirementsrequest.html#cfn-ec2-ec2fleet-instancerequirementsrequest-acceleratormanufacturers", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "AcceleratorNames": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-instancerequirementsrequest.html#cfn-ec2-ec2fleet-instancerequirementsrequest-acceleratornames", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "AcceleratorTotalMemoryMiB": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-instancerequirementsrequest.html#cfn-ec2-ec2fleet-instancerequirementsrequest-acceleratortotalmemorymib", + "Required": false, + "Type": "AcceleratorTotalMemoryMiBRequest", + "UpdateType": "Immutable" + }, + "AcceleratorTypes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-instancerequirementsrequest.html#cfn-ec2-ec2fleet-instancerequirementsrequest-acceleratortypes", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "BareMetal": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-instancerequirementsrequest.html#cfn-ec2-ec2fleet-instancerequirementsrequest-baremetal", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "BaselineEbsBandwidthMbps": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-instancerequirementsrequest.html#cfn-ec2-ec2fleet-instancerequirementsrequest-baselineebsbandwidthmbps", + "Required": false, + "Type": "BaselineEbsBandwidthMbpsRequest", + "UpdateType": "Immutable" + }, + "BurstablePerformance": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-instancerequirementsrequest.html#cfn-ec2-ec2fleet-instancerequirementsrequest-burstableperformance", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "CpuManufacturers": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-instancerequirementsrequest.html#cfn-ec2-ec2fleet-instancerequirementsrequest-cpumanufacturers", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "ExcludedInstanceTypes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-instancerequirementsrequest.html#cfn-ec2-ec2fleet-instancerequirementsrequest-excludedinstancetypes", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "InstanceGenerations": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-instancerequirementsrequest.html#cfn-ec2-ec2fleet-instancerequirementsrequest-instancegenerations", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "LocalStorage": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-instancerequirementsrequest.html#cfn-ec2-ec2fleet-instancerequirementsrequest-localstorage", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "LocalStorageTypes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-instancerequirementsrequest.html#cfn-ec2-ec2fleet-instancerequirementsrequest-localstoragetypes", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "MemoryGiBPerVCpu": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-instancerequirementsrequest.html#cfn-ec2-ec2fleet-instancerequirementsrequest-memorygibpervcpu", + "Required": false, + "Type": "MemoryGiBPerVCpuRequest", + "UpdateType": "Immutable" + }, + "MemoryMiB": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-instancerequirementsrequest.html#cfn-ec2-ec2fleet-instancerequirementsrequest-memorymib", + "Required": false, + "Type": "MemoryMiBRequest", + "UpdateType": "Immutable" + }, + "NetworkInterfaceCount": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-instancerequirementsrequest.html#cfn-ec2-ec2fleet-instancerequirementsrequest-networkinterfacecount", + "Required": false, + "Type": "NetworkInterfaceCountRequest", + "UpdateType": "Immutable" + }, + "OnDemandMaxPricePercentageOverLowestPrice": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-instancerequirementsrequest.html#cfn-ec2-ec2fleet-instancerequirementsrequest-ondemandmaxpricepercentageoverlowestprice", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + }, + "RequireHibernateSupport": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-instancerequirementsrequest.html#cfn-ec2-ec2fleet-instancerequirementsrequest-requirehibernatesupport", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Immutable" + }, + "SpotMaxPricePercentageOverLowestPrice": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-instancerequirementsrequest.html#cfn-ec2-ec2fleet-instancerequirementsrequest-spotmaxpricepercentageoverlowestprice", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + }, + "TotalLocalStorageGB": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-instancerequirementsrequest.html#cfn-ec2-ec2fleet-instancerequirementsrequest-totallocalstoragegb", + "Required": false, + "Type": "TotalLocalStorageGBRequest", + "UpdateType": "Immutable" + }, + "VCpuCount": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-instancerequirementsrequest.html#cfn-ec2-ec2fleet-instancerequirementsrequest-vcpucount", + "Required": false, + "Type": "VCpuCountRangeRequest", + "UpdateType": "Immutable" + } + } + }, + "AWS::EC2::EC2Fleet.MaintenanceStrategies": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-maintenancestrategies.html", + "Properties": { + "CapacityRebalance": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-maintenancestrategies.html#cfn-ec2-ec2fleet-maintenancestrategies-capacityrebalance", + "Required": false, + "Type": "CapacityRebalance", + "UpdateType": "Immutable" + } + } + }, + "AWS::EC2::EC2Fleet.MemoryGiBPerVCpuRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-memorygibpervcpurequest.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-memorygibpervcpurequest.html#cfn-ec2-ec2fleet-memorygibpervcpurequest-max", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Immutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-memorygibpervcpurequest.html#cfn-ec2-ec2fleet-memorygibpervcpurequest-min", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::EC2::EC2Fleet.MemoryMiBRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-memorymibrequest.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-memorymibrequest.html#cfn-ec2-ec2fleet-memorymibrequest-max", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-memorymibrequest.html#cfn-ec2-ec2fleet-memorymibrequest-min", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::EC2::EC2Fleet.NetworkInterfaceCountRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-networkinterfacecountrequest.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-networkinterfacecountrequest.html#cfn-ec2-ec2fleet-networkinterfacecountrequest-max", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-networkinterfacecountrequest.html#cfn-ec2-ec2fleet-networkinterfacecountrequest-min", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + } + } + }, "AWS::EC2::EC2Fleet.OnDemandOptionsRequest": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-ondemandoptionsrequest.html", "Properties": { @@ -19373,6 +20782,12 @@ "Required": false, "UpdateType": "Immutable" }, + "MaintenanceStrategies": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-spotoptionsrequest.html#cfn-ec2-ec2fleet-spotoptionsrequest-maintenancestrategies", + "Required": false, + "Type": "MaintenanceStrategies", + "UpdateType": "Immutable" + }, "MaxTotalPrice": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-spotoptionsrequest.html#cfn-ec2-ec2fleet-spotoptionsrequest-maxtotalprice", "PrimitiveType": "String", @@ -19439,6 +20854,12 @@ "Required": false, "UpdateType": "Mutable" }, + "TargetCapacityUnitType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-targetcapacityspecificationrequest.html#cfn-ec2-ec2fleet-targetcapacityspecificationrequest-targetcapacityunittype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "TotalTargetCapacity": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-targetcapacityspecificationrequest.html#cfn-ec2-ec2fleet-targetcapacityspecificationrequest-totaltargetcapacity", "PrimitiveType": "Integer", @@ -19447,6 +20868,40 @@ } } }, + "AWS::EC2::EC2Fleet.TotalLocalStorageGBRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-totallocalstoragegbrequest.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-totallocalstoragegbrequest.html#cfn-ec2-ec2fleet-totallocalstoragegbrequest-max", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Immutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-totallocalstoragegbrequest.html#cfn-ec2-ec2fleet-totallocalstoragegbrequest-min", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::EC2::EC2Fleet.VCpuCountRangeRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-vcpucountrangerequest.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-vcpucountrangerequest.html#cfn-ec2-ec2fleet-vcpucountrangerequest-max", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ec2fleet-vcpucountrangerequest.html#cfn-ec2-ec2fleet-vcpucountrangerequest-min", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + } + } + }, "AWS::EC2::Instance.AssociationParameter": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance-ssmassociations-associationparameters.html", "Properties": { @@ -21327,16 +22782,16 @@ } }, "AWS::EC2::NetworkInterface.PrivateIpAddressSpecification": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-network-interface-privateipspec.html", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-networkinterface-privateipaddressspecification.html", "Properties": { "Primary": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-network-interface-privateipspec.html#cfn-ec2-networkinterface-privateipspecification-primary", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-networkinterface-privateipaddressspecification.html#cfn-ec2-networkinterface-privateipaddressspecification-primary", "PrimitiveType": "Boolean", "Required": true, "UpdateType": "Mutable" }, "PrivateIpAddress": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-network-interface-privateipspec.html#cfn-ec2-networkinterface-privateipspecification-privateipaddress", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-networkinterface-privateipaddressspecification.html#cfn-ec2-networkinterface-privateipaddressspecification-privateipaddress", "PrimitiveType": "String", "Required": true, "UpdateType": "Mutable" @@ -21478,6 +22933,57 @@ } } }, + "AWS::EC2::SpotFleet.AcceleratorCountRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-acceleratorcountrequest.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-acceleratorcountrequest.html#cfn-ec2-spotfleet-acceleratorcountrequest-max", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-acceleratorcountrequest.html#cfn-ec2-spotfleet-acceleratorcountrequest-min", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::EC2::SpotFleet.AcceleratorTotalMemoryMiBRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-acceleratortotalmemorymibrequest.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-acceleratortotalmemorymibrequest.html#cfn-ec2-spotfleet-acceleratortotalmemorymibrequest-max", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-acceleratortotalmemorymibrequest.html#cfn-ec2-spotfleet-acceleratortotalmemorymibrequest-min", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::EC2::SpotFleet.BaselineEbsBandwidthMbpsRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-baselineebsbandwidthmbpsrequest.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-baselineebsbandwidthmbpsrequest.html#cfn-ec2-spotfleet-baselineebsbandwidthmbpsrequest-max", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-baselineebsbandwidthmbpsrequest.html#cfn-ec2-spotfleet-baselineebsbandwidthmbpsrequest-min", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + } + } + }, "AWS::EC2::SpotFleet.BlockDeviceMapping": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-blockdevicemapping.html", "Properties": { @@ -21705,6 +23211,151 @@ } } }, + "AWS::EC2::SpotFleet.InstanceRequirementsRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-instancerequirementsrequest.html", + "Properties": { + "AcceleratorCount": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-instancerequirementsrequest.html#cfn-ec2-spotfleet-instancerequirementsrequest-acceleratorcount", + "Required": false, + "Type": "AcceleratorCountRequest", + "UpdateType": "Immutable" + }, + "AcceleratorManufacturers": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-instancerequirementsrequest.html#cfn-ec2-spotfleet-instancerequirementsrequest-acceleratormanufacturers", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "AcceleratorNames": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-instancerequirementsrequest.html#cfn-ec2-spotfleet-instancerequirementsrequest-acceleratornames", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "AcceleratorTotalMemoryMiB": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-instancerequirementsrequest.html#cfn-ec2-spotfleet-instancerequirementsrequest-acceleratortotalmemorymib", + "Required": false, + "Type": "AcceleratorTotalMemoryMiBRequest", + "UpdateType": "Immutable" + }, + "AcceleratorTypes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-instancerequirementsrequest.html#cfn-ec2-spotfleet-instancerequirementsrequest-acceleratortypes", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "BareMetal": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-instancerequirementsrequest.html#cfn-ec2-spotfleet-instancerequirementsrequest-baremetal", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "BaselineEbsBandwidthMbps": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-instancerequirementsrequest.html#cfn-ec2-spotfleet-instancerequirementsrequest-baselineebsbandwidthmbps", + "Required": false, + "Type": "BaselineEbsBandwidthMbpsRequest", + "UpdateType": "Immutable" + }, + "BurstablePerformance": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-instancerequirementsrequest.html#cfn-ec2-spotfleet-instancerequirementsrequest-burstableperformance", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "CpuManufacturers": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-instancerequirementsrequest.html#cfn-ec2-spotfleet-instancerequirementsrequest-cpumanufacturers", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "ExcludedInstanceTypes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-instancerequirementsrequest.html#cfn-ec2-spotfleet-instancerequirementsrequest-excludedinstancetypes", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "InstanceGenerations": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-instancerequirementsrequest.html#cfn-ec2-spotfleet-instancerequirementsrequest-instancegenerations", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "LocalStorage": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-instancerequirementsrequest.html#cfn-ec2-spotfleet-instancerequirementsrequest-localstorage", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "LocalStorageTypes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-instancerequirementsrequest.html#cfn-ec2-spotfleet-instancerequirementsrequest-localstoragetypes", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "MemoryGiBPerVCpu": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-instancerequirementsrequest.html#cfn-ec2-spotfleet-instancerequirementsrequest-memorygibpervcpu", + "Required": false, + "Type": "MemoryGiBPerVCpuRequest", + "UpdateType": "Immutable" + }, + "MemoryMiB": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-instancerequirementsrequest.html#cfn-ec2-spotfleet-instancerequirementsrequest-memorymib", + "Required": false, + "Type": "MemoryMiBRequest", + "UpdateType": "Immutable" + }, + "NetworkInterfaceCount": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-instancerequirementsrequest.html#cfn-ec2-spotfleet-instancerequirementsrequest-networkinterfacecount", + "Required": false, + "Type": "NetworkInterfaceCountRequest", + "UpdateType": "Immutable" + }, + "OnDemandMaxPricePercentageOverLowestPrice": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-instancerequirementsrequest.html#cfn-ec2-spotfleet-instancerequirementsrequest-ondemandmaxpricepercentageoverlowestprice", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + }, + "RequireHibernateSupport": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-instancerequirementsrequest.html#cfn-ec2-spotfleet-instancerequirementsrequest-requirehibernatesupport", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Immutable" + }, + "SpotMaxPricePercentageOverLowestPrice": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-instancerequirementsrequest.html#cfn-ec2-spotfleet-instancerequirementsrequest-spotmaxpricepercentageoverlowestprice", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + }, + "TotalLocalStorageGB": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-instancerequirementsrequest.html#cfn-ec2-spotfleet-instancerequirementsrequest-totallocalstoragegb", + "Required": false, + "Type": "TotalLocalStorageGBRequest", + "UpdateType": "Immutable" + }, + "VCpuCount": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-instancerequirementsrequest.html#cfn-ec2-spotfleet-instancerequirementsrequest-vcpucount", + "Required": false, + "Type": "VCpuCountRangeRequest", + "UpdateType": "Immutable" + } + } + }, "AWS::EC2::SpotFleet.LaunchTemplateConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-launchtemplateconfig.html", "Properties": { @@ -21733,6 +23384,12 @@ "Required": false, "UpdateType": "Immutable" }, + "InstanceRequirements": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-launchtemplateoverrides.html#cfn-ec2-spotfleet-launchtemplateoverrides-instancerequirements", + "Required": false, + "Type": "InstanceRequirementsRequest", + "UpdateType": "Immutable" + }, "InstanceType": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-launchtemplateoverrides.html#cfn-ec2-spotfleet-launchtemplateoverrides-instancetype", "PrimitiveType": "String", @@ -21776,6 +23433,57 @@ } } }, + "AWS::EC2::SpotFleet.MemoryGiBPerVCpuRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-memorygibpervcpurequest.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-memorygibpervcpurequest.html#cfn-ec2-spotfleet-memorygibpervcpurequest-max", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Immutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-memorygibpervcpurequest.html#cfn-ec2-spotfleet-memorygibpervcpurequest-min", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::EC2::SpotFleet.MemoryMiBRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-memorymibrequest.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-memorymibrequest.html#cfn-ec2-spotfleet-memorymibrequest-max", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-memorymibrequest.html#cfn-ec2-spotfleet-memorymibrequest-min", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::EC2::SpotFleet.NetworkInterfaceCountRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-networkinterfacecountrequest.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-networkinterfacecountrequest.html#cfn-ec2-spotfleet-networkinterfacecountrequest-max", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-networkinterfacecountrequest.html#cfn-ec2-spotfleet-networkinterfacecountrequest-min", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + } + } + }, "AWS::EC2::SpotFleet.PrivateIpAddressSpecification": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-privateipaddressspecification.html", "Properties": { @@ -21801,6 +23509,12 @@ "PrimitiveType": "String", "Required": false, "UpdateType": "Immutable" + }, + "TerminationDelay": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-spotcapacityrebalance.html#cfn-ec2-spotfleet-spotcapacityrebalance-terminationdelay", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" } } }, @@ -21833,10 +23547,16 @@ "Required": true, "UpdateType": "Immutable" }, + "InstanceRequirements": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-spotfleetlaunchspecification.html#cfn-ec2-spotfleet-spotfleetlaunchspecification-instancerequirements", + "Required": false, + "Type": "InstanceRequirementsRequest", + "UpdateType": "Immutable" + }, "InstanceType": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-spotfleetlaunchspecification.html#cfn-ec2-spotfleet-spotfleetlaunchspecification-instancetype", "PrimitiveType": "String", - "Required": true, + "Required": false, "UpdateType": "Immutable" }, "KernelId": { @@ -22039,6 +23759,12 @@ "Required": true, "UpdateType": "Mutable" }, + "TargetCapacityUnitType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-spotfleetrequestconfigdata.html#cfn-ec2-spotfleet-spotfleetrequestconfigdata-targetcapacityunittype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "TerminateInstancesWithExpiration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-spotfleetrequestconfigdata.html#cfn-ec2-spotfleet-spotfleetrequestconfigdata-terminateinstanceswithexpiration", "PrimitiveType": "Boolean", @@ -22142,6 +23868,40 @@ } } }, + "AWS::EC2::SpotFleet.TotalLocalStorageGBRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-totallocalstoragegbrequest.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-totallocalstoragegbrequest.html#cfn-ec2-spotfleet-totallocalstoragegbrequest-max", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Immutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-totallocalstoragegbrequest.html#cfn-ec2-spotfleet-totallocalstoragegbrequest-min", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::EC2::SpotFleet.VCpuCountRangeRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-vcpucountrangerequest.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-vcpucountrangerequest.html#cfn-ec2-spotfleet-vcpucountrangerequest-max", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-spotfleet-vcpucountrangerequest.html#cfn-ec2-spotfleet-vcpucountrangerequest-min", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + } + } + }, "AWS::EC2::TrafficMirrorFilterRule.TrafficMirrorPortRange": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-trafficmirrorfilterrule-trafficmirrorportrange.html", "Properties": { @@ -22170,6 +23930,17 @@ } } }, + "AWS::EC2::TransitGatewayPeeringAttachment.TransitGatewayPeeringAttachmentOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-transitgatewaypeeringattachment-transitgatewaypeeringattachmentoptions.html", + "Properties": { + "DynamicRouting": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-transitgatewaypeeringattachment-transitgatewaypeeringattachmentoptions.html#cfn-ec2-transitgatewaypeeringattachment-transitgatewaypeeringattachmentoptions-dynamicrouting", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::EC2::VPNConnection.VpnTunnelOptionsSpecification": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-vpnconnection-vpntunneloptionsspecification.html", "Properties": { @@ -23419,6 +25190,23 @@ } } }, + "AWS::ECS::TaskDefinition.RuntimePlatform": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-runtimeplatform.html", + "Properties": { + "CpuArchitecture": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-runtimeplatform.html#cfn-ecs-taskdefinition-runtimeplatform-cpuarchitecture", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "OperatingSystemFamily": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-runtimeplatform.html#cfn-ecs-taskdefinition-runtimeplatform-operatingsystemfamily", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, "AWS::ECS::TaskDefinition.Secret": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-secret.html", "Properties": { @@ -23800,21 +25588,33 @@ } } }, + "AWS::EKS::Cluster.ClusterLogging": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-cluster-clusterlogging.html", + "Properties": { + "EnabledTypes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-cluster-clusterlogging.html#cfn-eks-cluster-clusterlogging-enabledtypes", + "ItemType": "LoggingTypeConfig", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::EKS::Cluster.EncryptionConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-cluster-encryptionconfig.html", "Properties": { "Provider": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-cluster-encryptionconfig.html#cfn-eks-cluster-encryptionconfig-provider", + "PrimitiveType": "Json", "Required": false, - "Type": "Provider", - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "Resources": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-cluster-encryptionconfig.html#cfn-eks-cluster-encryptionconfig-resources", "PrimitiveItemType": "String", "Required": false, "Type": "List", - "UpdateType": "Mutable" + "UpdateType": "Immutable" } } }, @@ -23825,15 +25625,26 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-cluster-kubernetesnetworkconfig.html#cfn-eks-cluster-kubernetesnetworkconfig-serviceipv4cidr", "PrimitiveType": "String", "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::EKS::Cluster.Logging": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-cluster-logging.html", + "Properties": { + "ClusterLogging": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-cluster-logging.html#cfn-eks-cluster-logging-clusterlogging", + "Required": false, + "Type": "ClusterLogging", "UpdateType": "Mutable" } } }, - "AWS::EKS::Cluster.Provider": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-cluster-provider.html", + "AWS::EKS::Cluster.LoggingTypeConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-cluster-loggingtypeconfig.html", "Properties": { - "KeyArn": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-cluster-provider.html#cfn-eks-cluster-provider-keyarn", + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-cluster-loggingtypeconfig.html#cfn-eks-cluster-loggingtypeconfig-type", "PrimitiveType": "String", "Required": false, "UpdateType": "Mutable" @@ -23843,19 +25654,38 @@ "AWS::EKS::Cluster.ResourcesVpcConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-cluster-resourcesvpcconfig.html", "Properties": { + "EndpointPrivateAccess": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-cluster-resourcesvpcconfig.html#cfn-eks-cluster-resourcesvpcconfig-endpointprivateaccess", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "EndpointPublicAccess": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-cluster-resourcesvpcconfig.html#cfn-eks-cluster-resourcesvpcconfig-endpointpublicaccess", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "PublicAccessCidrs": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-cluster-resourcesvpcconfig.html#cfn-eks-cluster-resourcesvpcconfig-publicaccesscidrs", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, "SecurityGroupIds": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-cluster-resourcesvpcconfig.html#cfn-eks-cluster-resourcesvpcconfig-securitygroupids", "PrimitiveItemType": "String", "Required": false, "Type": "List", - "UpdateType": "Mutable" + "UpdateType": "Immutable" }, "SubnetIds": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-eks-cluster-resourcesvpcconfig.html#cfn-eks-cluster-resourcesvpcconfig-subnetids", "PrimitiveItemType": "String", "Required": true, "Type": "List", - "UpdateType": "Mutable" + "UpdateType": "Immutable" } } }, @@ -32696,6 +34526,12 @@ "Required": false, "UpdateType": "Immutable" }, + "Throughput": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-containerrecipe-ebsinstanceblockdevicespecification.html#cfn-imagebuilder-containerrecipe-ebsinstanceblockdevicespecification-throughput", + "PrimitiveType": "Integer", + "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", @@ -32971,6 +34807,12 @@ "Required": false, "UpdateType": "Immutable" }, + "Throughput": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-imagerecipe-ebsinstanceblockdevicespecification.html#cfn-imagebuilder-imagerecipe-ebsinstanceblockdevicespecification-throughput", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + }, "VolumeSize": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-imagerecipe-ebsinstanceblockdevicespecification.html#cfn-imagebuilder-imagerecipe-ebsinstanceblockdevicespecification-volumesize", "PrimitiveType": "Integer", @@ -33025,6 +34867,23 @@ } } }, + "AWS::ImageBuilder::InfrastructureConfiguration.InstanceMetadataOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-infrastructureconfiguration-instancemetadataoptions.html", + "Properties": { + "HttpPutResponseHopLimit": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-infrastructureconfiguration-instancemetadataoptions.html#cfn-imagebuilder-infrastructureconfiguration-instancemetadataoptions-httpputresponsehoplimit", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "HttpTokens": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-infrastructureconfiguration-instancemetadataoptions.html#cfn-imagebuilder-infrastructureconfiguration-instancemetadataoptions-httptokens", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::ImageBuilder::InfrastructureConfiguration.Logging": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-infrastructureconfiguration-logging.html", "Properties": { @@ -34708,8 +36567,7 @@ } }, "AWS::IoTAnalytics::Channel.ServiceManagedS3": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-channel-servicemanageds3.html", - "Properties": {} + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-channel-servicemanageds3.html" }, "AWS::IoTAnalytics::Dataset.Action": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-dataset-action.html", @@ -34757,6 +36615,7 @@ }, "Variables": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-dataset-containeraction.html#cfn-iotanalytics-dataset-containeraction-variables", + "DuplicatesAllowed": true, "ItemType": "Variable", "Required": false, "Type": "List", @@ -34799,12 +36658,12 @@ } }, "AWS::IoTAnalytics::Dataset.DatasetContentVersionValue": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-dataset-variable-datasetcontentversionvalue.html", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-dataset-datasetcontentversionvalue.html", "Properties": { "DatasetName": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-dataset-variable-datasetcontentversionvalue.html#cfn-iotanalytics-dataset-variable-datasetcontentversionvalue-datasetname", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-dataset-datasetcontentversionvalue.html#cfn-iotanalytics-dataset-datasetcontentversionvalue-datasetname", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" } } @@ -34911,12 +36770,12 @@ } }, "AWS::IoTAnalytics::Dataset.OutputFileUriValue": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-dataset-variable-outputfileurivalue.html", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-dataset-outputfileurivalue.html", "Properties": { "FileName": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-dataset-variable-outputfileurivalue.html#cfn-iotanalytics-dataset-variable-outputfileurivalue-filename", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-dataset-outputfileurivalue.html#cfn-iotanalytics-dataset-outputfileurivalue-filename", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" } } @@ -34926,6 +36785,7 @@ "Properties": { "Filters": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-dataset-queryaction.html#cfn-iotanalytics-dataset-queryaction-filters", + "DuplicatesAllowed": true, "ItemType": "Filter", "Required": false, "Type": "List", @@ -35003,10 +36863,10 @@ } }, "AWS::IoTAnalytics::Dataset.Schedule": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-dataset-trigger-schedule.html", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-dataset-schedule.html", "Properties": { "ScheduleExpression": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-dataset-trigger-schedule.html#cfn-iotanalytics-dataset-trigger-schedule-scheduleexpression", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-dataset-schedule.html#cfn-iotanalytics-dataset-schedule-scheduleexpression", "PrimitiveType": "String", "Required": true, "UpdateType": "Mutable" @@ -35172,6 +37032,7 @@ "Properties": { "Partitions": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-datastore-datastorepartitions.html#cfn-iotanalytics-datastore-datastorepartitions-partitions", + "DuplicatesAllowed": true, "ItemType": "DatastorePartition", "Required": false, "Type": "List", @@ -35224,15 +37085,14 @@ "Properties": { "CustomerManagedS3Storage": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-datastore-iotsitewisemultilayerstorage.html#cfn-iotanalytics-datastore-iotsitewisemultilayerstorage-customermanageds3storage", - "Required": true, + "Required": false, "Type": "CustomerManagedS3Storage", "UpdateType": "Mutable" } } }, "AWS::IoTAnalytics::Datastore.JsonConfiguration": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-datastore-jsonconfiguration.html", - "Properties": {} + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-datastore-jsonconfiguration.html" }, "AWS::IoTAnalytics::Datastore.ParquetConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-datastore-parquetconfiguration.html", @@ -35278,6 +37138,7 @@ "Properties": { "Columns": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-datastore-schemadefinition.html#cfn-iotanalytics-datastore-schemadefinition-columns", + "DuplicatesAllowed": true, "ItemType": "Column", "Required": false, "Type": "List", @@ -35286,8 +37147,7 @@ } }, "AWS::IoTAnalytics::Datastore.ServiceManagedS3": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-datastore-servicemanageds3.html", - "Properties": {} + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-datastore-servicemanageds3.html" }, "AWS::IoTAnalytics::Datastore.TimestampPartition": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-datastore-timestamppartition.html", @@ -35376,14 +37236,15 @@ "Properties": { "Attributes": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-pipeline-addattributes.html#cfn-iotanalytics-pipeline-addattributes-attributes", - "PrimitiveType": "Json", - "Required": false, + "PrimitiveItemType": "String", + "Required": true, + "Type": "Map", "UpdateType": "Mutable" }, "Name": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-pipeline-addattributes.html#cfn-iotanalytics-pipeline-addattributes-name", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "Next": { @@ -35400,13 +37261,13 @@ "ChannelName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-pipeline-channel.html#cfn-iotanalytics-pipeline-channel-channelname", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "Name": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-pipeline-channel.html#cfn-iotanalytics-pipeline-channel-name", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "Next": { @@ -35423,13 +37284,13 @@ "DatastoreName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-pipeline-datastore.html#cfn-iotanalytics-pipeline-datastore-datastorename", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "Name": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-pipeline-datastore.html#cfn-iotanalytics-pipeline-datastore-name", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" } } @@ -35440,13 +37301,13 @@ "Attribute": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-pipeline-deviceregistryenrich.html#cfn-iotanalytics-pipeline-deviceregistryenrich-attribute", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "Name": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-pipeline-deviceregistryenrich.html#cfn-iotanalytics-pipeline-deviceregistryenrich-name", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "Next": { @@ -35458,13 +37319,13 @@ "RoleArn": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-pipeline-deviceregistryenrich.html#cfn-iotanalytics-pipeline-deviceregistryenrich-rolearn", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "ThingName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-pipeline-deviceregistryenrich.html#cfn-iotanalytics-pipeline-deviceregistryenrich-thingname", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" } } @@ -35475,13 +37336,13 @@ "Attribute": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-pipeline-deviceshadowenrich.html#cfn-iotanalytics-pipeline-deviceshadowenrich-attribute", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "Name": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-pipeline-deviceshadowenrich.html#cfn-iotanalytics-pipeline-deviceshadowenrich-name", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "Next": { @@ -35493,13 +37354,13 @@ "RoleArn": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-pipeline-deviceshadowenrich.html#cfn-iotanalytics-pipeline-deviceshadowenrich-rolearn", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "ThingName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-pipeline-deviceshadowenrich.html#cfn-iotanalytics-pipeline-deviceshadowenrich-thingname", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" } } @@ -35510,13 +37371,13 @@ "Filter": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-pipeline-filter.html#cfn-iotanalytics-pipeline-filter-filter", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "Name": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-pipeline-filter.html#cfn-iotanalytics-pipeline-filter-name", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "Next": { @@ -35533,19 +37394,19 @@ "BatchSize": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-pipeline-lambda.html#cfn-iotanalytics-pipeline-lambda-batchsize", "PrimitiveType": "Integer", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "LambdaName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-pipeline-lambda.html#cfn-iotanalytics-pipeline-lambda-lambdaname", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "Name": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-pipeline-lambda.html#cfn-iotanalytics-pipeline-lambda-name", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "Next": { @@ -35562,19 +37423,19 @@ "Attribute": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-pipeline-math.html#cfn-iotanalytics-pipeline-math-attribute", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "Math": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-pipeline-math.html#cfn-iotanalytics-pipeline-math-math", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "Name": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-pipeline-math.html#cfn-iotanalytics-pipeline-math-name", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "Next": { @@ -35590,15 +37451,16 @@ "Properties": { "Attributes": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-pipeline-removeattributes.html#cfn-iotanalytics-pipeline-removeattributes-attributes", + "DuplicatesAllowed": true, "PrimitiveItemType": "String", - "Required": false, + "Required": true, "Type": "List", "UpdateType": "Mutable" }, "Name": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-pipeline-removeattributes.html#cfn-iotanalytics-pipeline-removeattributes-name", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "Next": { @@ -35614,15 +37476,16 @@ "Properties": { "Attributes": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-pipeline-selectattributes.html#cfn-iotanalytics-pipeline-selectattributes-attributes", + "DuplicatesAllowed": true, "PrimitiveItemType": "String", - "Required": false, + "Required": true, "Type": "List", "UpdateType": "Mutable" }, "Name": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotanalytics-pipeline-selectattributes.html#cfn-iotanalytics-pipeline-selectattributes-name", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "Next": { @@ -41896,6 +43759,59 @@ } } }, + "AWS::Lightsail::Database.RelationalDatabaseParameter": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-database-relationaldatabaseparameter.html", + "Properties": { + "AllowedValues": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-database-relationaldatabaseparameter.html#cfn-lightsail-database-relationaldatabaseparameter-allowedvalues", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ApplyMethod": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-database-relationaldatabaseparameter.html#cfn-lightsail-database-relationaldatabaseparameter-applymethod", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ApplyType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-database-relationaldatabaseparameter.html#cfn-lightsail-database-relationaldatabaseparameter-applytype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "DataType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-database-relationaldatabaseparameter.html#cfn-lightsail-database-relationaldatabaseparameter-datatype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-database-relationaldatabaseparameter.html#cfn-lightsail-database-relationaldatabaseparameter-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "IsModifiable": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-database-relationaldatabaseparameter.html#cfn-lightsail-database-relationaldatabaseparameter-ismodifiable", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "ParameterName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-database-relationaldatabaseparameter.html#cfn-lightsail-database-relationaldatabaseparameter-parametername", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ParameterValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-database-relationaldatabaseparameter.html#cfn-lightsail-database-relationaldatabaseparameter-parametervalue", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::Lightsail::Disk.AddOn": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-disk-addon.html", "Properties": { @@ -42070,6 +43986,7 @@ "MonthlyTransfer": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-networking.html#cfn-lightsail-instance-networking-monthlytransfer", "Required": false, + "Type": "MonthlyTransfer", "UpdateType": "Mutable" }, "Ports": { @@ -43106,9 +45023,6 @@ } } }, - "AWS::MWAA::Environment.TagMap": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mwaa-environment-tagmap.html" - }, "AWS::Macie::FindingsFilter.Criterion": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-macie-findingsfilter-criterion.html" }, @@ -49286,6 +51200,20 @@ "AWS::NetworkFirewall::FirewallPolicy.FirewallPolicy": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-firewallpolicy-firewallpolicy.html", "Properties": { + "StatefulDefaultActions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-firewallpolicy-firewallpolicy.html#cfn-networkfirewall-firewallpolicy-firewallpolicy-statefuldefaultactions", + "DuplicatesAllowed": false, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "StatefulEngineOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-firewallpolicy-firewallpolicy.html#cfn-networkfirewall-firewallpolicy-firewallpolicy-statefulengineoptions", + "Required": false, + "Type": "StatefulEngineOptions", + "UpdateType": "Mutable" + }, "StatefulRuleGroupReferences": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-firewallpolicy-firewallpolicy.html#cfn-networkfirewall-firewallpolicy-firewallpolicy-statefulrulegroupreferences", "DuplicatesAllowed": false, @@ -49341,9 +51269,26 @@ } } }, + "AWS::NetworkFirewall::FirewallPolicy.StatefulEngineOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-firewallpolicy-statefulengineoptions.html", + "Properties": { + "RuleOrder": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-firewallpolicy-statefulengineoptions.html#cfn-networkfirewall-firewallpolicy-statefulengineoptions-ruleorder", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::NetworkFirewall::FirewallPolicy.StatefulRuleGroupReference": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-firewallpolicy-statefulrulegroupreference.html", "Properties": { + "Priority": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-firewallpolicy-statefulrulegroupreference.html#cfn-networkfirewall-firewallpolicy-statefulrulegroupreference-priority", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, "ResourceArn": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-firewallpolicy-statefulrulegroupreference.html#cfn-networkfirewall-firewallpolicy-statefulrulegroupreference-resourcearn", "PrimitiveType": "String", @@ -49638,6 +51583,12 @@ "Required": true, "Type": "RulesSource", "UpdateType": "Mutable" + }, + "StatefulRuleOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-rulegroup-rulegroup.html#cfn-networkfirewall-rulegroup-rulegroup-statefulruleoptions", + "Required": false, + "Type": "StatefulRuleOptions", + "UpdateType": "Mutable" } } }, @@ -49762,6 +51713,17 @@ } } }, + "AWS::NetworkFirewall::RuleGroup.StatefulRuleOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-rulegroup-statefulruleoptions.html", + "Properties": { + "RuleOrder": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-rulegroup-statefulruleoptions.html#cfn-networkfirewall-rulegroup-statefulruleoptions-ruleorder", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::NetworkFirewall::RuleGroup.StatelessRule": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkfirewall-rulegroup-statelessrule.html", "Properties": { @@ -50954,6 +52916,28 @@ } } }, + "AWS::Panorama::ApplicationInstance.ManifestOverridesPayload": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-panorama-applicationinstance-manifestoverridespayload.html", + "Properties": { + "PayloadData": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-panorama-applicationinstance-manifestoverridespayload.html#cfn-panorama-applicationinstance-manifestoverridespayload-payloaddata", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::Panorama::ApplicationInstance.ManifestPayload": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-panorama-applicationinstance-manifestpayload.html", + "Properties": { + "PayloadData": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-panorama-applicationinstance-manifestpayload.html#cfn-panorama-applicationinstance-manifestpayload-payloaddata", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, "AWS::Pinpoint::ApplicationSettings.CampaignHook": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-applicationsettings-campaignhook.html", "Properties": { @@ -51110,6 +53094,30 @@ } } }, + "AWS::Pinpoint::Campaign.CampaignInAppMessage": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-campaigninappmessage.html", + "Properties": { + "Content": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-campaigninappmessage.html#cfn-pinpoint-campaign-campaigninappmessage-content", + "ItemType": "InAppMessageContent", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "CustomConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-campaigninappmessage.html#cfn-pinpoint-campaign-campaigninappmessage-customconfig", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Mutable" + }, + "Layout": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-campaigninappmessage.html#cfn-pinpoint-campaign-campaigninappmessage-layout", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::Pinpoint::Campaign.CampaignSmsMessage": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-campaignsmsmessage.html", "Properties": { @@ -51151,6 +53159,47 @@ } } }, + "AWS::Pinpoint::Campaign.DefaultButtonConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-defaultbuttonconfiguration.html", + "Properties": { + "BackgroundColor": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-defaultbuttonconfiguration.html#cfn-pinpoint-campaign-defaultbuttonconfiguration-backgroundcolor", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "BorderRadius": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-defaultbuttonconfiguration.html#cfn-pinpoint-campaign-defaultbuttonconfiguration-borderradius", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "ButtonAction": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-defaultbuttonconfiguration.html#cfn-pinpoint-campaign-defaultbuttonconfiguration-buttonaction", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Link": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-defaultbuttonconfiguration.html#cfn-pinpoint-campaign-defaultbuttonconfiguration-link", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Text": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-defaultbuttonconfiguration.html#cfn-pinpoint-campaign-defaultbuttonconfiguration-text", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "TextColor": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-defaultbuttonconfiguration.html#cfn-pinpoint-campaign-defaultbuttonconfiguration-textcolor", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::Pinpoint::Campaign.EventDimensions": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-eventdimensions.html", "Properties": { @@ -51174,6 +53223,122 @@ } } }, + "AWS::Pinpoint::Campaign.InAppMessageBodyConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-inappmessagebodyconfig.html", + "Properties": { + "Alignment": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-inappmessagebodyconfig.html#cfn-pinpoint-campaign-inappmessagebodyconfig-alignment", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Body": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-inappmessagebodyconfig.html#cfn-pinpoint-campaign-inappmessagebodyconfig-body", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "TextColor": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-inappmessagebodyconfig.html#cfn-pinpoint-campaign-inappmessagebodyconfig-textcolor", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Pinpoint::Campaign.InAppMessageButton": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-inappmessagebutton.html", + "Properties": { + "Android": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-inappmessagebutton.html#cfn-pinpoint-campaign-inappmessagebutton-android", + "Required": false, + "Type": "OverrideButtonConfiguration", + "UpdateType": "Mutable" + }, + "DefaultConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-inappmessagebutton.html#cfn-pinpoint-campaign-inappmessagebutton-defaultconfig", + "Required": false, + "Type": "DefaultButtonConfiguration", + "UpdateType": "Mutable" + }, + "IOS": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-inappmessagebutton.html#cfn-pinpoint-campaign-inappmessagebutton-ios", + "Required": false, + "Type": "OverrideButtonConfiguration", + "UpdateType": "Mutable" + }, + "Web": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-inappmessagebutton.html#cfn-pinpoint-campaign-inappmessagebutton-web", + "Required": false, + "Type": "OverrideButtonConfiguration", + "UpdateType": "Mutable" + } + } + }, + "AWS::Pinpoint::Campaign.InAppMessageContent": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-inappmessagecontent.html", + "Properties": { + "BackgroundColor": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-inappmessagecontent.html#cfn-pinpoint-campaign-inappmessagecontent-backgroundcolor", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "BodyConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-inappmessagecontent.html#cfn-pinpoint-campaign-inappmessagecontent-bodyconfig", + "Required": false, + "Type": "InAppMessageBodyConfig", + "UpdateType": "Mutable" + }, + "HeaderConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-inappmessagecontent.html#cfn-pinpoint-campaign-inappmessagecontent-headerconfig", + "Required": false, + "Type": "InAppMessageHeaderConfig", + "UpdateType": "Mutable" + }, + "ImageUrl": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-inappmessagecontent.html#cfn-pinpoint-campaign-inappmessagecontent-imageurl", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "PrimaryBtn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-inappmessagecontent.html#cfn-pinpoint-campaign-inappmessagecontent-primarybtn", + "Required": false, + "Type": "InAppMessageButton", + "UpdateType": "Mutable" + }, + "SecondaryBtn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-inappmessagecontent.html#cfn-pinpoint-campaign-inappmessagecontent-secondarybtn", + "Required": false, + "Type": "InAppMessageButton", + "UpdateType": "Mutable" + } + } + }, + "AWS::Pinpoint::Campaign.InAppMessageHeaderConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-inappmessageheaderconfig.html", + "Properties": { + "Alignment": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-inappmessageheaderconfig.html#cfn-pinpoint-campaign-inappmessageheaderconfig-alignment", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Header": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-inappmessageheaderconfig.html#cfn-pinpoint-campaign-inappmessageheaderconfig-header", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "TextColor": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-inappmessageheaderconfig.html#cfn-pinpoint-campaign-inappmessageheaderconfig-textcolor", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::Pinpoint::Campaign.Limits": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-limits.html", "Properties": { @@ -51195,6 +53360,12 @@ "Required": false, "UpdateType": "Mutable" }, + "Session": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-limits.html#cfn-pinpoint-campaign-limits-session", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, "Total": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-limits.html#cfn-pinpoint-campaign-limits-total", "PrimitiveType": "Integer", @@ -51319,6 +53490,12 @@ "Type": "Message", "UpdateType": "Mutable" }, + "InAppMessage": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-messageconfiguration.html#cfn-pinpoint-campaign-messageconfiguration-inappmessage", + "Required": false, + "Type": "CampaignInAppMessage", + "UpdateType": "Mutable" + }, "SMSMessage": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-messageconfiguration.html#cfn-pinpoint-campaign-messageconfiguration-smsmessage", "Required": false, @@ -51344,6 +53521,23 @@ } } }, + "AWS::Pinpoint::Campaign.OverrideButtonConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-overridebuttonconfiguration.html", + "Properties": { + "ButtonAction": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-overridebuttonconfiguration.html#cfn-pinpoint-campaign-overridebuttonconfiguration-buttonaction", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Link": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-overridebuttonconfiguration.html#cfn-pinpoint-campaign-overridebuttonconfiguration-link", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::Pinpoint::Campaign.QuietTime": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-campaign-schedule-quiettime.html", "Properties": { @@ -51461,6 +53655,180 @@ } } }, + "AWS::Pinpoint::InAppTemplate.BodyConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-bodyconfig.html", + "Properties": { + "Alignment": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-bodyconfig.html#cfn-pinpoint-inapptemplate-bodyconfig-alignment", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Body": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-bodyconfig.html#cfn-pinpoint-inapptemplate-bodyconfig-body", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "TextColor": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-bodyconfig.html#cfn-pinpoint-inapptemplate-bodyconfig-textcolor", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Pinpoint::InAppTemplate.ButtonConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-buttonconfig.html", + "Properties": { + "Android": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-buttonconfig.html#cfn-pinpoint-inapptemplate-buttonconfig-android", + "Required": false, + "Type": "OverrideButtonConfiguration", + "UpdateType": "Mutable" + }, + "DefaultConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-buttonconfig.html#cfn-pinpoint-inapptemplate-buttonconfig-defaultconfig", + "Required": false, + "Type": "DefaultButtonConfiguration", + "UpdateType": "Mutable" + }, + "IOS": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-buttonconfig.html#cfn-pinpoint-inapptemplate-buttonconfig-ios", + "Required": false, + "Type": "OverrideButtonConfiguration", + "UpdateType": "Mutable" + }, + "Web": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-buttonconfig.html#cfn-pinpoint-inapptemplate-buttonconfig-web", + "Required": false, + "Type": "OverrideButtonConfiguration", + "UpdateType": "Mutable" + } + } + }, + "AWS::Pinpoint::InAppTemplate.DefaultButtonConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-defaultbuttonconfiguration.html", + "Properties": { + "BackgroundColor": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-defaultbuttonconfiguration.html#cfn-pinpoint-inapptemplate-defaultbuttonconfiguration-backgroundcolor", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "BorderRadius": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-defaultbuttonconfiguration.html#cfn-pinpoint-inapptemplate-defaultbuttonconfiguration-borderradius", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "ButtonAction": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-defaultbuttonconfiguration.html#cfn-pinpoint-inapptemplate-defaultbuttonconfiguration-buttonaction", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Link": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-defaultbuttonconfiguration.html#cfn-pinpoint-inapptemplate-defaultbuttonconfiguration-link", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Text": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-defaultbuttonconfiguration.html#cfn-pinpoint-inapptemplate-defaultbuttonconfiguration-text", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "TextColor": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-defaultbuttonconfiguration.html#cfn-pinpoint-inapptemplate-defaultbuttonconfiguration-textcolor", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Pinpoint::InAppTemplate.HeaderConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-headerconfig.html", + "Properties": { + "Alignment": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-headerconfig.html#cfn-pinpoint-inapptemplate-headerconfig-alignment", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Header": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-headerconfig.html#cfn-pinpoint-inapptemplate-headerconfig-header", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "TextColor": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-headerconfig.html#cfn-pinpoint-inapptemplate-headerconfig-textcolor", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Pinpoint::InAppTemplate.InAppMessageContent": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-inappmessagecontent.html", + "Properties": { + "BackgroundColor": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-inappmessagecontent.html#cfn-pinpoint-inapptemplate-inappmessagecontent-backgroundcolor", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "BodyConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-inappmessagecontent.html#cfn-pinpoint-inapptemplate-inappmessagecontent-bodyconfig", + "Required": false, + "Type": "BodyConfig", + "UpdateType": "Mutable" + }, + "HeaderConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-inappmessagecontent.html#cfn-pinpoint-inapptemplate-inappmessagecontent-headerconfig", + "Required": false, + "Type": "HeaderConfig", + "UpdateType": "Mutable" + }, + "ImageUrl": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-inappmessagecontent.html#cfn-pinpoint-inapptemplate-inappmessagecontent-imageurl", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "PrimaryBtn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-inappmessagecontent.html#cfn-pinpoint-inapptemplate-inappmessagecontent-primarybtn", + "Required": false, + "Type": "ButtonConfig", + "UpdateType": "Mutable" + }, + "SecondaryBtn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-inappmessagecontent.html#cfn-pinpoint-inapptemplate-inappmessagecontent-secondarybtn", + "Required": false, + "Type": "ButtonConfig", + "UpdateType": "Mutable" + } + } + }, + "AWS::Pinpoint::InAppTemplate.OverrideButtonConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-overridebuttonconfiguration.html", + "Properties": { + "ButtonAction": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-overridebuttonconfiguration.html#cfn-pinpoint-inapptemplate-overridebuttonconfiguration-buttonaction", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Link": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-inapptemplate-overridebuttonconfiguration.html#cfn-pinpoint-inapptemplate-overridebuttonconfiguration-link", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::Pinpoint::PushTemplate.APNSPushNotificationTemplate": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-pinpoint-pushtemplate-apnspushnotificationtemplate.html", "Properties": { @@ -53139,6 +55507,17 @@ } } }, + "AWS::QuickSight::DataSource.AmazonOpenSearchParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-amazonopensearchparameters.html", + "Properties": { + "Domain": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-amazonopensearchparameters.html#cfn-quicksight-datasource-amazonopensearchparameters-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": { @@ -53263,6 +55642,12 @@ "Type": "AmazonElasticsearchParameters", "UpdateType": "Mutable" }, + "AmazonOpenSearchParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-quicksight-datasource-datasourceparameters.html#cfn-quicksight-datasource-datasourceparameters-amazonopensearchparameters", + "Required": false, + "Type": "AmazonOpenSearchParameters", + "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, @@ -54354,6 +56739,103 @@ } } }, + "AWS::Redshift::EndpointAccess.VpcSecurityGroup": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-redshift-endpointaccess-vpcsecuritygroup.html", + "Properties": { + "Status": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-redshift-endpointaccess-vpcsecuritygroup.html#cfn-redshift-endpointaccess-vpcsecuritygroup-status", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "VpcSecurityGroupId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-redshift-endpointaccess-vpcsecuritygroup.html#cfn-redshift-endpointaccess-vpcsecuritygroup-vpcsecuritygroupid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Redshift::ScheduledAction.PauseClusterMessage": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-redshift-scheduledaction-pauseclustermessage.html", + "Properties": { + "ClusterIdentifier": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-redshift-scheduledaction-pauseclustermessage.html#cfn-redshift-scheduledaction-pauseclustermessage-clusteridentifier", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::Redshift::ScheduledAction.ResizeClusterMessage": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-redshift-scheduledaction-resizeclustermessage.html", + "Properties": { + "Classic": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-redshift-scheduledaction-resizeclustermessage.html#cfn-redshift-scheduledaction-resizeclustermessage-classic", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "ClusterIdentifier": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-redshift-scheduledaction-resizeclustermessage.html#cfn-redshift-scheduledaction-resizeclustermessage-clusteridentifier", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ClusterType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-redshift-scheduledaction-resizeclustermessage.html#cfn-redshift-scheduledaction-resizeclustermessage-clustertype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "NodeType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-redshift-scheduledaction-resizeclustermessage.html#cfn-redshift-scheduledaction-resizeclustermessage-nodetype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "NumberOfNodes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-redshift-scheduledaction-resizeclustermessage.html#cfn-redshift-scheduledaction-resizeclustermessage-numberofnodes", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Redshift::ScheduledAction.ResumeClusterMessage": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-redshift-scheduledaction-resumeclustermessage.html", + "Properties": { + "ClusterIdentifier": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-redshift-scheduledaction-resumeclustermessage.html#cfn-redshift-scheduledaction-resumeclustermessage-clusteridentifier", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::Redshift::ScheduledAction.ScheduledActionType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-redshift-scheduledaction-scheduledactiontype.html", + "Properties": { + "PauseCluster": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-redshift-scheduledaction-scheduledactiontype.html#cfn-redshift-scheduledaction-scheduledactiontype-pausecluster", + "Required": false, + "Type": "PauseClusterMessage", + "UpdateType": "Mutable" + }, + "ResizeCluster": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-redshift-scheduledaction-scheduledactiontype.html#cfn-redshift-scheduledaction-scheduledactiontype-resizecluster", + "Required": false, + "Type": "ResizeClusterMessage", + "UpdateType": "Mutable" + }, + "ResumeCluster": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-redshift-scheduledaction-scheduledactiontype.html#cfn-redshift-scheduledaction-scheduledactiontype-resumecluster", + "Required": false, + "Type": "ResumeClusterMessage", + "UpdateType": "Mutable" + } + } + }, "AWS::ResourceGroups::Group.ConfigurationItem": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resourcegroups-group-configurationitem.html", "Properties": { @@ -58582,6 +61064,12 @@ "Type": "CapacitySize", "UpdateType": "Mutable" }, + "LinearStepSize": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-endpoint-trafficroutingconfig.html#cfn-sagemaker-endpoint-trafficroutingconfig-linearstepsize", + "Required": false, + "Type": "CapacitySize", + "UpdateType": "Mutable" + }, "Type": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sagemaker-endpoint-trafficroutingconfig.html#cfn-sagemaker-endpoint-trafficroutingconfig-type", "PrimitiveType": "String", @@ -60918,6 +63406,17 @@ } } }, + "AWS::Synthetics::Canary.ArtifactConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-synthetics-canary-artifactconfig.html", + "Properties": { + "S3Encryption": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-synthetics-canary-artifactconfig.html#cfn-synthetics-canary-artifactconfig-s3encryption", + "Required": false, + "Type": "S3Encryption", + "UpdateType": "Mutable" + } + } + }, "AWS::Synthetics::Canary.BaseScreenshot": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-synthetics-canary-basescreenshot.html", "Properties": { @@ -61001,6 +63500,23 @@ } } }, + "AWS::Synthetics::Canary.S3Encryption": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-synthetics-canary-s3encryption.html", + "Properties": { + "EncryptionMode": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-synthetics-canary-s3encryption.html#cfn-synthetics-canary-s3encryption-encryptionmode", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "KmsKeyArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-synthetics-canary-s3encryption.html#cfn-synthetics-canary-s3encryption-kmskeyarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::Synthetics::Canary.Schedule": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-synthetics-canary-schedule.html", "Properties": { @@ -63150,6 +65666,79 @@ } } }, + "AWS::Wisdom::Assistant.ServerSideEncryptionConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wisdom-assistant-serversideencryptionconfiguration.html", + "Properties": { + "KmsKeyId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wisdom-assistant-serversideencryptionconfiguration.html#cfn-wisdom-assistant-serversideencryptionconfiguration-kmskeyid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::Wisdom::AssistantAssociation.AssociationData": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wisdom-assistantassociation-associationdata.html", + "Properties": { + "KnowledgeBaseId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wisdom-assistantassociation-associationdata.html#cfn-wisdom-assistantassociation-associationdata-knowledgebaseid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, + "AWS::Wisdom::KnowledgeBase.AppIntegrationsConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wisdom-knowledgebase-appintegrationsconfiguration.html", + "Properties": { + "AppIntegrationArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wisdom-knowledgebase-appintegrationsconfiguration.html#cfn-wisdom-knowledgebase-appintegrationsconfiguration-appintegrationarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "ObjectFields": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wisdom-knowledgebase-appintegrationsconfiguration.html#cfn-wisdom-knowledgebase-appintegrationsconfiguration-objectfields", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Immutable" + } + } + }, + "AWS::Wisdom::KnowledgeBase.RenderingConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wisdom-knowledgebase-renderingconfiguration.html", + "Properties": { + "TemplateUri": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wisdom-knowledgebase-renderingconfiguration.html#cfn-wisdom-knowledgebase-renderingconfiguration-templateuri", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Wisdom::KnowledgeBase.ServerSideEncryptionConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wisdom-knowledgebase-serversideencryptionconfiguration.html", + "Properties": { + "KmsKeyId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wisdom-knowledgebase-serversideencryptionconfiguration.html#cfn-wisdom-knowledgebase-serversideencryptionconfiguration-kmskeyid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::Wisdom::KnowledgeBase.SourceConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wisdom-knowledgebase-sourceconfiguration.html", + "Properties": { + "AppIntegrations": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wisdom-knowledgebase-sourceconfiguration.html#cfn-wisdom-knowledgebase-sourceconfiguration-appintegrations", + "Required": false, + "Type": "AppIntegrationsConfiguration", + "UpdateType": "Immutable" + } + } + }, "AWS::WorkSpaces::ConnectionAlias.ConnectionAliasAssociation": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-workspaces-connectionalias-connectionaliasassociation.html", "Properties": { @@ -63503,7 +66092,7 @@ } } }, - "ResourceSpecificationVersion": "43.0.0", + "ResourceSpecificationVersion": "47.0.0", "ResourceTypes": { "AWS::ACMPCA::Certificate": { "Attributes": { @@ -64373,6 +66962,11 @@ } }, "AWS::ApiGateway::Authorizer": { + "Attributes": { + "AuthorizerId": { + "PrimitiveType": "String" + } + }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-authorizer.html", "Properties": { "AuthType": { @@ -64414,7 +67008,7 @@ "Name": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-authorizer.html#cfn-apigateway-authorizer-name", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "ProviderARNs": { @@ -65165,6 +67759,13 @@ "Required": true, "UpdateType": "Mutable" }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-vpclink.html#cfn-apigateway-vpclink-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, "TargetArns": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-vpclink.html#cfn-apigateway-vpclink-targetarns", "PrimitiveItemType": "String", @@ -68042,6 +70643,12 @@ "Required": false, "UpdateType": "Mutable" }, + "DesiredCapacityType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-group.html#cfn-as-group-desiredcapacitytype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "HealthCheckGracePeriod": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-group.html#cfn-as-group-healthcheckgraceperiod", "PrimitiveType": "Integer", @@ -68306,52 +70913,52 @@ } }, "AWS::AutoScaling::LifecycleHook": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-as-lifecyclehook.html", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-lifecyclehook.html", "Properties": { "AutoScalingGroupName": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-as-lifecyclehook.html#cfn-as-lifecyclehook-autoscalinggroupname", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-lifecyclehook.html#cfn-autoscaling-lifecyclehook-autoscalinggroupname", "PrimitiveType": "String", "Required": true, "UpdateType": "Immutable" }, "DefaultResult": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-as-lifecyclehook.html#cfn-as-lifecyclehook-defaultresult", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-lifecyclehook.html#cfn-autoscaling-lifecyclehook-defaultresult", "PrimitiveType": "String", "Required": false, "UpdateType": "Mutable" }, "HeartbeatTimeout": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-as-lifecyclehook.html#cfn-as-lifecyclehook-heartbeattimeout", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-lifecyclehook.html#cfn-autoscaling-lifecyclehook-heartbeattimeout", "PrimitiveType": "Integer", "Required": false, "UpdateType": "Mutable" }, "LifecycleHookName": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-as-lifecyclehook.html#cfn-autoscaling-lifecyclehook-lifecyclehookname", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-lifecyclehook.html#cfn-autoscaling-lifecyclehook-lifecyclehookname", "PrimitiveType": "String", "Required": false, "UpdateType": "Immutable" }, "LifecycleTransition": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-as-lifecyclehook.html#cfn-as-lifecyclehook-lifecycletransition", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-lifecyclehook.html#cfn-autoscaling-lifecyclehook-lifecycletransition", "PrimitiveType": "String", "Required": true, "UpdateType": "Mutable" }, "NotificationMetadata": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-as-lifecyclehook.html#cfn-as-lifecyclehook-notificationmetadata", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-lifecyclehook.html#cfn-autoscaling-lifecyclehook-notificationmetadata", "PrimitiveType": "String", "Required": false, "UpdateType": "Mutable" }, "NotificationTargetARN": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-as-lifecyclehook.html#cfn-as-lifecyclehook-notificationtargetarn", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-lifecyclehook.html#cfn-autoscaling-lifecyclehook-notificationtargetarn", "PrimitiveType": "String", "Required": false, "UpdateType": "Mutable" }, "RoleARN": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-as-lifecyclehook.html#cfn-as-lifecyclehook-rolearn", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-lifecyclehook.html#cfn-autoscaling-lifecyclehook-rolearn", "PrimitiveType": "String", "Required": false, "UpdateType": "Mutable" @@ -68771,6 +71378,12 @@ "PrimitiveType": "String", "Required": true, "UpdateType": "Immutable" + }, + "UnmanagedvCpus": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-batch-computeenvironment.html#cfn-batch-computeenvironment-unmanagedvcpus", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" } } }, @@ -68820,6 +71433,12 @@ "Type": "RetryStrategy", "UpdateType": "Mutable" }, + "SchedulingPriority": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-batch-jobdefinition.html#cfn-batch-jobdefinition-schedulingpriority", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-batch-jobdefinition.html#cfn-batch-jobdefinition-tags", "PrimitiveType": "Json", @@ -68862,6 +71481,12 @@ "Required": true, "UpdateType": "Mutable" }, + "SchedulingPolicyArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-batch-jobqueue.html#cfn-batch-jobqueue-schedulingpolicyarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "State": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-batch-jobqueue.html#cfn-batch-jobqueue-state", "PrimitiveType": "String", @@ -68947,7 +71572,7 @@ "Subscribers": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-budgets-budgetsaction.html#cfn-budgets-budgetsaction-subscribers", "ItemType": "Subscriber", - "Required": false, + "Required": true, "Type": "List", "UpdateType": "Mutable" } @@ -69202,6 +71827,12 @@ "Type": "List", "UpdateType": "Immutable" }, + "DefaultTimeToLive": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cassandra-table.html#cfn-cassandra-table-defaulttimetolive", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, "EncryptionSpecification": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cassandra-table.html#cfn-cassandra-table-encryptionspecification", "Required": false, @@ -70161,6 +72792,25 @@ } } }, + "AWS::CloudFront::ResponseHeadersPolicy": { + "Attributes": { + "Id": { + "PrimitiveType": "String" + }, + "LastModifiedTime": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-responseheaderspolicy.html", + "Properties": { + "ResponseHeadersPolicyConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-responseheaderspolicy.html#cfn-cloudfront-responseheaderspolicy-responseheaderspolicyconfig", + "Required": true, + "Type": "ResponseHeadersPolicyConfig", + "UpdateType": "Mutable" + } + } + }, "AWS::CloudFront::StreamingDistribution": { "Attributes": { "DomainName": { @@ -71591,12 +74241,24 @@ }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codestarnotifications-notificationrule.html", "Properties": { + "CreatedBy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codestarnotifications-notificationrule.html#cfn-codestarnotifications-notificationrule-createdby", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "DetailType": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codestarnotifications-notificationrule.html#cfn-codestarnotifications-notificationrule-detailtype", "PrimitiveType": "String", "Required": true, "UpdateType": "Mutable" }, + "EventTypeId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codestarnotifications-notificationrule.html#cfn-codestarnotifications-notificationrule-eventtypeid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "EventTypeIds": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codestarnotifications-notificationrule.html#cfn-codestarnotifications-notificationrule-eventtypeids", "DuplicatesAllowed": true, @@ -71629,6 +74291,12 @@ "Required": false, "UpdateType": "Immutable" }, + "TargetAddress": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codestarnotifications-notificationrule.html#cfn-codestarnotifications-notificationrule-targetaddress", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "Targets": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codestarnotifications-notificationrule.html#cfn-codestarnotifications-notificationrule-targets", "DuplicatesAllowed": true, @@ -72711,6 +75379,56 @@ } } }, + "AWS::Connect::HoursOfOperation": { + "Attributes": { + "HoursOfOperationArn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-connect-hoursofoperation.html", + "Properties": { + "Config": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-connect-hoursofoperation.html#cfn-connect-hoursofoperation-config", + "DuplicatesAllowed": false, + "ItemType": "HoursOfOperationConfig", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-connect-hoursofoperation.html#cfn-connect-hoursofoperation-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "InstanceArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-connect-hoursofoperation.html#cfn-connect-hoursofoperation-instancearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-connect-hoursofoperation.html#cfn-connect-hoursofoperation-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-connect-hoursofoperation.html#cfn-connect-hoursofoperation-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "TimeZone": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-connect-hoursofoperation.html#cfn-connect-hoursofoperation-timezone", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::Connect::QuickConnect": { "Attributes": { "QuickConnectArn": { @@ -72753,6 +75471,108 @@ } } }, + "AWS::Connect::User": { + "Attributes": { + "UserArn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-connect-user.html", + "Properties": { + "DirectoryUserId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-connect-user.html#cfn-connect-user-directoryuserid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "HierarchyGroupArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-connect-user.html#cfn-connect-user-hierarchygrouparn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "IdentityInfo": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-connect-user.html#cfn-connect-user-identityinfo", + "Required": false, + "Type": "UserIdentityInfo", + "UpdateType": "Mutable" + }, + "InstanceArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-connect-user.html#cfn-connect-user-instancearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Password": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-connect-user.html#cfn-connect-user-password", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "PhoneConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-connect-user.html#cfn-connect-user-phoneconfig", + "Required": true, + "Type": "UserPhoneConfig", + "UpdateType": "Mutable" + }, + "RoutingProfileArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-connect-user.html#cfn-connect-user-routingprofilearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "SecurityProfileArns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-connect-user.html#cfn-connect-user-securityprofilearns", + "DuplicatesAllowed": false, + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-connect-user.html#cfn-connect-user-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Username": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-connect-user.html#cfn-connect-user-username", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::Connect::UserHierarchyGroup": { + "Attributes": { + "UserHierarchyGroupArn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-connect-userhierarchygroup.html", + "Properties": { + "InstanceArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-connect-userhierarchygroup.html#cfn-connect-userhierarchygroup-instancearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-connect-userhierarchygroup.html#cfn-connect-userhierarchygroup-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ParentGroupArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-connect-userhierarchygroup.html#cfn-connect-userhierarchygroup-parentgrouparn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, "AWS::CustomerProfiles::Domain": { "Attributes": { "CreatedAt": { @@ -73264,6 +76084,12 @@ "Type": "PostgreSqlSettings", "UpdateType": "Mutable" }, + "RedisSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-redissettings", + "Required": false, + "Type": "RedisSettings", + "UpdateType": "Mutable" + }, "RedshiftSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-redshiftsettings", "Required": false, @@ -74068,6 +76894,101 @@ } } }, + "AWS::DataSync::LocationHDFS": { + "Attributes": { + "LocationArn": { + "PrimitiveType": "String" + }, + "LocationUri": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-datasync-locationhdfs.html", + "Properties": { + "AgentArns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-datasync-locationhdfs.html#cfn-datasync-locationhdfs-agentarns", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "AuthenticationType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-datasync-locationhdfs.html#cfn-datasync-locationhdfs-authenticationtype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "BlockSize": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-datasync-locationhdfs.html#cfn-datasync-locationhdfs-blocksize", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "KerberosKeytab": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-datasync-locationhdfs.html#cfn-datasync-locationhdfs-kerberoskeytab", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "KerberosKrb5Conf": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-datasync-locationhdfs.html#cfn-datasync-locationhdfs-kerberoskrb5conf", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "KerberosPrincipal": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-datasync-locationhdfs.html#cfn-datasync-locationhdfs-kerberosprincipal", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "KmsKeyProviderUri": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-datasync-locationhdfs.html#cfn-datasync-locationhdfs-kmskeyprovideruri", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "NameNodes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-datasync-locationhdfs.html#cfn-datasync-locationhdfs-namenodes", + "ItemType": "NameNode", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "QopConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-datasync-locationhdfs.html#cfn-datasync-locationhdfs-qopconfiguration", + "Required": false, + "Type": "QopConfiguration", + "UpdateType": "Mutable" + }, + "ReplicationFactor": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-datasync-locationhdfs.html#cfn-datasync-locationhdfs-replicationfactor", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "SimpleUser": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-datasync-locationhdfs.html#cfn-datasync-locationhdfs-simpleuser", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Subdirectory": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-datasync-locationhdfs.html#cfn-datasync-locationhdfs-subdirectory", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-datasync-locationhdfs.html#cfn-datasync-locationhdfs-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::DataSync::LocationNFS": { "Attributes": { "LocationArn": { @@ -75121,6 +78042,74 @@ } } }, + "AWS::EC2::CapacityReservationFleet": { + "Attributes": { + "CapacityReservationFleetId": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-capacityreservationfleet.html", + "Properties": { + "AllocationStrategy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-capacityreservationfleet.html#cfn-ec2-capacityreservationfleet-allocationstrategy", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "EndDate": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-capacityreservationfleet.html#cfn-ec2-capacityreservationfleet-enddate", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "InstanceMatchCriteria": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-capacityreservationfleet.html#cfn-ec2-capacityreservationfleet-instancematchcriteria", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "InstanceTypeSpecifications": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-capacityreservationfleet.html#cfn-ec2-capacityreservationfleet-instancetypespecifications", + "DuplicatesAllowed": false, + "ItemType": "InstanceTypeSpecification", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "NoRemoveEndDate": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-capacityreservationfleet.html#cfn-ec2-capacityreservationfleet-noremoveenddate", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "RemoveEndDate": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-capacityreservationfleet.html#cfn-ec2-capacityreservationfleet-removeenddate", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "TagSpecifications": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-capacityreservationfleet.html#cfn-ec2-capacityreservationfleet-tagspecifications", + "DuplicatesAllowed": true, + "ItemType": "TagSpecification", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "Tenancy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-capacityreservationfleet.html#cfn-ec2-capacityreservationfleet-tenancy", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "TotalTargetCapacity": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-capacityreservationfleet.html#cfn-ec2-capacityreservationfleet-totaltargetcapacity", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::EC2::CarrierGateway": { "Attributes": { "CarrierGatewayId": { @@ -76007,6 +78996,11 @@ } }, "AWS::EC2::InternetGateway": { + "Attributes": { + "InternetGatewayId": { + "PrimitiveType": "String" + } + }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-internetgateway.html", "Properties": { "Tags": { @@ -76150,10 +79144,15 @@ } }, "AWS::EC2::NetworkAcl": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-acl.html", + "Attributes": { + "Id": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkacl.html", "Properties": { "Tags": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-acl.html#cfn-ec2-networkacl-tags", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkacl.html#cfn-ec2-networkacl-tags", "DuplicatesAllowed": true, "ItemType": "Tag", "Required": false, @@ -76161,7 +79160,7 @@ "UpdateType": "Mutable" }, "VpcId": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-acl.html#cfn-ec2-networkacl-vpcid", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkacl.html#cfn-ec2-networkacl-vpcid", "PrimitiveType": "String", "Required": true, "UpdateType": "Immutable" @@ -76169,58 +79168,63 @@ } }, "AWS::EC2::NetworkAclEntry": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-acl-entry.html", + "Attributes": { + "Id": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkaclentry.html", "Properties": { "CidrBlock": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-acl-entry.html#cfn-ec2-networkaclentry-cidrblock", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkaclentry.html#cfn-ec2-networkaclentry-cidrblock", "PrimitiveType": "String", "Required": false, "UpdateType": "Mutable" }, "Egress": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-acl-entry.html#cfn-ec2-networkaclentry-egress", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkaclentry.html#cfn-ec2-networkaclentry-egress", "PrimitiveType": "Boolean", "Required": false, "UpdateType": "Immutable" }, "Icmp": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-acl-entry.html#cfn-ec2-networkaclentry-icmp", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkaclentry.html#cfn-ec2-networkaclentry-icmp", "Required": false, "Type": "Icmp", "UpdateType": "Mutable" }, "Ipv6CidrBlock": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-acl-entry.html#cfn-ec2-networkaclentry-ipv6cidrblock", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkaclentry.html#cfn-ec2-networkaclentry-ipv6cidrblock", "PrimitiveType": "String", "Required": false, "UpdateType": "Mutable" }, "NetworkAclId": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-acl-entry.html#cfn-ec2-networkaclentry-networkaclid", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkaclentry.html#cfn-ec2-networkaclentry-networkaclid", "PrimitiveType": "String", "Required": true, "UpdateType": "Immutable" }, "PortRange": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-acl-entry.html#cfn-ec2-networkaclentry-portrange", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkaclentry.html#cfn-ec2-networkaclentry-portrange", "Required": false, "Type": "PortRange", "UpdateType": "Mutable" }, "Protocol": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-acl-entry.html#cfn-ec2-networkaclentry-protocol", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkaclentry.html#cfn-ec2-networkaclentry-protocol", "PrimitiveType": "Integer", "Required": true, "UpdateType": "Mutable" }, "RuleAction": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-acl-entry.html#cfn-ec2-networkaclentry-ruleaction", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkaclentry.html#cfn-ec2-networkaclentry-ruleaction", "PrimitiveType": "String", "Required": true, "UpdateType": "Mutable" }, "RuleNumber": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-acl-entry.html#cfn-ec2-networkaclentry-rulenumber", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkaclentry.html#cfn-ec2-networkaclentry-rulenumber", "PrimitiveType": "Integer", "Required": true, "UpdateType": "Immutable" @@ -76349,44 +79353,48 @@ }, "AWS::EC2::NetworkInterface": { "Attributes": { + "Id": { + "PrimitiveType": "String" + }, "PrimaryPrivateIpAddress": { "PrimitiveType": "String" }, "SecondaryPrivateIpAddresses": { + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Type": "List" } }, - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkinterface.html", "Properties": { "Description": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html#cfn-awsec2networkinterface-description", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkinterface.html#cfn-ec2-networkinterface-description", "PrimitiveType": "String", "Required": false, "UpdateType": "Mutable" }, "GroupSet": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html#cfn-awsec2networkinterface-groupset", - "DuplicatesAllowed": false, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkinterface.html#cfn-ec2-networkinterface-groupset", + "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": false, "Type": "List", "UpdateType": "Mutable" }, "InterfaceType": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html#cfn-ec2-networkinterface-interfacetype", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkinterface.html#cfn-ec2-networkinterface-interfacetype", "PrimitiveType": "String", "Required": false, "UpdateType": "Immutable" }, "Ipv6AddressCount": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html#cfn-ec2-networkinterface-ipv6addresscount", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkinterface.html#cfn-ec2-networkinterface-ipv6addresscount", "PrimitiveType": "Integer", "Required": false, "UpdateType": "Mutable" }, "Ipv6Addresses": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html#cfn-ec2-networkinterface-ipv6addresses", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkinterface.html#cfn-ec2-networkinterface-ipv6addresses", "DuplicatesAllowed": false, "ItemType": "InstanceIpv6Address", "Required": false, @@ -76394,39 +79402,39 @@ "UpdateType": "Mutable" }, "PrivateIpAddress": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html#cfn-awsec2networkinterface-privateipaddress", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkinterface.html#cfn-ec2-networkinterface-privateipaddress", "PrimitiveType": "String", "Required": false, "UpdateType": "Immutable" }, "PrivateIpAddresses": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html#cfn-awsec2networkinterface-privateipaddresses", - "DuplicatesAllowed": false, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkinterface.html#cfn-ec2-networkinterface-privateipaddresses", + "DuplicatesAllowed": true, "ItemType": "PrivateIpAddressSpecification", "Required": false, "Type": "List", - "UpdateType": "Conditional" + "UpdateType": "Mutable" }, "SecondaryPrivateIpAddressCount": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html#cfn-awsec2networkinterface-secondaryprivateipcount", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkinterface.html#cfn-ec2-networkinterface-secondaryprivateipaddresscount", "PrimitiveType": "Integer", "Required": false, "UpdateType": "Mutable" }, "SourceDestCheck": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html#cfn-awsec2networkinterface-sourcedestcheck", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkinterface.html#cfn-ec2-networkinterface-sourcedestcheck", "PrimitiveType": "Boolean", "Required": false, "UpdateType": "Mutable" }, "SubnetId": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html#cfn-awsec2networkinterface-subnetid", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkinterface.html#cfn-ec2-networkinterface-subnetid", "PrimitiveType": "String", "Required": true, "UpdateType": "Immutable" }, "Tags": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-network-interface.html#cfn-awsec2networkinterface-tags", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-networkinterface.html#cfn-ec2-networkinterface-tags", "DuplicatesAllowed": true, "ItemType": "Tag", "Required": false, @@ -76633,10 +79641,15 @@ } }, "AWS::EC2::RouteTable": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-route-table.html", + "Attributes": { + "RouteTableId": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-routetable.html", "Properties": { "Tags": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-route-table.html#cfn-ec2-routetable-tags", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-routetable.html#cfn-ec2-routetable-tags", "DuplicatesAllowed": true, "ItemType": "Tag", "Required": false, @@ -76644,7 +79657,7 @@ "UpdateType": "Mutable" }, "VpcId": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-route-table.html#cfn-ec2-routetable-vpcid", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-routetable.html#cfn-ec2-routetable-vpcid", "PrimitiveType": "String", "Required": true, "UpdateType": "Immutable" @@ -77499,6 +80512,12 @@ }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewaypeeringattachment.html", "Properties": { + "Options": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewaypeeringattachment.html#cfn-ec2-transitgatewaypeeringattachment-options", + "Required": false, + "Type": "TransitGatewayPeeringAttachmentOptions", + "UpdateType": "Mutable" + }, "PeerAccountId": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewaypeeringattachment.html#cfn-ec2-transitgatewaypeeringattachment-peeraccountid", "PrimitiveType": "String", @@ -77905,6 +80924,12 @@ "Required": false, "Type": "List", "UpdateType": "Mutable" + }, + "PayerResponsibility": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-vpcendpointservice.html#cfn-ec2-vpcendpointservice-payerresponsibility", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" } } }, @@ -78693,6 +81718,12 @@ "Type": "List", "UpdateType": "Immutable" }, + "RuntimePlatform": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-taskdefinition.html#cfn-ecs-taskdefinition-runtimeplatform", + "Required": false, + "Type": "RuntimePlatform", + "UpdateType": "Immutable" + }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-taskdefinition.html#cfn-ecs-taskdefinition-tags", "ItemType": "Tag", @@ -79039,6 +82070,12 @@ "Type": "KubernetesNetworkConfig", "UpdateType": "Immutable" }, + "Logging": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-cluster.html#cfn-eks-cluster-logging", + "Required": false, + "Type": "Logging", + "UpdateType": "Mutable" + }, "Name": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-cluster.html#cfn-eks-cluster-name", "PrimitiveType": "String", @@ -79049,7 +82086,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-cluster.html#cfn-eks-cluster-resourcesvpcconfig", "Required": true, "Type": "ResourcesVpcConfig", - "UpdateType": "Immutable" + "UpdateType": "Mutable" }, "RoleArn": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-cluster.html#cfn-eks-cluster-rolearn", @@ -79057,6 +82094,14 @@ "Required": true, "UpdateType": "Immutable" }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-cluster.html#cfn-eks-cluster-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, "Version": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-cluster.html#cfn-eks-cluster-version", "PrimitiveType": "String", @@ -81713,6 +84758,12 @@ "Type": "List", "UpdateType": "Mutable" }, + "ResourcesCleanUp": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fms-policy.html#cfn-fms-policy-resourcescleanup", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, "SecurityServicePolicyData": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fms-policy.html#cfn-fms-policy-securityservicepolicydata", "PrimitiveType": "Json", @@ -83325,7 +86376,7 @@ "ItemType": "Tag", "Required": false, "Type": "List", - "UpdateType": "Immutable" + "UpdateType": "Mutable" } } }, @@ -83387,7 +86438,7 @@ "ItemType": "Tag", "Required": false, "Type": "List", - "UpdateType": "Immutable" + "UpdateType": "Mutable" } } }, @@ -85586,6 +88637,12 @@ "Required": false, "UpdateType": "Mutable" }, + "InstanceMetadataOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-infrastructureconfiguration.html#cfn-imagebuilder-infrastructureconfiguration-instancemetadataoptions", + "Required": false, + "Type": "InstanceMetadataOptions", + "UpdateType": "Mutable" + }, "InstanceProfileName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-infrastructureconfiguration.html#cfn-imagebuilder-infrastructureconfiguration-instanceprofilename", "PrimitiveType": "String", @@ -86183,6 +89240,101 @@ } } }, + "AWS::IoT::JobTemplate": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-jobtemplate.html", + "Properties": { + "AbortConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-jobtemplate.html#cfn-iot-jobtemplate-abortconfig", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Immutable" + }, + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-jobtemplate.html#cfn-iot-jobtemplate-description", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Document": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-jobtemplate.html#cfn-iot-jobtemplate-document", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "DocumentSource": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-jobtemplate.html#cfn-iot-jobtemplate-documentsource", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "JobArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-jobtemplate.html#cfn-iot-jobtemplate-jobarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "JobExecutionsRolloutConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-jobtemplate.html#cfn-iot-jobtemplate-jobexecutionsrolloutconfig", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Immutable" + }, + "JobTemplateId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-jobtemplate.html#cfn-iot-jobtemplate-jobtemplateid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "PresignedUrlConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-jobtemplate.html#cfn-iot-jobtemplate-presignedurlconfig", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-jobtemplate.html#cfn-iot-jobtemplate-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "TimeoutConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-jobtemplate.html#cfn-iot-jobtemplate-timeoutconfig", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::IoT::Logging": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-logging.html", + "Properties": { + "AccountId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-logging.html#cfn-iot-logging-accountid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "DefaultLogLevel": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-logging.html#cfn-iot-logging-defaultloglevel", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-logging.html#cfn-iot-logging-rolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::IoT::MitigationAction": { "Attributes": { "MitigationActionArn": { @@ -86314,6 +89466,34 @@ } } }, + "AWS::IoT::ResourceSpecificLogging": { + "Attributes": { + "TargetId": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-resourcespecificlogging.html", + "Properties": { + "LogLevel": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-resourcespecificlogging.html#cfn-iot-resourcespecificlogging-loglevel", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "TargetName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-resourcespecificlogging.html#cfn-iot-resourcespecificlogging-targetname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "TargetType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iot-resourcespecificlogging.html#cfn-iot-resourcespecificlogging-targettype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, "AWS::IoT::ScheduledAudit": { "Attributes": { "ScheduledAuditArn": { @@ -86520,12 +89700,17 @@ } }, "AWS::IoTAnalytics::Channel": { + "Attributes": { + "Id": { + "PrimitiveType": "String" + } + }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotanalytics-channel.html", "Properties": { "ChannelName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotanalytics-channel.html#cfn-iotanalytics-channel-channelname", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Immutable" }, "ChannelStorage": { @@ -86542,6 +89727,7 @@ }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotanalytics-channel.html#cfn-iotanalytics-channel-tags", + "DuplicatesAllowed": true, "ItemType": "Tag", "Required": false, "Type": "List", @@ -86550,10 +89736,16 @@ } }, "AWS::IoTAnalytics::Dataset": { + "Attributes": { + "Id": { + "PrimitiveType": "String" + } + }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotanalytics-dataset.html", "Properties": { "Actions": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotanalytics-dataset.html#cfn-iotanalytics-dataset-actions", + "DuplicatesAllowed": true, "ItemType": "Action", "Required": true, "Type": "List", @@ -86561,6 +89753,7 @@ }, "ContentDeliveryRules": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotanalytics-dataset.html#cfn-iotanalytics-dataset-contentdeliveryrules", + "DuplicatesAllowed": true, "ItemType": "DatasetContentDeliveryRule", "Required": false, "Type": "List", @@ -86569,11 +89762,12 @@ "DatasetName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotanalytics-dataset.html#cfn-iotanalytics-dataset-datasetname", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Immutable" }, "LateDataRules": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotanalytics-dataset.html#cfn-iotanalytics-dataset-latedatarules", + "DuplicatesAllowed": true, "ItemType": "LateDataRule", "Required": false, "Type": "List", @@ -86587,6 +89781,7 @@ }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotanalytics-dataset.html#cfn-iotanalytics-dataset-tags", + "DuplicatesAllowed": true, "ItemType": "Tag", "Required": false, "Type": "List", @@ -86594,6 +89789,7 @@ }, "Triggers": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotanalytics-dataset.html#cfn-iotanalytics-dataset-triggers", + "DuplicatesAllowed": true, "ItemType": "Trigger", "Required": false, "Type": "List", @@ -86608,6 +89804,11 @@ } }, "AWS::IoTAnalytics::Datastore": { + "Attributes": { + "Id": { + "PrimitiveType": "String" + } + }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotanalytics-datastore.html", "Properties": { "DatastoreName": { @@ -86642,6 +89843,7 @@ }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotanalytics-datastore.html#cfn-iotanalytics-datastore-tags", + "DuplicatesAllowed": true, "ItemType": "Tag", "Required": false, "Type": "List", @@ -86650,10 +89852,16 @@ } }, "AWS::IoTAnalytics::Pipeline": { + "Attributes": { + "Id": { + "PrimitiveType": "String" + } + }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotanalytics-pipeline.html", "Properties": { "PipelineActivities": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotanalytics-pipeline.html#cfn-iotanalytics-pipeline-pipelineactivities", + "DuplicatesAllowed": true, "ItemType": "Activity", "Required": true, "Type": "List", @@ -86662,11 +89870,12 @@ "PipelineName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotanalytics-pipeline.html#cfn-iotanalytics-pipeline-pipelinename", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Immutable" }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotanalytics-pipeline.html#cfn-iotanalytics-pipeline-tags", + "DuplicatesAllowed": true, "ItemType": "Tag", "Required": false, "Type": "List", @@ -88957,6 +92166,110 @@ } } }, + "AWS::Lightsail::Database": { + "Attributes": { + "DatabaseArn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-database.html", + "Properties": { + "AvailabilityZone": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-database.html#cfn-lightsail-database-availabilityzone", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "BackupRetention": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-database.html#cfn-lightsail-database-backupretention", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "CaCertificateIdentifier": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-database.html#cfn-lightsail-database-cacertificateidentifier", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "MasterDatabaseName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-database.html#cfn-lightsail-database-masterdatabasename", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "MasterUserPassword": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-database.html#cfn-lightsail-database-masteruserpassword", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "MasterUsername": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-database.html#cfn-lightsail-database-masterusername", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "PreferredBackupWindow": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-database.html#cfn-lightsail-database-preferredbackupwindow", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "PreferredMaintenanceWindow": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-database.html#cfn-lightsail-database-preferredmaintenancewindow", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "PubliclyAccessible": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-database.html#cfn-lightsail-database-publiclyaccessible", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "RelationalDatabaseBlueprintId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-database.html#cfn-lightsail-database-relationaldatabaseblueprintid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "RelationalDatabaseBundleId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-database.html#cfn-lightsail-database-relationaldatabasebundleid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "RelationalDatabaseName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-database.html#cfn-lightsail-database-relationaldatabasename", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "RelationalDatabaseParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-database.html#cfn-lightsail-database-relationaldatabaseparameters", + "DuplicatesAllowed": false, + "ItemType": "RelationalDatabaseParameter", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "RotateMasterUserPassword": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-database.html#cfn-lightsail-database-rotatemasteruserpassword", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-database.html#cfn-lightsail-database-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::Lightsail::Disk": { "Attributes": { "AttachedTo": { @@ -89038,9 +92351,6 @@ "IsStaticIp": { "PrimitiveType": "Boolean" }, - "KeyPairName": { - "PrimitiveType": "String" - }, "Location.AvailabilityZone": { "PrimitiveType": "String" }, @@ -89071,9 +92381,6 @@ "SupportCode": { "PrimitiveType": "String" }, - "UserData": { - "PrimitiveType": "String" - }, "UserName": { "PrimitiveType": "String" } @@ -89117,6 +92424,12 @@ "Required": true, "UpdateType": "Immutable" }, + "KeyPairName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-instance.html#cfn-lightsail-instance-keypairname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "Location": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-instance.html#cfn-lightsail-instance-location", "Required": false, @@ -89142,6 +92455,40 @@ "Required": false, "Type": "List", "UpdateType": "Mutable" + }, + "UserData": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-instance.html#cfn-lightsail-instance-userdata", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Lightsail::StaticIp": { + "Attributes": { + "IpAddress": { + "PrimitiveType": "String" + }, + "IsAttached": { + "PrimitiveType": "Boolean" + }, + "StaticIpArn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-staticip.html", + "Properties": { + "AttachedTo": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-staticip.html#cfn-lightsail-staticip-attachedto", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "StaticIpName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-staticip.html#cfn-lightsail-staticip-staticipname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" } } }, @@ -89361,6 +92708,12 @@ "Required": false, "UpdateType": "Immutable" }, + "PositionFiltering": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-location-tracker.html#cfn-location-tracker-positionfiltering", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, "PricingPlan": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-location-tracker.html#cfn-location-tracker-pricingplan", "PrimitiveType": "String", @@ -89941,8 +93294,8 @@ }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-mwaa-environment.html#cfn-mwaa-environment-tags", + "PrimitiveType": "Json", "Required": false, - "Type": "TagMap", "UpdateType": "Mutable" }, "WebserverAccessMode": { @@ -91230,7 +94583,7 @@ "ACLName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-aclname", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "AutoMinorVersionUpgrade": { @@ -91284,7 +94637,7 @@ "NodeType": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-nodetype", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Mutable" }, "NumReplicasPerShard": { @@ -91396,7 +94749,7 @@ "Family": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-parametergroup.html#cfn-memorydb-parametergroup-family", "PrimitiveType": "String", - "Required": false, + "Required": true, "UpdateType": "Immutable" }, "ParameterGroupName": { @@ -91445,7 +94798,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-subnetgroup.html#cfn-memorydb-subnetgroup-subnetids", "DuplicatesAllowed": false, "PrimitiveItemType": "String", - "Required": false, + "Required": true, "Type": "List", "UpdateType": "Mutable" }, @@ -93403,6 +96756,190 @@ } } }, + "AWS::Panorama::ApplicationInstance": { + "Attributes": { + "ApplicationInstanceId": { + "PrimitiveType": "String" + }, + "Arn": { + "PrimitiveType": "String" + }, + "CreatedTime": { + "PrimitiveType": "Integer" + }, + "DefaultRuntimeContextDeviceName": { + "PrimitiveType": "String" + }, + "HealthStatus": { + "PrimitiveType": "String" + }, + "LastUpdatedTime": { + "PrimitiveType": "Integer" + }, + "Status": { + "PrimitiveType": "String" + }, + "StatusDescription": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-panorama-applicationinstance.html", + "Properties": { + "ApplicationInstanceIdToReplace": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-panorama-applicationinstance.html#cfn-panorama-applicationinstance-applicationinstanceidtoreplace", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "DefaultRuntimeContextDevice": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-panorama-applicationinstance.html#cfn-panorama-applicationinstance-defaultruntimecontextdevice", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-panorama-applicationinstance.html#cfn-panorama-applicationinstance-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "DeviceId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-panorama-applicationinstance.html#cfn-panorama-applicationinstance-deviceid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ManifestOverridesPayload": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-panorama-applicationinstance.html#cfn-panorama-applicationinstance-manifestoverridespayload", + "Required": false, + "Type": "ManifestOverridesPayload", + "UpdateType": "Immutable" + }, + "ManifestPayload": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-panorama-applicationinstance.html#cfn-panorama-applicationinstance-manifestpayload", + "Required": true, + "Type": "ManifestPayload", + "UpdateType": "Immutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-panorama-applicationinstance.html#cfn-panorama-applicationinstance-name", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "RuntimeRoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-panorama-applicationinstance.html#cfn-panorama-applicationinstance-runtimerolearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "StatusFilter": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-panorama-applicationinstance.html#cfn-panorama-applicationinstance-statusfilter", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-panorama-applicationinstance.html#cfn-panorama-applicationinstance-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Panorama::Package": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "CreatedTime": { + "PrimitiveType": "Integer" + }, + "PackageId": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-panorama-package.html", + "Properties": { + "PackageName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-panorama-package.html#cfn-panorama-package-packagename", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-panorama-package.html#cfn-panorama-package-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Panorama::PackageVersion": { + "Attributes": { + "IsLatestPatch": { + "PrimitiveType": "Boolean" + }, + "PackageArn": { + "PrimitiveType": "String" + }, + "PackageName": { + "PrimitiveType": "String" + }, + "RegisteredTime": { + "PrimitiveType": "Integer" + }, + "Status": { + "PrimitiveType": "String" + }, + "StatusDescription": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-panorama-packageversion.html", + "Properties": { + "MarkLatest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-panorama-packageversion.html#cfn-panorama-packageversion-marklatest", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "OwnerAccount": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-panorama-packageversion.html#cfn-panorama-packageversion-owneraccount", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "PackageId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-panorama-packageversion.html#cfn-panorama-packageversion-packageid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "PackageVersion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-panorama-packageversion.html#cfn-panorama-packageversion-packageversion", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "PatchVersion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-panorama-packageversion.html#cfn-panorama-packageversion-patchversion", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "UpdatedLatestPatchVersion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-panorama-packageversion.html#cfn-panorama-packageversion-updatedlatestpatchversion", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::Pinpoint::ADMChannel": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-pinpoint-admchannel.html", "Properties": { @@ -93820,6 +97357,12 @@ "Required": true, "UpdateType": "Mutable" }, + "Priority": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-pinpoint-campaign.html#cfn-pinpoint-campaign-priority", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, "Schedule": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-pinpoint-campaign.html#cfn-pinpoint-campaign-schedule", "Required": true, @@ -93997,6 +97540,53 @@ } } }, + "AWS::Pinpoint::InAppTemplate": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-pinpoint-inapptemplate.html", + "Properties": { + "Content": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-pinpoint-inapptemplate.html#cfn-pinpoint-inapptemplate-content", + "ItemType": "InAppMessageContent", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "CustomConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-pinpoint-inapptemplate.html#cfn-pinpoint-inapptemplate-customconfig", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Mutable" + }, + "Layout": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-pinpoint-inapptemplate.html#cfn-pinpoint-inapptemplate-layout", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-pinpoint-inapptemplate.html#cfn-pinpoint-inapptemplate-tags", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Mutable" + }, + "TemplateDescription": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-pinpoint-inapptemplate.html#cfn-pinpoint-inapptemplate-templatedescription", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "TemplateName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-pinpoint-inapptemplate.html#cfn-pinpoint-inapptemplate-templatename", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, "AWS::Pinpoint::PushTemplate": { "Attributes": { "Arn": { @@ -94487,7 +98077,7 @@ }, "SourceEntity": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-analysis.html#cfn-quicksight-analysis-sourceentity", - "Required": false, + "Required": true, "Type": "AnalysisSourceEntity", "UpdateType": "Mutable" }, @@ -94562,7 +98152,7 @@ }, "SourceEntity": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-dashboard.html#cfn-quicksight-dashboard-sourceentity", - "Required": false, + "Required": true, "Type": "DashboardSourceEntity", "UpdateType": "Mutable" }, @@ -94824,7 +98414,7 @@ }, "SourceEntity": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-quicksight-template.html#cfn-quicksight-template-sourceentity", - "Required": false, + "Required": true, "Type": "TemplateSourceEntity", "UpdateType": "Mutable" }, @@ -96416,6 +100006,273 @@ } } }, + "AWS::Redshift::EndpointAccess": { + "Attributes": { + "Address": { + "PrimitiveType": "String" + }, + "EndpointCreateTime": { + "PrimitiveType": "String" + }, + "EndpointStatus": { + "PrimitiveType": "String" + }, + "Port": { + "PrimitiveType": "Integer" + }, + "VpcSecurityGroups": { + "ItemType": "VpcSecurityGroup", + "Type": "List" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-endpointaccess.html", + "Properties": { + "ClusterIdentifier": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-endpointaccess.html#cfn-redshift-endpointaccess-clusteridentifier", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "EndpointName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-endpointaccess.html#cfn-redshift-endpointaccess-endpointname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "ResourceOwner": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-endpointaccess.html#cfn-redshift-endpointaccess-resourceowner", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "SubnetGroupName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-endpointaccess.html#cfn-redshift-endpointaccess-subnetgroupname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "VpcSecurityGroupIds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-endpointaccess.html#cfn-redshift-endpointaccess-vpcsecuritygroupids", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Redshift::EndpointAuthorization": { + "Attributes": { + "AllowedAllVPCs": { + "PrimitiveType": "Boolean" + }, + "AllowedVPCs": { + "PrimitiveItemType": "String", + "Type": "List" + }, + "AuthorizeTime": { + "PrimitiveType": "String" + }, + "ClusterStatus": { + "PrimitiveType": "String" + }, + "EndpointCount": { + "PrimitiveType": "Integer" + }, + "Grantee": { + "PrimitiveType": "String" + }, + "Grantor": { + "PrimitiveType": "String" + }, + "Status": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-endpointauthorization.html", + "Properties": { + "Account": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-endpointauthorization.html#cfn-redshift-endpointauthorization-account", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "ClusterIdentifier": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-endpointauthorization.html#cfn-redshift-endpointauthorization-clusteridentifier", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Force": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-endpointauthorization.html#cfn-redshift-endpointauthorization-force", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "VpcIds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-endpointauthorization.html#cfn-redshift-endpointauthorization-vpcids", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Redshift::EventSubscription": { + "Attributes": { + "CustSubscriptionId": { + "PrimitiveType": "String" + }, + "CustomerAwsId": { + "PrimitiveType": "String" + }, + "EventCategoriesList": { + "PrimitiveItemType": "String", + "Type": "List" + }, + "SourceIdsList": { + "PrimitiveItemType": "String", + "Type": "List" + }, + "Status": { + "PrimitiveType": "String" + }, + "SubscriptionCreationTime": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-eventsubscription.html", + "Properties": { + "Enabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-eventsubscription.html#cfn-redshift-eventsubscription-enabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "EventCategories": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-eventsubscription.html#cfn-redshift-eventsubscription-eventcategories", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Severity": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-eventsubscription.html#cfn-redshift-eventsubscription-severity", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SnsTopicArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-eventsubscription.html#cfn-redshift-eventsubscription-snstopicarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SourceIds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-eventsubscription.html#cfn-redshift-eventsubscription-sourceids", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "SourceType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-eventsubscription.html#cfn-redshift-eventsubscription-sourcetype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SubscriptionName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-eventsubscription.html#cfn-redshift-eventsubscription-subscriptionname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-eventsubscription.html#cfn-redshift-eventsubscription-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Redshift::ScheduledAction": { + "Attributes": { + "NextInvocations": { + "PrimitiveItemType": "String", + "Type": "List" + }, + "State": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-scheduledaction.html", + "Properties": { + "Enable": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-scheduledaction.html#cfn-redshift-scheduledaction-enable", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "EndTime": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-scheduledaction.html#cfn-redshift-scheduledaction-endtime", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "IamRole": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-scheduledaction.html#cfn-redshift-scheduledaction-iamrole", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Schedule": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-scheduledaction.html#cfn-redshift-scheduledaction-schedule", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ScheduledActionDescription": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-scheduledaction.html#cfn-redshift-scheduledaction-scheduledactiondescription", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ScheduledActionName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-scheduledaction.html#cfn-redshift-scheduledaction-scheduledactionname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "StartTime": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-scheduledaction.html#cfn-redshift-scheduledaction-starttime", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "TargetAction": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshift-scheduledaction.html#cfn-redshift-scheduledaction-targetaction", + "Required": false, + "Type": "ScheduledActionType", + "UpdateType": "Mutable" + } + } + }, + "AWS::Rekognition::Project": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-rekognition-project.html", + "Properties": { + "ProjectName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-rekognition-project.html#cfn-rekognition-project-projectname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, "AWS::ResourceGroups::Group": { "Attributes": { "Arn": { @@ -96947,6 +100804,13 @@ "PrimitiveType": "String", "Required": false, "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53recoverycontrol-cluster.html#cfn-route53recoverycontrol-cluster-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" } } }, @@ -96978,6 +100842,13 @@ "PrimitiveType": "String", "Required": true, "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53recoverycontrol-controlpanel.html#cfn-route53recoverycontrol-controlpanel-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" } } }, @@ -97052,6 +100923,13 @@ "Required": true, "Type": "RuleConfig", "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53recoverycontrol-safetyrule.html#cfn-route53recoverycontrol-safetyrule-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" } } }, @@ -97374,6 +101252,34 @@ } } }, + "AWS::Route53Resolver::ResolverConfig": { + "Attributes": { + "AutodefinedReverse": { + "PrimitiveType": "String" + }, + "Id": { + "PrimitiveType": "String" + }, + "OwnerId": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-resolverconfig.html", + "Properties": { + "AutodefinedReverseFlag": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-resolverconfig.html#cfn-route53resolver-resolverconfig-autodefinedreverseflag", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "ResourceId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-resolverconfig.html#cfn-route53resolver-resolverconfig-resourceid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, "AWS::Route53Resolver::ResolverDNSSECConfig": { "Attributes": { "Id": { @@ -97549,7 +101455,9 @@ "PrimitiveType": "String" }, "TargetIps": { - "PrimitiveType": "String" + "DuplicatesAllowed": true, + "ItemType": "TargetAddress", + "Type": "List" } }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-resolverrule.html", @@ -97580,6 +101488,7 @@ }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-resolverrule.html#cfn-route53resolver-resolverrule-tags", + "DuplicatesAllowed": true, "ItemType": "Tag", "Required": false, "Type": "List", @@ -97587,6 +101496,7 @@ }, "TargetIps": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53resolver-resolverrule.html#cfn-route53resolver-resolverrule-targetips", + "DuplicatesAllowed": true, "ItemType": "TargetAddress", "Required": false, "Type": "List", @@ -97943,7 +101853,7 @@ "Name": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-s3objectlambda-accesspoint.html#cfn-s3objectlambda-accesspoint-name", "PrimitiveType": "String", - "Required": true, + "Required": false, "UpdateType": "Immutable" }, "ObjectLambdaConfiguration": { @@ -99729,6 +103639,12 @@ "Required": false, "UpdateType": "Mutable" }, + "RetainDeploymentConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-endpoint.html#cfn-sagemaker-endpoint-retaindeploymentconfig", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-endpoint.html#cfn-sagemaker-endpoint-tags", "ItemType": "Tag", @@ -100361,6 +104277,12 @@ "Required": false, "UpdateType": "Immutable" }, + "PlatformIdentifier": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-notebookinstance.html#cfn-sagemaker-notebookinstance-platformidentifier", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, "RoleArn": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-notebookinstance.html#cfn-sagemaker-notebookinstance-rolearn", "PrimitiveType": "String", @@ -101785,6 +105707,9 @@ }, "AWS::StepFunctions::Activity": { "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, "Name": { "PrimitiveType": "String" } @@ -101799,6 +105724,7 @@ }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-activity.html#cfn-stepfunctions-activity-tags", + "DuplicatesAllowed": true, "ItemType": "TagsEntry", "Required": false, "Type": "List", @@ -101893,6 +105819,12 @@ }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-synthetics-canary.html", "Properties": { + "ArtifactConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-synthetics-canary.html#cfn-synthetics-canary-artifactconfig", + "Required": false, + "Type": "ArtifactConfig", + "UpdateType": "Mutable" + }, "ArtifactS3Location": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-synthetics-canary.html#cfn-synthetics-canary-artifacts3location", "PrimitiveType": "String", @@ -102886,6 +106818,150 @@ } } }, + "AWS::Wisdom::Assistant": { + "Attributes": { + "AssistantArn": { + "PrimitiveType": "String" + }, + "AssistantId": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wisdom-assistant.html", + "Properties": { + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wisdom-assistant.html#cfn-wisdom-assistant-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wisdom-assistant.html#cfn-wisdom-assistant-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "ServerSideEncryptionConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wisdom-assistant.html#cfn-wisdom-assistant-serversideencryptionconfiguration", + "Required": false, + "Type": "ServerSideEncryptionConfiguration", + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wisdom-assistant.html#cfn-wisdom-assistant-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wisdom-assistant.html#cfn-wisdom-assistant-type", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, + "AWS::Wisdom::AssistantAssociation": { + "Attributes": { + "AssistantArn": { + "PrimitiveType": "String" + }, + "AssistantAssociationArn": { + "PrimitiveType": "String" + }, + "AssistantAssociationId": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wisdom-assistantassociation.html", + "Properties": { + "AssistantId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wisdom-assistantassociation.html#cfn-wisdom-assistantassociation-assistantid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Association": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wisdom-assistantassociation.html#cfn-wisdom-assistantassociation-association", + "Required": true, + "Type": "AssociationData", + "UpdateType": "Immutable" + }, + "AssociationType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wisdom-assistantassociation.html#cfn-wisdom-assistantassociation-associationtype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wisdom-assistantassociation.html#cfn-wisdom-assistantassociation-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + } + } + }, + "AWS::Wisdom::KnowledgeBase": { + "Attributes": { + "KnowledgeBaseArn": { + "PrimitiveType": "String" + }, + "KnowledgeBaseId": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wisdom-knowledgebase.html", + "Properties": { + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wisdom-knowledgebase.html#cfn-wisdom-knowledgebase-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "KnowledgeBaseType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wisdom-knowledgebase.html#cfn-wisdom-knowledgebase-knowledgebasetype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wisdom-knowledgebase.html#cfn-wisdom-knowledgebase-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "RenderingConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wisdom-knowledgebase.html#cfn-wisdom-knowledgebase-renderingconfiguration", + "Required": false, + "Type": "RenderingConfiguration", + "UpdateType": "Mutable" + }, + "ServerSideEncryptionConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wisdom-knowledgebase.html#cfn-wisdom-knowledgebase-serversideencryptionconfiguration", + "Required": false, + "Type": "ServerSideEncryptionConfiguration", + "UpdateType": "Immutable" + }, + "SourceConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wisdom-knowledgebase.html#cfn-wisdom-knowledgebase-sourceconfiguration", + "Required": false, + "Type": "SourceConfiguration", + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-wisdom-knowledgebase.html#cfn-wisdom-knowledgebase-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + } + } + }, "AWS::WorkSpaces::ConnectionAlias": { "Attributes": { "AliasId": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/cfn-lint/StatefulResources/000.json b/packages/@aws-cdk/cfnspec/spec-source/cfn-lint/StatefulResources/000.json index 7037f14238497..dbfa3dfcdd033 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/cfn-lint/StatefulResources/000.json +++ b/packages/@aws-cdk/cfnspec/spec-source/cfn-lint/StatefulResources/000.json @@ -25,6 +25,7 @@ "AWS::SQS::Queue" : {}, "AWS::S3::Bucket" : { "DeleteRequiresEmptyResource": true - } + }, + "AWS::SecretsManager::Secret" : {} } } diff --git a/packages/@aws-cdk/cloud-assembly-schema/package.json b/packages/@aws-cdk/cloud-assembly-schema/package.json index 11226b0f1521a..06499db17d01e 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/package.json +++ b/packages/@aws-cdk/cloud-assembly-schema/package.json @@ -64,7 +64,7 @@ "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "@types/mock-fs": "^4.13.1", - "@types/semver": "^7.3.8", + "@types/semver": "^7.3.9", "jest": "^26.6.3", "mock-fs": "^4.14.0", "typescript-json-schema": "^0.51.0" diff --git a/packages/@aws-cdk/cloudformation-diff/package.json b/packages/@aws-cdk/cloudformation-diff/package.json index 3a3ad220ff70f..d101afe2b69d2 100644 --- a/packages/@aws-cdk/cloudformation-diff/package.json +++ b/packages/@aws-cdk/cloudformation-diff/package.json @@ -36,7 +36,7 @@ "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "@types/string-width": "^4.0.1", - "fast-check": "^2.18.0", + "fast-check": "^2.19.0", "jest": "^26.6.3", "ts-jest": "^26.5.6" }, diff --git a/packages/@aws-cdk/cloudformation-include/package.json b/packages/@aws-cdk/cloudformation-include/package.json index 28e63ecaed94c..c78117ba94df0 100644 --- a/packages/@aws-cdk/cloudformation-include/package.json +++ b/packages/@aws-cdk/cloudformation-include/package.json @@ -195,6 +195,7 @@ "@aws-cdk/aws-opensearchservice": "0.0.0", "@aws-cdk/aws-opsworks": "0.0.0", "@aws-cdk/aws-opsworkscm": "0.0.0", + "@aws-cdk/aws-panorama": "0.0.0", "@aws-cdk/aws-pinpoint": "0.0.0", "@aws-cdk/aws-pinpointemail": "0.0.0", "@aws-cdk/aws-qldb": "0.0.0", @@ -202,6 +203,7 @@ "@aws-cdk/aws-ram": "0.0.0", "@aws-cdk/aws-rds": "0.0.0", "@aws-cdk/aws-redshift": "0.0.0", + "@aws-cdk/aws-rekognition": "0.0.0", "@aws-cdk/aws-resourcegroups": "0.0.0", "@aws-cdk/aws-robomaker": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", @@ -234,6 +236,7 @@ "@aws-cdk/aws-waf": "0.0.0", "@aws-cdk/aws-wafregional": "0.0.0", "@aws-cdk/aws-wafv2": "0.0.0", + "@aws-cdk/aws-wisdom": "0.0.0", "@aws-cdk/aws-workspaces": "0.0.0", "@aws-cdk/aws-xray": "0.0.0", "@aws-cdk/core": "0.0.0", @@ -370,6 +373,7 @@ "@aws-cdk/aws-opensearchservice": "0.0.0", "@aws-cdk/aws-opsworks": "0.0.0", "@aws-cdk/aws-opsworkscm": "0.0.0", + "@aws-cdk/aws-panorama": "0.0.0", "@aws-cdk/aws-pinpoint": "0.0.0", "@aws-cdk/aws-pinpointemail": "0.0.0", "@aws-cdk/aws-qldb": "0.0.0", @@ -377,6 +381,7 @@ "@aws-cdk/aws-ram": "0.0.0", "@aws-cdk/aws-rds": "0.0.0", "@aws-cdk/aws-redshift": "0.0.0", + "@aws-cdk/aws-rekognition": "0.0.0", "@aws-cdk/aws-resourcegroups": "0.0.0", "@aws-cdk/aws-robomaker": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", @@ -409,6 +414,7 @@ "@aws-cdk/aws-waf": "0.0.0", "@aws-cdk/aws-wafregional": "0.0.0", "@aws-cdk/aws-wafv2": "0.0.0", + "@aws-cdk/aws-wisdom": "0.0.0", "@aws-cdk/aws-workspaces": "0.0.0", "@aws-cdk/aws-xray": "0.0.0", "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/core/package.json b/packages/@aws-cdk/core/package.json index f7cd653ca7e7f..a57f69397dba1 100644 --- a/packages/@aws-cdk/core/package.json +++ b/packages/@aws-cdk/core/package.json @@ -171,14 +171,14 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.84", + "@types/aws-lambda": "^8.10.85", "@types/fs-extra": "^8.1.2", "@types/jest": "^26.0.24", - "@types/lodash": "^4.14.175", + "@types/lodash": "^4.14.176", "@types/minimatch": "^3.0.5", "@types/node": "^10.17.60", "@types/sinon": "^9.0.11", - "fast-check": "^2.18.0", + "fast-check": "^2.19.0", "jest": "^26.6.3", "lodash": "^4.17.21", "sinon": "^9.2.4", @@ -191,7 +191,7 @@ "@balena/dockerignore": "^1.0.2", "constructs": "^3.3.69", "fs-extra": "^9.1.0", - "ignore": "^5.1.8", + "ignore": "^5.1.9", "minimatch": "^3.0.4" }, "bundledDependencies": [ diff --git a/packages/@aws-cdk/custom-resources/package.json b/packages/@aws-cdk/custom-resources/package.json index 698596d6ae0c0..f30e67b0a5838 100644 --- a/packages/@aws-cdk/custom-resources/package.json +++ b/packages/@aws-cdk/custom-resources/package.json @@ -80,14 +80,14 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/aws-lambda": "^8.10.84", + "@types/aws-lambda": "^8.10.85", "@types/fs-extra": "^8.1.2", "@types/jest": "^26.0.24", "@types/sinon": "^9.0.11", "aws-sdk": "^2.848.0", "aws-sdk-mock": "^5.4.0", "fs-extra": "^9.1.0", - "nock": "^13.1.3", + "nock": "^13.1.4", "sinon": "^9.2.4" }, "dependencies": { diff --git a/packages/@aws-cdk/cx-api/package.json b/packages/@aws-cdk/cx-api/package.json index 0a92e1c3492b6..6ed3341b1a082 100644 --- a/packages/@aws-cdk/cx-api/package.json +++ b/packages/@aws-cdk/cx-api/package.json @@ -70,7 +70,7 @@ "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "@types/mock-fs": "^4.13.1", - "@types/semver": "^7.3.8", + "@types/semver": "^7.3.9", "jest": "^26.6.3", "mock-fs": "^4.14.0" }, diff --git a/packages/@aws-cdk/example-construct-library/lib/example-resource.ts b/packages/@aws-cdk/example-construct-library/lib/example-resource.ts index 6c4630dab6ae4..3c514d01ba19c 100644 --- a/packages/@aws-cdk/example-construct-library/lib/example-resource.ts +++ b/packages/@aws-cdk/example-construct-library/lib/example-resource.ts @@ -137,7 +137,7 @@ export interface IExampleResource extends * The details of which metric methods you should have of course depends on the * resource that is being modeled. */ - metricCount(metricName: string, props?: cloudwatch.MetricOptions): cloudwatch.Metric; + metricCount(props?: cloudwatch.MetricOptions): cloudwatch.Metric; } /** @@ -212,12 +212,12 @@ abstract class ExampleResourceBase extends core.Resource implements IExampleReso } /** Implement the {@link IExampleResource.metricCount} method. */ - public metricCount(metricName: string, props?: cloudwatch.MetricOptions): cloudwatch.Metric { + public metricCount(props?: cloudwatch.MetricOptions): cloudwatch.Metric { return new cloudwatch.Metric({ // of course, you would put your resource-specific values here namespace: 'AWS/ExampleResource', + metricName: 'Count', dimensions: { ExampleResource: this.exampleResourceName }, - metricName, ...props, }).attachTo(this); } 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 db1e8d68d4830..cbfb43344ad25 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 @@ -6,9 +6,11 @@ import { Match, Template } from '@aws-cdk/assertions'; +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 core from '@aws-cdk/core'; + // Always import the module you're testing qualified - // don't import individual classes from it! // Importing it qualified tests whether everything that needs to be exported @@ -18,6 +20,12 @@ import * as er from '../lib'; /* We allow quotes in the object keys used for CloudFormation template assertions */ /* eslint-disable quote-props */ +const EXAMPLE_RESOURCE_NAME = { + 'Fn::Select': [1, { + 'Fn::Split': ['/', { 'Ref': 'ExampleResourceAC53F4AE' }], + }], +}; + describe('Example Resource', () => { let stack: core.Stack; @@ -111,6 +119,40 @@ describe('Example Resource', () => { }, }); }); + + test('onEvent adds an Event Rule', () => { + exampleResource.onEvent('MyEvent'); + + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { + EventPattern: { + detail: { + 'example-resource-name': [EXAMPLE_RESOURCE_NAME], + }, + }, + }); + }); + + test('metricCount returns a metric with correct dimensions', () => { + const countMetric = exampleResource.metricCount(); + + new cloudwatch.Alarm(stack, 'Alarm', { + metric: countMetric, + threshold: 10, + evaluationPeriods: 2, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::CloudWatch::Alarm', { + EvaluationPeriods: 2, + Dimensions: [ + { + Name: 'ExampleResource', + Value: EXAMPLE_RESOURCE_NAME, + }, + ], + MetricName: 'Count', + Namespace: 'AWS/ExampleResource', + }); + }); }); describe('created with a VPC', () => { @@ -146,6 +188,10 @@ describe('Example Resource', () => { 'my-example-resource-name'); }); + test('throws when accessing connections', () => { + expect(() => exampleResource.connections).toThrow(); + }); + test('has the same name as it was imported with', () => { expect(exampleResource.exampleResourceName).toEqual('my-example-resource-name'); }); diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/_codebuild-factory.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/_codebuild-factory.ts index fb523cf7d6818..7534aba9cb840 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/_codebuild-factory.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/_codebuild-factory.ts @@ -333,7 +333,7 @@ function generateInputArtifactLinkCommands(artifacts: ArtifactMap, inputs: FileS return inputs.map(input => { const fragments = []; - fragments.push(`[[ ! -d "${input.directory}" ]] || { echo 'additionalInputs: "${input.directory}" must not exist yet. If you want to merge multiple artifacts, use a "cp" command.'; exit 1; }`); + fragments.push(`[ ! -d "${input.directory}" ] || { echo 'additionalInputs: "${input.directory}" must not exist yet. If you want to merge multiple artifacts, use a "cp" command.'; exit 1; }`); const parentDirectory = path.dirname(input.directory); if (!['.', '..'].includes(parentDirectory)) { diff --git a/packages/@aws-cdk/pipelines/test/codepipeline/codebuild-step.test.ts b/packages/@aws-cdk/pipelines/test/codepipeline/codebuild-step.test.ts index 78f1e0f471655..166e6c9336dd1 100644 --- a/packages/@aws-cdk/pipelines/test/codepipeline/codebuild-step.test.ts +++ b/packages/@aws-cdk/pipelines/test/codepipeline/codebuild-step.test.ts @@ -34,7 +34,7 @@ test('additionalinputs creates the right commands', () => { phases: { install: { commands: [ - '[[ ! -d "some/deep/directory" ]] || { echo \'additionalInputs: "some/deep/directory" must not exist yet. If you want to merge multiple artifacts, use a "cp" command.\'; exit 1; } && mkdir -p -- "some/deep" && ln -s -- "$CODEBUILD_SRC_DIR_test2_test2_Source" "some/deep/directory"', + '[ ! -d "some/deep/directory" ] || { echo \'additionalInputs: "some/deep/directory" must not exist yet. If you want to merge multiple artifacts, use a "cp" command.\'; exit 1; } && mkdir -p -- "some/deep" && ln -s -- "$CODEBUILD_SRC_DIR_test2_test2_Source" "some/deep/directory"', ], }, }, diff --git a/packages/@aws-cdk/pipelines/test/compliance/synths.test.ts b/packages/@aws-cdk/pipelines/test/compliance/synths.test.ts index 4b5a072099469..03ee0686f1807 100644 --- a/packages/@aws-cdk/pipelines/test/compliance/synths.test.ts +++ b/packages/@aws-cdk/pipelines/test/compliance/synths.test.ts @@ -748,7 +748,7 @@ behavior('Pipeline action contains a hash that changes as the buildspec changes' behavior('Synth CodeBuild project role can be granted permissions', (suite) => { let bucket: s3.IBucket; beforeEach(() => { - bucket = s3.Bucket.fromBucketArn(pipelineStack, 'Bucket', 'arn:aws:s3:::ThisParticularBucket'); + bucket = s3.Bucket.fromBucketArn(pipelineStack, 'Bucket', 'arn:aws:s3:::this-particular-bucket'); }); @@ -787,7 +787,7 @@ behavior('Synth CodeBuild project role can be granted permissions', (suite) => { PolicyDocument: { Statement: Match.arrayWith([Match.objectLike({ Action: ['s3:GetObject*', 's3:GetBucket*', 's3:List*'], - Resource: ['arn:aws:s3:::ThisParticularBucket', 'arn:aws:s3:::ThisParticularBucket/*'], + Resource: ['arn:aws:s3:::this-particular-bucket', 'arn:aws:s3:::this-particular-bucket/*'], })]), }, }); @@ -947,8 +947,8 @@ behavior('Multiple input sources in side-by-side directories', (suite) => { phases: { install: { commands: [ - '[[ ! -d "../sibling" ]] || { echo \'additionalInputs: "../sibling" must not exist yet. If you want to merge multiple artifacts, use a "cp" command.\'; exit 1; } && ln -s -- "$CODEBUILD_SRC_DIR_foo_bar_Source" "../sibling"', - '[[ ! -d "sub" ]] || { echo \'additionalInputs: "sub" must not exist yet. If you want to merge multiple artifacts, use a "cp" command.\'; exit 1; } && ln -s -- "$CODEBUILD_SRC_DIR_Prebuild_Output" "sub"', + '[ ! -d "../sibling" ] || { echo \'additionalInputs: "../sibling" must not exist yet. If you want to merge multiple artifacts, use a "cp" command.\'; exit 1; } && ln -s -- "$CODEBUILD_SRC_DIR_foo_bar_Source" "../sibling"', + '[ ! -d "sub" ] || { echo \'additionalInputs: "sub" must not exist yet. If you want to merge multiple artifacts, use a "cp" command.\'; exit 1; } && ln -s -- "$CODEBUILD_SRC_DIR_Prebuild_Output" "sub"', ], }, build: { diff --git a/packages/@aws-cdk/pipelines/test/compliance/validations.test.ts b/packages/@aws-cdk/pipelines/test/compliance/validations.test.ts index 7a6a562a8707a..c61cd40474388 100644 --- a/packages/@aws-cdk/pipelines/test/compliance/validations.test.ts +++ b/packages/@aws-cdk/pipelines/test/compliance/validations.test.ts @@ -463,7 +463,7 @@ behavior('can add policy statements to shell script action', (suite) => { behavior('can grant permissions to shell script action', (suite) => { let bucket: s3.IBucket; beforeEach(() => { - bucket = s3.Bucket.fromBucketArn(pipelineStack, 'Bucket', 'arn:aws:s3:::ThisParticularBucket'); + bucket = s3.Bucket.fromBucketArn(pipelineStack, 'Bucket', 'arn:aws:s3:::this-particular-bucket'); }); suite.legacy(() => { @@ -505,7 +505,7 @@ behavior('can grant permissions to shell script action', (suite) => { PolicyDocument: { Statement: Match.arrayWith([Match.objectLike({ Action: ['s3:GetObject*', 's3:GetBucket*', 's3:List*'], - Resource: ['arn:aws:s3:::ThisParticularBucket', 'arn:aws:s3:::ThisParticularBucket/*'], + Resource: ['arn:aws:s3:::this-particular-bucket', 'arn:aws:s3:::this-particular-bucket/*'], })]), }, }); diff --git a/packages/@monocdk-experiment/rewrite-imports/package.json b/packages/@monocdk-experiment/rewrite-imports/package.json index 7f602376d551a..3142c44c79526 100644 --- a/packages/@monocdk-experiment/rewrite-imports/package.json +++ b/packages/@monocdk-experiment/rewrite-imports/package.json @@ -35,7 +35,7 @@ "typescript": "~3.9.10" }, "devDependencies": { - "@types/glob": "^7.1.4", + "@types/glob": "^7.2.0", "@types/jest": "^26.0.24", "@types/node": "^10.17.60", "@aws-cdk/cdk-build-tools": "0.0.0", diff --git a/packages/aws-cdk-lib/package.json b/packages/aws-cdk-lib/package.json index de4d8379cac35..3e8a5932ffcc1 100644 --- a/packages/aws-cdk-lib/package.json +++ b/packages/aws-cdk-lib/package.json @@ -114,7 +114,7 @@ "diff": "^5.0.0", "fast-deep-equal": "^3.1.3", "fs-extra": "^9.1.0", - "ignore": "^5.1.8", + "ignore": "^5.1.9", "jsonschema": "^1.4.0", "minimatch": "^3.0.4", "punycode": "^2.1.1", @@ -280,6 +280,7 @@ "@aws-cdk/aws-opensearchservice": "0.0.0", "@aws-cdk/aws-opsworks": "0.0.0", "@aws-cdk/aws-opsworkscm": "0.0.0", + "@aws-cdk/aws-panorama": "0.0.0", "@aws-cdk/aws-pinpoint": "0.0.0", "@aws-cdk/aws-pinpointemail": "0.0.0", "@aws-cdk/aws-qldb": "0.0.0", @@ -287,6 +288,7 @@ "@aws-cdk/aws-ram": "0.0.0", "@aws-cdk/aws-rds": "0.0.0", "@aws-cdk/aws-redshift": "0.0.0", + "@aws-cdk/aws-rekognition": "0.0.0", "@aws-cdk/aws-resourcegroups": "0.0.0", "@aws-cdk/aws-robomaker": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", @@ -327,6 +329,7 @@ "@aws-cdk/aws-waf": "0.0.0", "@aws-cdk/aws-wafregional": "0.0.0", "@aws-cdk/aws-wafv2": "0.0.0", + "@aws-cdk/aws-wisdom": "0.0.0", "@aws-cdk/aws-workspaces": "0.0.0", "@aws-cdk/aws-xray": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", diff --git a/packages/aws-cdk-migration/package.json b/packages/aws-cdk-migration/package.json index 1ce16c5670458..34a387cadab5f 100644 --- a/packages/aws-cdk-migration/package.json +++ b/packages/aws-cdk-migration/package.json @@ -38,7 +38,7 @@ "typescript": "~3.9.10" }, "devDependencies": { - "@types/glob": "^7.1.4", + "@types/glob": "^7.2.0", "@types/jest": "^26.0.24", "@types/node": "^10.17.60", "@aws-cdk/cdk-build-tools": "0.0.0", diff --git a/packages/aws-cdk/README.md b/packages/aws-cdk/README.md index e4566b7bbb690..1bd9e491e34e4 100644 --- a/packages/aws-cdk/README.md +++ b/packages/aws-cdk/README.md @@ -372,6 +372,69 @@ For this reason, only use it for development purposes. **⚠ Note #2**: This command is considered experimental, and might have breaking changes in the future. +### `cdk watch` + +The `watch` command is similar to `deploy`, +but instead of being a one-shot operation, +the command continuously monitors the files of the project, +and triggers a deployment whenever it detects any changes: + +```console +$ cdk watch DevelopmentStack +Detected change to 'lambda-code/index.js' (type: change). Triggering 'cdk deploy' +DevelopmentStack: deploying... + + ✅ DevelopmentStack + +^C +``` + +To end a `cdk watch` session, interrupt the process by pressing Ctrl+C. + +What files are observed is determined by the `"watch"` setting in your `cdk.json` file. +It has two sub-keys, `"include"` and `"exclude"`, each of which can be either a single string, or an array of strings. +Each entry is interpreted as a path relative to the location of the `cdk.json` file. +Globs, both `*` and `**`, are allowed to be used. +Example: + +```json +{ + "app": "mvn -e -q compile exec:java", + "watch": { + "include": "src/main/**", + "exclude": "target/*" + } +} +``` + +The default for `"include"` is `"**/*"` +(which means all files and directories in the root of the project), +and `"exclude"` is optional +(note that we always ignore files and directories starting with `.`, +the CDK output directory, and the `node_modules` directory), +so the minimal settings to enable `watch` are `"watch": {}`. + +If either your CDK code, or application code, needs a build step before being deployed, +`watch` works with the `"build"` key in the `cdk.json` file, +for example: + +```json +{ + "app": "mvn -e -q exec:java", + "build": "mvn package", + "watch": { + "include": "src/main/**", + "exclude": "target/*" + } +} +``` + +Note that `watch` by default uses hotswap deployments (see above for details) -- +to turn them off, pass the `--no-hotswap` option when invoking it. + +**Note**: This command is considered experimental, +and might have breaking changes in the future. + ### `cdk destroy` Deletes a stack from it's environment. This will cause the resources in the stack to be destroyed (unless they were @@ -464,6 +527,7 @@ Some of the interesting keys that can be used in the JSON configuration files: ```json5 { "app": "node bin/main.js", // Command to start the CDK app (--app='node bin/main.js') + "build": "mvn package", // Specify pre-synth build (no command line option) "context": { // Context entries (--context=key=value) "key": "value" }, @@ -473,6 +537,12 @@ Some of the interesting keys that can be used in the JSON configuration files: } ``` +If specified, the command in the `build` key will be executed immediately before synthesis. +This can be used to build Lambda Functions, CDK Application code, or other assets. +`build` cannot be specified on the command line or in the User configuration, +and must be specified in the Project configuration. The command specified +in `build` will be executed by the "watch" process before deployment. + ### Environment The following environment variables affect aws-cdk: diff --git a/packages/aws-cdk/bin/cdk.ts b/packages/aws-cdk/bin/cdk.ts index aaaef0deb3182..a938b00f3c02f 100644 --- a/packages/aws-cdk/bin/cdk.ts +++ b/packages/aws-cdk/bin/cdk.ts @@ -105,16 +105,58 @@ async function parseCommandLineArguments() { .option('outputs-file', { type: 'string', alias: 'O', desc: 'Path to file where stack outputs will be written as JSON', requiresArg: true }) .option('previous-parameters', { type: 'boolean', default: true, desc: 'Use previous values for existing parameters (you must specify all parameters on every deployment if this is disabled)' }) .option('progress', { type: 'string', choices: [StackActivityProgress.BAR, StackActivityProgress.EVENTS], desc: 'Display mode for stack activity events' }) - .option('rollback', { type: 'boolean', desc: 'Rollback stack to stable state on failure (iterate more rapidly with --no-rollback or -R)' }) + .option('rollback', { + type: 'boolean', + desc: "Rollback stack to stable state on failure. Defaults to 'true', iterate more rapidly with --no-rollback or -R. " + + 'Note: do **not** disable this flag for deployments with resource replacements, as that will always fail', + }) // Hack to get '-R' as an alias for '--no-rollback', suggested by: https://github.com/yargs/yargs/issues/1729 - .option('R', { type: 'boolean', hidden: true }) - .middleware(yargsNegativeAlias('R', 'rollback'), true) + .option('R', { type: 'boolean', hidden: true }).middleware(yargsNegativeAlias('R', 'rollback'), true) .option('hotswap', { type: 'boolean', desc: "Attempts to perform a 'hotswap' deployment, " + 'which skips CloudFormation and updates the resources directly, ' + 'and falls back to a full deployment if that is not possible. ' + 'Do not use this in production environments', + }) + .option('watch', { + type: 'boolean', + desc: 'Continuously observe the project files, ' + + 'and deploy the given stack(s) automatically when changes are detected. ' + + 'Implies --hotswap by default', + }), + ) + .command('watch [STACKS..]', "Shortcut for 'deploy --watch'", yargs => yargs + // I'm fairly certain none of these options, present for 'deploy', make sense for 'watch': + // .option('all', { type: 'boolean', default: false, desc: 'Deploy all available stacks' }) + // .option('ci', { type: 'boolean', desc: 'Force CI detection', default: process.env.CI !== undefined }) + // @deprecated(v2) -- tags are part of the Cloud Assembly and tags specified here will be overwritten on the next deployment + // .option('tags', { type: 'array', alias: 't', desc: 'Tags to add to the stack (KEY=VALUE), overrides tags from Cloud Assembly (deprecated)', nargs: 1, requiresArg: true }) + // .option('execute', { type: 'boolean', desc: 'Whether to execute ChangeSet (--no-execute will NOT execute the ChangeSet)', default: true }) + // These options, however, are more subtle - I could be convinced some of these should also be available for 'watch': + // .option('require-approval', { type: 'string', choices: [RequireApproval.Never, RequireApproval.AnyChange, RequireApproval.Broadening], desc: 'What security-sensitive changes need manual approval' }) + // .option('parameters', { type: 'array', desc: 'Additional parameters passed to CloudFormation at deploy time (STACK:KEY=VALUE)', nargs: 1, requiresArg: true, default: {} }) + // .option('previous-parameters', { type: 'boolean', default: true, desc: 'Use previous values for existing parameters (you must specify all parameters on every deployment if this is disabled)' }) + // .option('outputs-file', { type: 'string', alias: 'O', desc: 'Path to file where stack outputs will be written as JSON', requiresArg: true }) + // .option('notification-arns', { type: 'array', desc: 'ARNs of SNS topics that CloudFormation will notify with stack related events', nargs: 1, requiresArg: true }) + .option('build-exclude', { type: 'array', alias: 'E', nargs: 1, desc: 'Do not rebuild asset with the given ID. Can be specified multiple times', default: [] }) + .option('exclusively', { type: 'boolean', alias: 'e', desc: 'Only deploy requested stacks, don\'t include dependencies' }) + .option('change-set-name', { type: 'string', desc: 'Name of the CloudFormation change set to create' }) + .option('force', { alias: 'f', type: 'boolean', desc: 'Always deploy stack even if templates are identical', default: false }) + .option('progress', { type: 'string', choices: [StackActivityProgress.BAR, StackActivityProgress.EVENTS], desc: 'Display mode for stack activity events' }) + .option('rollback', { + type: 'boolean', + desc: "Rollback stack to stable state on failure. Defaults to 'true', iterate more rapidly with --no-rollback or -R. " + + 'Note: do **not** disable this flag for deployments with resource replacements, as that will always fail', + }) + // same hack for -R as above in 'deploy' + .option('R', { type: 'boolean', hidden: true }).middleware(yargsNegativeAlias('R', 'rollback'), true) + .option('hotswap', { + type: 'boolean', + desc: "Attempts to perform a 'hotswap' deployment, " + + 'which skips CloudFormation and updates the resources directly, ' + + 'and falls back to a full deployment if that is not possible. ' + + "'true' by default, use --no-hotswap to turn off", }), ) .command('destroy [STACKS..]', 'Destroy the stack(s) named STACKS', yargs => yargs @@ -332,6 +374,26 @@ async function initCommandLine() { ci: args.ci, rollback: configuration.settings.get(['rollback']), hotswap: args.hotswap, + watch: args.watch, + }); + + case 'watch': + return cli.watch({ + selector, + // parameters: parameterMap, + // usePreviousParameters: args['previous-parameters'], + // outputsFile: configuration.settings.get(['outputsFile']), + // requireApproval: configuration.settings.get(['requireApproval']), + // notificationArns: args.notificationArns, + exclusively: args.exclusively, + toolkitStackName, + roleArn: args.roleArn, + reuseAssets: args['build-exclude'], + changeSetName: args.changeSetName, + force: args.force, + progress: configuration.settings.get(['progress']), + rollback: configuration.settings.get(['rollback']), + hotswap: args.hotswap, }); case 'destroy': diff --git a/packages/aws-cdk/lib/api/aws-auth/awscli-compatible.ts b/packages/aws-cdk/lib/api/aws-auth/awscli-compatible.ts index b409274efa59c..eb141768b9644 100644 --- a/packages/aws-cdk/lib/api/aws-auth/awscli-compatible.ts +++ b/packages/aws-cdk/lib/api/aws-auth/awscli-compatible.ts @@ -177,12 +177,18 @@ async function isEc2Instance() { let instance = false; if (process.platform === 'win32') { // https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/identify_ec2_instances.html - const result = await util.promisify(child_process.exec)('wmic path win32_computersystemproduct get uuid', { encoding: 'utf-8' }); - // output looks like - // UUID - // EC2AE145-D1DC-13B2-94ED-01234ABCDEF - const lines = result.stdout.toString().split('\n'); - instance = lines.some(x => matchesRegex(/^ec2/i, x)); + try { + const result = await util.promisify(child_process.exec)('wmic path win32_computersystemproduct get uuid', { encoding: 'utf-8' }); + // output looks like + // UUID + // EC2AE145-D1DC-13B2-94ED-01234ABCDEF + const lines = result.stdout.toString().split('\n'); + instance = lines.some(x => matchesRegex(/^ec2/i, x)); + } catch (e) { + // Modern machines may not have wmic.exe installed. No reason to fail, just assume it's not an EC2 instance. + debug(`Checking using WMIC failed, assuming NOT an EC2 instance: ${e.message} (pass --ec2creds to force)`); + instance = false; + } } else { // https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/identify_ec2_instances.html const files: Array<[string, RegExp]> = [ diff --git a/packages/aws-cdk/lib/api/cloudformation-deployments.ts b/packages/aws-cdk/lib/api/cloudformation-deployments.ts index 914efd51cd574..da8db43ae8005 100644 --- a/packages/aws-cdk/lib/api/cloudformation-deployments.ts +++ b/packages/aws-cdk/lib/api/cloudformation-deployments.ts @@ -142,7 +142,7 @@ export interface DeployStackOptions { * A 'hotswap' deployment will attempt to short-circuit CloudFormation * and update the affected resources like Lambda functions directly. * - * @default - false (do not perform a 'hotswap' deployment) + * @default - false for regular deployments, true for 'watch' deployments */ readonly hotswap?: boolean; } diff --git a/packages/aws-cdk/lib/api/cxapp/cloud-executable.ts b/packages/aws-cdk/lib/api/cxapp/cloud-executable.ts index eeebec8e90f44..9bbb607de44fb 100644 --- a/packages/aws-cdk/lib/api/cxapp/cloud-executable.ts +++ b/packages/aws-cdk/lib/api/cxapp/cloud-executable.ts @@ -46,10 +46,14 @@ export class CloudExecutable { } /** - * Synthesize a set of stacks + * Synthesize a set of stacks. + * + * @param cacheCloudAssembly whether to cache the Cloud Assembly after it has been first synthesized. + * This is 'true' by default, and only set to 'false' for 'cdk watch', + * which needs to re-synthesize the Assembly each time it detects a change to the project files */ - public async synthesize(): Promise { - if (!this._cloudAssembly) { + public async synthesize(cacheCloudAssembly: boolean = true): Promise { + if (!this._cloudAssembly || !cacheCloudAssembly) { this._cloudAssembly = await this.doSynthesize(); } return this._cloudAssembly; diff --git a/packages/aws-cdk/lib/api/cxapp/exec.ts b/packages/aws-cdk/lib/api/cxapp/exec.ts index facaf24a3bfe0..bcc298deaeea2 100644 --- a/packages/aws-cdk/lib/api/cxapp/exec.ts +++ b/packages/aws-cdk/lib/api/cxapp/exec.ts @@ -46,6 +46,11 @@ export async function execProgram(aws: SdkProvider, config: Configuration): Prom debug('context:', context); env[cxapi.CONTEXT_ENV] = JSON.stringify(context); + const build = config.settings.get(['build']); + if (build) { + await exec(build); + } + const app = config.settings.get(['app']); if (!app) { throw new Error(`--app is required either in command-line, in ${PROJECT_CONFIG} or in ${USER_DEFAULTS}`); @@ -74,7 +79,7 @@ export async function execProgram(aws: SdkProvider, config: Configuration): Prom debug('env:', env); - await exec(); + await exec(commandLine.join(' ')); return createAssembly(outdir); @@ -91,7 +96,7 @@ export async function execProgram(aws: SdkProvider, config: Configuration): Prom } } - async function exec() { + async function exec(commandAndArgs: string) { return new Promise((ok, fail) => { // We use a slightly lower-level interface to: // @@ -103,7 +108,7 @@ export async function execProgram(aws: SdkProvider, config: Configuration): Prom // anyway, and if the subprocess is printing to it for debugging purposes the // user gets to see it sooner. Plus, capturing doesn't interact nicely with some // processes like Maven. - const proc = childProcess.spawn(commandLine[0], commandLine.slice(1), { + const proc = childProcess.spawn(commandAndArgs, { stdio: ['ignore', 'inherit', 'inherit'], detached: false, shell: true, diff --git a/packages/aws-cdk/lib/api/deploy-stack.ts b/packages/aws-cdk/lib/api/deploy-stack.ts index ab662d34b517c..f73eebed57f54 100644 --- a/packages/aws-cdk/lib/api/deploy-stack.ts +++ b/packages/aws-cdk/lib/api/deploy-stack.ts @@ -179,7 +179,7 @@ export interface DeployStackOptions { * A 'hotswap' deployment will attempt to short-circuit CloudFormation * and update the affected resources like Lambda functions directly. * - * @default - false (do not perform a 'hotswap' deployment) + * @default - false for regular deployments, true for 'watch' deployments */ readonly hotswap?: boolean; } @@ -317,7 +317,7 @@ async function prepareAndExecuteChangeSet( if (execute) { debug('Initiating execution of changeset %s on stack %s', changeSet.Id, deployName); - const shouldDisableRollback = (options.rollback === undefined && options.hotswap === true) || options.rollback === false; + const shouldDisableRollback = options.rollback === false; // Do a bit of contortions to only pass the `DisableRollback` flag if it's true. That way, // CloudFormation won't balk at the unrecognized option in regions where the feature is not available yet. const disableRollback = shouldDisableRollback ? { DisableRollback: true } : undefined; diff --git a/packages/aws-cdk/lib/cdk-toolkit.ts b/packages/aws-cdk/lib/cdk-toolkit.ts index 6bc109dd37822..95da6dd39e139 100644 --- a/packages/aws-cdk/lib/cdk-toolkit.ts +++ b/packages/aws-cdk/lib/cdk-toolkit.ts @@ -1,6 +1,7 @@ import * as path from 'path'; import { format } from 'util'; import * as cxapi from '@aws-cdk/cx-api'; +import * as chokidar from 'chokidar'; import * as colors from 'colors/safe'; import * as fs from 'fs-extra'; import * as promptly from 'promptly'; @@ -12,9 +13,9 @@ import { CloudAssembly, DefaultSelection, ExtendedStackSelection, StackCollectio import { CloudExecutable } from './api/cxapp/cloud-executable'; import { StackActivityProgress } from './api/util/cloudformation/stack-activity-monitor'; import { printSecurityDiff, printStackDiff, RequireApproval } from './diff'; -import { data, error, highlight, print, success, warning } from './logging'; +import { data, debug, error, highlight, print, success, warning } from './logging'; import { deserializeStructure } from './serialize'; -import { Configuration } from './settings'; +import { Configuration, PROJECT_CONFIG } from './settings'; import { numberFromBool, partition } from './util'; export interface CdkToolkitProps { @@ -112,7 +113,11 @@ export class CdkToolkit { } public async deploy(options: DeployOptions) { - const stacks = await this.selectStacksForDeploy(options.selector, options.exclusively); + if (options.watch) { + return this.watch(options); + } + + const stacks = await this.selectStacksForDeploy(options.selector, options.exclusively, options.cacheCloudAssembly); const requireApproval = options.requireApproval ?? RequireApproval.Broadening; @@ -243,6 +248,85 @@ export class CdkToolkit { } } + public async watch(options: WatchOptions) { + const rootDir = path.dirname(path.resolve(PROJECT_CONFIG)); + debug("root directory used for 'watch' is: %s", rootDir); + + const watchSettings: { include?: string | string[], exclude: string | string [] } | undefined = + this.props.configuration.settings.get(['watch']); + if (!watchSettings) { + throw new Error("Cannot use the 'watch' command without specifying at least one directory to monitor. " + + 'Make sure to add a "watch" key to your cdk.json'); + } + + // For the "include" subkey under the "watch" key, the behavior is: + // 1. No "watch" setting? We error out. + // 2. "watch" setting without an "include" key? We default to observing "./**". + // 3. "watch" setting with an empty "include" key? We default to observing "./**". + // 4. Non-empty "include" key? Just use the "include" key. + const watchIncludes = this.patternsArrayForWatch(watchSettings.include, { rootDir, returnRootDirIfEmpty: true }); + debug("'include' patterns for 'watch': %s", watchIncludes); + + // For the "exclude" subkey under the "watch" key, + // the behavior is to add some default excludes in addition to the ones specified by the user: + // 1. The CDK output directory. + // 2. Any file whose name starts with a dot. + // 3. Any directory's content whose name starts with a dot. + // 4. Any node_modules and its content (even if it's not a JS/TS project, you might be using a local aws-cli package) + const outputDir = this.props.configuration.settings.get(['output']); + const watchExcludes = this.patternsArrayForWatch(watchSettings.exclude, { rootDir, returnRootDirIfEmpty: false }).concat( + `${outputDir}/**`, + '**/.*', + '**/.*/**', + '**/node_modules/**', + ); + debug("'exclude' patterns for 'watch': %s", watchExcludes); + + // Since 'cdk deploy' is a relatively slow operation for a 'watch' process, + // introduce a concurrency latch that tracks the state. + // This way, if file change events arrive when a 'cdk deploy' is still executing, + // we will batch them, and trigger another 'cdk deploy' after the current one finishes, + // making sure 'cdk deploy's always execute one at a time. + // Here's a diagram showing the state transitions: + // -------------- -------- file changed -------------- file changed -------------- file changed + // | | ready event | | ------------------> | | ------------------> | | --------------| + // | pre-ready | -------------> | open | | deploying | | queued | | + // | | | | <------------------ | | <------------------ | | <-------------| + // -------------- -------- 'cdk deploy' done -------------- 'cdk deploy' done -------------- + let latch: 'pre-ready' | 'open' | 'deploying' | 'queued' = 'pre-ready'; + chokidar.watch(watchIncludes, { + ignored: watchExcludes, + cwd: rootDir, + // ignoreInitial: true, + }).on('ready', () => { + latch = 'open'; + debug("'watch' received the 'ready' event. From now on, all file changes will trigger a deployment"); + }).on('all', async (event, filePath) => { + if (latch === 'pre-ready') { + print(`'watch' is observing ${event === 'addDir' ? 'directory' : 'the file'} '%s' for changes`, filePath); + } else if (latch === 'open') { + latch = 'deploying'; + print("Detected change to '%s' (type: %s). Triggering 'cdk deploy'", filePath, event); + await this.invokeDeployFromWatch(options); + + // If latch is still 'deploying' after the 'await', that's fine, + // but if it's 'queued', that means we need to deploy again + while ((latch as 'deploying' | 'queued') === 'queued') { + // TypeScript doesn't realize latch can change between 'awaits', + // and thinks the above 'while' condition is always 'false' without the cast + latch = 'deploying'; + print("Detected file changes during deployment. Invoking 'cdk deploy' again"); + await this.invokeDeployFromWatch(options); + } + latch = 'open'; + } else { // this means latch is either 'deploying' or 'queued' + latch = 'queued'; + print("Detected change to '%s' (type: %s) while 'cdk deploy' is still running. " + + 'Will queue for another deployment after this one finishes', filePath, event); + } + }); + } + public async destroy(options: DestroyOptions) { let stacks = await this.selectStacksForDestroy(options.selector, options.exclusively); @@ -282,7 +366,7 @@ export class CdkToolkit { const long = []; for (const stack of stacks.stackArtifacts) { long.push({ - id: stack.id, + id: stack.hierarchicalId, name: stack.stackName, environment: stack.environment, }); @@ -397,8 +481,8 @@ export class CdkToolkit { return stacks; } - private async selectStacksForDeploy(selector: StackSelector, exclusively?: boolean): Promise { - const assembly = await this.assembly(); + private async selectStacksForDeploy(selector: StackSelector, exclusively?: boolean, cacheCloudAssembly?: boolean): Promise { + const assembly = await this.assembly(cacheCloudAssembly); const stacks = await assembly.selectStacks(selector, { extend: exclusively ? ExtendedStackSelection.None : ExtendedStackSelection.Upstream, defaultBehavior: DefaultSelection.OnlySingle, @@ -480,10 +564,38 @@ export class CdkToolkit { return assembly.stackById(stacks.firstStack.id); } - private assembly(): Promise { - return this.props.cloudExecutable.synthesize(); + private assembly(cacheCloudAssembly?: boolean): Promise { + return this.props.cloudExecutable.synthesize(cacheCloudAssembly); } + private patternsArrayForWatch(patterns: string | string[] | undefined, options: { rootDir: string, returnRootDirIfEmpty: boolean }): string[] { + const patternsArray: string[] = patterns !== undefined + ? (Array.isArray(patterns) ? patterns : [patterns]) + : []; + return patternsArray.length > 0 + ? patternsArray + : (options.returnRootDirIfEmpty ? [options.rootDir] : []); + } + + private async invokeDeployFromWatch(options: WatchOptions): Promise { + // 'watch' has different defaults than regular 'deploy' + const deployOptions: DeployOptions = { + ...options, + requireApproval: RequireApproval.Never, + // if 'watch' is called by invoking 'cdk deploy --watch', + // we need to make sure to not call 'deploy' with 'watch' again, + // as that would lead to a cycle + watch: false, + cacheCloudAssembly: false, + hotswap: options.hotswap === undefined ? true : options.hotswap, + }; + + try { + await this.deploy(deployOptions); + } catch (e) { + // just continue - deploy will show the error + } + } } export interface DiffOptions { @@ -542,7 +654,7 @@ export interface DiffOptions { securityOnly?: boolean; } -export interface DeployOptions { +interface WatchOptions { /** * Criteria for selecting stacks to deploy */ @@ -567,6 +679,49 @@ export interface DeployOptions { */ roleArn?: string; + /** + * Reuse the assets with the given asset IDs + */ + reuseAssets?: string[]; + + /** + * Optional name to use for the CloudFormation change set. + * If not provided, a name will be generated automatically. + */ + changeSetName?: string; + + /** + * Always deploy, even if templates are identical. + * @default false + */ + force?: boolean; + + /** + * Display mode for stack deployment progress. + * + * @default - StackActivityProgress.Bar - stack events will be displayed for + * the resource currently being deployed. + */ + progress?: StackActivityProgress; + + /** + * Rollback failed deployments + * + * @default true + */ + readonly rollback?: boolean; + + /** + * Whether to perform a 'hotswap' deployment. + * A 'hotswap' deployment will attempt to short-circuit CloudFormation + * and update the affected resources like Lambda functions directly. + * + * @default - false for regular deployments, true for 'watch' deployments + */ + readonly hotswap?: boolean; +} + +export interface DeployOptions extends WatchOptions { /** * ARNs of SNS topics that CloudFormation will notify with stack related events */ @@ -579,11 +734,6 @@ export interface DeployOptions { */ requireApproval?: RequireApproval; - /** - * Reuse the assets with the given asset IDs - */ - reuseAssets?: string[]; - /** * Tags to pass to CloudFormation for deployment */ @@ -596,18 +746,6 @@ export interface DeployOptions { */ execute?: boolean; - /** - * Optional name to use for the CloudFormation change set. - * If not provided, a name will be generated automatically. - */ - changeSetName?: string; - - /** - * Always deploy, even if templates are identical. - * @default false - */ - force?: boolean; - /** * Additional parameters for CloudFormation at deploy time * @default {} @@ -623,14 +761,6 @@ export interface DeployOptions { */ usePreviousParameters?: boolean; - /** - * Display mode for stack deployment progress. - * - * @default - StackActivityProgress.Bar - stack events will be displayed for - * the resource currently being deployed. - */ - progress?: StackActivityProgress; - /** * Path to file where stack outputs will be written after a successful deploy as JSON * @default - Outputs are not written to any file @@ -645,19 +775,20 @@ export interface DeployOptions { readonly ci?: boolean; /** - * Rollback failed deployments + * Whether this 'deploy' command should actually delegate to the 'watch' command. * - * @default true + * @default false */ - readonly rollback?: boolean; - /* - * Whether to perform a 'hotswap' deployment. - * A 'hotswap' deployment will attempt to short-circuit CloudFormation - * and update the affected resources like Lambda functions directly. + readonly watch?: boolean; + + /** + * Whether we should cache the Cloud Assembly after the first time it has been synthesized. + * The default is 'true', we only don't want to do it in case the deployment is triggered by + * 'cdk watch'. * - * @default - false (do not perform a 'hotswap' deployment) + * @default true */ - readonly hotswap?: boolean; + readonly cacheCloudAssembly?: boolean; } export interface DestroyOptions { 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 index 24a2b0e90b616..742ed4c64ce7b 100644 --- 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 @@ -2,9 +2,9 @@ package main import ( "github.com/aws/aws-cdk-go/awscdk" - "github.com/aws/aws-cdk-go/awscdk/awssns" + // "github.com/aws/aws-cdk-go/awscdk/awssqs" "github.com/aws/constructs-go/constructs/v3" - "github.com/aws/jsii-runtime-go" + // "github.com/aws/jsii-runtime-go" ) type %name.PascalCased%StackProps struct { @@ -20,10 +20,10 @@ func New%name.PascalCased%Stack(scope constructs.Construct, id string, props *%n // 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"), - }) + // example resource + // queue := awssqs.NewQueue(stack, jsii.String("%name.PascalCased%Queue"), &awssqs.QueueProps{ + // VisibilityTimeout: awscdk.Duration_Seconds(jsii.Number(300)), + // }) return stack } 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 index c0534249b6282..78742540bc2f7 100644 --- 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 @@ -1,28 +1,26 @@ package main -import ( - "encoding/json" - "testing" +// import ( +// "testing" - "github.com/aws/aws-cdk-go/awscdk" - "github.com/stretchr/testify/assert" - "github.com/tidwall/gjson" -) +// "github.com/aws/aws-cdk-go/awscdk" +// "github.com/aws/aws-cdk-go/awscdk/assertions" +// "github.com/aws/jsii-runtime-go" +// ) -func Test%name.PascalCased%Stack(t *testing.T) { - // GIVEN - app := awscdk.NewApp(nil) +// example tests. To run these tests, uncomment this file along with the +// example resource in %name%_test.go +// func Test%name.PascalCased%Stack(t *testing.T) { +// // GIVEN +// app := awscdk.NewApp(nil) - // WHEN - stack := New%name.PascalCased%Stack(app, "MyStack", 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) - } +// // THEN +// template := assertions.Template_FromStack(stack) - template := gjson.ParseBytes(bytes) - displayName := template.Get("Resources.MyTopic86869434.Properties.DisplayName").String() - assert.Equal(t, "MyCoolTopic", displayName) -} +// template.HasResourceProperties(jsii.String("AWS::SQS::Queue"), map[string]interface{}{ +// "VisibilityTimeout": 300, +// }) +// } 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 index a1dcb391c1614..5dbef39984826 100644 --- 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 @@ -6,8 +6,4 @@ 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/pom.template.xml b/packages/aws-cdk/lib/init-templates/v1/app/java/pom.template.xml index fb0b6cf828aaf..b8b00e798209c 100644 --- a/packages/aws-cdk/lib/init-templates/v1/app/java/pom.template.xml +++ b/packages/aws-cdk/lib/init-templates/v1/app/java/pom.template.xml @@ -43,24 +43,18 @@ core ${cdk.version} - - org.junit.jupiter - junit-jupiter-api - ${junit.version} - test + software.amazon.awscdk + assertions + ${cdk.version} + test + org.junit.jupiter - junit-jupiter-engine + junit-jupiter ${junit.version} test - - org.assertj - assertj-core - 3.18.1 - test - diff --git a/packages/aws-cdk/lib/init-templates/v1/app/java/src/main/java/com/myorg/%name.PascalCased%Stack.template.java b/packages/aws-cdk/lib/init-templates/v1/app/java/src/main/java/com/myorg/%name.PascalCased%Stack.template.java index e0d4b5a0be8b1..a4dbab1dbd8b9 100644 --- a/packages/aws-cdk/lib/init-templates/v1/app/java/src/main/java/com/myorg/%name.PascalCased%Stack.template.java +++ b/packages/aws-cdk/lib/init-templates/v1/app/java/src/main/java/com/myorg/%name.PascalCased%Stack.template.java @@ -3,6 +3,8 @@ import software.amazon.awscdk.core.Construct; import software.amazon.awscdk.core.Stack; import software.amazon.awscdk.core.StackProps; +// import software.amazon.awscdk.services.sqs.Queue; +// import software.amazon.awscdk.core.Duration; public class %name.PascalCased%Stack extends Stack { public %name.PascalCased%Stack(final Construct scope, final String id) { @@ -13,5 +15,10 @@ public class %name.PascalCased%Stack extends Stack { super(scope, id, props); // The code that defines your stack goes here + + // example resource + // final Queue queue = Queue.Builder.create(this, "%name.PascalCased%Queue") + // .visibilityTimeout(Duration.seconds(300)) + // .build(); } } 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 9494caf63d628..e095565be7920 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 @@ -1,28 +1,26 @@ -package com.myorg; +// package com.myorg; -import software.amazon.awscdk.core.App; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; +// import software.amazon.awscdk.core.App; +// import software.amazon.awscdk.assertions.Template; +// import java.io.IOException; -import java.io.IOException; +// import java.util.HashMap; -import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; +// import org.junit.jupiter.api.Test; -public class %name.PascalCased%Test { - private final static ObjectMapper JSON = - new ObjectMapper().configure(SerializationFeature.INDENT_OUTPUT, true); +// example test. To run these tests, uncomment this file, along with the +// example resource in java/src/main/java/com/myorg/%name.PascalCased%Stack.java +// public class %name.PascalCased%Test { - @Test - public void testStack() throws IOException { - App app = new App(); - %name.PascalCased%Stack stack = new %name.PascalCased%Stack(app, "test"); +// @Test +// 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 - JsonNode actual = JSON.valueToTree(app.synth().getStackArtifact(stack.getArtifactId()).getTemplate()); +// Template template = Template.fromStack(stack); - // Update once resources have been added to the stack - assertThat(actual.get("Resources")).isNull(); - } -} +// template.hasResourceProperties("AWS::SQS::Queue", new HashMap() {{ +// put("VisibilityTimeout", 300); +// }}); +// } +// } diff --git a/packages/aws-cdk/lib/init-templates/v1/app/javascript/lib/%name%-stack.template.js b/packages/aws-cdk/lib/init-templates/v1/app/javascript/lib/%name%-stack.template.js index 2c52c5f65244c..8004c54a568aa 100644 --- a/packages/aws-cdk/lib/init-templates/v1/app/javascript/lib/%name%-stack.template.js +++ b/packages/aws-cdk/lib/init-templates/v1/app/javascript/lib/%name%-stack.template.js @@ -1,4 +1,5 @@ const cdk = require('@aws-cdk/core'); +// const sqs = require('@aws-cdk/aws-sqs'); class %name.PascalCased%Stack extends cdk.Stack { /** @@ -11,6 +12,11 @@ class %name.PascalCased%Stack extends cdk.Stack { super(scope, id, props); // The code that defines your stack goes here + + // example resource + // const queue = new sqs.Queue(this, '%name.PascalCased%Queue', { + // visibilityTimeout: cdk.Duration.seconds(300) + // }); } } diff --git a/packages/aws-cdk/lib/init-templates/v1/app/javascript/package.template.json b/packages/aws-cdk/lib/init-templates/v1/app/javascript/package.template.json index 5547dacf3a673..abe1218b79d96 100644 --- a/packages/aws-cdk/lib/init-templates/v1/app/javascript/package.template.json +++ b/packages/aws-cdk/lib/init-templates/v1/app/javascript/package.template.json @@ -10,7 +10,7 @@ "test": "jest" }, "devDependencies": { - "@aws-cdk/assert": "%cdk-version%", + "@aws-cdk/assertions": "%cdk-version%", "aws-cdk": "%cdk-version%", "jest": "^26.4.2" }, diff --git a/packages/aws-cdk/lib/init-templates/v1/app/javascript/test/%name%.test.template.js b/packages/aws-cdk/lib/init-templates/v1/app/javascript/test/%name%.test.template.js index 54e6bb172e0a9..514cd34e9faf1 100644 --- a/packages/aws-cdk/lib/init-templates/v1/app/javascript/test/%name%.test.template.js +++ b/packages/aws-cdk/lib/init-templates/v1/app/javascript/test/%name%.test.template.js @@ -1,13 +1,18 @@ -const { expect, matchTemplate, MatchStyle } = require('@aws-cdk/assert'); -const cdk = require('@aws-cdk/core'); -const %name.PascalCased% = require('../lib/%name%-stack'); +// const { Template } = require('@aws-cdk/assertions'); +// const cdk = require('@aws-cdk/core'); +// const %name.PascalCased% = require('../lib/%name%-stack'); -test('Empty Stack', () => { - const app = new cdk.App(); - // WHEN - const stack = new %name.PascalCased%.%name.PascalCased%Stack(app, 'MyTestStack'); - // THEN - expect(stack).to(matchTemplate({ - "Resources": {} - }, MatchStyle.EXACT)) +// example test. To run these tests, uncomment this file along with the +// example resource in lib/%name%-stack.js +test('SQS Queue Created', () => { +// const app = new cdk.App(); +// // WHEN +// const stack = new %name.PascalCased%.%name.PascalCased%Stack(app, 'MyTestStack'); +// // THEN +// const template = Template.fromStack(stack); + +// template.hasResourceProperties('AWS::SQS::Queue', { +// VisibilityTimeout: 300 +// }); }); + diff --git a/packages/aws-cdk/lib/init-templates/v1/app/python/%name.PythonModule%/%name.PythonModule%_stack.template.py b/packages/aws-cdk/lib/init-templates/v1/app/python/%name.PythonModule%/%name.PythonModule%_stack.template.py index 6b4ed6e8ea6ed..9c5de032e839d 100644 --- a/packages/aws-cdk/lib/init-templates/v1/app/python/%name.PythonModule%/%name.PythonModule%_stack.template.py +++ b/packages/aws-cdk/lib/init-templates/v1/app/python/%name.PythonModule%/%name.PythonModule%_stack.template.py @@ -1,4 +1,7 @@ -from aws_cdk import core as cdk +from aws_cdk import ( + core as cdk + # aws_sqs as sqs, +) # For consistency with other languages, `cdk` is the preferred import name for # the CDK's core module. The following line also imports it as `core` for use @@ -13,3 +16,9 @@ def __init__(self, scope: cdk.Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) # The code that defines your stack goes here + + # example resource + # queue = sqs.Queue( + # self, "%name.PascalCased%Queue", + # visibility_timeout=cdk.Duration.seconds(300), + # ) diff --git a/packages/aws-cdk/lib/init-templates/v1/app/python/requirements-dev.txt b/packages/aws-cdk/lib/init-templates/v1/app/python/requirements-dev.txt new file mode 100644 index 0000000000000..927094516e657 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v1/app/python/requirements-dev.txt @@ -0,0 +1 @@ +pytest==6.2.5 diff --git a/packages/aws-cdk/lib/init-templates/v1/app/python/requirements.template.txt b/packages/aws-cdk/lib/init-templates/v1/app/python/requirements.template.txt new file mode 100644 index 0000000000000..87cbb00cfac55 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v1/app/python/requirements.template.txt @@ -0,0 +1,2 @@ +aws-cdk.core>=%cdk-version% +aws-cdk.assertions>=%cdk-version% diff --git a/packages/aws-cdk/lib/init-templates/v1/app/python/requirements.txt b/packages/aws-cdk/lib/init-templates/v1/app/python/requirements.txt deleted file mode 100644 index d6e1198b1ab1f..0000000000000 --- a/packages/aws-cdk/lib/init-templates/v1/app/python/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . 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 deleted file mode 100644 index 113bf29e54755..0000000000000 --- a/packages/aws-cdk/lib/init-templates/v1/app/python/setup.template.py +++ /dev/null @@ -1,43 +0,0 @@ -import setuptools - - -with open("README.md") as fp: - long_description = fp.read() - - -setuptools.setup( - name="%name.PythonModule%", - version="0.0.1", - - description="An empty CDK Python app", - long_description=long_description, - long_description_content_type="text/markdown", - - author="author", - - package_dir={"": "%name.PythonModule%"}, - packages=setuptools.find_packages(where="%name.PythonModule%"), - - install_requires=[ - "aws-cdk.core==%cdk-version%", - ], - - python_requires=">=3.6", - - classifiers=[ - "Development Status :: 4 - Beta", - - "Intended Audience :: Developers", - - "Programming Language :: JavaScript", - "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - - "Topic :: Software Development :: Code Generators", - "Topic :: Utilities", - - "Typing :: Typed", - ], -) diff --git a/packages/aws-cdk/lib/init-templates/v1/app/python/tests/__init__.py b/packages/aws-cdk/lib/init-templates/v1/app/python/tests/__init__.py new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/aws-cdk/lib/init-templates/v1/app/python/tests/unit/__init__.py b/packages/aws-cdk/lib/init-templates/v1/app/python/tests/unit/__init__.py new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/aws-cdk/lib/init-templates/v1/app/python/tests/unit/test_%name.PythonModule%_stack.template.py b/packages/aws-cdk/lib/init-templates/v1/app/python/tests/unit/test_%name.PythonModule%_stack.template.py new file mode 100644 index 0000000000000..1b0e4b66e9aaa --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v1/app/python/tests/unit/test_%name.PythonModule%_stack.template.py @@ -0,0 +1,19 @@ +# from aws_cdk import ( +# core, +# assertions +# ) + +# from %name.PythonModule%.%name.PythonModule%_stack import %name.PascalCased%Stack + + +# example tests. To run these tests, uncomment this file along with the example +# resource in %name.PythonModule%/%name.PythonModule%_stack.py +def test_sqs_queue_created(): +# app = core.App() +# stack = %name.PascalCased%Stack(app, "%name.StackName%") +# template = assertions.Template.from_stack(stack) + +# template.has_resource_properties("AWS::SQS::Queue", { +# "VisibilityTimeout": 300 +# }) + pass diff --git a/packages/aws-cdk/lib/init-templates/v1/app/typescript/lib/%name%-stack.template.ts b/packages/aws-cdk/lib/init-templates/v1/app/typescript/lib/%name%-stack.template.ts index 80fa43a59ea24..82fd9a48ac0dd 100644 --- a/packages/aws-cdk/lib/init-templates/v1/app/typescript/lib/%name%-stack.template.ts +++ b/packages/aws-cdk/lib/init-templates/v1/app/typescript/lib/%name%-stack.template.ts @@ -1,9 +1,15 @@ import * as cdk from '@aws-cdk/core'; +// import * as sqs from '@aws-cdk/aws-sqs'; export class %name.PascalCased%Stack extends cdk.Stack { constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); // The code that defines your stack goes here + + // example resource + // const queue = new sqs.Queue(this, '%name.PascalCased%Queue', { + // visibilityTimeout: cdk.Duration.seconds(300) + // }); } } diff --git a/packages/aws-cdk/lib/init-templates/v1/app/typescript/package.template.json b/packages/aws-cdk/lib/init-templates/v1/app/typescript/package.template.json index df89ae6a206bb..94bbd07dae3ac 100644 --- a/packages/aws-cdk/lib/init-templates/v1/app/typescript/package.template.json +++ b/packages/aws-cdk/lib/init-templates/v1/app/typescript/package.template.json @@ -11,7 +11,7 @@ "cdk": "cdk" }, "devDependencies": { - "@aws-cdk/assert": "%cdk-version%", + "@aws-cdk/assertions": "%cdk-version%", "@types/jest": "^26.0.10", "@types/node": "10.17.27", "jest": "^26.4.2", diff --git a/packages/aws-cdk/lib/init-templates/v1/app/typescript/test/%name%.test.template.ts b/packages/aws-cdk/lib/init-templates/v1/app/typescript/test/%name%.test.template.ts index a574690020687..d41f3aaf74d04 100644 --- a/packages/aws-cdk/lib/init-templates/v1/app/typescript/test/%name%.test.template.ts +++ b/packages/aws-cdk/lib/init-templates/v1/app/typescript/test/%name%.test.template.ts @@ -1,13 +1,17 @@ -import { expect as expectCDK, matchTemplate, MatchStyle } from '@aws-cdk/assert'; -import * as cdk from '@aws-cdk/core'; -import * as %name.PascalCased% from '../lib/%name%-stack'; +// import { Template } from '@aws-cdk/assertions'; +// import * as cdk from '@aws-cdk/core'; +// import * as %name.PascalCased% from '../lib/%name%-stack'; -test('Empty Stack', () => { - const app = new cdk.App(); - // WHEN - const stack = new %name.PascalCased%.%name.PascalCased%Stack(app, 'MyTestStack'); - // THEN - expectCDK(stack).to(matchTemplate({ - "Resources": {} - }, MatchStyle.EXACT)); +// example test. To run these tests, uncomment this file along with the +// example resource in lib/%name%-stack.ts +test('SQS Queue Created', () => { +// const app = new cdk.App(); +// // WHEN +// const stack = new %name.PascalCased%.%name.PascalCased%Stack(app, 'MyTestStack'); +// // THEN +// const template = Template.fromStack(stack); + +// template.hasResourceProperties('AWS::SQS::Queue', { +// VisibilityTimeout: 300 +// }); }); diff --git a/packages/aws-cdk/lib/init-templates/v1/lib/typescript/lib/index.template.ts b/packages/aws-cdk/lib/init-templates/v1/lib/typescript/lib/index.template.ts index d05d444fc8f09..49c002d8e8271 100644 --- a/packages/aws-cdk/lib/init-templates/v1/lib/typescript/lib/index.template.ts +++ b/packages/aws-cdk/lib/init-templates/v1/lib/typescript/lib/index.template.ts @@ -1,4 +1,5 @@ import * as cdk from '@aws-cdk/core'; +// import * as sqs from '@aws-cdk/aws-sqs'; export interface %name.PascalCased%Props { // Define construct properties here @@ -10,5 +11,10 @@ export class %name.PascalCased% extends cdk.Construct { super(scope, id); // Define construct contents here + + // example resource + // const queue = new sqs.Queue(this, '%name.PascalCased%Queue', { + // visibilityTimeout: cdk.Duration.seconds(300) + // }); } } diff --git a/packages/aws-cdk/lib/init-templates/v1/lib/typescript/package.template.json b/packages/aws-cdk/lib/init-templates/v1/lib/typescript/package.template.json index 8d9ef219c74ca..4e99fa16cbc8f 100644 --- a/packages/aws-cdk/lib/init-templates/v1/lib/typescript/package.template.json +++ b/packages/aws-cdk/lib/init-templates/v1/lib/typescript/package.template.json @@ -9,7 +9,7 @@ "test": "jest" }, "devDependencies": { - "@aws-cdk/assert": "%cdk-version%", + "@aws-cdk/assertions": "%cdk-version%", "@types/jest": "^26.0.10", "@types/node": "10.17.27", "jest": "^26.4.2", 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 0b49cb3cc99d1..641b974082aa7 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 @@ -1,15 +1,18 @@ -import { expect as expectCDK, countResources } from '@aws-cdk/assert'; -import * as cdk from '@aws-cdk/core'; -import * as %name.PascalCased% from '../lib/index'; +// import { Template } from '@aws-cdk/assertions'; +// import * as cdk from '@aws-cdk/core'; +// import * as %name.PascalCased% from '../lib/index'; -/* - * Example test - */ -test('SNS Topic Created', () => { - const app = new cdk.App(); - const stack = new cdk.Stack(app, "TestStack"); - // WHEN - new %name.PascalCased%.%name.PascalCased%(stack, 'MyTestConstruct'); - // THEN - expectCDK(stack).to(countResources("AWS::SNS::Topic",0)); +// example test. To run these tests, uncomment this file along with the +// example resource in lib/index.ts +test('SQS Queue Created', () => { +// const app = new cdk.App(); +// const stack = new cdk.Stack(app, 'TestStack'); +// // WHEN +// new %name.PascalCased%.%name.PascalCased%(stack, 'MyTestConstruct'); +// // THEN +// const template = Template.fromStack(stack); + +// template.hasResourceProperties('AWS::SQS::Queue', { +// VisibilityTimeout: 300 +// }); }); diff --git a/packages/aws-cdk/lib/init-templates/v1/sample-app/go/%name%.template.go b/packages/aws-cdk/lib/init-templates/v1/sample-app/go/%name%.template.go new file mode 100644 index 0000000000000..5ac97c495740f --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v1/sample-app/go/%name%.template.go @@ -0,0 +1,71 @@ +package main + +import ( + "github.com/aws/aws-cdk-go/awscdk" + "github.com/aws/aws-cdk-go/awscdk/awssns" + "github.com/aws/aws-cdk-go/awscdk/awssnssubscriptions" + "github.com/aws/aws-cdk-go/awscdk/awssqs" + "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) + + + queue := awssqs.NewQueue(stack, jsii.String("%name.PascalCased%Queue"), &awssqs.QueueProps{ + VisibilityTimeout: awscdk.Duration_Seconds(jsii.Number(300)), + }) + + topic := awssns.NewTopic(stack, jsii.String("%name.PascalCased%Topic"), &awssns.TopicProps{}) + topic.AddSubscription(awssnssubscriptions.NewSqsSubscription(queue, &awssnssubscriptions.SqsSubscriptionProps{})) + + 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/sample-app/go/%name%_test.template.go b/packages/aws-cdk/lib/init-templates/v1/sample-app/go/%name%_test.template.go new file mode 100644 index 0000000000000..834f4830cf23e --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v1/sample-app/go/%name%_test.template.go @@ -0,0 +1,25 @@ +package main + +import ( + "testing" + + "github.com/aws/aws-cdk-go/awscdk" + "github.com/aws/aws-cdk-go/awscdk/assertions" + "github.com/aws/jsii-runtime-go" +) + +func Test%name.PascalCased%Stack(t *testing.T) { + // GIVEN + app := awscdk.NewApp(nil) + + // WHEN + stack := New%name.PascalCased%Stack(app, "MyStack", nil) + + // THEN + template := assertions.Template_FromStack(stack) + + template.HasResourceProperties(jsii.String("AWS::SQS::Queue"), map[string]interface{}{ + "VisibilityTimeout": 300, + }) + template.ResourceCountIs(jsii.String("AWS::SNS::Topic"), jsii.Number(1)) +} diff --git a/packages/aws-cdk/lib/init-templates/v1/sample-app/go/.template.gitignore b/packages/aws-cdk/lib/init-templates/v1/sample-app/go/.template.gitignore new file mode 100644 index 0000000000000..92fe1ec34b4b6 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v1/sample-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/sample-app/go/README.md b/packages/aws-cdk/lib/init-templates/v1/sample-app/go/README.md new file mode 100644 index 0000000000000..9b8d4b29f26e3 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v1/sample-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/sample-app/go/cdk.template.json b/packages/aws-cdk/lib/init-templates/v1/sample-app/go/cdk.template.json new file mode 100644 index 0000000000000..ad88cd7ef75f3 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v1/sample-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/sample-app/go/go.template.mod b/packages/aws-cdk/lib/init-templates/v1/sample-app/go/go.template.mod new file mode 100644 index 0000000000000..5dbef39984826 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v1/sample-app/go/go.template.mod @@ -0,0 +1,9 @@ +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 +) diff --git a/packages/aws-cdk/lib/init-templates/v1/sample-app/java/pom.template.xml b/packages/aws-cdk/lib/init-templates/v1/sample-app/java/pom.template.xml index 5d679d2570040..e25c5e7c23a9b 100644 --- a/packages/aws-cdk/lib/init-templates/v1/sample-app/java/pom.template.xml +++ b/packages/aws-cdk/lib/init-templates/v1/sample-app/java/pom.template.xml @@ -55,24 +55,18 @@ sqs ${cdk.version} - - org.junit.jupiter - junit-jupiter-api - ${junit.version} - test + software.amazon.awscdk + assertions + ${cdk.version} + test + org.junit.jupiter - junit-jupiter-engine + junit-jupiter ${junit.version} test - - org.assertj - assertj-core - 3.18.1 - test - diff --git a/packages/aws-cdk/lib/init-templates/v1/sample-app/java/src/test/java/com/myorg/%name.PascalCased%StackTest.template.java b/packages/aws-cdk/lib/init-templates/v1/sample-app/java/src/test/java/com/myorg/%name.PascalCased%StackTest.template.java index 93b00f5d770c2..5cbbe8a127e4f 100644 --- a/packages/aws-cdk/lib/init-templates/v1/sample-app/java/src/test/java/com/myorg/%name.PascalCased%StackTest.template.java +++ b/packages/aws-cdk/lib/init-templates/v1/sample-app/java/src/test/java/com/myorg/%name.PascalCased%StackTest.template.java @@ -1,27 +1,26 @@ package com.myorg; import software.amazon.awscdk.core.App; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; +import software.amazon.awscdk.assertions.Template; +import software.amazon.awscdk.assertions.Match; import java.io.IOException; +import java.util.HashMap; + import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; public class %name.PascalCased%StackTest { - private final static ObjectMapper JSON = - new ObjectMapper().configure(SerializationFeature.INDENT_OUTPUT, true); @Test public void testStack() throws IOException { App app = new App(); %name.PascalCased%Stack stack = new %name.PascalCased%Stack(app, "test"); - JsonNode actual = JSON.valueToTree(app.synth().getStackArtifact(stack.getArtifactId()).getTemplate()); + Template template = Template.fromStack(stack); - assertThat(actual.toString()) - .contains("AWS::SQS::Queue") - .contains("AWS::SNS::Topic"); + template.hasResourceProperties("AWS::SQS::Queue", new HashMap() {{ + put("VisibilityTimeout", 300); + }}); + template.resourceCountIs("AWS::SNS::Topic", 1); } } diff --git a/packages/aws-cdk/lib/init-templates/v1/sample-app/javascript/package.template.json b/packages/aws-cdk/lib/init-templates/v1/sample-app/javascript/package.template.json index 7594be2ffb151..43b6f94c6f314 100644 --- a/packages/aws-cdk/lib/init-templates/v1/sample-app/javascript/package.template.json +++ b/packages/aws-cdk/lib/init-templates/v1/sample-app/javascript/package.template.json @@ -10,7 +10,7 @@ "test": "jest" }, "devDependencies": { - "@aws-cdk/assert": "%cdk-version%", + "@aws-cdk/assertions": "%cdk-version%", "aws-cdk": "%cdk-version%", "jest": "^26.4.2" }, diff --git a/packages/aws-cdk/lib/init-templates/v1/sample-app/javascript/test/%name%.test.template.js b/packages/aws-cdk/lib/init-templates/v1/sample-app/javascript/test/%name%.test.template.js index 7e786e6ee3753..4e53341387c69 100644 --- a/packages/aws-cdk/lib/init-templates/v1/sample-app/javascript/test/%name%.test.template.js +++ b/packages/aws-cdk/lib/init-templates/v1/sample-app/javascript/test/%name%.test.template.js @@ -1,15 +1,17 @@ -const { expect, haveResource } = require('@aws-cdk/assert'); +const { Template, Match } = require('@aws-cdk/assertions'); const cdk = require('@aws-cdk/core'); const %name.PascalCased% = require('../lib/%name%-stack'); test('SQS Queue Created', () => { - const app = new cdk.App(); - // WHEN - const stack = new %name.PascalCased%.%name.PascalCased%Stack(app, 'MyTestStack'); - // THEN - expect(stack).to(haveResource("AWS::SQS::Queue",{ - VisibilityTimeout: 300 - })); + const app = new cdk.App(); + // WHEN + const stack = new %name.PascalCased%.%name.PascalCased%Stack(app, 'MyTestStack'); + // THEN + const template = Template.fromStack(stack); + + template.hasResourceProperties('AWS::SQS::Queue', { + VisibilityTimeout: 300 + }); }); test('SNS Topic Created', () => { @@ -17,5 +19,7 @@ test('SNS Topic Created', () => { // WHEN const stack = new %name.PascalCased%.%name.PascalCased%Stack(app, 'MyTestStack'); // THEN - expect(stack).to(haveResource("AWS::SNS::Topic")); + const template = Template.fromStack(stack); + + template.resourceCountIs('AWS::SNS::Topic', 1); }); diff --git a/packages/aws-cdk/lib/init-templates/v1/sample-app/python/requirements-dev.txt b/packages/aws-cdk/lib/init-templates/v1/sample-app/python/requirements-dev.txt new file mode 100644 index 0000000000000..927094516e657 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v1/sample-app/python/requirements-dev.txt @@ -0,0 +1 @@ +pytest==6.2.5 diff --git a/packages/aws-cdk/lib/init-templates/v1/sample-app/python/requirements.template.txt b/packages/aws-cdk/lib/init-templates/v1/sample-app/python/requirements.template.txt new file mode 100644 index 0000000000000..6c20aced0687a --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v1/sample-app/python/requirements.template.txt @@ -0,0 +1,7 @@ +aws-cdk.core==%cdk-version% +aws-cdk.aws_iam==%cdk-version% +aws-cdk.aws_sqs==%cdk-version% +aws-cdk.aws_sns==%cdk-version% +aws-cdk.aws_sns_subscriptions==%cdk-version% +aws-cdk.aws_s3==%cdk-version% +aws-cdk.assertions==%cdk-version% diff --git a/packages/aws-cdk/lib/init-templates/v1/sample-app/python/requirements.txt b/packages/aws-cdk/lib/init-templates/v1/sample-app/python/requirements.txt deleted file mode 100644 index ae60ed5f14ca8..0000000000000 --- a/packages/aws-cdk/lib/init-templates/v1/sample-app/python/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ --e . -pytest 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 deleted file mode 100644 index d79611021c860..0000000000000 --- a/packages/aws-cdk/lib/init-templates/v1/sample-app/python/setup.template.py +++ /dev/null @@ -1,48 +0,0 @@ -import setuptools - - -with open("README.md") as fp: - long_description = fp.read() - - -setuptools.setup( - name="%name.PythonModule%", - version="0.0.1", - - description="A sample CDK Python app", - long_description=long_description, - long_description_content_type="text/markdown", - - author="author", - - package_dir={"": "%name.PythonModule%"}, - packages=setuptools.find_packages(where="%name.PythonModule%"), - - install_requires=[ - "aws-cdk.core==%cdk-version%", - "aws-cdk.aws_iam==%cdk-version%", - "aws-cdk.aws_sqs==%cdk-version%", - "aws-cdk.aws_sns==%cdk-version%", - "aws-cdk.aws_sns_subscriptions==%cdk-version%", - "aws-cdk.aws_s3==%cdk-version%", - ], - - python_requires=">=3.6", - - classifiers=[ - "Development Status :: 4 - Beta", - - "Intended Audience :: Developers", - - "Programming Language :: JavaScript", - "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - - "Topic :: Software Development :: Code Generators", - "Topic :: Utilities", - - "Typing :: Typed", - ], -) diff --git a/packages/aws-cdk/lib/init-templates/v1/sample-app/python/tests/unit/test_%name.PythonModule%_stack.template.py b/packages/aws-cdk/lib/init-templates/v1/sample-app/python/tests/unit/test_%name.PythonModule%_stack.template.py index 182d07fe09855..99a6a26b4a15e 100644 --- a/packages/aws-cdk/lib/init-templates/v1/sample-app/python/tests/unit/test_%name.PythonModule%_stack.template.py +++ b/packages/aws-cdk/lib/init-templates/v1/sample-app/python/tests/unit/test_%name.PythonModule%_stack.template.py @@ -1,19 +1,24 @@ -import json -import pytest +from aws_cdk import ( + core, + assertions + ) -from aws_cdk import core from %name.PythonModule%.%name.PythonModule%_stack import %name.PascalCased%Stack -def get_template(): +def test_sqs_queue_created(): app = core.App() - %name.PascalCased%Stack(app, "%name.StackName%") - return json.dumps(app.synth().get_stack("%name.StackName%").template) - + stack = %name.PascalCased%Stack(app, "%name.StackName%") + template = assertions.Template.from_stack(stack) -def test_sqs_queue_created(): - assert("AWS::SQS::Queue" in get_template()) + template.has_resource_properties("AWS::SQS::Queue", { + "VisibilityTimeout": 300 + }) def test_sns_topic_created(): - assert("AWS::SNS::Topic" in get_template()) + app = core.App() + stack = %name.PascalCased%Stack(app, "%name.StackName%") + template = assertions.Template.from_stack(stack) + + template.resource_count_is("AWS::SNS::Topic", 1) diff --git a/packages/aws-cdk/lib/init-templates/v1/sample-app/typescript/package.template.json b/packages/aws-cdk/lib/init-templates/v1/sample-app/typescript/package.template.json index 98942aa31c167..550691f4eb2c5 100644 --- a/packages/aws-cdk/lib/init-templates/v1/sample-app/typescript/package.template.json +++ b/packages/aws-cdk/lib/init-templates/v1/sample-app/typescript/package.template.json @@ -12,7 +12,7 @@ }, "devDependencies": { "aws-cdk": "%cdk-version%", - "@aws-cdk/assert": "%cdk-version%", + "@aws-cdk/assertions": "%cdk-version%", "@types/jest": "^26.0.10", "@types/node": "10.17.27", "jest": "^26.4.2", diff --git a/packages/aws-cdk/lib/init-templates/v1/sample-app/typescript/test/%name%.test.template.ts b/packages/aws-cdk/lib/init-templates/v1/sample-app/typescript/test/%name%.test.template.ts index 3a602380d6f6d..45cd6cca71ba4 100644 --- a/packages/aws-cdk/lib/init-templates/v1/sample-app/typescript/test/%name%.test.template.ts +++ b/packages/aws-cdk/lib/init-templates/v1/sample-app/typescript/test/%name%.test.template.ts @@ -1,15 +1,17 @@ -import { expect as expectCDK, haveResource } from '@aws-cdk/assert'; +import { Template, Match } from '@aws-cdk/assertions'; import * as cdk from '@aws-cdk/core'; import * as %name.PascalCased% from '../lib/%name%-stack'; test('SQS Queue Created', () => { - const app = new cdk.App(); + const app = new cdk.App(); // WHEN - const stack = new %name.PascalCased%.%name.PascalCased%Stack(app, 'MyTestStack'); + const stack = new %name.PascalCased%.%name.PascalCased%Stack(app, 'MyTestStack'); // THEN - expectCDK(stack).to(haveResource("AWS::SQS::Queue",{ - VisibilityTimeout: 300 - })); + const template = Template.fromStack(stack); + + template.hasResourceProperties('AWS::SQS::Queue', { + VisibilityTimeout: 300 + }); }); test('SNS Topic Created', () => { @@ -17,5 +19,7 @@ test('SNS Topic Created', () => { // WHEN const stack = new %name.PascalCased%.%name.PascalCased%Stack(app, 'MyTestStack'); // THEN - expectCDK(stack).to(haveResource("AWS::SNS::Topic")); + const template = Template.fromStack(stack); + + template.resourceCountIs('AWS::SNS::Topic', 1); }); diff --git a/packages/aws-cdk/lib/init-templates/v2/app/go/%name%.template.go b/packages/aws-cdk/lib/init-templates/v2/app/go/%name%.template.go index 46577faef90f6..a2ab8b5d8f8fd 100644 --- a/packages/aws-cdk/lib/init-templates/v2/app/go/%name%.template.go +++ b/packages/aws-cdk/lib/init-templates/v2/app/go/%name%.template.go @@ -2,9 +2,9 @@ package main import ( "github.com/aws/aws-cdk-go/awscdk/v2" - "github.com/aws/aws-cdk-go/awscdk/v2/awssns" + // "github.com/aws/aws-cdk-go/awscdk/v2/awssqs" "github.com/aws/constructs-go/constructs/v10" - "github.com/aws/jsii-runtime-go" + // "github.com/aws/jsii-runtime-go" ) type %name.PascalCased%StackProps struct { @@ -20,10 +20,10 @@ func New%name.PascalCased%Stack(scope constructs.Construct, id string, props *%n // 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"), - }) + // example resource + // queue := awssqs.NewQueue(stack, jsii.String("%name.PascalCased%Queue"), &awssqs.QueueProps{ + // VisibilityTimeout: awscdk.Duration_Seconds(jsii.Number(300)), + // }) return stack } diff --git a/packages/aws-cdk/lib/init-templates/v2/app/go/%name%_test.template.go b/packages/aws-cdk/lib/init-templates/v2/app/go/%name%_test.template.go index 6c166d681b0ce..e1b5f2c91adcb 100644 --- a/packages/aws-cdk/lib/init-templates/v2/app/go/%name%_test.template.go +++ b/packages/aws-cdk/lib/init-templates/v2/app/go/%name%_test.template.go @@ -1,28 +1,26 @@ package main -import ( - "encoding/json" - "testing" +// import ( +// "testing" - "github.com/aws/aws-cdk-go/awscdk/v2" - "github.com/stretchr/testify/assert" - "github.com/tidwall/gjson" -) +// "github.com/aws/aws-cdk-go/awscdk/v2" +// assertions "github.com/aws/aws-cdk-go/awscdkassertionsalpha/v2" +// "github.com/aws/jsii-runtime-go" +// ) -func Test%name.PascalCased%Stack(t *testing.T) { - // GIVEN - app := awscdk.NewApp(nil) +// example tests. To run these tests, uncomment this file along with the +// example resource in %name%_test.go +// func Test%name.PascalCased%Stack(t *testing.T) { +// // GIVEN +// app := awscdk.NewApp(nil) - // WHEN - stack := New%name.PascalCased%Stack(app, "MyStack", 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) - } +// // THEN +// template := assertions.Template_FromStack(stack) - template := gjson.ParseBytes(bytes) - displayName := template.Get("Resources.MyTopic86869434.Properties.DisplayName").String() - assert.Equal(t, "MyCoolTopic", displayName) -} +// template.HasResourceProperties(jsii.String("AWS::SQS::Queue"), map[string]interface{}{ +// "VisibilityTimeout": 300, +// }) +// } diff --git a/packages/aws-cdk/lib/init-templates/v2/app/go/go.template.mod b/packages/aws-cdk/lib/init-templates/v2/app/go/go.template.mod index 50f21389478f4..3f1a4a639d1e3 100644 --- a/packages/aws-cdk/lib/init-templates/v2/app/go/go.template.mod +++ b/packages/aws-cdk/lib/init-templates/v2/app/go/go.template.mod @@ -4,10 +4,7 @@ go 1.16 require ( github.com/aws/aws-cdk-go/awscdk/v2 v%cdk-version% + github.com/aws/aws-cdk-go/awscdkassertionsalpha/v2 v%cdk-version% github.com/aws/constructs-go/constructs/v10 v10.0.5 github.com/aws/jsii-runtime-go v1.29.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/v2/app/java/pom.template.xml b/packages/aws-cdk/lib/init-templates/v2/app/java/pom.template.xml index 1d0eb742d4f8e..3173c567c1149 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 @@ -50,24 +50,18 @@ constructs ${constructs.version} - - org.junit.jupiter - junit-jupiter-api - ${junit.version} - test + software.amazon.awscdk + assertions-alpha + ${cdk.version} + test + org.junit.jupiter - junit-jupiter-engine + junit-jupiter ${junit.version} test - - org.assertj - assertj-core - 3.18.1 - test - diff --git a/packages/aws-cdk/lib/init-templates/v2/app/java/src/main/java/com/myorg/%name.PascalCased%Stack.template.java b/packages/aws-cdk/lib/init-templates/v2/app/java/src/main/java/com/myorg/%name.PascalCased%Stack.template.java index 0d8cbf10bf988..e944bde388603 100644 --- a/packages/aws-cdk/lib/init-templates/v2/app/java/src/main/java/com/myorg/%name.PascalCased%Stack.template.java +++ b/packages/aws-cdk/lib/init-templates/v2/app/java/src/main/java/com/myorg/%name.PascalCased%Stack.template.java @@ -3,6 +3,8 @@ import software.constructs.Construct; import software.amazon.awscdk.Stack; import software.amazon.awscdk.StackProps; +// import software.amazon.awscdk.Duration; +// import software.amazon.awscdk.services.sqs.Queue; public class %name.PascalCased%Stack extends Stack { public %name.PascalCased%Stack(final Construct scope, final String id) { @@ -13,5 +15,10 @@ public class %name.PascalCased%Stack extends Stack { super(scope, id, props); // The code that defines your stack goes here + + // example resource + // final Queue queue = Queue.Builder.create(this, "%name.PascalCased%Queue") + // .visibilityTimeout(Duration.seconds(300)) + // .build(); } } diff --git a/packages/aws-cdk/lib/init-templates/v2/app/java/src/test/java/com/myorg/%name.PascalCased%Test.template.java b/packages/aws-cdk/lib/init-templates/v2/app/java/src/test/java/com/myorg/%name.PascalCased%Test.template.java index 715840abd0de1..564b1682848ca 100644 --- a/packages/aws-cdk/lib/init-templates/v2/app/java/src/test/java/com/myorg/%name.PascalCased%Test.template.java +++ b/packages/aws-cdk/lib/init-templates/v2/app/java/src/test/java/com/myorg/%name.PascalCased%Test.template.java @@ -1,29 +1,26 @@ -package com.myorg; +// package com.myorg; -import software.amazon.awscdk.App; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; +// import software.amazon.awscdk.App; +// import software.amazon.awscdk.assertions.alpha.Template; +// import java.io.IOException; -import java.io.IOException; +// import java.util.HashMap; -import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; +// import org.junit.jupiter.api.Test; -public class %name.PascalCased%Test { - private final static ObjectMapper JSON = - new ObjectMapper().configure(SerializationFeature.INDENT_OUTPUT, true); +// example test. To run these tests, uncomment this file, along with the +// example resource in java/src/main/java/com/myorg/%name.PascalCased%Stack.java +// public class %name.PascalCased%Test { - @Test - public void testStack() throws IOException { - App app = new App(); - %name.PascalCased%Stack stack = new %name.PascalCased%Stack(app, "test"); +// @Test +// 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. - JsonNode actual = JSON.valueToTree(app.synth().getStackArtifact(stack.getArtifactId()).getTemplate()); +// Template template = Template.fromStack(stack); - // Update once resources have been added to the stack - assertThat(actual.get("Resources")).isNull(); - } -} +// template.hasResourceProperties("AWS::SQS::Queue", new HashMap() {{ +// put("VisibilityTimeout", 300); +// }}); +// } +// } diff --git a/packages/aws-cdk/lib/init-templates/v2/app/javascript/lib/%name%-stack.template.js b/packages/aws-cdk/lib/init-templates/v2/app/javascript/lib/%name%-stack.template.js index d5d66d9bd229e..cb7c095969484 100644 --- a/packages/aws-cdk/lib/init-templates/v2/app/javascript/lib/%name%-stack.template.js +++ b/packages/aws-cdk/lib/init-templates/v2/app/javascript/lib/%name%-stack.template.js @@ -1,4 +1,5 @@ -const { Stack } = require('aws-cdk-lib'); +const { Stack, Duration } = require('aws-cdk-lib'); +// const sqs = require('aws-cdk-lib/aws-sqs'); class %name.PascalCased%Stack extends Stack { /** @@ -11,6 +12,11 @@ class %name.PascalCased%Stack extends Stack { super(scope, id, props); // The code that defines your stack goes here + + // example resource + // const queue = new sqs.Queue(this, '%name.PascalCased%Queue', { + // visibilityTimeout: Duration.seconds(300) + // }); } } diff --git a/packages/aws-cdk/lib/init-templates/v2/app/javascript/package.template.json b/packages/aws-cdk/lib/init-templates/v2/app/javascript/package.template.json index 550e7544f9b44..3fcda877c39da 100644 --- a/packages/aws-cdk/lib/init-templates/v2/app/javascript/package.template.json +++ b/packages/aws-cdk/lib/init-templates/v2/app/javascript/package.template.json @@ -11,6 +11,7 @@ }, "devDependencies": { "aws-cdk": "%cdk-version%", + "@aws-cdk/assertions-alpha": "%cdk-version%", "jest": "^26.4.2" }, "dependencies": { 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 79db241da8e0e..874a74f5b17d8 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 @@ -1,11 +1,17 @@ -const cdk = require('aws-cdk-lib'); -const %name.PascalCased% = require('../lib/%name%-stack'); +// const cdk = require('aws-cdk-lib'); +// const { Template } = require('@aws-cdk/assertions-alpha'); +// const %name.PascalCased% = require('../lib/%name%-stack'); -test('Empty Stack', () => { - const app = new cdk.App(); - // WHEN - const stack = new %name.PascalCased%.%name.PascalCased%Stack(app, 'MyTestStack'); - // THEN - const actual = app.synth().getStackArtifact(stack.artifactId).template; - expect(actual.Resources || {}).toEqual({}); +// example test. To run these tests, uncomment this file along with the +// example resource in lib/%name%-stack.js +test('SQS Queue Created', () => { +// const app = new cdk.App(); +// // WHEN +// const stack = new %name.PascalCased%.%name.PascalCased%Stack(app, 'MyTestStack'); +// // THEN +// const template = Template.fromStack(stack); + +// template.hasResourceProperties('AWS::SQS::Queue', { +// VisibilityTimeout: 300 +// }); }); 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 4599c4f6e19f6..b93133ce944cf 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,8 @@ -from aws_cdk import Stack +from aws_cdk import ( + # Duration, + Stack, + # aws_sqs as sqs, +) from constructs import Construct class %name.PascalCased%Stack(Stack): @@ -7,3 +11,9 @@ def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) # The code that defines your stack goes here + + # example resource + # queue = sqs.Queue( + # self, "%name.PascalCased%Queue", + # visibility_timeout=Duration.seconds(300), + # ) diff --git a/packages/aws-cdk/lib/init-templates/v2/app/python/requirements-dev.txt b/packages/aws-cdk/lib/init-templates/v2/app/python/requirements-dev.txt new file mode 100644 index 0000000000000..927094516e657 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v2/app/python/requirements-dev.txt @@ -0,0 +1 @@ +pytest==6.2.5 diff --git a/packages/aws-cdk/lib/init-templates/v2/app/python/requirements.template.txt b/packages/aws-cdk/lib/init-templates/v2/app/python/requirements.template.txt new file mode 100644 index 0000000000000..f8d8c52349751 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v2/app/python/requirements.template.txt @@ -0,0 +1,3 @@ +aws-cdk-lib==%cdk-version% +aws-cdk.assertions-alpha==%cdk-version% +constructs%constructs-version% diff --git a/packages/aws-cdk/lib/init-templates/v2/app/python/requirements.txt b/packages/aws-cdk/lib/init-templates/v2/app/python/requirements.txt deleted file mode 100644 index d6e1198b1ab1f..0000000000000 --- a/packages/aws-cdk/lib/init-templates/v2/app/python/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . 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 deleted file mode 100644 index d819a7bcadb77..0000000000000 --- a/packages/aws-cdk/lib/init-templates/v2/app/python/setup.template.py +++ /dev/null @@ -1,44 +0,0 @@ -import setuptools - - -with open("README.md") as fp: - long_description = fp.read() - - -setuptools.setup( - name="%name.PythonModule%", - version="0.0.1", - - description="An empty CDK Python app", - long_description=long_description, - long_description_content_type="text/markdown", - - author="author", - - package_dir={"": "%name.PythonModule%"}, - packages=setuptools.find_packages(where="%name.PythonModule%"), - - install_requires=[ - "aws-cdk-lib==%cdk-version%", - "constructs%constructs-version%", - ], - - python_requires=">=3.6", - - classifiers=[ - "Development Status :: 4 - Beta", - - "Intended Audience :: Developers", - - "Programming Language :: JavaScript", - "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - - "Topic :: Software Development :: Code Generators", - "Topic :: Utilities", - - "Typing :: Typed", - ], -) diff --git a/packages/aws-cdk/lib/init-templates/v2/app/python/tests/__init__.py b/packages/aws-cdk/lib/init-templates/v2/app/python/tests/__init__.py new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/aws-cdk/lib/init-templates/v2/app/python/tests/unit/__init__.py b/packages/aws-cdk/lib/init-templates/v2/app/python/tests/unit/__init__.py new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/aws-cdk/lib/init-templates/v2/app/python/tests/unit/test_%name.PythonModule%_stack.template.py b/packages/aws-cdk/lib/init-templates/v2/app/python/tests/unit/test_%name.PythonModule%_stack.template.py new file mode 100644 index 0000000000000..19c612a3da691 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v2/app/python/tests/unit/test_%name.PythonModule%_stack.template.py @@ -0,0 +1,15 @@ +# import aws_cdk as core +# import aws_cdk.assertions_alpha as assertions + +# from %name.PythonModule%.%name.PythonModule%_stack import %name.PascalCased%Stack + +# example tests. To run these tests, uncomment this file along with the example +# resource in %name.PythonModule%/%name.PythonModule%_stack.py +# def test_sqs_queue_created(): +# app = core.App() +# stack = %name.PascalCased%Stack(app, "%name.StackName%") +# template = assertions.Template.from_stack(stack) + +# template.has_resource_properties("AWS::SQS::Queue", { +# "VisibilityTimeout": 300 +# }) diff --git a/packages/aws-cdk/lib/init-templates/v2/app/typescript/lib/%name%-stack.template.ts b/packages/aws-cdk/lib/init-templates/v2/app/typescript/lib/%name%-stack.template.ts index 82d70c083134e..3d6c54bd3dca2 100644 --- a/packages/aws-cdk/lib/init-templates/v2/app/typescript/lib/%name%-stack.template.ts +++ b/packages/aws-cdk/lib/init-templates/v2/app/typescript/lib/%name%-stack.template.ts @@ -1,10 +1,16 @@ import { Stack, StackProps } from 'aws-cdk-lib'; import { Construct } from 'constructs'; +// import * as sqs from 'aws-cdk-lib/aws-sqs'; export class %name.PascalCased%Stack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); // The code that defines your stack goes here + + // example resource + // const queue = new sqs.Queue(this, '%name.PascalCased%Queue', { + // visibilityTimeout: cdk.Duration.seconds(300) + // }); } } diff --git a/packages/aws-cdk/lib/init-templates/v2/app/typescript/package.template.json b/packages/aws-cdk/lib/init-templates/v2/app/typescript/package.template.json index a599c63f6ec35..9f6f0d47cade9 100644 --- a/packages/aws-cdk/lib/init-templates/v2/app/typescript/package.template.json +++ b/packages/aws-cdk/lib/init-templates/v2/app/typescript/package.template.json @@ -11,6 +11,7 @@ "cdk": "cdk" }, "devDependencies": { + "@aws-cdk/assertions-alpha": "%cdk-version%", "@types/jest": "^26.0.10", "@types/node": "10.17.27", "jest": "^26.4.2", 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 a2542902315c8..61e6e96d0dcab 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 @@ -1,11 +1,17 @@ -import * as cdk from 'aws-cdk-lib'; -import * as %name.PascalCased% from '../lib/%name%-stack'; +// import * as cdk from 'aws-cdk-lib'; +// import { Template } from '@aws-cdk/assertions-alpha'; +// import * as %name.PascalCased% from '../lib/%name%-stack'; -test('Empty Stack', () => { - const app = new cdk.App(); - // WHEN - const stack = new %name.PascalCased%.%name.PascalCased%Stack(app, 'MyTestStack'); - // THEN - const actual = app.synth().getStackArtifact(stack.artifactId).template; - expect(actual.Resources ?? {}).toEqual({}); +// example test. To run these tests, uncomment this file along with the +// example resource in lib/%name%-stack.ts +test('SQS Queue Created', () => { +// const app = new cdk.App(); +// // WHEN +// const stack = new %name.PascalCased%.%name.PascalCased%Stack(app, 'MyTestStack'); +// // THEN +// const template = Template.fromStack(stack); + +// template.hasResourceProperties('AWS::SQS::Queue', { +// VisibilityTimeout: 300 +// }); }); diff --git a/packages/aws-cdk/lib/init-templates/v2/lib/typescript/lib/index.template.ts b/packages/aws-cdk/lib/init-templates/v2/lib/typescript/lib/index.template.ts index 3c48194882c3d..bbd6f13d470bd 100644 --- a/packages/aws-cdk/lib/init-templates/v2/lib/typescript/lib/index.template.ts +++ b/packages/aws-cdk/lib/init-templates/v2/lib/typescript/lib/index.template.ts @@ -1,4 +1,5 @@ import { Construct } from 'constructs'; +// import * as sqs from 'aws-cdk-lib/aws-sqs'; export interface %name.PascalCased%Props { // Define construct properties here @@ -10,5 +11,10 @@ export class %name.PascalCased% extends Construct { super(scope, id); // Define construct contents here + + // example resource + // const queue = new sqs.Queue(this, '%name.PascalCased%Queue', { + // visibilityTimeout: cdk.Duration.seconds(300) + // }); } } diff --git a/packages/aws-cdk/lib/init-templates/v2/lib/typescript/package.template.json b/packages/aws-cdk/lib/init-templates/v2/lib/typescript/package.template.json index b388f5270b769..59211fe81715c 100644 --- a/packages/aws-cdk/lib/init-templates/v2/lib/typescript/package.template.json +++ b/packages/aws-cdk/lib/init-templates/v2/lib/typescript/package.template.json @@ -12,6 +12,7 @@ "@types/jest": "^26.0.10", "@types/node": "10.17.27", "aws-cdk-lib": "%cdk-version%", + "@aws-cdk/assertions-alpha": "%cdk-version%", "constructs": "%constructs-version%", "jest": "^26.4.2", "ts-jest": "^26.2.0", 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 0aa210d01ae5c..f7200d5dd5cc9 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 @@ -1,12 +1,18 @@ -import * as cdk from 'aws-cdk-lib'; -import * as %name.PascalCased% from '../lib/index'; +// import * as cdk from 'aws-cdk-lib'; +// import { Template } from '@aws-cdk/assertions-alpha'; +// import * as %name.PascalCased% from '../lib/index'; -test('Empty Stack', () => { - const app = new cdk.App(); - const stack = new cdk.Stack(app, "TestStack"); - // WHEN - new %name.PascalCased%.%name.PascalCased%(stack, 'MyTestConstruct'); - // THEN - const actual = app.synth().getStackArtifact(stack.artifactId).template; - expect(actual.Resources ?? {}).toEqual({}); +// example test. To run these tests, uncomment this file along with the +// example resource in lib/index.ts +test('SQS Queue Created', () => { +// const app = new cdk.App(); +// const stack = new cdk.Stack(app, "TestStack"); +// // WHEN +// new %name.PascalCased%.%name.PascalCased%(stack, 'MyTestConstruct'); +// // THEN +// const template = Template.fromStack(stack); + +// template.hasResourceProperties('AWS::SQS::Queue', { +// VisibilityTimeout: 300 +// }); }); diff --git a/packages/aws-cdk/lib/init-templates/v2/sample-app/go/%name%.template.go b/packages/aws-cdk/lib/init-templates/v2/sample-app/go/%name%.template.go new file mode 100644 index 0000000000000..1ae8249703373 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v2/sample-app/go/%name%.template.go @@ -0,0 +1,71 @@ +package main + +import ( + "github.com/aws/aws-cdk-go/awscdk/v2" + "github.com/aws/aws-cdk-go/awscdk/v2/awssns" + "github.com/aws/aws-cdk-go/awscdk/v2/awssnssubscriptions" + "github.com/aws/aws-cdk-go/awscdk/v2/awssqs" + "github.com/aws/constructs-go/constructs/v10" + "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) + + + queue := awssqs.NewQueue(stack, jsii.String("%name.PascalCased%Queue"), &awssqs.QueueProps{ + VisibilityTimeout: awscdk.Duration_Seconds(jsii.Number(300)), + }) + + topic := awssns.NewTopic(stack, jsii.String("%name.PascalCased%Topic"), &awssns.TopicProps{}) + topic.AddSubscription(awssnssubscriptions.NewSqsSubscription(queue, &awssnssubscriptions.SqsSubscriptionProps{})) + + 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/v2/sample-app/go/%name%_test.template.go b/packages/aws-cdk/lib/init-templates/v2/sample-app/go/%name%_test.template.go new file mode 100644 index 0000000000000..53b15a49266d1 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v2/sample-app/go/%name%_test.template.go @@ -0,0 +1,25 @@ +package main + +import ( + "testing" + + "github.com/aws/aws-cdk-go/awscdk/v2" + assertions "github.com/aws/aws-cdk-go/awscdkassertionsalpha/v2" + "github.com/aws/jsii-runtime-go" +) + +func Test%name.PascalCased%Stack(t *testing.T) { + // GIVEN + app := awscdk.NewApp(nil) + + // WHEN + stack := New%name.PascalCased%Stack(app, "MyStack", nil) + + // THEN + template := assertions.Template_FromStack(stack) + + template.HasResourceProperties(jsii.String("AWS::SQS::Queue"), map[string]interface{}{ + "VisibilityTimeout": 300, + }) + template.ResourceCountIs(jsii.String("AWS::SNS::Topic"), jsii.Number(1)) +} diff --git a/packages/aws-cdk/lib/init-templates/v2/sample-app/go/.template.gitignore b/packages/aws-cdk/lib/init-templates/v2/sample-app/go/.template.gitignore new file mode 100644 index 0000000000000..92fe1ec34b4b6 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v2/sample-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/v2/sample-app/go/README.md b/packages/aws-cdk/lib/init-templates/v2/sample-app/go/README.md new file mode 100644 index 0000000000000..9b8d4b29f26e3 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v2/sample-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/v2/sample-app/go/cdk.template.json b/packages/aws-cdk/lib/init-templates/v2/sample-app/go/cdk.template.json new file mode 100644 index 0000000000000..ad88cd7ef75f3 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v2/sample-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/v2/sample-app/go/go.template.mod b/packages/aws-cdk/lib/init-templates/v2/sample-app/go/go.template.mod new file mode 100644 index 0000000000000..3f1a4a639d1e3 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v2/sample-app/go/go.template.mod @@ -0,0 +1,10 @@ +module %name% + +go 1.16 + +require ( + github.com/aws/aws-cdk-go/awscdk/v2 v%cdk-version% + github.com/aws/aws-cdk-go/awscdkassertionsalpha/v2 v%cdk-version% + github.com/aws/constructs-go/constructs/v10 v10.0.5 + github.com/aws/jsii-runtime-go v1.29.0 +) 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 79c769157ceee..78217b2650669 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 @@ -44,24 +44,18 @@ constructs ${constructs.version} - - org.junit.jupiter - junit-jupiter-api - ${junit.version} - test + software.amazon.awscdk + assertions-alpha + ${cdk.version} + test + org.junit.jupiter - junit-jupiter-engine + junit-jupiter ${junit.version} test - - org.assertj - assertj-core - 3.18.1 - test - diff --git a/packages/aws-cdk/lib/init-templates/v2/sample-app/java/src/test/java/com/myorg/%name.PascalCased%StackTest.template.java b/packages/aws-cdk/lib/init-templates/v2/sample-app/java/src/test/java/com/myorg/%name.PascalCased%StackTest.template.java index a6f7c4f4590b4..1cd39ad8da3bb 100644 --- a/packages/aws-cdk/lib/init-templates/v2/sample-app/java/src/test/java/com/myorg/%name.PascalCased%StackTest.template.java +++ b/packages/aws-cdk/lib/init-templates/v2/sample-app/java/src/test/java/com/myorg/%name.PascalCased%StackTest.template.java @@ -1,27 +1,27 @@ package com.myorg; import software.amazon.awscdk.App; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; +import software.amazon.awscdk.assertions.alpha.Template; +import software.amazon.awscdk.assertions.alpha.Match; import java.io.IOException; +import java.util.HashMap; + import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; public class %name.PascalCased%StackTest { - private final static ObjectMapper JSON = - new ObjectMapper().configure(SerializationFeature.INDENT_OUTPUT, true); @Test public void testStack() throws IOException { App app = new App(); %name.PascalCased%Stack stack = new %name.PascalCased%Stack(app, "test"); - JsonNode actual = JSON.valueToTree(app.synth().getStackArtifact(stack.getArtifactId()).getTemplate()); + Template template = Template.fromStack(stack); + + template.hasResourceProperties("AWS::SQS::Queue", new HashMap() {{ + put("VisibilityTimeout", 300); + }}); - assertThat(actual.toString()) - .contains("AWS::SQS::Queue") - .contains("AWS::SNS::Topic"); + template.resourceCountIs("AWS::SNS::Topic", 1); } } diff --git a/packages/aws-cdk/lib/init-templates/v2/sample-app/javascript/package.template.json b/packages/aws-cdk/lib/init-templates/v2/sample-app/javascript/package.template.json index 550e7544f9b44..3fcda877c39da 100644 --- a/packages/aws-cdk/lib/init-templates/v2/sample-app/javascript/package.template.json +++ b/packages/aws-cdk/lib/init-templates/v2/sample-app/javascript/package.template.json @@ -11,6 +11,7 @@ }, "devDependencies": { "aws-cdk": "%cdk-version%", + "@aws-cdk/assertions-alpha": "%cdk-version%", "jest": "^26.4.2" }, "dependencies": { diff --git a/packages/aws-cdk/lib/init-templates/v2/sample-app/javascript/test/%name%.test.template.js b/packages/aws-cdk/lib/init-templates/v2/sample-app/javascript/test/%name%.test.template.js index b741d4045225b..93294bf407633 100644 --- a/packages/aws-cdk/lib/init-templates/v2/sample-app/javascript/test/%name%.test.template.js +++ b/packages/aws-cdk/lib/init-templates/v2/sample-app/javascript/test/%name%.test.template.js @@ -1,12 +1,16 @@ const cdk = require('aws-cdk-lib'); +const { Template, Match } = require('@aws-cdk/assertions-alpha'); const %name.PascalCased% = require('../lib/%name%-stack'); test('SQS Queue and SNS Topic Created', () => { - const app = new cdk.App(); - // WHEN - const stack = new %name.PascalCased%.%name.PascalCased%Stack(app, 'MyTestStack'); - // THEN - const actual = JSON.stringify(app.synth().getStackArtifact(stack.artifactId).template); - expect(actual).toContain('AWS::SQS::Queue'); - expect(actual).toContain('AWS::SNS::Topic'); + const app = new cdk.App(); + // WHEN + const stack = new %name.PascalCased%.%name.PascalCased%Stack(app, 'MyTestStack'); + // THEN + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::SQS::Queue', { + VisibilityTimeout: 300, + }); + + template.resourceCountIs('AWS::SNS::Topic', 1); }); diff --git a/packages/aws-cdk/lib/init-templates/v2/sample-app/python/requirements-dev.txt b/packages/aws-cdk/lib/init-templates/v2/sample-app/python/requirements-dev.txt new file mode 100644 index 0000000000000..927094516e657 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v2/sample-app/python/requirements-dev.txt @@ -0,0 +1 @@ +pytest==6.2.5 diff --git a/packages/aws-cdk/lib/init-templates/v2/sample-app/python/requirements.template.txt b/packages/aws-cdk/lib/init-templates/v2/sample-app/python/requirements.template.txt new file mode 100644 index 0000000000000..f8d8c52349751 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/v2/sample-app/python/requirements.template.txt @@ -0,0 +1,3 @@ +aws-cdk-lib==%cdk-version% +aws-cdk.assertions-alpha==%cdk-version% +constructs%constructs-version% diff --git a/packages/aws-cdk/lib/init-templates/v2/sample-app/python/requirements.txt b/packages/aws-cdk/lib/init-templates/v2/sample-app/python/requirements.txt deleted file mode 100644 index ae60ed5f14ca8..0000000000000 --- a/packages/aws-cdk/lib/init-templates/v2/sample-app/python/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ --e . -pytest 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 deleted file mode 100644 index f9eb461178472..0000000000000 --- a/packages/aws-cdk/lib/init-templates/v2/sample-app/python/setup.template.py +++ /dev/null @@ -1,44 +0,0 @@ -import setuptools - - -with open("README.md") as fp: - long_description = fp.read() - - -setuptools.setup( - name="%name.PythonModule%", - version="0.0.1", - - description="A sample CDK Python app", - long_description=long_description, - long_description_content_type="text/markdown", - - author="author", - - package_dir={"": "%name.PythonModule%"}, - packages=setuptools.find_packages(where="%name.PythonModule%"), - - install_requires=[ - "aws-cdk-lib==%cdk-version%", - "constructs%constructs-version%", - ], - - python_requires=">=3.6", - - classifiers=[ - "Development Status :: 4 - Beta", - - "Intended Audience :: Developers", - - "Programming Language :: JavaScript", - "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - - "Topic :: Software Development :: Code Generators", - "Topic :: Utilities", - - "Typing :: Typed", - ], -) diff --git a/packages/aws-cdk/lib/init-templates/v2/sample-app/python/tests/unit/test_%name.PythonModule%_stack.template.py b/packages/aws-cdk/lib/init-templates/v2/sample-app/python/tests/unit/test_%name.PythonModule%_stack.template.py index b51a164ff8c5e..50632eb42dae6 100644 --- a/packages/aws-cdk/lib/init-templates/v2/sample-app/python/tests/unit/test_%name.PythonModule%_stack.template.py +++ b/packages/aws-cdk/lib/init-templates/v2/sample-app/python/tests/unit/test_%name.PythonModule%_stack.template.py @@ -1,19 +1,21 @@ -import json -import pytest - -import aws_cdk_lib as core +import aws_cdk as core +import aws_cdk.assertions_alpha as assertions from %name.PythonModule%.%name.PythonModule%_stack import %name.PascalCased%Stack -def get_template(): +def test_sqs_queue_created(): app = core.App() - %name.PascalCased%Stack(app, "%name.StackName%") - return json.dumps(app.synth().get_stack("%name.StackName%").template) - + stack = %name.PascalCased%Stack(app, "%name.StackName%") + template = assertions.Template.from_stack(stack) -def test_sqs_queue_created(): - assert("AWS::SQS::Queue" in get_template()) + template.has_resource_properties("AWS::SQS::Queue", { + "VisibilityTimeout": 300 + }) def test_sns_topic_created(): - assert("AWS::SNS::Topic" in get_template()) + app = core.App() + stack = %name.PascalCased%Stack(app, "%name.StackName%") + template = assertions.Template.from_stack(stack) + + template.resource_count_is("AWS::SNS::Topic", 1) diff --git a/packages/aws-cdk/lib/init-templates/v2/sample-app/typescript/package.template.json b/packages/aws-cdk/lib/init-templates/v2/sample-app/typescript/package.template.json index d4d76c656ba2e..20e4c3829d597 100644 --- a/packages/aws-cdk/lib/init-templates/v2/sample-app/typescript/package.template.json +++ b/packages/aws-cdk/lib/init-templates/v2/sample-app/typescript/package.template.json @@ -12,6 +12,7 @@ }, "devDependencies": { "aws-cdk": "%cdk-version%", + "@aws-cdk/assertions-alpha": "%cdk-version%", "@types/jest": "^26.0.10", "@types/node": "10.17.27", "jest": "^26.4.2", diff --git a/packages/aws-cdk/lib/init-templates/v2/sample-app/typescript/test/%name%.test.template.ts b/packages/aws-cdk/lib/init-templates/v2/sample-app/typescript/test/%name%.test.template.ts index a563f50309295..5cfaa87ab2ce5 100644 --- a/packages/aws-cdk/lib/init-templates/v2/sample-app/typescript/test/%name%.test.template.ts +++ b/packages/aws-cdk/lib/init-templates/v2/sample-app/typescript/test/%name%.test.template.ts @@ -1,12 +1,17 @@ import * as cdk from 'aws-cdk-lib'; +import { Template, Match } from '@aws-cdk/assertions-alpha'; import * as %name.PascalCased% from '../lib/%name%-stack'; test('SQS Queue and SNS Topic Created', () => { - const app = new cdk.App(); - // WHEN - const stack = new %name.PascalCased%.%name.PascalCased%Stack(app, 'MyTestStack'); - // THEN - const actual = JSON.stringify(app.synth().getStackArtifact(stack.artifactId).template); - expect(actual).toContain('AWS::SQS::Queue'); - expect(actual).toContain('AWS::SNS::Topic'); + const app = new cdk.App(); + // WHEN + const stack = new %name.PascalCased%.%name.PascalCased%Stack(app, 'MyTestStack'); + // THEN + + const template = Template.fromStack(stack); + + template.hasResourceProperties('AWS::SQS::Queue', { + VisibilityTimeout: 300 + }); + template.resourceCountIs('AWS::SNS::Topic', 1); }); diff --git a/packages/aws-cdk/lib/settings.ts b/packages/aws-cdk/lib/settings.ts index 4bfafd447d607..6182ecc26e0c3 100644 --- a/packages/aws-cdk/lib/settings.ts +++ b/packages/aws-cdk/lib/settings.ts @@ -113,6 +113,10 @@ export class Configuration { const readUserContext = this.props.readUserContext ?? true; + if (userConfig.get(['build'])) { + throw new Error('The `build` key cannot be specified in the user config (~/.cdk.json), specify it in the project config (cdk.json) instead'); + } + const contextSources = [ this.commandLineContext, this.projectConfig.subSettings([CONTEXT_KEY]).makeReadOnly(), diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index 4492f92549b45..40fa126a94cb4 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -41,13 +41,13 @@ "@octokit/rest": "^18.12.0", "@types/archiver": "^5.3.0", "@types/fs-extra": "^8.1.2", - "@types/glob": "^7.1.4", + "@types/glob": "^7.2.0", "@types/jest": "^26.0.24", "@types/minimatch": "^3.0.5", "@types/mockery": "^1.4.30", "@types/node": "^10.17.60", "@types/promptly": "^3.0.2", - "@types/semver": "^7.3.8", + "@types/semver": "^7.3.9", "@types/sinon": "^9.0.11", "@types/table": "^6.0.0", "@types/uuid": "^8.3.1", @@ -59,7 +59,7 @@ "jest": "^26.6.3", "make-runnable": "^1.3.10", "mockery": "^2.1.0", - "nock": "^13.1.3", + "nock": "^13.1.4", "@aws-cdk/pkglint": "0.0.0", "sinon": "^9.2.4", "ts-jest": "^26.5.6", @@ -71,11 +71,12 @@ "@aws-cdk/cloudformation-diff": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/region-info": "0.0.0", - "@jsii/check-node": "1.40.0", + "@jsii/check-node": "1.42.0", "archiver": "^5.3.0", "aws-sdk": "^2.979.0", "camelcase": "^6.2.0", "cdk-assets": "0.0.0", + "chokidar": "^3.5.2", "colors": "^1.4.0", "decamelize": "^5.0.1", "fs-extra": "^9.1.0", diff --git a/packages/aws-cdk/test/api/deploy-stack.test.ts b/packages/aws-cdk/test/api/deploy-stack.test.ts index 13e4640ff01ec..4770e2ad9528f 100644 --- a/packages/aws-cdk/test/api/deploy-stack.test.ts +++ b/packages/aws-cdk/test/api/deploy-stack.test.ts @@ -98,7 +98,7 @@ test("does not call tryHotswapDeployment() if 'hotswap' is false", async () => { expect(tryHotswapDeployment).not.toHaveBeenCalled(); }); -test("rollback defaults to disabled if 'hotswap' is true", async () => { +test("rollback still defaults to enabled even if 'hotswap' is enabled", async () => { // WHEN await deployStack({ ...standardDeployStackArguments(), @@ -107,7 +107,7 @@ test("rollback defaults to disabled if 'hotswap' is true", async () => { }); // THEN - expect(cfnMocks.executeChangeSet).toHaveBeenCalledWith(expect.objectContaining({ + expect(cfnMocks.executeChangeSet).not.toHaveBeenCalledWith(expect.objectContaining({ DisableRollback: true, })); }); diff --git a/packages/aws-cdk/test/api/exec.test.ts b/packages/aws-cdk/test/api/exec.test.ts index d2e65907527fa..b9c5637acce1a 100644 --- a/packages/aws-cdk/test/api/exec.test.ts +++ b/packages/aws-cdk/test/api/exec.test.ts @@ -137,7 +137,7 @@ test('the application set in --app is executed', async () => { // GIVEN config.settings.set(['app'], 'cloud-executable'); mockSpawn({ - commandLine: ['cloud-executable'], + commandLine: 'cloud-executable', sideEffect: () => writeOutputAssembly(), }); @@ -149,7 +149,7 @@ test('the application set in --app is executed as-is if it contains a filename t // GIVEN config.settings.set(['app'], 'does-not-exist'); mockSpawn({ - commandLine: ['does-not-exist'], + commandLine: 'does-not-exist', sideEffect: () => writeOutputAssembly(), }); @@ -161,7 +161,7 @@ test('the application set in --app is executed with arguments', async () => { // GIVEN config.settings.set(['app'], 'cloud-executable an-arg'); mockSpawn({ - commandLine: ['cloud-executable', 'an-arg'], + commandLine: 'cloud-executable an-arg', sideEffect: () => writeOutputAssembly(), }); @@ -174,7 +174,7 @@ test('application set in --app as `*.js` always uses handler on windows', async sinon.stub(process, 'platform').value('win32'); config.settings.set(['app'], 'windows.js'); mockSpawn({ - commandLine: [process.execPath, 'windows.js'], + commandLine: process.execPath + ' windows.js', sideEffect: () => writeOutputAssembly(), }); @@ -186,7 +186,7 @@ test('application set in --app is `*.js` and executable', async () => { // GIVEN config.settings.set(['app'], 'executable-app.js'); mockSpawn({ - commandLine: ['executable-app.js'], + commandLine: 'executable-app.js', sideEffect: () => writeOutputAssembly(), }); @@ -194,6 +194,36 @@ test('application set in --app is `*.js` and executable', async () => { await execProgram(sdkProvider, config); }); +test('cli throws when the `build` script fails', async () => { + // GIVEN + config.settings.set(['build'], 'fake-command'); + mockSpawn({ + commandLine: 'fake-command', + exitCode: 127, + }); + + // WHEN + await expect(execProgram(sdkProvider, config)).rejects.toEqual(new Error('Subprocess exited with error 127')); +}, TEN_SECOND_TIMEOUT); + +test('cli does not throw when the `build` script succeeds', async () => { + // GIVEN + config.settings.set(['build'], 'real command'); + config.settings.set(['app'], 'executable-app.js'); + mockSpawn({ + commandLine: 'real command', // `build` key is not split on whitespace + exitCode: 0, + }, + { + commandLine: 'executable-app.js', + sideEffect: () => writeOutputAssembly(), + }); + + // WHEN + await execProgram(sdkProvider, config); +}, TEN_SECOND_TIMEOUT); + + function writeOutputAssembly() { const asm = testAssembly({ stacks: [], diff --git a/packages/aws-cdk/test/cdk-toolkit.test.ts b/packages/aws-cdk/test/cdk-toolkit.test.ts index 19276b15b7b7b..e8445da68a6b6 100644 --- a/packages/aws-cdk/test/cdk-toolkit.test.ts +++ b/packages/aws-cdk/test/cdk-toolkit.test.ts @@ -1,3 +1,52 @@ +// We need to mock the chokidar library, used by 'cdk watch' +const mockChokidarWatcherOn = jest.fn(); +const fakeChokidarWatcher = { + on: mockChokidarWatcherOn, +}; +const fakeChokidarWatcherOn = { + get readyCallback(): () => void { + expect(mockChokidarWatcherOn.mock.calls.length).toBeGreaterThanOrEqual(1); + // The call to the first 'watcher.on()' in the production code is the one we actually want here. + // This is a pretty fragile, but at least with this helper class, + // we would have to change it only in one place if it ever breaks + const firstCall = mockChokidarWatcherOn.mock.calls[0]; + // let's make sure the first argument is the 'ready' event, + // just to be double safe + expect(firstCall[0]).toBe('ready'); + // the second argument is the callback + return firstCall[1]; + }, + + get fileEventCallback(): (event: 'add' | 'addDir' | 'change' | 'unlink' | 'unlinkDir', path: string) => Promise { + expect(mockChokidarWatcherOn.mock.calls.length).toBeGreaterThanOrEqual(2); + const secondCall = mockChokidarWatcherOn.mock.calls[1]; + // let's make sure the first argument is not the 'ready' event, + // just to be double safe + expect(secondCall[0]).not.toBe('ready'); + // the second argument is the callback + return secondCall[1]; + }, +}; + +const mockChokidarWatch = jest.fn(); +jest.mock('chokidar', () => ({ + watch: mockChokidarWatch, +})); +const fakeChokidarWatch = { + get includeArgs(): string[] { + expect(mockChokidarWatch.mock.calls.length).toBe(1); + // the include args are the first parameter to the 'watch()' call + return mockChokidarWatch.mock.calls[0][0]; + }, + + get excludeArgs(): string[] { + expect(mockChokidarWatch.mock.calls.length).toBe(1); + // the ignore args are a property of the second parameter to the 'watch()' call + const chokidarWatchOpts = mockChokidarWatch.mock.calls[0][1]; + return chokidarWatchOpts.ignored; + }, +}; + import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import * as cxapi from '@aws-cdk/cx-api'; import { Bootstrapper } from '../lib/api/bootstrap'; @@ -11,6 +60,12 @@ import { instanceMockFrom, MockCloudExecutable, TestStackArtifact } from './util let cloudExecutable: MockCloudExecutable; let bootstrapper: jest.Mocked; beforeEach(() => { + jest.resetAllMocks(); + + mockChokidarWatch.mockReturnValue(fakeChokidarWatcher); + // on() in chokidar's Watcher returns 'this' + mockChokidarWatcherOn.mockReturnValue(fakeChokidarWatcher); + bootstrapper = instanceMockFrom(Bootstrapper); bootstrapper.bootstrapEnvironment.mockResolvedValue({ noOp: false, outputs: {} } as any); @@ -191,6 +246,141 @@ describe('deploy', () => { }); }); +describe('watch', () => { + test("fails when no 'watch' settings are found", async () => { + const toolkit = defaultToolkitSetup(); + + await expect(() => { + return toolkit.watch({ selector: { patterns: [] } }); + }).rejects.toThrow("Cannot use the 'watch' command without specifying at least one directory to monitor. " + + 'Make sure to add a "watch" key to your cdk.json'); + }); + + test('observes only the root directory by default', async () => { + cloudExecutable.configuration.settings.set(['watch'], {}); + const toolkit = defaultToolkitSetup(); + + await toolkit.watch({ selector: { patterns: [] } }); + + const includeArgs = fakeChokidarWatch.includeArgs; + expect(includeArgs.length).toBe(1); + }); + + test("allows providing a single string in 'watch.include'", async () => { + cloudExecutable.configuration.settings.set(['watch'], { + include: 'my-dir', + }); + const toolkit = defaultToolkitSetup(); + + await toolkit.watch({ selector: { patterns: [] } }); + + expect(fakeChokidarWatch.includeArgs).toStrictEqual(['my-dir']); + }); + + test("allows providing an array of strings in 'watch.include'", async () => { + cloudExecutable.configuration.settings.set(['watch'], { + include: ['my-dir1', '**/my-dir2/*'], + }); + const toolkit = defaultToolkitSetup(); + + await toolkit.watch({ selector: { patterns: [] } }); + + expect(fakeChokidarWatch.includeArgs).toStrictEqual(['my-dir1', '**/my-dir2/*']); + }); + + test('ignores the output dir, dot files, dot directories, and node_modules by default', async () => { + cloudExecutable.configuration.settings.set(['watch'], {}); + cloudExecutable.configuration.settings.set(['output'], 'cdk.out'); + const toolkit = defaultToolkitSetup(); + + await toolkit.watch({ selector: { patterns: [] } }); + + expect(fakeChokidarWatch.excludeArgs).toStrictEqual([ + 'cdk.out/**', + '**/.*', + '**/.*/**', + '**/node_modules/**', + ]); + }); + + test("allows providing a single string in 'watch.exclude'", async () => { + cloudExecutable.configuration.settings.set(['watch'], { + exclude: 'my-dir', + }); + const toolkit = defaultToolkitSetup(); + + await toolkit.watch({ selector: { patterns: [] } }); + + const excludeArgs = fakeChokidarWatch.excludeArgs; + expect(excludeArgs.length).toBe(5); + expect(excludeArgs[0]).toBe('my-dir'); + }); + + test("allows providing an array of strings in 'watch.exclude'", async () => { + cloudExecutable.configuration.settings.set(['watch'], { + exclude: ['my-dir1', '**/my-dir2'], + }); + const toolkit = defaultToolkitSetup(); + + await toolkit.watch({ selector: { patterns: [] } }); + + const excludeArgs = fakeChokidarWatch.excludeArgs; + expect(excludeArgs.length).toBe(6); + expect(excludeArgs[0]).toBe('my-dir1'); + expect(excludeArgs[1]).toBe('**/my-dir2'); + }); + + describe('with file change events', () => { + let toolkit: CdkToolkit; + let cdkDeployMock: jest.Mock; + + beforeEach(async () => { + cloudExecutable.configuration.settings.set(['watch'], {}); + toolkit = defaultToolkitSetup(); + cdkDeployMock = jest.fn(); + toolkit.deploy = cdkDeployMock; + await toolkit.watch({ selector: { patterns: [] } }); + }); + + test("does not trigger a 'deploy' before the 'ready' event has fired", async () => { + await fakeChokidarWatcherOn.fileEventCallback('add', 'my-file'); + + expect(cdkDeployMock).not.toHaveBeenCalled(); + }); + + describe("when the 'ready' event has already fired", () => { + beforeEach(() => { + fakeChokidarWatcherOn.readyCallback(); + }); + + test("does trigger a 'deploy' for a file change", async () => { + await fakeChokidarWatcherOn.fileEventCallback('add', 'my-file'); + + expect(cdkDeployMock).toHaveBeenCalled(); + }); + + test("triggers a 'deploy' twice for two file changes", async () => { + await Promise.all([ + fakeChokidarWatcherOn.fileEventCallback('add', 'my-file1'), + fakeChokidarWatcherOn.fileEventCallback('change', 'my-file2'), + ]); + + expect(cdkDeployMock).toHaveBeenCalledTimes(2); + }); + + test("batches file changes that happen during 'deploy'", async () => { + await Promise.all([ + fakeChokidarWatcherOn.fileEventCallback('add', 'my-file1'), + fakeChokidarWatcherOn.fileEventCallback('change', 'my-file2'), + fakeChokidarWatcherOn.fileEventCallback('unlink', 'my-file3'), + ]); + + expect(cdkDeployMock).toHaveBeenCalledTimes(2); + }); + }); + }); +}); + describe('synth', () => { test('with no stdout option', async () => { // GIVE diff --git a/packages/aws-cdk/test/integ/cli-regression-patches/v1.130.0/NOTES.md b/packages/aws-cdk/test/integ/cli-regression-patches/v1.130.0/NOTES.md new file mode 100644 index 0000000000000..5e17983dd23b4 --- /dev/null +++ b/packages/aws-cdk/test/integ/cli-regression-patches/v1.130.0/NOTES.md @@ -0,0 +1,12 @@ +--------------------------------------- + +On november 2nd 2021, lambda started deprecating the nodejs10.x runtime. This meant we can no longer create functions with this runtime. +Our integration tests use this runtime for one of its stacks. + +This patch brings https://github.com/aws/aws-cdk/pull/17282 into the regression suite. + +---------------------------------------- + +Needs to disable an existing test due to change in bootstrap of integration tests. + +This patch brings https://github.com/aws/aws-cdk/pull/17337 into the regression suite. \ No newline at end of file diff --git a/packages/aws-cdk/test/integ/cli-regression-patches/v1.130.0/app/app.js b/packages/aws-cdk/test/integ/cli-regression-patches/v1.130.0/app/app.js new file mode 100644 index 0000000000000..f0e332eb351fa --- /dev/null +++ b/packages/aws-cdk/test/integ/cli-regression-patches/v1.130.0/app/app.js @@ -0,0 +1,378 @@ +const path = require('path'); + +var constructs = require('constructs'); +if (process.env.PACKAGE_LAYOUT_VERSION === '1') { + var cdk = require('@aws-cdk/core'); + var ec2 = require('@aws-cdk/aws-ec2'); + var ssm = require('@aws-cdk/aws-ssm'); + var iam = require('@aws-cdk/aws-iam'); + var sns = require('@aws-cdk/aws-sns'); + var lambda = require('@aws-cdk/aws-lambda'); + var docker = require('@aws-cdk/aws-ecr-assets'); +} else { + var cdk = require('aws-cdk-lib'); + var { + aws_ec2: ec2, + aws_ssm: ssm, + aws_iam: iam, + aws_sns: sns, + aws_lambda: lambda, + aws_ecr_assets: docker + } = require('aws-cdk-lib'); +} + +const { Annotations } = cdk; +const { StackWithNestedStack, StackWithNestedStackUsingParameters } = require('./nested-stack'); + +const stackPrefix = process.env.STACK_NAME_PREFIX; +if (!stackPrefix) { + throw new Error(`the STACK_NAME_PREFIX environment variable is required`); +} + +class MyStack extends cdk.Stack { + constructor(parent, id, props) { + super(parent, id, props); + new sns.Topic(this, 'topic'); + + if (cdk.AvailabilityZoneProvider) { // <= 0.34.0 + new cdk.AvailabilityZoneProvider(this).availabilityZones; + } else if (cdk.Context) { // <= 0.35.0 + cdk.Context.getAvailabilityZones(this); + } else { + this.availabilityZones; + } + + const parameterName = '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2'; + getSsmParameterValue(this, parameterName); + } +} + +function getSsmParameterValue(scope, parameterName) { + return ssm.StringParameter.valueFromLookup(scope, parameterName); +} + +class YourStack extends cdk.Stack { + constructor(parent, id, props) { + super(parent, id, props); + new sns.Topic(this, 'topic1'); + new sns.Topic(this, 'topic2'); + } +} + +class StackUsingContext extends cdk.Stack { + constructor(parent, id, props) { + super(parent, id, props); + new cdk.CfnResource(this, 'Handle', { + type: 'AWS::CloudFormation::WaitConditionHandle' + }); + + new cdk.CfnOutput(this, 'Output', { + value: this.availabilityZones, + }); + } +} + +class ParameterStack extends cdk.Stack { + constructor(parent, id, props) { + super(parent, id, props); + + new sns.Topic(this, 'TopicParameter', { + topicName: new cdk.CfnParameter(this, 'TopicNameParam').valueAsString + }); + } +} + +class OtherParameterStack extends cdk.Stack { + constructor(parent, id, props) { + super(parent, id, props); + + new sns.Topic(this, 'TopicParameter', { + topicName: new cdk.CfnParameter(this, 'OtherTopicNameParam').valueAsString + }); + } +} + +class MultiParameterStack extends cdk.Stack { + constructor(parent, id, props) { + super(parent, id, props); + + new sns.Topic(this, 'TopicParameter', { + displayName: new cdk.CfnParameter(this, 'DisplayNameParam').valueAsString + }); + new sns.Topic(this, 'OtherTopicParameter', { + displayName: new cdk.CfnParameter(this, 'OtherDisplayNameParam').valueAsString + }); + } +} + +class OutputsStack extends cdk.Stack { + constructor(parent, id, props) { + super(parent, id, props); + + const topic = new sns.Topic(this, 'MyOutput', { + topicName: `${cdk.Stack.of(this).stackName}MyTopic` + }); + + new cdk.CfnOutput(this, 'TopicName', { + value: topic.topicName + }) + } +} + +class AnotherOutputsStack extends cdk.Stack { + constructor(parent, id, props) { + super(parent, id, props); + + const topic = new sns.Topic(this, 'MyOtherOutput', { + topicName: `${cdk.Stack.of(this).stackName}MyOtherTopic` + }); + + new cdk.CfnOutput(this, 'TopicName', { + value: topic.topicName + }); + } +} + +class IamStack extends cdk.Stack { + constructor(parent, id, props) { + super(parent, id, props); + + new iam.Role(this, 'SomeRole', { + assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com') + }); + } +} + +class ProvidingStack extends cdk.Stack { + constructor(parent, id, props) { + super(parent, id, props); + + this.topic = new sns.Topic(this, 'BogusTopic'); // Some filler + } +} + +class StackWithError extends cdk.Stack { + constructor(parent, id, props) { + super(parent, id, props); + + this.topic = new sns.Topic(this, 'BogusTopic'); // Some filler + Annotations.of(this).addError('This is an error'); + } +} + +class StageWithError extends cdk.Stage { + constructor(parent, id, props) { + super(parent, id, props); + + new StackWithError(this, 'Stack'); + } +} + +class ConsumingStack extends cdk.Stack { + constructor(parent, id, props) { + super(parent, id, props); + + new sns.Topic(this, 'BogusTopic'); // Some filler + new cdk.CfnOutput(this, 'IConsumedSomething', { value: props.providingStack.topic.topicArn }); + } +} + +class MissingSSMParameterStack extends cdk.Stack { + constructor(parent, id, props) { + super(parent, id, props); + + const parameterName = constructs.Node.of(this).tryGetContext('test:ssm-parameter-name'); + if (parameterName) { + const param = getSsmParameterValue(this, parameterName); + new iam.Role(this, 'PhonyRole', { assumedBy: new iam.AccountPrincipal(param) }); + } + } +} + +class LambdaStack extends cdk.Stack { + constructor(parent, id, props) { + super(parent, id, props); + + const fn = new lambda.Function(this, 'my-function', { + code: lambda.Code.asset(path.join(__dirname, 'lambda')), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' + }); + + new cdk.CfnOutput(this, 'FunctionArn', { value: fn.functionArn }); + } +} + +class DockerStack extends cdk.Stack { + constructor(parent, id, props) { + super(parent, id, props); + + new docker.DockerImageAsset(this, 'image', { + directory: path.join(__dirname, 'docker') + }); + + // Add at least a single resource (WaitConditionHandle), otherwise this stack will never + // be deployed (and its assets never built) + new cdk.CfnResource(this, 'Handle', { + type: 'AWS::CloudFormation::WaitConditionHandle' + }); + } +} + +class DockerStackWithCustomFile extends cdk.Stack { + constructor(parent, id, props) { + super(parent, id, props); + + new docker.DockerImageAsset(this, 'image', { + directory: path.join(__dirname, 'docker'), + file: 'Dockerfile.Custom' + }); + + // Add at least a single resource (WaitConditionHandle), otherwise this stack will never + // be deployed (and its assets never built) + new cdk.CfnResource(this, 'Handle', { + type: 'AWS::CloudFormation::WaitConditionHandle' + }); + } +} + +class FailedStack extends cdk.Stack { + + constructor(parent, id, props) { + super(parent, id, props); + + // fails on 'Property PolicyDocument cannot be empty'. + new cdk.CfnResource(this, 'EmptyPolicy', { + type: 'AWS::IAM::Policy' + }) + + } + +} + +const VPC_TAG_NAME = 'custom-tag'; +const VPC_TAG_VALUE = `${stackPrefix}-bazinga!`; + +class DefineVpcStack extends cdk.Stack { + constructor(parent, id, props) { + super(parent, id, props); + + const vpc = new ec2.Vpc(this, 'VPC', { + maxAzs: 1, + }) + cdk.Aspects.of(vpc).add(new cdk.Tag(VPC_TAG_NAME, VPC_TAG_VALUE)); + } +} + +class ImportVpcStack extends cdk.Stack { + constructor(parent, id, props) { + super(parent, id, props); + + ec2.Vpc.fromLookup(this, 'DefaultVPC', { isDefault: true }); + ec2.Vpc.fromLookup(this, 'ByTag', { tags: { [VPC_TAG_NAME]: VPC_TAG_VALUE } }); + } +} + +class ConditionalResourceStack extends cdk.Stack { + constructor(parent, id, props) { + super(parent, id, props); + + if (!process.env.NO_RESOURCE) { + new iam.User(this, 'User'); + } + } +} + +class SomeStage extends cdk.Stage { + constructor(parent, id, props) { + super(parent, id, props); + + new YourStack(this, 'StackInStage'); + } +} + +class StageUsingContext extends cdk.Stage { + constructor(parent, id, props) { + super(parent, id, props); + + new StackUsingContext(this, 'StackInStage'); + } +} + +const app = new cdk.App(); + +const defaultEnv = { + account: process.env.CDK_DEFAULT_ACCOUNT, + region: process.env.CDK_DEFAULT_REGION +}; + +// Sometimes we don't want to synthesize all stacks because it will impact the results +const stackSet = process.env.INTEG_STACK_SET || 'default'; + +switch (stackSet) { + case 'default': + // Deploy all does a wildcard ${stackPrefix}-test-* + new MyStack(app, `${stackPrefix}-test-1`, { env: defaultEnv }); + new YourStack(app, `${stackPrefix}-test-2`); + // Deploy wildcard with parameters does ${stackPrefix}-param-test-* + new ParameterStack(app, `${stackPrefix}-param-test-1`); + new OtherParameterStack(app, `${stackPrefix}-param-test-2`); + // Deploy stack with multiple parameters + new MultiParameterStack(app, `${stackPrefix}-param-test-3`); + // Deploy stack with outputs does ${stackPrefix}-outputs-test-* + new OutputsStack(app, `${stackPrefix}-outputs-test-1`); + new AnotherOutputsStack(app, `${stackPrefix}-outputs-test-2`); + // Not included in wildcard + new IamStack(app, `${stackPrefix}-iam-test`, { env: defaultEnv }); + const providing = new ProvidingStack(app, `${stackPrefix}-order-providing`); + new ConsumingStack(app, `${stackPrefix}-order-consuming`, { providingStack: providing }); + + new MissingSSMParameterStack(app, `${stackPrefix}-missing-ssm-parameter`, { env: defaultEnv }); + + new LambdaStack(app, `${stackPrefix}-lambda`); + new DockerStack(app, `${stackPrefix}-docker`); + new DockerStackWithCustomFile(app, `${stackPrefix}-docker-with-custom-file`); + new FailedStack(app, `${stackPrefix}-failed`) + + if (process.env.ENABLE_VPC_TESTING) { // Gating so we don't do context fetching unless that's what we are here for + const env = { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION }; + if (process.env.ENABLE_VPC_TESTING === 'DEFINE') + new DefineVpcStack(app, `${stackPrefix}-define-vpc`, { env }); + if (process.env.ENABLE_VPC_TESTING === 'IMPORT') + new ImportVpcStack(app, `${stackPrefix}-import-vpc`, { env }); + } + + new ConditionalResourceStack(app, `${stackPrefix}-conditional-resource`) + + new StackWithNestedStack(app, `${stackPrefix}-with-nested-stack`); + new StackWithNestedStackUsingParameters(app, `${stackPrefix}-with-nested-stack-using-parameters`); + + new YourStack(app, `${stackPrefix}-termination-protection`, { + terminationProtection: process.env.TERMINATION_PROTECTION !== 'FALSE' ? true : false, + }); + + new SomeStage(app, `${stackPrefix}-stage`); + break; + + case 'stage-using-context': + // Cannot be combined with other test stacks, because we use this to test + // that stage context is propagated up and causes synth to fail when combined + // with '--no-lookups'. + + // Needs a dummy stack at the top level because the CLI will fail otherwise + new YourStack(app, `${stackPrefix}-toplevel`, { env: defaultEnv }); + new StageUsingContext(app, `${stackPrefix}-stage-using-context`, { + env: defaultEnv, + }); + break; + + case 'stage-with-errors': + const stage = new StageWithError(app, `${stackPrefix}-stage-with-errors`); + stage.synth({ validateOnSynthesis: true }); + break; + + default: + throw new Error(`Unrecognized INTEG_STACK_SET: '${stackSet}'`); +} + +app.synth(); diff --git a/packages/aws-cdk/test/integ/cli-regression-patches/v1.130.0/bootstrapping.integtest.js b/packages/aws-cdk/test/integ/cli-regression-patches/v1.130.0/bootstrapping.integtest.js new file mode 100644 index 0000000000000..5895d49ff1ad9 --- /dev/null +++ b/packages/aws-cdk/test/integ/cli-regression-patches/v1.130.0/bootstrapping.integtest.js @@ -0,0 +1,220 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const fs = require("fs"); +const path = require("path"); +const cdk_1 = require("../helpers/cdk"); +const test_helpers_1 = require("../helpers/test-helpers"); +const timeout = process.env.CODEBUILD_BUILD_ID ? // if the process is running in CodeBuild + 3600000 : // 1 hour + 600000; // 10 minutes +jest.setTimeout(timeout); +process.stdout.write(`bootstrapping.integtest.ts: Setting jest time out to ${timeout} ms`); +test_helpers_1.integTest('can bootstrap without execution', cdk_1.withDefaultFixture(async (fixture) => { + var _a; + const bootstrapStackName = fixture.bootstrapStackName; + await fixture.cdkBootstrapLegacy({ + toolkitStackName: bootstrapStackName, + noExecute: true, + }); + const resp = await fixture.aws.cloudFormation('describeStacks', { + StackName: bootstrapStackName, + }); + expect((_a = resp.Stacks) === null || _a === void 0 ? void 0 : _a[0].StackStatus).toEqual('REVIEW_IN_PROGRESS'); +})); +test_helpers_1.integTest('upgrade legacy bootstrap stack to new bootstrap stack while in use', cdk_1.withDefaultFixture(async (fixture) => { + const bootstrapStackName = fixture.bootstrapStackName; + const legacyBootstrapBucketName = `aws-cdk-bootstrap-integ-test-legacy-bckt-${cdk_1.randomString()}`; + const newBootstrapBucketName = `aws-cdk-bootstrap-integ-test-v2-bckt-${cdk_1.randomString()}`; + fixture.rememberToDeleteBucket(legacyBootstrapBucketName); // This one will leak + 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.cdkBootstrapLegacy({ + toolkitStackName: bootstrapStackName, + bootstrapBucketName: legacyBootstrapBucketName, + }); + // Deploy stack that uses file assets + await fixture.cdkDeploy('lambda', { + options: ['--toolkit-stack-name', bootstrapStackName], + }); + // Upgrade bootstrap stack to "new" style + await fixture.cdkBootstrapModern({ + toolkitStackName: bootstrapStackName, + bootstrapBucketName: newBootstrapBucketName, + cfnExecutionPolicy: 'arn:aws:iam::aws:policy/AdministratorAccess', + }); + // (Force) deploy stack again + // --force to bypass the check which says that the template hasn't changed. + await fixture.cdkDeploy('lambda', { + options: [ + '--toolkit-stack-name', bootstrapStackName, + '--force', + ], + }); +})); +test_helpers_1.integTest('can and deploy if omitting execution policies', cdk_1.withDefaultFixture(async (fixture) => { + const bootstrapStackName = fixture.bootstrapStackName; + await fixture.cdkBootstrapModern({ + toolkitStackName: bootstrapStackName, + }); + // Deploy stack that uses file assets + await fixture.cdkDeploy('lambda', { + options: [ + '--toolkit-stack-name', bootstrapStackName, + '--context', `@aws-cdk/core:bootstrapQualifier=${fixture.qualifier}`, + '--context', '@aws-cdk/core:newStyleStackSynthesis=1', + ], + }); +})); +test_helpers_1.integTest('deploy new style synthesis to new style bootstrap', cdk_1.withDefaultFixture(async (fixture) => { + const bootstrapStackName = fixture.bootstrapStackName; + await fixture.cdkBootstrapModern({ + toolkitStackName: bootstrapStackName, + cfnExecutionPolicy: 'arn:aws:iam::aws:policy/AdministratorAccess', + }); + // Deploy stack that uses file assets + await fixture.cdkDeploy('lambda', { + options: [ + '--toolkit-stack-name', bootstrapStackName, + '--context', `@aws-cdk/core:bootstrapQualifier=${fixture.qualifier}`, + '--context', '@aws-cdk/core:newStyleStackSynthesis=1', + ], + }); +})); +test_helpers_1.integTest('deploy new style synthesis to new style bootstrap (with docker image)', cdk_1.withDefaultFixture(async (fixture) => { + const bootstrapStackName = fixture.bootstrapStackName; + await fixture.cdkBootstrapModern({ + toolkitStackName: bootstrapStackName, + cfnExecutionPolicy: 'arn:aws:iam::aws:policy/AdministratorAccess', + }); + // Deploy stack that uses file assets + await fixture.cdkDeploy('docker', { + options: [ + '--toolkit-stack-name', bootstrapStackName, + '--context', `@aws-cdk/core:bootstrapQualifier=${fixture.qualifier}`, + '--context', '@aws-cdk/core:newStyleStackSynthesis=1', + ], + }); +})); +test_helpers_1.integTest('deploy old style synthesis to new style bootstrap', cdk_1.withDefaultFixture(async (fixture) => { + const bootstrapStackName = fixture.bootstrapStackName; + await fixture.cdkBootstrapModern({ + toolkitStackName: bootstrapStackName, + cfnExecutionPolicy: 'arn:aws:iam::aws:policy/AdministratorAccess', + }); + // Deploy stack that uses file assets + await fixture.cdkDeploy('lambda', { + options: [ + '--toolkit-stack-name', bootstrapStackName, + ], + }); +})); +test_helpers_1.integTest('can create a legacy bootstrap stack with --public-access-block-configuration=false', cdk_1.withDefaultFixture(async (fixture) => { + var _a; + const bootstrapStackName = fixture.bootstrapStackName; + await fixture.cdkBootstrapLegacy({ + verbose: true, + toolkitStackName: bootstrapStackName, + publicAccessBlockConfiguration: false, + tags: 'Foo=Bar', + }); + const response = await fixture.aws.cloudFormation('describeStacks', { StackName: bootstrapStackName }); + expect((_a = response.Stacks) === null || _a === void 0 ? void 0 : _a[0].Tags).toEqual([ + { Key: 'Foo', Value: 'Bar' }, + ]); +})); +test_helpers_1.integTest('can create multiple legacy bootstrap stacks', cdk_1.withDefaultFixture(async (fixture) => { + var _a; + 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.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((_a = response.Stacks) === null || _a === void 0 ? void 0 : _a[0].Tags).toEqual([ + { Key: 'Foo', Value: 'Bar' }, + ]); +})); +test_helpers_1.integTest('can dump the template, modify and use it to deploy a custom bootstrap stack', cdk_1.withDefaultFixture(async (fixture) => { + let template = await fixture.cdkBootstrapModern({ + // toolkitStackName doesn't matter for this particular invocation + toolkitStackName: fixture.bootstrapStackName, + showTemplate: true, + cliOptions: { + captureStderr: false, + }, + }); + expect(template).toContain('BootstrapVersion:'); + template += '\n' + [ + ' TwiddleDee:', + ' Value: Template got twiddled', + ].join('\n'); + const filename = path.join(fixture.integTestDir, `${fixture.qualifier}-template.yaml`); + fs.writeFileSync(filename, template, { encoding: 'utf-8' }); + await fixture.cdkBootstrapModern({ + toolkitStackName: fixture.bootstrapStackName, + template: filename, + cfnExecutionPolicy: 'arn:aws:iam::aws:policy/AdministratorAccess', + }); +})); +test_helpers_1.integTest('switch on termination protection, switch is left alone on re-bootstrap', cdk_1.withDefaultFixture(async (fixture) => { + var _a; + const bootstrapStackName = fixture.bootstrapStackName; + 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, + }); + const response = await fixture.aws.cloudFormation('describeStacks', { StackName: bootstrapStackName }); + expect((_a = response.Stacks) === null || _a === void 0 ? void 0 : _a[0].EnableTerminationProtection).toEqual(true); +})); +test_helpers_1.integTest('add tags, left alone on re-bootstrap', cdk_1.withDefaultFixture(async (fixture) => { + var _a; + const bootstrapStackName = fixture.bootstrapStackName; + 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, + }); + const response = await fixture.aws.cloudFormation('describeStacks', { StackName: bootstrapStackName }); + expect((_a = response.Stacks) === null || _a === void 0 ? void 0 : _a[0].Tags).toEqual([ + { Key: 'Foo', Value: 'Bar' }, + ]); +})); +test_helpers_1.integTest('can deploy modern-synthesized stack even if bootstrap stack name is unknown', cdk_1.withDefaultFixture(async (fixture) => { + const bootstrapStackName = fixture.bootstrapStackName; + await fixture.cdkBootstrapModern({ + toolkitStackName: bootstrapStackName, + cfnExecutionPolicy: 'arn:aws:iam::aws:policy/AdministratorAccess', + }); + // Deploy stack that uses file assets + await fixture.cdkDeploy('lambda', { + options: [ + // Explicity pass a name that's sure to not exist, otherwise the CLI might accidentally find a + // default bootstracp stack if that happens to be in the account already. + '--toolkit-stack-name', 'DefinitelyDoesNotExist', + '--context', `@aws-cdk/core:bootstrapQualifier=${fixture.qualifier}`, + '--context', '@aws-cdk/core:newStyleStackSynthesis=1', + ], + }); +})); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYm9vdHN0cmFwcGluZy5pbnRlZ3Rlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJib290c3RyYXBwaW5nLmludGVndGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLHlCQUF5QjtBQUN6Qiw2QkFBNkI7QUFDN0Isd0NBQWtFO0FBQ2xFLDBEQUFvRDtBQUVwRCxNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLGtCQUFrQixDQUFDLENBQUMsQ0FBQyx5Q0FBeUM7SUFDeEYsT0FBUyxDQUFDLENBQUMsQ0FBQyxTQUFTO0lBQ3JCLE1BQU8sQ0FBQyxDQUFDLGFBQWE7QUFDeEIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUMsQ0FBQztBQUN6QixPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyx3REFBd0QsT0FBTyxLQUFLLENBQUMsQ0FBQztBQUUzRix3QkFBUyxDQUFDLGlDQUFpQyxFQUFFLHdCQUFrQixDQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsRUFBRTs7SUFDaEYsTUFBTSxrQkFBa0IsR0FBRyxPQUFPLENBQUMsa0JBQWtCLENBQUM7SUFFdEQsTUFBTSxPQUFPLENBQUMsa0JBQWtCLENBQUM7UUFDL0IsZ0JBQWdCLEVBQUUsa0JBQWtCO1FBQ3BDLFNBQVMsRUFBRSxJQUFJO0tBQ2hCLENBQUMsQ0FBQztJQUVILE1BQU0sSUFBSSxHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxjQUFjLENBQUMsZ0JBQWdCLEVBQUU7UUFDOUQsU0FBUyxFQUFFLGtCQUFrQjtLQUM5QixDQUFDLENBQUM7SUFFSCxNQUFNLE9BQUMsSUFBSSxDQUFDLE1BQU0sMENBQUcsQ0FBQyxFQUFFLFdBQVcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO0FBQ3JFLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFFSix3QkFBUyxDQUFDLG9FQUFvRSxFQUFFLHdCQUFrQixDQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsRUFBRTtJQUNuSCxNQUFNLGtCQUFrQixHQUFHLE9BQU8sQ0FBQyxrQkFBa0IsQ0FBQztJQUV0RCxNQUFNLHlCQUF5QixHQUFHLDRDQUE0QyxrQkFBWSxFQUFFLEVBQUUsQ0FBQztJQUMvRixNQUFNLHNCQUFzQixHQUFHLHdDQUF3QyxrQkFBWSxFQUFFLEVBQUUsQ0FBQztJQUN4RixPQUFPLENBQUMsc0JBQXNCLENBQUMseUJBQXlCLENBQUMsQ0FBQyxDQUFDLHFCQUFxQjtJQUNoRixPQUFPLENBQUMsc0JBQXNCLENBQUMsc0JBQXNCLENBQUMsQ0FBQyxDQUFDLHFGQUFxRjtJQUU3SSxtQkFBbUI7SUFDbkIsTUFBTSxPQUFPLENBQUMsa0JBQWtCLENBQUM7UUFDL0IsZ0JBQWdCLEVBQUUsa0JBQWtCO1FBQ3BDLG1CQUFtQixFQUFFLHlCQUF5QjtLQUMvQyxDQUFDLENBQUM7SUFFSCxxQ0FBcUM7SUFDckMsTUFBTSxPQUFPLENBQUMsU0FBUyxDQUFDLFFBQVEsRUFBRTtRQUNoQyxPQUFPLEVBQUUsQ0FBQyxzQkFBc0IsRUFBRSxrQkFBa0IsQ0FBQztLQUN0RCxDQUFDLENBQUM7SUFFSCx5Q0FBeUM7SUFDekMsTUFBTSxPQUFPLENBQUMsa0JBQWtCLENBQUM7UUFDL0IsZ0JBQWdCLEVBQUUsa0JBQWtCO1FBQ3BDLG1CQUFtQixFQUFFLHNCQUFzQjtRQUMzQyxrQkFBa0IsRUFBRSw2Q0FBNkM7S0FDbEUsQ0FBQyxDQUFDO0lBRUgsNkJBQTZCO0lBQzdCLDJFQUEyRTtJQUMzRSxNQUFNLE9BQU8sQ0FBQyxTQUFTLENBQUMsUUFBUSxFQUFFO1FBQ2hDLE9BQU8sRUFBRTtZQUNQLHNCQUFzQixFQUFFLGtCQUFrQjtZQUMxQyxTQUFTO1NBQ1Y7S0FDRixDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBRUosd0JBQVMsQ0FBQywrQ0FBK0MsRUFBRSx3QkFBa0IsQ0FBQyxLQUFLLEVBQUUsT0FBTyxFQUFFLEVBQUU7SUFDOUYsTUFBTSxrQkFBa0IsR0FBRyxPQUFPLENBQUMsa0JBQWtCLENBQUM7SUFFdEQsTUFBTSxPQUFPLENBQUMsa0JBQWtCLENBQUM7UUFDL0IsZ0JBQWdCLEVBQUUsa0JBQWtCO0tBQ3JDLENBQUMsQ0FBQztJQUVILHFDQUFxQztJQUNyQyxNQUFNLE9BQU8sQ0FBQyxTQUFTLENBQUMsUUFBUSxFQUFFO1FBQ2hDLE9BQU8sRUFBRTtZQUNQLHNCQUFzQixFQUFFLGtCQUFrQjtZQUMxQyxXQUFXLEVBQUUsb0NBQW9DLE9BQU8sQ0FBQyxTQUFTLEVBQUU7WUFDcEUsV0FBVyxFQUFFLHdDQUF3QztTQUN0RDtLQUNGLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFFSix3QkFBUyxDQUFDLG1EQUFtRCxFQUFFLHdCQUFrQixDQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsRUFBRTtJQUNsRyxNQUFNLGtCQUFrQixHQUFHLE9BQU8sQ0FBQyxrQkFBa0IsQ0FBQztJQUV0RCxNQUFNLE9BQU8sQ0FBQyxrQkFBa0IsQ0FBQztRQUMvQixnQkFBZ0IsRUFBRSxrQkFBa0I7UUFDcEMsa0JBQWtCLEVBQUUsNkNBQTZDO0tBQ2xFLENBQUMsQ0FBQztJQUVILHFDQUFxQztJQUNyQyxNQUFNLE9BQU8sQ0FBQyxTQUFTLENBQUMsUUFBUSxFQUFFO1FBQ2hDLE9BQU8sRUFBRTtZQUNQLHNCQUFzQixFQUFFLGtCQUFrQjtZQUMxQyxXQUFXLEVBQUUsb0NBQW9DLE9BQU8sQ0FBQyxTQUFTLEVBQUU7WUFDcEUsV0FBVyxFQUFFLHdDQUF3QztTQUN0RDtLQUNGLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFFSix3QkFBUyxDQUFDLHVFQUF1RSxFQUFFLHdCQUFrQixDQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsRUFBRTtJQUN0SCxNQUFNLGtCQUFrQixHQUFHLE9BQU8sQ0FBQyxrQkFBa0IsQ0FBQztJQUV0RCxNQUFNLE9BQU8sQ0FBQyxrQkFBa0IsQ0FBQztRQUMvQixnQkFBZ0IsRUFBRSxrQkFBa0I7UUFDcEMsa0JBQWtCLEVBQUUsNkNBQTZDO0tBQ2xFLENBQUMsQ0FBQztJQUVILHFDQUFxQztJQUNyQyxNQUFNLE9BQU8sQ0FBQyxTQUFTLENBQUMsUUFBUSxFQUFFO1FBQ2hDLE9BQU8sRUFBRTtZQUNQLHNCQUFzQixFQUFFLGtCQUFrQjtZQUMxQyxXQUFXLEVBQUUsb0NBQW9DLE9BQU8sQ0FBQyxTQUFTLEVBQUU7WUFDcEUsV0FBVyxFQUFFLHdDQUF3QztTQUN0RDtLQUNGLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFFSix3QkFBUyxDQUFDLG1EQUFtRCxFQUFFLHdCQUFrQixDQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsRUFBRTtJQUNsRyxNQUFNLGtCQUFrQixHQUFHLE9BQU8sQ0FBQyxrQkFBa0IsQ0FBQztJQUV0RCxNQUFNLE9BQU8sQ0FBQyxrQkFBa0IsQ0FBQztRQUMvQixnQkFBZ0IsRUFBRSxrQkFBa0I7UUFDcEMsa0JBQWtCLEVBQUUsNkNBQTZDO0tBQ2xFLENBQUMsQ0FBQztJQUVILHFDQUFxQztJQUNyQyxNQUFNLE9BQU8sQ0FBQyxTQUFTLENBQUMsUUFBUSxFQUFFO1FBQ2hDLE9BQU8sRUFBRTtZQUNQLHNCQUFzQixFQUFFLGtCQUFrQjtTQUMzQztLQUNGLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFFSix3QkFBUyxDQUFDLG9GQUFvRixFQUFFLHdCQUFrQixDQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsRUFBRTs7SUFDbkksTUFBTSxrQkFBa0IsR0FBRyxPQUFPLENBQUMsa0JBQWtCLENBQUM7SUFFdEQsTUFBTSxPQUFPLENBQUMsa0JBQWtCLENBQUM7UUFDL0IsT0FBTyxFQUFFLElBQUk7UUFDYixnQkFBZ0IsRUFBRSxrQkFBa0I7UUFDcEMsOEJBQThCLEVBQUUsS0FBSztRQUNyQyxJQUFJLEVBQUUsU0FBUztLQUNoQixDQUFDLENBQUM7SUFFSCxNQUFNLFFBQVEsR0FBRyxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUMsY0FBYyxDQUFDLGdCQUFnQixFQUFFLEVBQUUsU0FBUyxFQUFFLGtCQUFrQixFQUFFLENBQUMsQ0FBQztJQUN2RyxNQUFNLE9BQUMsUUFBUSxDQUFDLE1BQU0sMENBQUcsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDLE9BQU8sQ0FBQztRQUN4QyxFQUFFLEdBQUcsRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRTtLQUM3QixDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBRUosd0JBQVMsQ0FBQyw2Q0FBNkMsRUFBRSx3QkFBa0IsQ0FBQyxLQUFLLEVBQUUsT0FBTyxFQUFFLEVBQUU7O0lBQzVGLE1BQU0sbUJBQW1CLEdBQUcsR0FBRyxPQUFPLENBQUMsa0JBQWtCLElBQUksQ0FBQztJQUM5RCxNQUFNLG1CQUFtQixHQUFHLEdBQUcsT0FBTyxDQUFDLGtCQUFrQixJQUFJLENBQUM7SUFFOUQsa0VBQWtFO0lBQ2xFLGdCQUFnQjtJQUNoQixNQUFNLE9BQU8sQ0FBQyxrQkFBa0IsQ0FBQztRQUMvQixPQUFPLEVBQUUsSUFBSTtRQUNiLGdCQUFnQixFQUFFLG1CQUFtQjtRQUNyQyxJQUFJLEVBQUUsU0FBUztLQUNoQixDQUFDLENBQUM7SUFDSCxNQUFNLE9BQU8sQ0FBQyxrQkFBa0IsQ0FBQztRQUMvQixPQUFPLEVBQUUsSUFBSTtRQUNiLGdCQUFnQixFQUFFLG1CQUFtQjtLQUN0QyxDQUFDLENBQUM7SUFFSCxNQUFNLFFBQVEsR0FBRyxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUMsY0FBYyxDQUFDLGdCQUFnQixFQUFFLEVBQUUsU0FBUyxFQUFFLG1CQUFtQixFQUFFLENBQUMsQ0FBQztJQUN4RyxNQUFNLE9BQUMsUUFBUSxDQUFDLE1BQU0sMENBQUcsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDLE9BQU8sQ0FBQztRQUN4QyxFQUFFLEdBQUcsRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRTtLQUM3QixDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBRUosd0JBQVMsQ0FBQyw2RUFBNkUsRUFBRSx3QkFBa0IsQ0FBQyxLQUFLLEVBQUUsT0FBTyxFQUFFLEVBQUU7SUFDNUgsSUFBSSxRQUFRLEdBQUcsTUFBTSxPQUFPLENBQUMsa0JBQWtCLENBQUM7UUFDOUMsaUVBQWlFO1FBQ2pFLGdCQUFnQixFQUFFLE9BQU8sQ0FBQyxrQkFBa0I7UUFDNUMsWUFBWSxFQUFFLElBQUk7UUFDbEIsVUFBVSxFQUFFO1lBQ1YsYUFBYSxFQUFFLEtBQUs7U0FDckI7S0FDRixDQUFDLENBQUM7SUFFSCxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUMsU0FBUyxDQUFDLG1CQUFtQixDQUFDLENBQUM7SUFFaEQsUUFBUSxJQUFJLElBQUksR0FBRztRQUNqQixlQUFlO1FBQ2Ysa0NBQWtDO0tBQ25DLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBRWIsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsWUFBWSxFQUFFLEdBQUcsT0FBTyxDQUFDLFNBQVMsZ0JBQWdCLENBQUMsQ0FBQztJQUN2RixFQUFFLENBQUMsYUFBYSxDQUFDLFFBQVEsRUFBRSxRQUFRLEVBQUUsRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztJQUM1RCxNQUFNLE9BQU8sQ0FBQyxrQkFBa0IsQ0FBQztRQUMvQixnQkFBZ0IsRUFBRSxPQUFPLENBQUMsa0JBQWtCO1FBQzVDLFFBQVEsRUFBRSxRQUFRO1FBQ2xCLGtCQUFrQixFQUFFLDZDQUE2QztLQUNsRSxDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBRUosd0JBQVMsQ0FBQyx3RUFBd0UsRUFBRSx3QkFBa0IsQ0FBQyxLQUFLLEVBQUUsT0FBTyxFQUFFLEVBQUU7O0lBQ3ZILE1BQU0sa0JBQWtCLEdBQUcsT0FBTyxDQUFDLGtCQUFrQixDQUFDO0lBRXRELE1BQU0sT0FBTyxDQUFDLGtCQUFrQixDQUFDO1FBQy9CLE9BQU8sRUFBRSxJQUFJO1FBQ2IsZ0JBQWdCLEVBQUUsa0JBQWtCO1FBQ3BDLHFCQUFxQixFQUFFLElBQUk7UUFDM0Isa0JBQWtCLEVBQUUsNkNBQTZDO0tBQ2xFLENBQUMsQ0FBQztJQUNILE1BQU0sT0FBTyxDQUFDLGtCQUFrQixDQUFDO1FBQy9CLE9BQU8sRUFBRSxJQUFJO1FBQ2IsZ0JBQWdCLEVBQUUsa0JBQWtCO1FBQ3BDLEtBQUssRUFBRSxJQUFJO0tBQ1osQ0FBQyxDQUFDO0lBRUgsTUFBTSxRQUFRLEdBQUcsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLGNBQWMsQ0FBQyxnQkFBZ0IsRUFBRSxFQUFFLFNBQVMsRUFBRSxrQkFBa0IsRUFBRSxDQUFDLENBQUM7SUFDdkcsTUFBTSxPQUFDLFFBQVEsQ0FBQyxNQUFNLDBDQUFHLENBQUMsRUFBRSwyQkFBMkIsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztBQUN6RSxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBRUosd0JBQVMsQ0FBQyxzQ0FBc0MsRUFBRSx3QkFBa0IsQ0FBQyxLQUFLLEVBQUUsT0FBTyxFQUFFLEVBQUU7O0lBQ3JGLE1BQU0sa0JBQWtCLEdBQUcsT0FBTyxDQUFDLGtCQUFrQixDQUFDO0lBRXRELE1BQU0sT0FBTyxDQUFDLGtCQUFrQixDQUFDO1FBQy9CLE9BQU8sRUFBRSxJQUFJO1FBQ2IsZ0JBQWdCLEVBQUUsa0JBQWtCO1FBQ3BDLElBQUksRUFBRSxTQUFTO1FBQ2Ysa0JBQWtCLEVBQUUsNkNBQTZDO0tBQ2xFLENBQUMsQ0FBQztJQUNILE1BQU0sT0FBTyxDQUFDLGtCQUFrQixDQUFDO1FBQy9CLE9BQU8sRUFBRSxJQUFJO1FBQ2IsZ0JBQWdCLEVBQUUsa0JBQWtCO1FBQ3BDLEtBQUssRUFBRSxJQUFJO0tBQ1osQ0FBQyxDQUFDO0lBRUgsTUFBTSxRQUFRLEdBQUcsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLGNBQWMsQ0FBQyxnQkFBZ0IsRUFBRSxFQUFFLFNBQVMsRUFBRSxrQkFBa0IsRUFBRSxDQUFDLENBQUM7SUFDdkcsTUFBTSxPQUFDLFFBQVEsQ0FBQyxNQUFNLDBDQUFHLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQyxPQUFPLENBQUM7UUFDeEMsRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUU7S0FDN0IsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUVKLHdCQUFTLENBQUMsNkVBQTZFLEVBQUUsd0JBQWtCLENBQUMsS0FBSyxFQUFFLE9BQU8sRUFBRSxFQUFFO0lBQzVILE1BQU0sa0JBQWtCLEdBQUcsT0FBTyxDQUFDLGtCQUFrQixDQUFDO0lBRXRELE1BQU0sT0FBTyxDQUFDLGtCQUFrQixDQUFDO1FBQy9CLGdCQUFnQixFQUFFLGtCQUFrQjtRQUNwQyxrQkFBa0IsRUFBRSw2Q0FBNkM7S0FDbEUsQ0FBQyxDQUFDO0lBRUgscUNBQXFDO0lBQ3JDLE1BQU0sT0FBTyxDQUFDLFNBQVMsQ0FBQyxRQUFRLEVBQUU7UUFDaEMsT0FBTyxFQUFFO1lBQ1AsOEZBQThGO1lBQzlGLHlFQUF5RTtZQUN6RSxzQkFBc0IsRUFBRSx3QkFBd0I7WUFDaEQsV0FBVyxFQUFFLG9DQUFvQyxPQUFPLENBQUMsU0FBUyxFQUFFO1lBQ3BFLFdBQVcsRUFBRSx3Q0FBd0M7U0FDdEQ7S0FDRixDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgZnMgZnJvbSAnZnMnO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB7IHJhbmRvbVN0cmluZywgd2l0aERlZmF1bHRGaXh0dXJlIH0gZnJvbSAnLi4vaGVscGVycy9jZGsnO1xuaW1wb3J0IHsgaW50ZWdUZXN0IH0gZnJvbSAnLi4vaGVscGVycy90ZXN0LWhlbHBlcnMnO1xuXG5jb25zdCB0aW1lb3V0ID0gcHJvY2Vzcy5lbnYuQ09ERUJVSUxEX0JVSUxEX0lEID8gLy8gaWYgdGhlIHByb2Nlc3MgaXMgcnVubmluZyBpbiBDb2RlQnVpbGRcbiAgM182MDBfMDAwIDogLy8gMSBob3VyXG4gIDYwMF8wMDA7IC8vIDEwIG1pbnV0ZXNcbmplc3Quc2V0VGltZW91dCh0aW1lb3V0KTtcbnByb2Nlc3Muc3Rkb3V0LndyaXRlKGBib290c3RyYXBwaW5nLmludGVndGVzdC50czogU2V0dGluZyBqZXN0IHRpbWUgb3V0IHRvICR7dGltZW91dH0gbXNgKTtcblxuaW50ZWdUZXN0KCdjYW4gYm9vdHN0cmFwIHdpdGhvdXQgZXhlY3V0aW9uJywgd2l0aERlZmF1bHRGaXh0dXJlKGFzeW5jIChmaXh0dXJlKSA9PiB7XG4gIGNvbnN0IGJvb3RzdHJhcFN0YWNrTmFtZSA9IGZpeHR1cmUuYm9vdHN0cmFwU3RhY2tOYW1lO1xuXG4gIGF3YWl0IGZpeHR1cmUuY2RrQm9vdHN0cmFwTGVnYWN5KHtcbiAgICB0b29sa2l0U3RhY2tOYW1lOiBib290c3RyYXBTdGFja05hbWUsXG4gICAgbm9FeGVjdXRlOiB0cnVlLFxuICB9KTtcblxuICBjb25zdCByZXNwID0gYXdhaXQgZml4dHVyZS5hd3MuY2xvdWRGb3JtYXRpb24oJ2Rlc2NyaWJlU3RhY2tzJywge1xuICAgIFN0YWNrTmFtZTogYm9vdHN0cmFwU3RhY2tOYW1lLFxuICB9KTtcblxuICBleHBlY3QocmVzcC5TdGFja3M/LlswXS5TdGFja1N0YXR1cykudG9FcXVhbCgnUkVWSUVXX0lOX1BST0dSRVNTJyk7XG59KSk7XG5cbmludGVnVGVzdCgndXBncmFkZSBsZWdhY3kgYm9vdHN0cmFwIHN0YWNrIHRvIG5ldyBib290c3RyYXAgc3RhY2sgd2hpbGUgaW4gdXNlJywgd2l0aERlZmF1bHRGaXh0dXJlKGFzeW5jIChmaXh0dXJlKSA9PiB7XG4gIGNvbnN0IGJvb3RzdHJhcFN0YWNrTmFtZSA9IGZpeHR1cmUuYm9vdHN0cmFwU3RhY2tOYW1lO1xuXG4gIGNvbnN0IGxlZ2FjeUJvb3RzdHJhcEJ1Y2tldE5hbWUgPSBgYXdzLWNkay1ib290c3RyYXAtaW50ZWctdGVzdC1sZWdhY3ktYmNrdC0ke3JhbmRvbVN0cmluZygpfWA7XG4gIGNvbnN0IG5ld0Jvb3RzdHJhcEJ1Y2tldE5hbWUgPSBgYXdzLWNkay1ib290c3RyYXAtaW50ZWctdGVzdC12Mi1iY2t0LSR7cmFuZG9tU3RyaW5nKCl9YDtcbiAgZml4dHVyZS5yZW1lbWJlclRvRGVsZXRlQnVja2V0KGxlZ2FjeUJvb3RzdHJhcEJ1Y2tldE5hbWUpOyAvLyBUaGlzIG9uZSB3aWxsIGxlYWtcbiAgZml4dHVyZS5yZW1lbWJlclRvRGVsZXRlQnVja2V0KG5ld0Jvb3RzdHJhcEJ1Y2tldE5hbWUpOyAvLyBUaGlzIG9uZSBzaG91bGRuJ3QgbGVhayBpZiB0aGUgdGVzdCBzdWNjZWVkcywgYnV0IGxldCdzIGJlIHNhZmUgaW4gY2FzZSBpdCBkb2Vzbid0XG5cbiAgLy8gTGVnYWN5IGJvb3RzdHJhcFxuICBhd2FpdCBmaXh0dXJlLmNka0Jvb3RzdHJhcExlZ2FjeSh7XG4gICAgdG9vbGtpdFN0YWNrTmFtZTogYm9vdHN0cmFwU3RhY2tOYW1lLFxuICAgIGJvb3RzdHJhcEJ1Y2tldE5hbWU6IGxlZ2FjeUJvb3RzdHJhcEJ1Y2tldE5hbWUsXG4gIH0pO1xuXG4gIC8vIERlcGxveSBzdGFjayB0aGF0IHVzZXMgZmlsZSBhc3NldHNcbiAgYXdhaXQgZml4dHVyZS5jZGtEZXBsb3koJ2xhbWJkYScsIHtcbiAgICBvcHRpb25zOiBbJy0tdG9vbGtpdC1zdGFjay1uYW1lJywgYm9vdHN0cmFwU3RhY2tOYW1lXSxcbiAgfSk7XG5cbiAgLy8gVXBncmFkZSBib290c3RyYXAgc3RhY2sgdG8gXCJuZXdcIiBzdHlsZVxuICBhd2FpdCBmaXh0dXJlLmNka0Jvb3RzdHJhcE1vZGVybih7XG4gICAgdG9vbGtpdFN0YWNrTmFtZTogYm9vdHN0cmFwU3RhY2tOYW1lLFxuICAgIGJvb3RzdHJhcEJ1Y2tldE5hbWU6IG5ld0Jvb3RzdHJhcEJ1Y2tldE5hbWUsXG4gICAgY2ZuRXhlY3V0aW9uUG9saWN5OiAnYXJuOmF3czppYW06OmF3czpwb2xpY3kvQWRtaW5pc3RyYXRvckFjY2VzcycsXG4gIH0pO1xuXG4gIC8vIChGb3JjZSkgZGVwbG95IHN0YWNrIGFnYWluXG4gIC8vIC0tZm9yY2UgdG8gYnlwYXNzIHRoZSBjaGVjayB3aGljaCBzYXlzIHRoYXQgdGhlIHRlbXBsYXRlIGhhc24ndCBjaGFuZ2VkLlxuICBhd2FpdCBmaXh0dXJlLmNka0RlcGxveSgnbGFtYmRhJywge1xuICAgIG9wdGlvbnM6IFtcbiAgICAgICctLXRvb2xraXQtc3RhY2stbmFtZScsIGJvb3RzdHJhcFN0YWNrTmFtZSxcbiAgICAgICctLWZvcmNlJyxcbiAgICBdLFxuICB9KTtcbn0pKTtcblxuaW50ZWdUZXN0KCdjYW4gYW5kIGRlcGxveSBpZiBvbWl0dGluZyBleGVjdXRpb24gcG9saWNpZXMnLCB3aXRoRGVmYXVsdEZpeHR1cmUoYXN5bmMgKGZpeHR1cmUpID0+IHtcbiAgY29uc3QgYm9vdHN0cmFwU3RhY2tOYW1lID0gZml4dHVyZS5ib290c3RyYXBTdGFja05hbWU7XG5cbiAgYXdhaXQgZml4dHVyZS5jZGtCb290c3RyYXBNb2Rlcm4oe1xuICAgIHRvb2xraXRTdGFja05hbWU6IGJvb3RzdHJhcFN0YWNrTmFtZSxcbiAgfSk7XG5cbiAgLy8gRGVwbG95IHN0YWNrIHRoYXQgdXNlcyBmaWxlIGFzc2V0c1xuICBhd2FpdCBmaXh0dXJlLmNka0RlcGxveSgnbGFtYmRhJywge1xuICAgIG9wdGlvbnM6IFtcbiAgICAgICctLXRvb2xraXQtc3RhY2stbmFtZScsIGJvb3RzdHJhcFN0YWNrTmFtZSxcbiAgICAgICctLWNvbnRleHQnLCBgQGF3cy1jZGsvY29yZTpib290c3RyYXBRdWFsaWZpZXI9JHtmaXh0dXJlLnF1YWxpZmllcn1gLFxuICAgICAgJy0tY29udGV4dCcsICdAYXdzLWNkay9jb3JlOm5ld1N0eWxlU3RhY2tTeW50aGVzaXM9MScsXG4gICAgXSxcbiAgfSk7XG59KSk7XG5cbmludGVnVGVzdCgnZGVwbG95IG5ldyBzdHlsZSBzeW50aGVzaXMgdG8gbmV3IHN0eWxlIGJvb3RzdHJhcCcsIHdpdGhEZWZhdWx0Rml4dHVyZShhc3luYyAoZml4dHVyZSkgPT4ge1xuICBjb25zdCBib290c3RyYXBTdGFja05hbWUgPSBmaXh0dXJlLmJvb3RzdHJhcFN0YWNrTmFtZTtcblxuICBhd2FpdCBmaXh0dXJlLmNka0Jvb3RzdHJhcE1vZGVybih7XG4gICAgdG9vbGtpdFN0YWNrTmFtZTogYm9vdHN0cmFwU3RhY2tOYW1lLFxuICAgIGNmbkV4ZWN1dGlvblBvbGljeTogJ2Fybjphd3M6aWFtOjphd3M6cG9saWN5L0FkbWluaXN0cmF0b3JBY2Nlc3MnLFxuICB9KTtcblxuICAvLyBEZXBsb3kgc3RhY2sgdGhhdCB1c2VzIGZpbGUgYXNzZXRzXG4gIGF3YWl0IGZpeHR1cmUuY2RrRGVwbG95KCdsYW1iZGEnLCB7XG4gICAgb3B0aW9uczogW1xuICAgICAgJy0tdG9vbGtpdC1zdGFjay1uYW1lJywgYm9vdHN0cmFwU3RhY2tOYW1lLFxuICAgICAgJy0tY29udGV4dCcsIGBAYXdzLWNkay9jb3JlOmJvb3RzdHJhcFF1YWxpZmllcj0ke2ZpeHR1cmUucXVhbGlmaWVyfWAsXG4gICAgICAnLS1jb250ZXh0JywgJ0Bhd3MtY2RrL2NvcmU6bmV3U3R5bGVTdGFja1N5bnRoZXNpcz0xJyxcbiAgICBdLFxuICB9KTtcbn0pKTtcblxuaW50ZWdUZXN0KCdkZXBsb3kgbmV3IHN0eWxlIHN5bnRoZXNpcyB0byBuZXcgc3R5bGUgYm9vdHN0cmFwICh3aXRoIGRvY2tlciBpbWFnZSknLCB3aXRoRGVmYXVsdEZpeHR1cmUoYXN5bmMgKGZpeHR1cmUpID0+IHtcbiAgY29uc3QgYm9vdHN0cmFwU3RhY2tOYW1lID0gZml4dHVyZS5ib290c3RyYXBTdGFja05hbWU7XG5cbiAgYXdhaXQgZml4dHVyZS5jZGtCb290c3RyYXBNb2Rlcm4oe1xuICAgIHRvb2xraXRTdGFja05hbWU6IGJvb3RzdHJhcFN0YWNrTmFtZSxcbiAgICBjZm5FeGVjdXRpb25Qb2xpY3k6ICdhcm46YXdzOmlhbTo6YXdzOnBvbGljeS9BZG1pbmlzdHJhdG9yQWNjZXNzJyxcbiAgfSk7XG5cbiAgLy8gRGVwbG95IHN0YWNrIHRoYXQgdXNlcyBmaWxlIGFzc2V0c1xuICBhd2FpdCBmaXh0dXJlLmNka0RlcGxveSgnZG9ja2VyJywge1xuICAgIG9wdGlvbnM6IFtcbiAgICAgICctLXRvb2xraXQtc3RhY2stbmFtZScsIGJvb3RzdHJhcFN0YWNrTmFtZSxcbiAgICAgICctLWNvbnRleHQnLCBgQGF3cy1jZGsvY29yZTpib290c3RyYXBRdWFsaWZpZXI9JHtmaXh0dXJlLnF1YWxpZmllcn1gLFxuICAgICAgJy0tY29udGV4dCcsICdAYXdzLWNkay9jb3JlOm5ld1N0eWxlU3RhY2tTeW50aGVzaXM9MScsXG4gICAgXSxcbiAgfSk7XG59KSk7XG5cbmludGVnVGVzdCgnZGVwbG95IG9sZCBzdHlsZSBzeW50aGVzaXMgdG8gbmV3IHN0eWxlIGJvb3RzdHJhcCcsIHdpdGhEZWZhdWx0Rml4dHVyZShhc3luYyAoZml4dHVyZSkgPT4ge1xuICBjb25zdCBib290c3RyYXBTdGFja05hbWUgPSBmaXh0dXJlLmJvb3RzdHJhcFN0YWNrTmFtZTtcblxuICBhd2FpdCBmaXh0dXJlLmNka0Jvb3RzdHJhcE1vZGVybih7XG4gICAgdG9vbGtpdFN0YWNrTmFtZTogYm9vdHN0cmFwU3RhY2tOYW1lLFxuICAgIGNmbkV4ZWN1dGlvblBvbGljeTogJ2Fybjphd3M6aWFtOjphd3M6cG9saWN5L0FkbWluaXN0cmF0b3JBY2Nlc3MnLFxuICB9KTtcblxuICAvLyBEZXBsb3kgc3RhY2sgdGhhdCB1c2VzIGZpbGUgYXNzZXRzXG4gIGF3YWl0IGZpeHR1cmUuY2RrRGVwbG95KCdsYW1iZGEnLCB7XG4gICAgb3B0aW9uczogW1xuICAgICAgJy0tdG9vbGtpdC1zdGFjay1uYW1lJywgYm9vdHN0cmFwU3RhY2tOYW1lLFxuICAgIF0sXG4gIH0pO1xufSkpO1xuXG5pbnRlZ1Rlc3QoJ2NhbiBjcmVhdGUgYSBsZWdhY3kgYm9vdHN0cmFwIHN0YWNrIHdpdGggLS1wdWJsaWMtYWNjZXNzLWJsb2NrLWNvbmZpZ3VyYXRpb249ZmFsc2UnLCB3aXRoRGVmYXVsdEZpeHR1cmUoYXN5bmMgKGZpeHR1cmUpID0+IHtcbiAgY29uc3QgYm9vdHN0cmFwU3RhY2tOYW1lID0gZml4dHVyZS5ib290c3RyYXBTdGFja05hbWU7XG5cbiAgYXdhaXQgZml4dHVyZS5jZGtCb290c3RyYXBMZWdhY3koe1xuICAgIHZlcmJvc2U6IHRydWUsXG4gICAgdG9vbGtpdFN0YWNrTmFtZTogYm9vdHN0cmFwU3RhY2tOYW1lLFxuICAgIHB1YmxpY0FjY2Vzc0Jsb2NrQ29uZmlndXJhdGlvbjogZmFsc2UsXG4gICAgdGFnczogJ0Zvbz1CYXInLFxuICB9KTtcblxuICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZpeHR1cmUuYXdzLmNsb3VkRm9ybWF0aW9uKCdkZXNjcmliZVN0YWNrcycsIHsgU3RhY2tOYW1lOiBib290c3RyYXBTdGFja05hbWUgfSk7XG4gIGV4cGVjdChyZXNwb25zZS5TdGFja3M/LlswXS5UYWdzKS50b0VxdWFsKFtcbiAgICB7IEtleTogJ0ZvbycsIFZhbHVlOiAnQmFyJyB9LFxuICBdKTtcbn0pKTtcblxuaW50ZWdUZXN0KCdjYW4gY3JlYXRlIG11bHRpcGxlIGxlZ2FjeSBib290c3RyYXAgc3RhY2tzJywgd2l0aERlZmF1bHRGaXh0dXJlKGFzeW5jIChmaXh0dXJlKSA9PiB7XG4gIGNvbnN0IGJvb3RzdHJhcFN0YWNrTmFtZTEgPSBgJHtmaXh0dXJlLmJvb3RzdHJhcFN0YWNrTmFtZX0tMWA7XG4gIGNvbnN0IGJvb3RzdHJhcFN0YWNrTmFtZTIgPSBgJHtmaXh0dXJlLmJvb3RzdHJhcFN0YWNrTmFtZX0tMmA7XG5cbiAgLy8gZGVwbG95IHR3byB0b29sa2l0IHN0YWNrcyBpbnRvIHRoZSBzYW1lIGVudmlyb25tZW50IChzZWUgIzE0MTYpXG4gIC8vIG9uZSB3aXRoIHRhZ3NcbiAgYXdhaXQgZml4dHVyZS5jZGtCb290c3RyYXBMZWdhY3koe1xuICAgIHZlcmJvc2U6IHRydWUsXG4gICAgdG9vbGtpdFN0YWNrTmFtZTogYm9vdHN0cmFwU3RhY2tOYW1lMSxcbiAgICB0YWdzOiAnRm9vPUJhcicsXG4gIH0pO1xuICBhd2FpdCBmaXh0dXJlLmNka0Jvb3RzdHJhcExlZ2FjeSh7XG4gICAgdmVyYm9zZTogdHJ1ZSxcbiAgICB0b29sa2l0U3RhY2tOYW1lOiBib290c3RyYXBTdGFja05hbWUyLFxuICB9KTtcblxuICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZpeHR1cmUuYXdzLmNsb3VkRm9ybWF0aW9uKCdkZXNjcmliZVN0YWNrcycsIHsgU3RhY2tOYW1lOiBib290c3RyYXBTdGFja05hbWUxIH0pO1xuICBleHBlY3QocmVzcG9uc2UuU3RhY2tzPy5bMF0uVGFncykudG9FcXVhbChbXG4gICAgeyBLZXk6ICdGb28nLCBWYWx1ZTogJ0JhcicgfSxcbiAgXSk7XG59KSk7XG5cbmludGVnVGVzdCgnY2FuIGR1bXAgdGhlIHRlbXBsYXRlLCBtb2RpZnkgYW5kIHVzZSBpdCB0byBkZXBsb3kgYSBjdXN0b20gYm9vdHN0cmFwIHN0YWNrJywgd2l0aERlZmF1bHRGaXh0dXJlKGFzeW5jIChmaXh0dXJlKSA9PiB7XG4gIGxldCB0ZW1wbGF0ZSA9IGF3YWl0IGZpeHR1cmUuY2RrQm9vdHN0cmFwTW9kZXJuKHtcbiAgICAvLyB0b29sa2l0U3RhY2tOYW1lIGRvZXNuJ3QgbWF0dGVyIGZvciB0aGlzIHBhcnRpY3VsYXIgaW52b2NhdGlvblxuICAgIHRvb2xraXRTdGFja05hbWU6IGZpeHR1cmUuYm9vdHN0cmFwU3RhY2tOYW1lLFxuICAgIHNob3dUZW1wbGF0ZTogdHJ1ZSxcbiAgICBjbGlPcHRpb25zOiB7XG4gICAgICBjYXB0dXJlU3RkZXJyOiBmYWxzZSxcbiAgICB9LFxuICB9KTtcblxuICBleHBlY3QodGVtcGxhdGUpLnRvQ29udGFpbignQm9vdHN0cmFwVmVyc2lvbjonKTtcblxuICB0ZW1wbGF0ZSArPSAnXFxuJyArIFtcbiAgICAnICBUd2lkZGxlRGVlOicsXG4gICAgJyAgICBWYWx1ZTogVGVtcGxhdGUgZ290IHR3aWRkbGVkJyxcbiAgXS5qb2luKCdcXG4nKTtcblxuICBjb25zdCBmaWxlbmFtZSA9IHBhdGguam9pbihmaXh0dXJlLmludGVnVGVzdERpciwgYCR7Zml4dHVyZS5xdWFsaWZpZXJ9LXRlbXBsYXRlLnlhbWxgKTtcbiAgZnMud3JpdGVGaWxlU3luYyhmaWxlbmFtZSwgdGVtcGxhdGUsIHsgZW5jb2Rpbmc6ICd1dGYtOCcgfSk7XG4gIGF3YWl0IGZpeHR1cmUuY2RrQm9vdHN0cmFwTW9kZXJuKHtcbiAgICB0b29sa2l0U3RhY2tOYW1lOiBmaXh0dXJlLmJvb3RzdHJhcFN0YWNrTmFtZSxcbiAgICB0ZW1wbGF0ZTogZmlsZW5hbWUsXG4gICAgY2ZuRXhlY3V0aW9uUG9saWN5OiAnYXJuOmF3czppYW06OmF3czpwb2xpY3kvQWRtaW5pc3RyYXRvckFjY2VzcycsXG4gIH0pO1xufSkpO1xuXG5pbnRlZ1Rlc3QoJ3N3aXRjaCBvbiB0ZXJtaW5hdGlvbiBwcm90ZWN0aW9uLCBzd2l0Y2ggaXMgbGVmdCBhbG9uZSBvbiByZS1ib290c3RyYXAnLCB3aXRoRGVmYXVsdEZpeHR1cmUoYXN5bmMgKGZpeHR1cmUpID0+IHtcbiAgY29uc3QgYm9vdHN0cmFwU3RhY2tOYW1lID0gZml4dHVyZS5ib290c3RyYXBTdGFja05hbWU7XG5cbiAgYXdhaXQgZml4dHVyZS5jZGtCb290c3RyYXBNb2Rlcm4oe1xuICAgIHZlcmJvc2U6IHRydWUsXG4gICAgdG9vbGtpdFN0YWNrTmFtZTogYm9vdHN0cmFwU3RhY2tOYW1lLFxuICAgIHRlcm1pbmF0aW9uUHJvdGVjdGlvbjogdHJ1ZSxcbiAgICBjZm5FeGVjdXRpb25Qb2xpY3k6ICdhcm46YXdzOmlhbTo6YXdzOnBvbGljeS9BZG1pbmlzdHJhdG9yQWNjZXNzJyxcbiAgfSk7XG4gIGF3YWl0IGZpeHR1cmUuY2RrQm9vdHN0cmFwTW9kZXJuKHtcbiAgICB2ZXJib3NlOiB0cnVlLFxuICAgIHRvb2xraXRTdGFja05hbWU6IGJvb3RzdHJhcFN0YWNrTmFtZSxcbiAgICBmb3JjZTogdHJ1ZSxcbiAgfSk7XG5cbiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmaXh0dXJlLmF3cy5jbG91ZEZvcm1hdGlvbignZGVzY3JpYmVTdGFja3MnLCB7IFN0YWNrTmFtZTogYm9vdHN0cmFwU3RhY2tOYW1lIH0pO1xuICBleHBlY3QocmVzcG9uc2UuU3RhY2tzPy5bMF0uRW5hYmxlVGVybWluYXRpb25Qcm90ZWN0aW9uKS50b0VxdWFsKHRydWUpO1xufSkpO1xuXG5pbnRlZ1Rlc3QoJ2FkZCB0YWdzLCBsZWZ0IGFsb25lIG9uIHJlLWJvb3RzdHJhcCcsIHdpdGhEZWZhdWx0Rml4dHVyZShhc3luYyAoZml4dHVyZSkgPT4ge1xuICBjb25zdCBib290c3RyYXBTdGFja05hbWUgPSBmaXh0dXJlLmJvb3RzdHJhcFN0YWNrTmFtZTtcblxuICBhd2FpdCBmaXh0dXJlLmNka0Jvb3RzdHJhcE1vZGVybih7XG4gICAgdmVyYm9zZTogdHJ1ZSxcbiAgICB0b29sa2l0U3RhY2tOYW1lOiBib290c3RyYXBTdGFja05hbWUsXG4gICAgdGFnczogJ0Zvbz1CYXInLFxuICAgIGNmbkV4ZWN1dGlvblBvbGljeTogJ2Fybjphd3M6aWFtOjphd3M6cG9saWN5L0FkbWluaXN0cmF0b3JBY2Nlc3MnLFxuICB9KTtcbiAgYXdhaXQgZml4dHVyZS5jZGtCb290c3RyYXBNb2Rlcm4oe1xuICAgIHZlcmJvc2U6IHRydWUsXG4gICAgdG9vbGtpdFN0YWNrTmFtZTogYm9vdHN0cmFwU3RhY2tOYW1lLFxuICAgIGZvcmNlOiB0cnVlLFxuICB9KTtcblxuICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZpeHR1cmUuYXdzLmNsb3VkRm9ybWF0aW9uKCdkZXNjcmliZVN0YWNrcycsIHsgU3RhY2tOYW1lOiBib290c3RyYXBTdGFja05hbWUgfSk7XG4gIGV4cGVjdChyZXNwb25zZS5TdGFja3M/LlswXS5UYWdzKS50b0VxdWFsKFtcbiAgICB7IEtleTogJ0ZvbycsIFZhbHVlOiAnQmFyJyB9LFxuICBdKTtcbn0pKTtcblxuaW50ZWdUZXN0KCdjYW4gZGVwbG95IG1vZGVybi1zeW50aGVzaXplZCBzdGFjayBldmVuIGlmIGJvb3RzdHJhcCBzdGFjayBuYW1lIGlzIHVua25vd24nLCB3aXRoRGVmYXVsdEZpeHR1cmUoYXN5bmMgKGZpeHR1cmUpID0+IHtcbiAgY29uc3QgYm9vdHN0cmFwU3RhY2tOYW1lID0gZml4dHVyZS5ib290c3RyYXBTdGFja05hbWU7XG5cbiAgYXdhaXQgZml4dHVyZS5jZGtCb290c3RyYXBNb2Rlcm4oe1xuICAgIHRvb2xraXRTdGFja05hbWU6IGJvb3RzdHJhcFN0YWNrTmFtZSxcbiAgICBjZm5FeGVjdXRpb25Qb2xpY3k6ICdhcm46YXdzOmlhbTo6YXdzOnBvbGljeS9BZG1pbmlzdHJhdG9yQWNjZXNzJyxcbiAgfSk7XG5cbiAgLy8gRGVwbG95IHN0YWNrIHRoYXQgdXNlcyBmaWxlIGFzc2V0c1xuICBhd2FpdCBmaXh0dXJlLmNka0RlcGxveSgnbGFtYmRhJywge1xuICAgIG9wdGlvbnM6IFtcbiAgICAgIC8vIEV4cGxpY2l0eSBwYXNzIGEgbmFtZSB0aGF0J3Mgc3VyZSB0byBub3QgZXhpc3QsIG90aGVyd2lzZSB0aGUgQ0xJIG1pZ2h0IGFjY2lkZW50YWxseSBmaW5kIGFcbiAgICAgIC8vIGRlZmF1bHQgYm9vdHN0cmFjcCBzdGFjayBpZiB0aGF0IGhhcHBlbnMgdG8gYmUgaW4gdGhlIGFjY291bnQgYWxyZWFkeS5cbiAgICAgICctLXRvb2xraXQtc3RhY2stbmFtZScsICdEZWZpbml0ZWx5RG9lc05vdEV4aXN0JyxcbiAgICAgICctLWNvbnRleHQnLCBgQGF3cy1jZGsvY29yZTpib290c3RyYXBRdWFsaWZpZXI9JHtmaXh0dXJlLnF1YWxpZmllcn1gLFxuICAgICAgJy0tY29udGV4dCcsICdAYXdzLWNkay9jb3JlOm5ld1N0eWxlU3RhY2tTeW50aGVzaXM9MScsXG4gICAgXSxcbiAgfSk7XG59KSk7XG4iXX0= \ No newline at end of file diff --git a/packages/aws-cdk/test/integ/cli/app/app.js b/packages/aws-cdk/test/integ/cli/app/app.js index 450662ac268e0..f0e332eb351fa 100644 --- a/packages/aws-cdk/test/integ/cli/app/app.js +++ b/packages/aws-cdk/test/integ/cli/app/app.js @@ -195,7 +195,7 @@ class LambdaStack extends cdk.Stack { const fn = new lambda.Function(this, 'my-function', { code: lambda.Code.asset(path.join(__dirname, 'lambda')), - runtime: lambda.Runtime.NODEJS_10_X, + runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler' }); diff --git a/packages/aws-cdk/test/integ/cli/bootstrapping.integtest.ts b/packages/aws-cdk/test/integ/cli/bootstrapping.integtest.ts index d7716a2ac3e70..1298c77a5fca8 100644 --- a/packages/aws-cdk/test/integ/cli/bootstrapping.integtest.ts +++ b/packages/aws-cdk/test/integ/cli/bootstrapping.integtest.ts @@ -1,6 +1,6 @@ import * as fs from 'fs'; import * as path from 'path'; -import { MAJOR_VERSION, randomString, withDefaultFixture } from '../helpers/cdk'; +import { randomString, withDefaultFixture } from '../helpers/cdk'; import { integTest } from '../helpers/test-helpers'; const timeout = process.env.CODEBUILD_BUILD_ID ? // if the process is running in CodeBuild @@ -129,28 +129,6 @@ integTest('deploy old style synthesis to new style bootstrap', withDefaultFixtur }); })); -if (MAJOR_VERSION === '1') { - // For v2, the default bootstrap is the modern bootstrap, so this test is predicated on invalid - // assumptions. - - integTest('deploying new style synthesis to old style bootstrap fails', withDefaultFixture(async (fixture) => { - const bootstrapStackName = fixture.bootstrapStackName; - - await fixture.cdkBootstrapLegacy({ - toolkitStackName: bootstrapStackName, - }); - - // Deploy stack that uses file assets, this fails because the bootstrap stack - // is version checked. - await expect(fixture.cdkDeploy('lambda', { - options: [ - '--toolkit-stack-name', bootstrapStackName, - '--context', '@aws-cdk/core:newStyleStackSynthesis=1', - ], - })).rejects.toThrow('exited with error'); - })); -} - integTest('can create a legacy bootstrap stack with --public-access-block-configuration=false', withDefaultFixture(async (fixture) => { const bootstrapStackName = fixture.bootstrapStackName; diff --git a/packages/aws-cdk/test/integ/helpers/cdk.ts b/packages/aws-cdk/test/integ/helpers/cdk.ts index edf996ba36ed6..12e60efe243f7 100644 --- a/packages/aws-cdk/test/integ/helpers/cdk.ts +++ b/packages/aws-cdk/test/integ/helpers/cdk.ts @@ -541,11 +541,22 @@ let sanityChecked: boolean | undefined; * by hand so let's just mass-automate it. */ async function ensureBootstrapped(fixture: TestFixture) { - // 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}`]); - } + // Always use the modern bootstrap stack, otherwise we may get the error + // "refusing to downgrade from version 7 to version 0" when bootstrapping with default + // settings using a v1 CLI. + // + // It doesn't matter for tests: when they want to test something about an actual legacy + // bootstrap stack, they'll create a bootstrap stack with a non-default name to test that exact property. + const envSpecifier = `aws://${await fixture.aws.account()}/${fixture.aws.region}`; + if (ALREADY_BOOTSTRAPPED_IN_THIS_RUN.has(envSpecifier)) { return; } + + await fixture.cdk(['bootstrap', envSpecifier], { + modEnv: { + // Even for v1, use new bootstrap + CDK_NEW_BOOTSTRAP: '1', + }, + }); + ALREADY_BOOTSTRAPPED_IN_THIS_RUN.add(envSpecifier); } /** @@ -689,3 +700,5 @@ const installNpm7 = memoize0(async (): Promise => { return path.join(installDir, 'node_modules', '.bin', 'npm'); }); + +const ALREADY_BOOTSTRAPPED_IN_THIS_RUN = new Set(); \ No newline at end of file diff --git a/packages/aws-cdk/test/integ/init/test-go.sh b/packages/aws-cdk/test/integ/init/test-go.sh index 6b461f3e25ef5..58959855073f0 100755 --- a/packages/aws-cdk/test/integ/init/test-go.sh +++ b/packages/aws-cdk/test/integ/init/test-go.sh @@ -5,13 +5,14 @@ set -eu scriptdir=$(cd $(dirname $0) && pwd) source ${scriptdir}/common.bash +dist_root=$(cd ${DIST_ROOT:-.} && pwd) header Go #------------------------------------------------------------------ if [[ "${1:-}" == "" ]]; then - templates="app" + templates="app sample-app" else templates="$@" fi @@ -22,5 +23,8 @@ for template in $templates; do setup cdk init -l go $template + go mod edit -replace github.com/aws/aws-cdk-go/awscdk=$dist_root/go/awscdk + go mod tidy + go test cdk synth done diff --git a/packages/aws-cdk/test/integ/init/test-java.sh b/packages/aws-cdk/test/integ/init/test-java.sh index f27441809da3c..d2c95984fb178 100755 --- a/packages/aws-cdk/test/integ/init/test-java.sh +++ b/packages/aws-cdk/test/integ/init/test-java.sh @@ -22,5 +22,6 @@ for template in $templates; do setup cdk init -l java $template + mvn package cdk synth done diff --git a/packages/aws-cdk/test/integ/init/test-python.sh b/packages/aws-cdk/test/integ/init/test-python.sh index 1f5163df5ae48..d40d94d4534ca 100755 --- a/packages/aws-cdk/test/integ/init/test-python.sh +++ b/packages/aws-cdk/test/integ/init/test-python.sh @@ -26,6 +26,8 @@ for template in $templates; do source .venv/bin/activate type -p pip pip install -r requirements.txt + ./.venv/bin/pip install -r requirements-dev.txt + pytest cdk synth done diff --git a/packages/aws-cdk/test/integ/run-against-dist b/packages/aws-cdk/test/integ/run-against-dist index ed17ddee88243..c7ade80dbb1f3 100755 --- a/packages/aws-cdk/test/integ/run-against-dist +++ b/packages/aws-cdk/test/integ/run-against-dist @@ -24,6 +24,11 @@ if [[ ! -f $dist_root/build.json ]]; then fi export CANDIDATE_VERSION=$(node -p "require('${dist_root}/build.json').version") + +# FRAMEWORK_VERSION is the version that will be 'npm install'ed by the tests +if [[ "${FRAMEWORK_VERSION:-}" = "" ]]; then + export FRAMEWORK_VERSION=${CANDIDATE_VERSION} +fi export TEST_RUNNER=dist serve_npm_packages diff --git a/packages/aws-cdk/test/integ/run-against-release b/packages/aws-cdk/test/integ/run-against-release index 0865bd331a25d..1e4c0a8b3aba1 100755 --- a/packages/aws-cdk/test/integ/run-against-release +++ b/packages/aws-cdk/test/integ/run-against-release @@ -12,7 +12,14 @@ rm -rf $npmws mkdir -p $npmws # Install the CLI and put it on the PATH -(cd $npmws && npm install aws-cdk) +(cd $npmws && npm install aws-cdk@${RELEASE_TAG:-latest}) + +# FRAMEWORK_VERSION is the version that will be 'npm install'ed by the tests +if [[ "${FRAMEWORK_VERSION:-}" = "" ]]; then + cli_version=$(cd $npmws && node -p "require('aws-cdk/package.json').version") + export FRAMEWORK_VERSION=${cli_version} +fi + export PATH=$npmws/node_modules/.bin:$PATH export TEST_RUNNER=release diff --git a/packages/aws-cdk/test/usersettings.test.ts b/packages/aws-cdk/test/usersettings.test.ts index 948b3b3f907bc..92d7db4a44025 100644 --- a/packages/aws-cdk/test/usersettings.test.ts +++ b/packages/aws-cdk/test/usersettings.test.ts @@ -69,4 +69,24 @@ test('load context from all 3 files if available', async () => { expect(config.context.get('project')).toBe('foobar'); expect(config.context.get('foo')).toBe('bar'); expect(config.context.get('test')).toBe('bar'); +}); + +test('throws an error if the `build` key is specified in the user config', async () => { + // GIVEN + const GIVEN_CONFIG: Map = new Map([ + [USER_CONFIG, { + build: 'foobar', + }], + ]); + + // WHEN + mockedFs.pathExists.mockImplementation(path => { + return GIVEN_CONFIG.has(path); + }); + mockedFs.readJSON.mockImplementation(path => { + return GIVEN_CONFIG.get(path); + }); + + // THEN + await expect(new Configuration().load()).rejects.toEqual(new Error('The `build` key cannot be specified in the user config (~/.cdk.json), specify it in the project config (cdk.json) instead')); }); \ No newline at end of file diff --git a/packages/aws-cdk/test/util/mock-child_process.ts b/packages/aws-cdk/test/util/mock-child_process.ts index 539fd06273399..d7645b4c2ce1a 100644 --- a/packages/aws-cdk/test/util/mock-child_process.ts +++ b/packages/aws-cdk/test/util/mock-child_process.ts @@ -6,16 +6,11 @@ if (!(child_process as any).spawn.mockImplementationOnce) { } export interface Invocation { - commandLine: string[]; + commandLine: string; cwd?: string; exitCode?: number; stdout?: string; - /** - * Only match a prefix of the command (don't care about the details of the arguments) - */ - prefix?: boolean; - /** * Run this function as a side effect, if present */ @@ -26,14 +21,8 @@ export function mockSpawn(...invocations: Invocation[]) { let mock = (child_process.spawn as any); for (const _invocation of invocations) { const invocation = _invocation; // Mirror into variable for closure - mock = mock.mockImplementationOnce((binary: string, args: string[], options: child_process.SpawnOptions) => { - if (invocation.prefix) { - // Match command line prefix - expect([binary, ...args].slice(0, invocation.commandLine.length)).toEqual(invocation.commandLine); - } else { - // Match full command line - expect([binary, ...args]).toEqual(invocation.commandLine); - } + mock = mock.mockImplementationOnce((binary: string, options: child_process.SpawnOptions) => { + expect(binary).toEqual(invocation.commandLine); if (invocation.cwd != null) { expect(options.cwd).toBe(invocation.cwd); @@ -60,8 +49,8 @@ export function mockSpawn(...invocations: Invocation[]) { }); } - mock.mockImplementation((binary: string, args: string[], _options: any) => { - throw new Error(`Did not expect call of ${JSON.stringify([binary, ...args])}`); + mock.mockImplementation((binary: string, _options: any) => { + throw new Error(`Did not expect call of ${binary}`); }); } diff --git a/packages/awslint/package.json b/packages/awslint/package.json index df07c732685ef..626809090c391 100644 --- a/packages/awslint/package.json +++ b/packages/awslint/package.json @@ -18,11 +18,11 @@ "awslint": "bin/awslint" }, "dependencies": { - "@jsii/spec": "^1.41.0", + "@jsii/spec": "^1.42.0", "camelcase": "^6.2.0", "colors": "^1.4.0", "fs-extra": "^9.1.0", - "jsii-reflect": "^1.41.0", + "jsii-reflect": "^1.42.0", "yargs": "^16.2.0" }, "devDependencies": { diff --git a/packages/cdk-assets/package.json b/packages/cdk-assets/package.json index e5572280b04df..d594eccfc0e02 100644 --- a/packages/cdk-assets/package.json +++ b/packages/cdk-assets/package.json @@ -31,7 +31,7 @@ "license": "Apache-2.0", "devDependencies": { "@types/archiver": "^5.3.0", - "@types/glob": "^7.1.4", + "@types/glob": "^7.2.0", "@types/jest": "^26.0.24", "@types/mime": "^2.0.3", "@types/mock-fs": "^4.13.1", @@ -49,7 +49,7 @@ "archiver": "^5.3.0", "aws-sdk": "^2.848.0", "glob": "^7.2.0", - "mime": "^2.5.2", + "mime": "^2.6.0", "yargs": "^16.2.0" }, "repository": { diff --git a/packages/cdk-dasm/package.json b/packages/cdk-dasm/package.json index c7147f7e5b4a5..6589159649794 100644 --- a/packages/cdk-dasm/package.json +++ b/packages/cdk-dasm/package.json @@ -28,7 +28,7 @@ }, "license": "Apache-2.0", "dependencies": { - "codemaker": "^1.39.0", + "codemaker": "^1.42.0", "yaml": "1.10.2" }, "devDependencies": { diff --git a/packages/decdk/package.json b/packages/decdk/package.json index 7ebd9cc3d632c..5867570ec77f1 100644 --- a/packages/decdk/package.json +++ b/packages/decdk/package.json @@ -183,6 +183,7 @@ "@aws-cdk/aws-opensearchservice": "0.0.0", "@aws-cdk/aws-opsworks": "0.0.0", "@aws-cdk/aws-opsworkscm": "0.0.0", + "@aws-cdk/aws-panorama": "0.0.0", "@aws-cdk/aws-pinpoint": "0.0.0", "@aws-cdk/aws-pinpointemail": "0.0.0", "@aws-cdk/aws-qldb": "0.0.0", @@ -190,6 +191,7 @@ "@aws-cdk/aws-ram": "0.0.0", "@aws-cdk/aws-rds": "0.0.0", "@aws-cdk/aws-redshift": "0.0.0", + "@aws-cdk/aws-rekognition": "0.0.0", "@aws-cdk/aws-resourcegroups": "0.0.0", "@aws-cdk/aws-robomaker": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", @@ -230,6 +232,7 @@ "@aws-cdk/aws-waf": "0.0.0", "@aws-cdk/aws-wafregional": "0.0.0", "@aws-cdk/aws-wafv2": "0.0.0", + "@aws-cdk/aws-wisdom": "0.0.0", "@aws-cdk/aws-workspaces": "0.0.0", "@aws-cdk/aws-xray": "0.0.0", "@aws-cdk/cfnspec": "0.0.0", @@ -244,7 +247,7 @@ "@aws-cdk/region-info": "0.0.0", "constructs": "^3.3.69", "fs-extra": "^9.1.0", - "jsii-reflect": "^1.41.0", + "jsii-reflect": "^1.42.0", "jsonschema": "^1.4.0", "yaml": "1.10.2", "yargs": "^16.2.0" @@ -255,7 +258,7 @@ "@types/yaml": "1.9.7", "@types/yargs": "^15.0.14", "jest": "^26.6.3", - "jsii": "^1.41.0" + "jsii": "^1.42.0" }, "keywords": [ "aws", diff --git a/packages/monocdk/package.json b/packages/monocdk/package.json index 7e0b967fe70ab..1f2e65a012070 100644 --- a/packages/monocdk/package.json +++ b/packages/monocdk/package.json @@ -111,7 +111,7 @@ "diff": "^5.0.0", "fast-deep-equal": "^3.1.3", "fs-extra": "^9.1.0", - "ignore": "^5.1.8", + "ignore": "^5.1.9", "jsonschema": "^1.4.0", "minimatch": "^3.0.4", "punycode": "^2.1.1", @@ -277,6 +277,7 @@ "@aws-cdk/aws-opensearchservice": "0.0.0", "@aws-cdk/aws-opsworks": "0.0.0", "@aws-cdk/aws-opsworkscm": "0.0.0", + "@aws-cdk/aws-panorama": "0.0.0", "@aws-cdk/aws-pinpoint": "0.0.0", "@aws-cdk/aws-pinpointemail": "0.0.0", "@aws-cdk/aws-qldb": "0.0.0", @@ -284,6 +285,7 @@ "@aws-cdk/aws-ram": "0.0.0", "@aws-cdk/aws-rds": "0.0.0", "@aws-cdk/aws-redshift": "0.0.0", + "@aws-cdk/aws-rekognition": "0.0.0", "@aws-cdk/aws-resourcegroups": "0.0.0", "@aws-cdk/aws-robomaker": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", @@ -324,6 +326,7 @@ "@aws-cdk/aws-waf": "0.0.0", "@aws-cdk/aws-wafregional": "0.0.0", "@aws-cdk/aws-wafv2": "0.0.0", + "@aws-cdk/aws-wisdom": "0.0.0", "@aws-cdk/aws-workspaces": "0.0.0", "@aws-cdk/aws-xray": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", diff --git a/packages/monocdk/rosetta/basic-portfolio.ts-fixture b/packages/monocdk/rosetta/basic-portfolio.ts-fixture index d8925e6645aa7..3029872ea1f0d 100644 --- a/packages/monocdk/rosetta/basic-portfolio.ts-fixture +++ b/packages/monocdk/rosetta/basic-portfolio.ts-fixture @@ -1,9 +1,9 @@ // Fixture with packages imported, but nothing else -import { Construct, Stack } from '@aws-cdk/core'; +import * as cdk from '@aws-cdk/core'; import * as servicecatalog from '@aws-cdk/aws-servicecatalog'; -class Fixture extends Stack { - constructor(scope: Construct, id: string) { +class Fixture extends cdk.Stack { + constructor(scope: cdk.Construct, id: string) { super(scope, id); const portfolio = new servicecatalog.Portfolio(this, "MyFirstPortfolio", { diff --git a/packages/monocdk/rosetta/basic.ts-fixture b/packages/monocdk/rosetta/basic.ts-fixture new file mode 100644 index 0000000000000..0cc6d1104d521 --- /dev/null +++ b/packages/monocdk/rosetta/basic.ts-fixture @@ -0,0 +1,12 @@ +// Fixture with packages imported, but nothing else +import { Construct } from 'constructs'; +import { Stack, Duration } from '@aws-cdk/core'; + +class Fixture extends Stack { + 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 index 4886d590211df..34c83a31ced35 100644 --- a/packages/monocdk/rosetta/client-vpn.ts-fixture +++ b/packages/monocdk/rosetta/client-vpn.ts-fixture @@ -9,7 +9,7 @@ class Fixture extends Stack { const vpc = new ec2.Vpc(this, 'VPC'); const samlProvider = new iam.SamlProvider(this, 'Provider', { - metadataDocument: SamlMetadataDocument.fromXml('xml'), + metadataDocument: iam.SamlMetadataDocument.fromXml('xml'), }) /// here diff --git a/packages/monocdk/rosetta/conns.ts-fixture b/packages/monocdk/rosetta/conns.ts-fixture deleted file mode 100644 index f29d9a1816a6e..0000000000000 --- a/packages/monocdk/rosetta/conns.ts-fixture +++ /dev/null @@ -1,26 +0,0 @@ -// 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 index 558cc09b1c049..61a973840f007 100644 --- a/packages/monocdk/rosetta/default.ts-fixture +++ b/packages/monocdk/rosetta/default.ts-fixture @@ -1,65 +1,29 @@ -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'; +// Fixture with packages imported, but nothing else +import { Construct, CfnOutput, Stage, Stack, StackProps, StageProps } from '@aws-cdk/core'; +import cdk = require('@aws-cdk/core'); +import codepipeline = require('@aws-cdk/aws-codepipeline'); +import cpactions = require('@aws-cdk/aws-codepipeline-actions'); +import codebuild = require('@aws-cdk/aws-codebuild'); +import codecommit = require('@aws-cdk/aws-codecommit'); +import dynamodb = require('@aws-cdk/aws-dynamodb'); +import ecr = require('@aws-cdk/aws-ecr'); +import ec2 = require('@aws-cdk/aws-ec2'); +import iam = require('@aws-cdk/aws-iam'); +import pipelines = require('@aws-cdk/pipelines'); +import secretsmanager = require('@aws-cdk/aws-secretsmanager'); +import sns = require('@aws-cdk/aws-sns'); +import subscriptions = require('@aws-cdk/aws-sns-subscriptions'); +import s3 = require('@aws-cdk/aws-s3'); -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 MyApplicationStage extends Stage { + constructor(scope: Construct, id: string, props?: StageProps) { + super(scope, id, props); + } +} -class fixture$construct extends Construct { - public constructor(scope: Construct, id: string) { +class Fixture extends Stack { + constructor(scope: Construct, id: string) { super(scope, id); - /// here } } diff --git a/packages/monocdk/rosetta/function.ts-fixture b/packages/monocdk/rosetta/function.ts-fixture deleted file mode 100644 index 91eafe0abfcc0..0000000000000 --- a/packages/monocdk/rosetta/function.ts-fixture +++ /dev/null @@ -1,18 +0,0 @@ -// Fixture with function (`fn`) already created -import * as path from 'path'; -import { Construct, Stack } from '@aws-cdk/core'; -import { Alias, Code, Function, Runtime } from '@aws-cdk/aws-lambda'; - -class Fixture extends Stack { - constructor(scope: Construct, id: string) { - super(scope, id); - - const fn = new Function(this, 'MyFunction', { - runtime: Runtime.NODEJS_12_X, - handler: 'index.handler', - code: Code.fromAsset(path.join(__dirname, 'lambda-handler')), - }); - - /// here - } -} diff --git a/packages/monocdk/rosetta/init.ts-fixture b/packages/monocdk/rosetta/init.ts-fixture new file mode 100644 index 0000000000000..ce18625a2744b --- /dev/null +++ b/packages/monocdk/rosetta/init.ts-fixture @@ -0,0 +1,3 @@ +import { Template } from '@aws-cdk/assertions'; + +/// here \ No newline at end of file diff --git a/packages/monocdk/rosetta/with-batch-job.ts-fixture b/packages/monocdk/rosetta/with-batch-job.ts-fixture deleted file mode 100644 index 47672ba140841..0000000000000 --- a/packages/monocdk/rosetta/with-batch-job.ts-fixture +++ /dev/null @@ -1,38 +0,0 @@ -// 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-objects.ts-fixture b/packages/monocdk/rosetta/with-objects.ts-fixture new file mode 100644 index 0000000000000..1251aad728423 --- /dev/null +++ b/packages/monocdk/rosetta/with-objects.ts-fixture @@ -0,0 +1,49 @@ +// Fixture with packages imported, but nothing else +import { Construct, Stack } from '@aws-cdk/core'; +import appsync = require('@aws-cdk/aws-appsync'); +const pluralize = require('pluralize'); + +const args = { + after: appsync.GraphqlType.string(), + first: appsync.GraphqlType.int(), + before: appsync.GraphqlType.string(), + last: appsync.GraphqlType.int(), +}; + +const Node = new appsync.InterfaceType('Node', { + definition: { id: appsync.GraphqlType.string() } +}); + +const FilmNode = new appsync.ObjectType('FilmNode', { + interfaceTypes: [Node], + definition: { filmName: appsync.GraphqlType.string() } +}); + +function generateEdgeAndConnection(base: appsync.ObjectType) { + const edge = new appsync.ObjectType(`${base.name}Edge`, { + definition: { node: base.attribute(), cursor: appsync.GraphqlType.string() } + }); + const connection = new appsync.ObjectType(`${base.name}Connection`, { + definition: { + edges: edge.attribute({ isList: true }), + [pluralize(base.name)]: base.attribute({ isList: true }), + totalCount: appsync.GraphqlType.int(), + } + }); + return { edge: edge, connection: connection }; +} + +const demo = new appsync.ObjectType('Demo', { + definition: { + id: appsync.GraphqlType.string({ isRequired: true }), + version: appsync.GraphqlType.string({ isRequired: true }), + }, +}); + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + /// here + } +} diff --git a/scripts/cache-load.sh b/scripts/cache-load.sh new file mode 100755 index 0000000000000..23aff254f4f1f --- /dev/null +++ b/scripts/cache-load.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# +# If the environment variable S3_BUILD_CACHE is set, download and extract the +# tarball it points to into the directory $HOME/.s3buildcache. +# +set -eu + +cachedir=$HOME/.s3buildcache +mkdir -p $cachedir + +if [[ "${S3_BUILD_CACHE:-}" = "" ]]; then + exit 0 +fi + +echo "🧳 Build cache enabled: ${S3_BUILD_CACHE}" +if ! aws s3 ls ${S3_BUILD_CACHE} > /dev/null; then + echo "🧳⚠️ Cache not found." + exit 0 +fi + +if ! (cd $cachedir && aws s3 cp ${S3_BUILD_CACHE} - | tar xzv); then + echo "🧳⚠️ Something went wrong fetching the cache. Continuing anyway." +fi diff --git a/scripts/cache-store.sh b/scripts/cache-store.sh new file mode 100755 index 0000000000000..aaf99cbca4f0f --- /dev/null +++ b/scripts/cache-store.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# +# If the environment variable S3_BUILD_CACHE is set, compress and upload the +# contents of $HOME/.s3buildcache to it. +# +set -eu + +cachedir=$HOME/.s3buildcache +mkdir -p $cachedir + +if [[ "${S3_BUILD_CACHE:-}" = "" ]]; then + exit 0 +fi + +echo "🧳 Storing build cache at: ${S3_BUILD_CACHE}" + +if ! (cd $cachedir && tar czv . | aws s3 cp - ${S3_BUILD_CACHE}); then + echo "🧳⚠️ Something went wrong storing the cache." +fi + +echo "🧳 Finished." diff --git a/scripts/list-packages b/scripts/list-packages index 95a2c5ecc0379..fe89f84db9410 100755 --- a/scripts/list-packages +++ b/scripts/list-packages @@ -12,7 +12,9 @@ if (process.argv.length < 4) { process.exit(1); } -child_process.exec('lerna ls --toposort --json', { shell: true }, (error, stdout) => { +const lerna = path.resolve(__dirname, '..', 'node_modules', '.bin', 'lerna'); + +child_process.exec(`${lerna} ls --toposort --json`, { shell: true }, (error, stdout) => { if (error) { console.error('Error: ', error); process.exit(-1); diff --git a/scripts/run-rosetta.sh b/scripts/run-rosetta.sh new file mode 100755 index 0000000000000..0148eeccc3630 --- /dev/null +++ b/scripts/run-rosetta.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# +# Run jsii-rosetta on all jsii packages, using the S3 build cache if available. +# +# Usage: run-rosetta [PKGSFILE] +# +# If you already have a file with a list of all the JSII package directories +# in it, pass it as the first argument. Otherwise, this script will run +# 'list-packages' to determine a list itself. +set -eu +scriptdir=$(cd $(dirname $0) && pwd) + +ROSETTA=${ROSETTA:-npx jsii-rosetta} + +if [[ "${1:-}" = "" ]]; then + echo "Collecting package list..." >&2 + TMPDIR=${TMPDIR:-$(dirname $(mktemp -u))} + node $scriptdir/list-packages $TMPDIR/jsii.txt $TMPDIR/nonjsii.txt + jsii_pkgs_file=$TMPDIR/jsii.txt +else + jsii_pkgs_file=$1 +fi + +rosetta_cache_file=$HOME/.s3buildcache/rosetta-cache.tabl.json +rosetta_cache_opts="" +if [[ -f $rosetta_cache_file ]]; then + rosetta_cache_opts="--cache-from ${rosetta_cache_file}" +fi + +$ROSETTA \ + --compile \ + --output samples.tabl.json \ + $rosetta_cache_opts \ + --directory packages/decdk \ + $(cat $jsii_pkgs_file) + +if [[ -d $(dirname $rosetta_cache_file) ]]; then + # If the cache directory is available, copy the current tablet into it + cp samples.tabl.json $rosetta_cache_file +fi diff --git a/scripts/transform.sh b/scripts/transform.sh index da780c3df49ff..c0bb83b3a6edf 100755 --- a/scripts/transform.sh +++ b/scripts/transform.sh @@ -25,12 +25,11 @@ createSymlinks() { runtarget="build" run_tests="true" -extract_snippets="false" skip_build="" while [[ "${1:-}" != "" ]]; do case $1 in -h|--help) - echo "Usage: transform.sh [--skip-test/build] [--extract]" + echo "Usage: transform.sh [--skip-test/build]" exit 1 ;; --skip-test|--skip-tests) @@ -39,9 +38,6 @@ while [[ "${1:-}" != "" ]]; do --skip-build) skip_build="true" ;; - --extract) - extract_snippets="true" - ;; *) echo "Unrecognized options: $1" exit 1 @@ -52,9 +48,6 @@ done if [ "$run_tests" == "true" ]; then runtarget="$runtarget+test" fi -if [ "$extract_snippets" == "true" ]; then - runtarget="$runtarget+extract" -fi export NODE_OPTIONS="--max-old-space-size=4096 --experimental-worker ${NODE_OPTIONS:-}" diff --git a/tools/@aws-cdk/cdk-build-tools/config/jest.config.js b/tools/@aws-cdk/cdk-build-tools/config/jest.config.js index b8e056af3c8a3..367fff38462a4 100644 --- a/tools/@aws-cdk/cdk-build-tools/config/jest.config.js +++ b/tools/@aws-cdk/cdk-build-tools/config/jest.config.js @@ -21,6 +21,7 @@ module.exports = { coveragePathIgnorePatterns: [ "/lib/.*\\.generated\\.[jt]s", "/test/.*\\.[jt]s", + "/.*\\.jsii\\.js", ], reporters: [ "default", diff --git a/tools/@aws-cdk/cdk-build-tools/lib/package-info.ts b/tools/@aws-cdk/cdk-build-tools/lib/package-info.ts index 5b79a2d675a0a..b264d3043b1b6 100644 --- a/tools/@aws-cdk/cdk-build-tools/lib/package-info.ts +++ b/tools/@aws-cdk/cdk-build-tools/lib/package-info.ts @@ -99,7 +99,7 @@ export function packageCompiler(compilers: CompilerOverrides, options?: CDKBuild if (isJsii()) { const args = ['--silence-warnings=reserved-word']; if (options?.stripDeprecated) { - args.push('--strip-deprecated'); + args.push(`--strip-deprecated ${path.join(__dirname, '..', '..', '..', '..', 'deprecated_apis.txt')}`); } return [compilers.jsii || require.resolve('jsii/bin/jsii'), ...args]; } else { diff --git a/tools/@aws-cdk/cdk-build-tools/package.json b/tools/@aws-cdk/cdk-build-tools/package.json index a99a32059c006..5e2015222bc13 100644 --- a/tools/@aws-cdk/cdk-build-tools/package.json +++ b/tools/@aws-cdk/cdk-build-tools/package.json @@ -38,7 +38,7 @@ "@aws-cdk/pkglint": "0.0.0", "@types/fs-extra": "^8.1.2", "@types/jest": "^26.0.24", - "@types/semver": "^7.3.8", + "@types/semver": "^7.3.9", "@types/yargs": "^15.0.14" }, "dependencies": { @@ -56,9 +56,9 @@ "fs-extra": "^9.1.0", "jest": "^27.3.1", "jest-junit": "^11.1.0", - "jsii": "^1.41.0", - "jsii-pacmak": "^1.41.0", - "jsii-reflect": "^1.41.0", + "jsii": "^1.42.0", + "jsii-pacmak": "^1.42.0", + "jsii-reflect": "^1.42.0", "markdownlint-cli": "^0.29.0", "nyc": "^15.1.0", "semver": "^7.3.5", diff --git a/tools/@aws-cdk/cdk-release/lib/release-notes.ts b/tools/@aws-cdk/cdk-release/lib/release-notes.ts index 4647b4db71533..694613b6c7a0f 100644 --- a/tools/@aws-cdk/cdk-release/lib/release-notes.ts +++ b/tools/@aws-cdk/cdk-release/lib/release-notes.ts @@ -40,6 +40,8 @@ async function releaseNoteContents(currentVersion: Versions, opts: ReleaseNotesO return [ stableChangelogContents, '---', + // DO NOT CHANGE THE FORMAT OF THE FOLLOWING LINE. This will cause the v2 publishing verification canary to skip verification of Alpha modules. + // See https://github.com/cdklabs/cdk-ops/pull/1769. `## Alpha modules (${currentVersion.alphaVersion})`, alphaChangelogContents, ].join('\n'); diff --git a/tools/@aws-cdk/cdk-release/package.json b/tools/@aws-cdk/cdk-release/package.json index ed0b5705e94df..26b5d08f9764e 100644 --- a/tools/@aws-cdk/cdk-release/package.json +++ b/tools/@aws-cdk/cdk-release/package.json @@ -43,7 +43,7 @@ "conventional-changelog-config-spec": "^2.1.0", "conventional-changelog-preset-loader": "^2.3.4", "conventional-changelog-writer": "^4.1.0", - "conventional-commits-parser": "^3.2.2", + "conventional-commits-parser": "^3.2.3", "detect-indent": "^6.1.0", "detect-newline": "^3.1.0", "fs-extra": "^9.1.0", diff --git a/tools/@aws-cdk/cfn2ts/package.json b/tools/@aws-cdk/cfn2ts/package.json index dbb024e64cb32..8b484144ee4f8 100644 --- a/tools/@aws-cdk/cfn2ts/package.json +++ b/tools/@aws-cdk/cfn2ts/package.json @@ -32,7 +32,7 @@ "license": "Apache-2.0", "dependencies": { "@aws-cdk/cfnspec": "0.0.0", - "codemaker": "^1.39.0", + "codemaker": "^1.42.0", "fast-json-patch": "^3.1.0", "fs-extra": "^9.1.0", "yargs": "^16.2.0" diff --git a/tools/@aws-cdk/eslint-plugin/package.json b/tools/@aws-cdk/eslint-plugin/package.json index 87c004f94d846..19b0e287247d2 100644 --- a/tools/@aws-cdk/eslint-plugin/package.json +++ b/tools/@aws-cdk/eslint-plugin/package.json @@ -14,7 +14,7 @@ "build+extract": "npm run build" }, "devDependencies": { - "@types/eslint": "^7.28.1", + "@types/eslint": "^7.28.2", "@types/fs-extra": "^8.1.2", "@types/jest": "^26.0.24", "@types/node": "^10.17.60", diff --git a/tools/@aws-cdk/individual-pkg-gen/transform-packages.ts b/tools/@aws-cdk/individual-pkg-gen/transform-packages.ts index b56e39c788f2b..a2855fb2fa1b3 100644 --- a/tools/@aws-cdk/individual-pkg-gen/transform-packages.ts +++ b/tools/@aws-cdk/individual-pkg-gen/transform-packages.ts @@ -6,6 +6,21 @@ const lerna_project = require('@lerna/project'); // eslint-disable-next-line @typescript-eslint/no-require-imports const ver = require('../../../scripts/resolve-version'); +const CFN_STABILITY_BANNER = [ + '![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', +].join('\n'); + +const FEATURE_CFN_STABILITY_BANNER = `> **CFN Resources:** 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`; + +const FEATURE_CFN_STABILITY_LINE = /CFN Resources\s+\| !\[Stable]\(https:\/\/img\.shields\.io\/badge\/stable-success\.svg\?style=for-the-badge\)\n/gm; + /** * @aws-cdk/ scoped packages that may be present in devDependencies and need to * be retained (or else pkglint might declare the package unworthy). @@ -109,6 +124,13 @@ function transformPackages(): void { packageUnscopedName: `${pkg.name.substring('@aws-cdk/'.length)}`, }); fs.outputFileSync(destination, sourceCodeOutput); + } else if (sourceFileName === 'README.md') { + // Remove the stability banner for Cfn constructs, since they don't exist in the alpha modules + let sourceCode = fs.readFileSync(source).toString(); + [CFN_STABILITY_BANNER, FEATURE_CFN_STABILITY_BANNER, FEATURE_CFN_STABILITY_LINE].forEach(pattern => { + sourceCode = sourceCode.replace(pattern, ''); + }); + fs.outputFileSync(destination, sourceCode); } else { const stat = fs.statSync(source); if (stat.isDirectory()) { diff --git a/tools/@aws-cdk/pkglint/package.json b/tools/@aws-cdk/pkglint/package.json index 72283bad492b2..463b2b96c3e5e 100644 --- a/tools/@aws-cdk/pkglint/package.json +++ b/tools/@aws-cdk/pkglint/package.json @@ -39,9 +39,9 @@ "devDependencies": { "@aws-cdk/eslint-plugin": "0.0.0", "@types/fs-extra": "^8.1.2", - "@types/glob": "^7.1.4", + "@types/glob": "^7.2.0", "@types/jest": "^26.0.24", - "@types/semver": "^7.3.8", + "@types/semver": "^7.3.9", "@types/yargs": "^15.0.14", "@typescript-eslint/eslint-plugin": "^4.33.0", "@typescript-eslint/parser": "^4.33.0", diff --git a/tools/@aws-cdk/prlint/package.json b/tools/@aws-cdk/prlint/package.json index 1c45caf95233d..c85296b6a292a 100644 --- a/tools/@aws-cdk/prlint/package.json +++ b/tools/@aws-cdk/prlint/package.json @@ -13,14 +13,14 @@ "dependencies": { "@actions/core": "^1.6.0", "@actions/github": "^2.2.0", - "conventional-commits-parser": "^3.2.2", + "conventional-commits-parser": "^3.2.3", "fs-extra": "^9.1.0", "github-api": "^3.4.0", "glob": "^7.2.0" }, "devDependencies": { "@types/fs-extra": "^9.0.13", - "@types/glob": "^7.1.4", + "@types/glob": "^7.2.0", "@types/jest": "^26.0.24", "jest": "^26.6.3", "make-runnable": "^1.3.10", diff --git a/tools/@aws-cdk/yarn-cling/package.json b/tools/@aws-cdk/yarn-cling/package.json index b8c930eb66867..036cf5377eac2 100644 --- a/tools/@aws-cdk/yarn-cling/package.json +++ b/tools/@aws-cdk/yarn-cling/package.json @@ -40,7 +40,7 @@ "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "@types/node": "^10.17.60", - "@types/semver": "^7.3.8", + "@types/semver": "^7.3.9", "@types/yarnpkg__lockfile": "^1.1.5", "jest": "^26.6.3", "typescript": "~3.9.10" diff --git a/version.v1.json b/version.v1.json index cf3002b8d98b8..1d5c1405e9991 100644 --- a/version.v1.json +++ b/version.v1.json @@ -1,3 +1,3 @@ { - "version": "1.130.0" + "version": "1.131.0" } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 48ecde5d6ee28..b98b3ecdb6050 100644 --- a/yarn.lock +++ b/yarn.lock @@ -32,32 +32,32 @@ dependencies: "@babel/highlight" "^7.10.4" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.14.5", "@babel/code-frame@^7.15.8": - version "7.15.8" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz#45990c47adadb00c03677baa89221f7cc23d2503" - integrity sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg== - dependencies: - "@babel/highlight" "^7.14.5" - -"@babel/compat-data@^7.15.0": - version "7.15.0" - resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz#2dbaf8b85334796cafbb0f5793a90a2fc010b176" - integrity sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA== - -"@babel/core@^7.1.0", "@babel/core@^7.7.2", "@babel/core@^7.7.5": - version "7.15.8" - resolved "https://registry.npmjs.org/@babel/core/-/core-7.15.8.tgz#195b9f2bffe995d2c6c159e72fe525b4114e8c10" - integrity sha512-3UG9dsxvYBMYwRv+gS41WKHno4K60/9GPy1CJaH6xy3Elq8CTtvtjT5R5jmNhXfCYLX2mTw+7/aq5ak/gOE0og== - dependencies: - "@babel/code-frame" "^7.15.8" - "@babel/generator" "^7.15.8" - "@babel/helper-compilation-targets" "^7.15.4" - "@babel/helper-module-transforms" "^7.15.8" - "@babel/helpers" "^7.15.4" - "@babel/parser" "^7.15.8" - "@babel/template" "^7.15.4" - "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.6" +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.0.tgz#0dfc80309beec8411e65e706461c408b0bb9b431" + integrity sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA== + dependencies: + "@babel/highlight" "^7.16.0" + +"@babel/compat-data@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.0.tgz#ea269d7f78deb3a7826c39a4048eecda541ebdaa" + integrity sha512-DGjt2QZse5SGd9nfOSqO4WLJ8NN/oHkijbXbPrxuoJO3oIPJL3TciZs9FX+cOHNiY9E9l0opL8g7BmLe3T+9ew== + +"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.7.2", "@babel/core@^7.7.5": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.16.0.tgz#c4ff44046f5fe310525cc9eb4ef5147f0c5374d4" + integrity sha512-mYZEvshBRHGsIAiyH5PzCFTCfbWfoYbO/jcSdXQSUQu1/pW0xDZAUP7KEc32heqWTAfAHhV9j1vH8Sav7l+JNQ== + dependencies: + "@babel/code-frame" "^7.16.0" + "@babel/generator" "^7.16.0" + "@babel/helper-compilation-targets" "^7.16.0" + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helpers" "^7.16.0" + "@babel/parser" "^7.16.0" + "@babel/template" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" @@ -65,113 +65,113 @@ semver "^6.3.0" source-map "^0.5.0" -"@babel/generator@^7.15.4", "@babel/generator@^7.15.8", "@babel/generator@^7.7.2": - version "7.15.8" - resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.15.8.tgz#fa56be6b596952ceb231048cf84ee499a19c0cd1" - integrity sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g== +"@babel/generator@^7.16.0", "@babel/generator@^7.7.2": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.16.0.tgz#d40f3d1d5075e62d3500bccb67f3daa8a95265b2" + integrity sha512-RR8hUCfRQn9j9RPKEVXo9LiwoxLPYn6hNZlvUOR8tSnaxlD0p0+la00ZP9/SnRt6HchKr+X0fO2r8vrETiJGew== dependencies: - "@babel/types" "^7.15.6" + "@babel/types" "^7.16.0" jsesc "^2.5.1" source-map "^0.5.0" -"@babel/helper-compilation-targets@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz#cf6d94f30fbefc139123e27dd6b02f65aeedb7b9" - integrity sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ== +"@babel/helper-compilation-targets@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.0.tgz#01d615762e796c17952c29e3ede9d6de07d235a8" + integrity sha512-S7iaOT1SYlqK0sQaCi21RX4+13hmdmnxIEAnQUB/eh7GeAnRjOUgTYpLkUOiRXzD+yog1JxP0qyAQZ7ZxVxLVg== dependencies: - "@babel/compat-data" "^7.15.0" + "@babel/compat-data" "^7.16.0" "@babel/helper-validator-option" "^7.14.5" browserslist "^4.16.6" semver "^6.3.0" -"@babel/helper-function-name@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz#845744dafc4381a4a5fb6afa6c3d36f98a787ebc" - integrity sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw== +"@babel/helper-function-name@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz#b7dd0797d00bbfee4f07e9c4ea5b0e30c8bb1481" + integrity sha512-BZh4mEk1xi2h4HFjWUXRQX5AEx4rvaZxHgax9gcjdLWdkjsY7MKt5p0otjsg5noXw+pB+clMCjw+aEVYADMjog== dependencies: - "@babel/helper-get-function-arity" "^7.15.4" - "@babel/template" "^7.15.4" - "@babel/types" "^7.15.4" + "@babel/helper-get-function-arity" "^7.16.0" + "@babel/template" "^7.16.0" + "@babel/types" "^7.16.0" -"@babel/helper-get-function-arity@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz#098818934a137fce78b536a3e015864be1e2879b" - integrity sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA== +"@babel/helper-get-function-arity@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz#0088c7486b29a9cb5d948b1a1de46db66e089cfa" + integrity sha512-ASCquNcywC1NkYh/z7Cgp3w31YW8aojjYIlNg4VeJiHkqyP4AzIvr4qx7pYDb4/s8YcsZWqqOSxgkvjUz1kpDQ== dependencies: - "@babel/types" "^7.15.4" + "@babel/types" "^7.16.0" -"@babel/helper-hoist-variables@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz#09993a3259c0e918f99d104261dfdfc033f178df" - integrity sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA== +"@babel/helper-hoist-variables@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.0.tgz#4c9023c2f1def7e28ff46fc1dbcd36a39beaa81a" + integrity sha512-1AZlpazjUR0EQZQv3sgRNfM9mEVWPK3M6vlalczA+EECcPz3XPh6VplbErL5UoMpChhSck5wAJHthlj1bYpcmg== dependencies: - "@babel/types" "^7.15.4" + "@babel/types" "^7.16.0" -"@babel/helper-member-expression-to-functions@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz#bfd34dc9bba9824a4658b0317ec2fd571a51e6ef" - integrity sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA== +"@babel/helper-member-expression-to-functions@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.0.tgz#29287040efd197c77636ef75188e81da8bccd5a4" + integrity sha512-bsjlBFPuWT6IWhl28EdrQ+gTvSvj5tqVP5Xeftp07SEuz5pLnsXZuDkDD3Rfcxy0IsHmbZ+7B2/9SHzxO0T+sQ== dependencies: - "@babel/types" "^7.15.4" + "@babel/types" "^7.16.0" -"@babel/helper-module-imports@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.15.4.tgz#e18007d230632dea19b47853b984476e7b4e103f" - integrity sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA== +"@babel/helper-module-imports@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz#90538e60b672ecf1b448f5f4f5433d37e79a3ec3" + integrity sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg== dependencies: - "@babel/types" "^7.15.4" + "@babel/types" "^7.16.0" -"@babel/helper-module-transforms@^7.15.8": - version "7.15.8" - resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.8.tgz#d8c0e75a87a52e374a8f25f855174786a09498b2" - integrity sha512-DfAfA6PfpG8t4S6npwzLvTUpp0sS7JrcuaMiy1Y5645laRJIp/LiLGIBbQKaXSInK8tiGNI7FL7L8UvB8gdUZg== +"@babel/helper-module-transforms@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.0.tgz#1c82a8dd4cb34577502ebd2909699b194c3e9bb5" + integrity sha512-My4cr9ATcaBbmaEa8M0dZNA74cfI6gitvUAskgDtAFmAqyFKDSHQo5YstxPbN+lzHl2D9l/YOEFqb2mtUh4gfA== dependencies: - "@babel/helper-module-imports" "^7.15.4" - "@babel/helper-replace-supers" "^7.15.4" - "@babel/helper-simple-access" "^7.15.4" - "@babel/helper-split-export-declaration" "^7.15.4" + "@babel/helper-module-imports" "^7.16.0" + "@babel/helper-replace-supers" "^7.16.0" + "@babel/helper-simple-access" "^7.16.0" + "@babel/helper-split-export-declaration" "^7.16.0" "@babel/helper-validator-identifier" "^7.15.7" - "@babel/template" "^7.15.4" - "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.6" + "@babel/template" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" -"@babel/helper-optimise-call-expression@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz#f310a5121a3b9cc52d9ab19122bd729822dee171" - integrity sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw== +"@babel/helper-optimise-call-expression@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.0.tgz#cecdb145d70c54096b1564f8e9f10cd7d193b338" + integrity sha512-SuI467Gi2V8fkofm2JPnZzB/SUuXoJA5zXe/xzyPP2M04686RzFKFHPK6HDVN6JvWBIEW8tt9hPR7fXdn2Lgpw== dependencies: - "@babel/types" "^7.15.4" + "@babel/types" "^7.16.0" "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0": version "7.14.5" resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9" integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ== -"@babel/helper-replace-supers@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz#52a8ab26ba918c7f6dee28628b07071ac7b7347a" - integrity sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw== +"@babel/helper-replace-supers@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.0.tgz#73055e8d3cf9bcba8ddb55cad93fedc860f68f17" + integrity sha512-TQxuQfSCdoha7cpRNJvfaYxxxzmbxXw/+6cS7V02eeDYyhxderSoMVALvwupA54/pZcOTtVeJ0xccp1nGWladA== dependencies: - "@babel/helper-member-expression-to-functions" "^7.15.4" - "@babel/helper-optimise-call-expression" "^7.15.4" - "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.4" + "@babel/helper-member-expression-to-functions" "^7.16.0" + "@babel/helper-optimise-call-expression" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" -"@babel/helper-simple-access@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.15.4.tgz#ac368905abf1de8e9781434b635d8f8674bcc13b" - integrity sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg== +"@babel/helper-simple-access@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.0.tgz#21d6a27620e383e37534cf6c10bba019a6f90517" + integrity sha512-o1rjBT/gppAqKsYfUdfHq5Rk03lMQrkPHG1OWzHWpLgVXRH4HnMM9Et9CVdIqwkCQlobnGHEJMsgWP/jE1zUiw== dependencies: - "@babel/types" "^7.15.4" + "@babel/types" "^7.16.0" -"@babel/helper-split-export-declaration@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz#aecab92dcdbef6a10aa3b62ab204b085f776e257" - integrity sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw== +"@babel/helper-split-export-declaration@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.0.tgz#29672f43663e936df370aaeb22beddb3baec7438" + integrity sha512-0YMMRpuDFNGTHNRiiqJX19GjNXA4H0E8jZ2ibccfSxaCogbm3am5WN/2nQNj0YnQwGWM1J06GOcQ2qnh3+0paw== dependencies: - "@babel/types" "^7.15.4" + "@babel/types" "^7.16.0" -"@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.14.9", "@babel/helper-validator-identifier@^7.15.7": +"@babel/helper-validator-identifier@^7.15.7": version "7.15.7" resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== @@ -181,28 +181,28 @@ resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow== -"@babel/helpers@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.4.tgz#5f40f02050a3027121a3cf48d497c05c555eaf43" - integrity sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ== +"@babel/helpers@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.0.tgz#875519c979c232f41adfbd43a3b0398c2e388183" + integrity sha512-dVRM0StFMdKlkt7cVcGgwD8UMaBfWJHl3A83Yfs8GQ3MO0LHIIIMvK7Fa0RGOGUQ10qikLaX6D7o5htcQWgTMQ== dependencies: - "@babel/template" "^7.15.4" - "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.4" + "@babel/template" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" -"@babel/highlight@^7.10.4", "@babel/highlight@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9" - integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg== +"@babel/highlight@^7.10.4", "@babel/highlight@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.0.tgz#6ceb32b2ca4b8f5f361fb7fd821e3fddf4a1725a" + integrity sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g== dependencies: - "@babel/helper-validator-identifier" "^7.14.5" + "@babel/helper-validator-identifier" "^7.15.7" chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.15.4", "@babel/parser@^7.15.8", "@babel/parser@^7.7.2": - version "7.15.8" - resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.15.8.tgz#7bacdcbe71bdc3ff936d510c15dcea7cf0b99016" - integrity sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA== +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.0", "@babel/parser@^7.7.2": + version "7.16.2" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.16.2.tgz#3723cd5c8d8773eef96ce57ea1d9b7faaccd12ac" + integrity sha512-RUVpT0G2h6rOZwqLDTrKk7ksNv7YpAilTnYe1/Q+eDjxEceRMKVWbCsX7t8h6C1qCFi/1Y8WZjcEPBAFG27GPw== "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" @@ -289,42 +289,42 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-typescript@^7.7.2": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz#b82c6ce471b165b5ce420cf92914d6fb46225716" - integrity sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q== + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.0.tgz#2feeb13d9334cc582ea9111d3506f773174179bb" + integrity sha512-Xv6mEXqVdaqCBfJFyeab0fH2DnUoMsDmhamxsSi4j8nLd4Vtw213WMJr55xxqipC/YVWyPY3K0blJncPYji+dQ== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/template@^7.15.4", "@babel/template@^7.3.3": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz#51898d35dcf3faa670c4ee6afcfd517ee139f194" - integrity sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg== - dependencies: - "@babel/code-frame" "^7.14.5" - "@babel/parser" "^7.15.4" - "@babel/types" "^7.15.4" - -"@babel/traverse@^7.1.0", "@babel/traverse@^7.15.4", "@babel/traverse@^7.7.2": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz#ff8510367a144bfbff552d9e18e28f3e2889c22d" - integrity sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA== - dependencies: - "@babel/code-frame" "^7.14.5" - "@babel/generator" "^7.15.4" - "@babel/helper-function-name" "^7.15.4" - "@babel/helper-hoist-variables" "^7.15.4" - "@babel/helper-split-export-declaration" "^7.15.4" - "@babel/parser" "^7.15.4" - "@babel/types" "^7.15.4" +"@babel/template@^7.16.0", "@babel/template@^7.3.3": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.16.0.tgz#d16a35ebf4cd74e202083356fab21dd89363ddd6" + integrity sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A== + dependencies: + "@babel/code-frame" "^7.16.0" + "@babel/parser" "^7.16.0" + "@babel/types" "^7.16.0" + +"@babel/traverse@^7.1.0", "@babel/traverse@^7.16.0", "@babel/traverse@^7.7.2": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.0.tgz#965df6c6bfc0a958c1e739284d3c9fa4a6e3c45b" + integrity sha512-qQ84jIs1aRQxaGaxSysII9TuDaguZ5yVrEuC0BN2vcPlalwfLovVmCjbFDPECPXcYM/wLvNFfp8uDOliLxIoUQ== + dependencies: + "@babel/code-frame" "^7.16.0" + "@babel/generator" "^7.16.0" + "@babel/helper-function-name" "^7.16.0" + "@babel/helper-hoist-variables" "^7.16.0" + "@babel/helper-split-export-declaration" "^7.16.0" + "@babel/parser" "^7.16.0" + "@babel/types" "^7.16.0" debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.15.4", "@babel/types@^7.15.6", "@babel/types@^7.3.0", "@babel/types@^7.3.3": - version "7.15.6" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz#99abdc48218b2881c058dd0a7ab05b99c9be758f" - integrity sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig== +"@babel/types@^7.0.0", "@babel/types@^7.16.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.16.0.tgz#db3b313804f96aadd0b776c4823e127ad67289ba" + integrity sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg== dependencies: - "@babel/helper-validator-identifier" "^7.14.9" + "@babel/helper-validator-identifier" "^7.15.7" to-fast-properties "^2.0.0" "@balena/dockerignore@^1.0.2": @@ -387,9 +387,9 @@ minimatch "^3.0.4" "@humanwhocodes/object-schema@^1.2.0": - version "1.2.0" - resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf" - integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w== + version "1.2.1" + resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== "@hutson/parse-repository-url@^3.0.0": version "3.0.2" @@ -752,26 +752,18 @@ "@types/yargs" "^16.0.0" chalk "^4.0.0" -"@jsii/check-node@1.40.0": - version "1.40.0" - resolved "https://registry.npmjs.org/@jsii/check-node/-/check-node-1.40.0.tgz#49882a61ad1b3a37cd35c35fa1a2301955f1c058" - integrity sha512-rk0hFXxFQR8rDGUfsZT9ua6OufOpnLQWsNFyFU86AvpoKQ0ciw2KlGdWs7OYFnzPq8sQGhSS+iuBrUboaHW3jg== +"@jsii/check-node@1.42.0": + version "1.42.0" + resolved "https://registry.npmjs.org/@jsii/check-node/-/check-node-1.42.0.tgz#10dd84fbefa020344c9574079361c1a18754872a" + integrity sha512-URX4s0iOmuxbERL2rO10JlwedYbAT/3vM2HqswgjtJUbZTFgHsmg+Tzh3JglJzKuCg8Xm4m6CP4UlFMPqPRcqA== dependencies: chalk "^4.1.2" semver "^7.3.5" -"@jsii/check-node@1.41.0": - version "1.41.0" - resolved "https://registry.npmjs.org/@jsii/check-node/-/check-node-1.41.0.tgz#17b6895e1fcc0b8bbb8fa81b52b17c47c9c47674" - integrity sha512-lV/vMK1HZQcUye2vXPu6XsmnTk7fEui0GnQsPAX1eLWfRMkxkRblT4VZ9DQTYjMno2HuVP4IH51fiFoICMmnkA== - dependencies: - chalk "^4.1.2" - semver "^7.3.5" - -"@jsii/spec@^1.41.0": - version "1.41.0" - resolved "https://registry.npmjs.org/@jsii/spec/-/spec-1.41.0.tgz#d504c8536139a97986b1ec63201d3575972e1e9c" - integrity sha512-sN7x6C0DGLngiO6SkrM/7gVaHyeja59bDZODZtBXIq8kBIC+GgAFS8P0s1e5FpU9mHHvvHq4rvzvcIbxw0nkXw== +"@jsii/spec@^1.42.0": + version "1.42.0" + resolved "https://registry.npmjs.org/@jsii/spec/-/spec-1.42.0.tgz#39e787e5ac2ddc96256b73421603bc734c56f7d8" + integrity sha512-SS2Q1Ds/yiTejd/0KO5lC6SUGqlfjuqZ6nAxJxLU76JQ99v1spRJeS7oi/2OW+ZmTEwBy81DgjOxA8bwUc0U/Q== dependencies: jsonschema "^1.4.0" @@ -1468,9 +1460,9 @@ fastq "^1.6.0" "@npmcli/ci-detect@^1.0.0": - version "1.3.0" - resolved "https://registry.npmjs.org/@npmcli/ci-detect/-/ci-detect-1.3.0.tgz#6c1d2c625fb6ef1b9dea85ad0a5afcbef85ef22a" - integrity sha512-oN3y7FAROHhrAt7Rr7PnTSwrHrZVRTS2ZbyxeQwSSYD0ifwM3YNgQqbaRmjcWoPyq77MjchusjJDspbzMmip1Q== + version "1.4.0" + resolved "https://registry.npmjs.org/@npmcli/ci-detect/-/ci-detect-1.4.0.tgz#18478bbaa900c37bfbd8a2006a6262c62e8b0fe1" + integrity sha512-3BGrt6FLjqM6br5AhWRKTr3u5GIVkjRYeAFrMp3HjnfICrg4xOrVRwFavKT6tsp++bq5dluL5t8ME/Nha/6c1Q== "@npmcli/fs@^1.0.0": version "1.0.0" @@ -1774,10 +1766,10 @@ dependencies: "@types/glob" "*" -"@types/aws-lambda@^8.10.84": - version "8.10.84" - resolved "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.84.tgz#b1f391ceeb6908b28d8416d93f27afe8d1348d4e" - integrity sha512-5V78eLtmN0d4RA14hKDwcsMQRl3JotQJlhGFDBo/jdE2TyDFRaYwB/UmMUC4SzhSvRGn+YMkh7jGPnXi8COAng== +"@types/aws-lambda@^8.10.85": + version "8.10.85" + resolved "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.85.tgz#26cd76897b1972247cbc1a34b6f21d023e987437" + integrity sha512-cMRXVxb+NMb6EekKel1fPBfz2ZqE5cGhIS14G7FVUM4Bqilx0lHKnZbsDLWLSeckDpkvlp5six2F7UWyEEJSoQ== "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14", "@types/babel__core@^7.1.7": version "7.1.16" @@ -1817,10 +1809,10 @@ resolved "https://registry.npmjs.org/@types/changelog-parser/-/changelog-parser-2.7.1.tgz#da124373fc8abfb6951fef83718ea5f041fea527" integrity sha512-OFZB7OlG6nrkcnvJhcyV2Zm/PUGk40oHyfaEBRjlm+ghrKxbFQI+xao/IzYL0G72fpLCTGGs3USrhe38/FF6QQ== -"@types/eslint@^7.28.1": - version "7.28.1" - resolved "https://registry.npmjs.org/@types/eslint/-/eslint-7.28.1.tgz#50b07747f1f84c2ba8cd394cf0fe0ba07afce320" - integrity sha512-XhZKznR3i/W5dXqUhgU9fFdJekufbeBd5DALmkuXoeFcjbQcPk+2cL+WLHf6Q81HWAnM2vrslIHpGVyCAviRwg== +"@types/eslint@^7.28.2": + version "7.28.2" + resolved "https://registry.npmjs.org/@types/eslint/-/eslint-7.28.2.tgz#0ff2947cdd305897c52d5372294e8c76f351db68" + integrity sha512-KubbADPkfoU75KgKeKLsFHXnU4ipH7wYg0TRT33NK3N3yiu7jlFAAoygIWBV+KbuHx/G+AvuGX6DllnK35gfJA== dependencies: "@types/estree" "*" "@types/json-schema" "*" @@ -1844,10 +1836,10 @@ dependencies: "@types/node" "*" -"@types/glob@*", "@types/glob@^7.1.4": - version "7.1.4" - resolved "https://registry.npmjs.org/@types/glob/-/glob-7.1.4.tgz#ea59e21d2ee5c517914cb4bc8e4153b99e566672" - integrity sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA== +"@types/glob@*", "@types/glob@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" + integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== dependencies: "@types/minimatch" "*" "@types/node" "*" @@ -1878,7 +1870,7 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@^26.0.24": +"@types/jest@^26.0.22", "@types/jest@^26.0.24": version "26.0.24" resolved "https://registry.npmjs.org/@types/jest/-/jest-26.0.24.tgz#943d11976b16739185913a1936e0de0c4a7d595a" integrity sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w== @@ -1896,10 +1888,10 @@ resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= -"@types/lodash@^4.14.175": - version "4.14.175" - resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.175.tgz#b78dfa959192b01fae0ad90e166478769b215f45" - integrity sha512-XmdEOrKQ8a1Y/yxQFOMbC47G/V2VDO1GvMRnl4O75M4GW/abC5tnfzadQYkqEveqRM1dEJGFFegfPNA2vvx2iw== +"@types/lodash@^4.14.176": + version "4.14.176" + resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.176.tgz#641150fc1cda36fbfa329de603bbb175d7ee20c0" + integrity sha512-xZmuPTa3rlZoIbtDUyJKZQimJV3bxCmzMIO2c9Pz9afyDro6kr7R79GwcB6mRhuoPmV2p1Vb66WOJH7F886WKQ== "@types/md5@^2.3.1": version "2.3.1" @@ -1936,9 +1928,9 @@ integrity sha512-uv53RrNdhbkV/3VmVCtfImfYCWC3GTTRn3R11Whni3EJ+gb178tkZBVNj2edLY5CMrB749dQi+SJkg87jsN8UQ== "@types/node@*", "@types/node@>= 8", "@types/node@^16.9.2": - version "16.10.5" - resolved "https://registry.npmjs.org/@types/node/-/node-16.10.5.tgz#7fe4123b061753f1a58a6cd077ff0bb069ee752d" - integrity sha512-9iI3OOlkyOjLQQ9s+itIJNMRepDhB/96jW3fqduJ2FTPQj1dJjw6Q3QCImF9FE1wmdBs5QSun4FjDSFS8d8JLw== + version "16.11.6" + resolved "https://registry.npmjs.org/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" + integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== "@types/node@^10.17.60": version "10.17.60" @@ -1977,10 +1969,10 @@ resolved "https://registry.npmjs.org/@types/punycode/-/punycode-2.1.0.tgz#89e4f3d09b3f92e87a80505af19be7e0c31d4e83" integrity sha512-PG5aLpW6PJOeV2fHRslP4IOMWn+G+Uq8CfnyJ+PDS8ndCbU+soO+fB3NKCKo0p/Jh2Y4aPaiQZsrOXFdzpcA6g== -"@types/semver@^7.3.8": - version "7.3.8" - resolved "https://registry.npmjs.org/@types/semver/-/semver-7.3.8.tgz#508a27995498d7586dcecd77c25e289bfaf90c59" - integrity sha512-D/2EJvAlCEtYFEYmmlGwbGXuK886HzyCc3nZX/tkFTQdEU8jZDAgiv08P162yB17y4ZXZoq7yFAnW4GDBb9Now== +"@types/semver@^7.3.9": + version "7.3.9" + resolved "https://registry.npmjs.org/@types/semver/-/semver-7.3.9.tgz#152c6c20a7688c30b967ec1841d31ace569863fc" + integrity sha512-L/TMpyURfBkf+o/526Zb6kd/tchUP3iBDEPjqjb+U2MAJhVRxxrmr2fwpe08E7QsV7YLcpq0tUaQ9O9x97ZIxQ== "@types/sinon@^9.0.11": version "9.0.11" @@ -2295,7 +2287,7 @@ anymatch@^2.0.0: micromatch "^3.1.4" normalize-path "^2.1.1" -anymatch@^3.0.3: +anymatch@^3.0.3, anymatch@~3.1.2: version "3.1.2" resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== @@ -2484,9 +2476,9 @@ astral-regex@^2.0.0: integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== async@^3.2.0: - version "3.2.1" - resolved "https://registry.npmjs.org/async/-/async-3.2.1.tgz#d3274ec66d107a47476a4c49136aacdb00665fc8" - integrity sha512-XdD5lRO/87udXCMC9meWdYiR+Nq6ZjUfXidViUZGu2F1MO4T3XwZ1et0hb2++BgLfhyJwy44BGB/yx80ABx8hg== + version "3.2.2" + resolved "https://registry.npmjs.org/async/-/async-3.2.2.tgz#2eb7671034bb2194d45d30e31e24ec7e7f9670cd" + integrity sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g== asynckit@^0.4.0: version "0.4.0" @@ -2523,9 +2515,9 @@ aws-sdk-mock@^5.4.0: traverse "^0.6.6" aws-sdk@^2.596.0, aws-sdk@^2.848.0, aws-sdk@^2.928.0, aws-sdk@^2.979.0: - version "2.1006.0" - resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1006.0.tgz#fc2f7e267d19a6297f732e19449461bb944682af" - integrity sha512-lwXAy706+1HVQqMnHaahdeBZZbdu6TWrtTY0ydeG0qanwldTFNMLczwnETTZWYsqNAU+wjl1VzmFdMO4gePLNQ== + version "2.1020.0" + resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1020.0.tgz#91fee48f3897e21b0fa6fbd066ea716ac2f0957d" + integrity sha512-cCFLGRfzJn0whOioljFjcFpQTXWB4PTdVnrpNhX2R687W3Yz6WriHxHqIxVnIke1yp9twU00z4kW522U809l0g== dependencies: buffer "4.9.2" events "1.1.1" @@ -2583,14 +2575,14 @@ babel-jest@^27.3.1: slash "^3.0.0" babel-plugin-istanbul@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765" - integrity sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ== + version "6.1.1" + resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@istanbuljs/load-nyc-config" "^1.0.0" "@istanbuljs/schema" "^0.1.2" - istanbul-lib-instrument "^4.0.0" + istanbul-lib-instrument "^5.0.4" test-exclude "^6.0.0" babel-plugin-jest-hoist@^26.6.2: @@ -2682,6 +2674,11 @@ before-after-hook@^2.0.0, before-after-hook@^2.2.0: resolved "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e" integrity sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ== +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + bl@^4.0.3: version "4.1.0" resolved "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" @@ -2720,7 +2717,7 @@ braces@^2.3.1: split-string "^3.0.2" to-regex "^3.0.1" -braces@^3.0.1: +braces@^3.0.1, braces@~3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -2733,15 +2730,15 @@ browser-process-hrtime@^1.0.0: integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== browserslist@^4.16.6: - version "4.17.3" - resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.17.3.tgz#2844cd6eebe14d12384b0122d217550160d2d624" - integrity sha512-59IqHJV5VGdcJZ+GZ2hU5n4Kv3YiASzW6Xk5g9tf5a/MAzGeFwgGWU39fVzNIOVcgB3+Gp+kiQu0HEfTVU/3VQ== + version "4.17.6" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.17.6.tgz#c76be33e7786b497f66cad25a73756c8b938985d" + integrity sha512-uPgz3vyRTlEiCv4ee9KlsKgo2V6qPk7Jsn0KAn2OBqbqKo3iNcPEC1Ti6J4dwnz+aIRfEEEuOzC9IBk8tXUomw== dependencies: - caniuse-lite "^1.0.30001264" - electron-to-chromium "^1.3.857" + caniuse-lite "^1.0.30001274" + electron-to-chromium "^1.3.886" escalade "^3.1.1" - node-releases "^1.1.77" - picocolors "^0.2.1" + node-releases "^2.0.1" + picocolors "^1.0.0" bs-logger@0.x: version "0.2.6" @@ -2890,10 +2887,10 @@ camelcase@^6.0.0, camelcase@^6.2.0: resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== -caniuse-lite@^1.0.30001264: - version "1.0.30001265" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001265.tgz#0613c9e6c922e422792e6fcefdf9a3afeee4f8c3" - integrity sha512-YzBnspggWV5hep1m9Z6sZVLOt7vrju8xWooFAgN6BA5qvy98qPAPb7vNUzypFaoh2pb3vlfzbDO8tB57UPGbtw== +caniuse-lite@^1.0.30001274: + version "1.0.30001275" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001275.tgz#26f5076629fe4e52bbd245f9046ad7b90aafdf57" + integrity sha512-ihJVvj8RX0kn9GgP43HKhb5q9s2XQn4nEQhdldEJvZhCsuiB2XOq6fAMYQZaN6FPWfsr2qU0cdL0CSbETwbJAg== capture-exit@^2.0.0: version "2.0.0" @@ -2968,6 +2965,21 @@ charenc@0.0.2: resolved "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= +chokidar@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" + integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + chownr@^1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" @@ -3081,19 +3093,10 @@ co@^4.6.0: resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= -codemaker@^1.39.0: - version "1.39.0" - resolved "https://registry.npmjs.org/codemaker/-/codemaker-1.39.0.tgz#d8103f4b587210b1d6aa073d62ffb510ac20bc42" - integrity sha512-1PPD7ZCC05nrkN47elPcno3zm4Md7XSkG52CvIbNsEcXddc0Ma2xgoMZnWPu+Ab6801FunSqov9X4O+OZle95A== - dependencies: - camelcase "^6.2.0" - decamelize "^5.0.1" - fs-extra "^9.1.0" - -codemaker@^1.41.0: - version "1.41.0" - resolved "https://registry.npmjs.org/codemaker/-/codemaker-1.41.0.tgz#814edff6ffd241727794e76f81c5f9e4df135162" - integrity sha512-Iow0udcpshcVmztwSSJDTRhJxTbH0nXU3pxf7iF0gv6+BWC5Nd2aWQ2W5rHECySQPIvmWn4KEpV/SvXgvfl0aA== +codemaker@^1.42.0: + version "1.42.0" + resolved "https://registry.npmjs.org/codemaker/-/codemaker-1.42.0.tgz#dab2ae818e424803d7aa5f837838d7ec5f1dab4b" + integrity sha512-pjLw1YeWKdY09tDmr6HmeZCGd6G+Ku1UP3cK/oX79x5iEL2ZEm8kJrGQisasK6pk/Er75sDZA86c5Cn7sIx4GQ== dependencies: camelcase "^6.2.0" decamelize "^5.0.1" @@ -3270,16 +3273,7 @@ conventional-changelog-config-spec@2.1.0, conventional-changelog-config-spec@^2. resolved "https://registry.npmjs.org/conventional-changelog-config-spec/-/conventional-changelog-config-spec-2.1.0.tgz#874a635287ef8b581fd8558532bf655d4fb59f2d" integrity sha512-IpVePh16EbbB02V+UA+HQnnPIohgXvJRxHcS5+Uwk4AT5LjzCZJm5sp/yqs5C6KZJ1jMsV4paEV13BN1pvDuxQ== -conventional-changelog-conventionalcommits@4.5.0: - version "4.5.0" - resolved "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.5.0.tgz#a02e0b06d11d342fdc0f00c91d78265ed0bc0a62" - integrity sha512-buge9xDvjjOxJlyxUnar/+6i/aVEVGA7EEh4OafBCXPlLUQPGbRUBhBUveWRxzvR8TEjhKEP4BdepnpG2FSZXw== - dependencies: - compare-func "^2.0.0" - lodash "^4.17.15" - q "^1.5.1" - -conventional-changelog-conventionalcommits@^4.5.0: +conventional-changelog-conventionalcommits@4.6.1, conventional-changelog-conventionalcommits@^4.5.0: version "4.6.1" resolved "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.6.1.tgz#f4c0921937050674e578dc7875f908351ccf4014" integrity sha512-lzWJpPZhbM1R0PIzkwzGBCnAkH5RKJzJfFQZcl/D+2lsJxAwGnDKBqn/F4C1RD31GJNn8NuKWQzAZDAVXPp2Mw== @@ -3405,10 +3399,10 @@ conventional-commits-filter@^2.0.7: lodash.ismatch "^4.4.0" modify-values "^1.0.0" -conventional-commits-parser@^3.2.0, conventional-commits-parser@^3.2.2: - version "3.2.2" - resolved "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.2.tgz#190fb9900c6e02be0c0bca9b03d57e24982639fd" - integrity sha512-Jr9KAKgqAkwXMRHjxDwO/zOCDKod1XdAESHAGuJX38iZ7ZzVti/tvVoysO0suMsdAObp9NQ2rHSsSbnAqZ5f5g== +conventional-commits-parser@^3.2.0, conventional-commits-parser@^3.2.3: + version "3.2.3" + resolved "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.3.tgz#fc43704698239451e3ef35fd1d8ed644f46bd86e" + integrity sha512-YyRDR7On9H07ICFpRm/igcdjIqebXbvf4Cff+Pf0BrBys1i1EOzx9iFXNlAbdrLAR8jf7bkUYkDAr8pEy0q4Pw== dependencies: JSONStream "^1.0.4" is-text-path "^1.0.1" @@ -3876,10 +3870,10 @@ ecc-jsbn@~0.1.1: jsbn "~0.1.0" safer-buffer "^2.1.0" -electron-to-chromium@^1.3.857: - version "1.3.867" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.867.tgz#7cb484db4b57c28da0b65c51e434c3a1f3f9aa0d" - integrity sha512-WbTXOv7hsLhjJyl7jBfDkioaY++iVVZomZ4dU6TMe/SzucV6mUAs2VZn/AehBwuZMiNEQDaPuTGn22YK5o+aDw== +electron-to-chromium@^1.3.886: + version "1.3.887" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.887.tgz#b36aeed12a28aaa19460a467823f5bbe1f3c6f06" + integrity sha512-QQUumrEjFDKSVYVdaeBmFdyQGoaV+fCSMyWHvfx/u22bRHSTeBQYt6P4jMY+gFd4kgKB9nqk7RMtWkDB49OYPA== emittery@^0.7.1: version "0.7.2" @@ -4008,107 +4002,113 @@ es6-error@^4.0.1: resolved "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== -esbuild-android-arm64@0.13.5: - version "0.13.5" - resolved "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.13.5.tgz#a299a18fd8a016ae19fd948fc659b3f65d1b992f" - integrity sha512-xaNH58b9XRAWT5q0rwA2GNTgJynb51JhdotlNKdLmSCyKXPVlF87yqNLNdmlX/zndzRDrZdtpCWSALdn/J63Ug== - -esbuild-darwin-64@0.13.5: - version "0.13.5" - resolved "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.13.5.tgz#01359f2c6921bd2704d0a895f5603ab33f2eeb1b" - integrity sha512-ClGQeUObXIxEpZviGzjTinDikXy9XodojP9jLKwqLCBpZ9wdV3MW7JOmw60fgXgnbNRvkZCqM6uEi+ur8p80Ow== - -esbuild-darwin-arm64@0.13.5: - version "0.13.5" - resolved "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.13.5.tgz#1dbe362ebc9afcdab4f9af9bb320dacd73e2aedc" - integrity sha512-qro6M/qzs1dBPh14Ca+5moIkLo2KE3ll3dOpiN7aAususkM1HmqQptCEchi0XwX+6nfqWI96YvVqPJ3DfUUK5A== - -esbuild-freebsd-64@0.13.5: - version "0.13.5" - resolved "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.13.5.tgz#fecee59fa491a3f544c731b0c0319bd5a9da7d50" - integrity sha512-vklf7L7fghREEvS1sjAFcxcw/Qqt+Z+L0ySN+pEeb7rA8nPLfRBSFdXAru8UNuHsMWns6CrcZ5eDOKTerZZ5ng== - -esbuild-freebsd-arm64@0.13.5: - version "0.13.5" - resolved "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.13.5.tgz#4e98c0e33ed19a63ffd4db87314986b9d93850b5" - integrity sha512-kJoouhbZt4QvjiPak7/Lz57Azok0CgFnNtixiOsqEQXTabIaKmMmnq4qgjD6EBFeU/hvSXDrPe6U8dWhBZOrWQ== - -esbuild-linux-32@0.13.5: - version "0.13.5" - resolved "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.13.5.tgz#00083740af7f1416951c634a461e3d01ed812cd0" - integrity sha512-/QufG6tTGKAf42pIYkOVZzKBPxF01xH1kCPyOFJZukZBV/Tk3TeOZfhJIAf7pxl4jhfa+c4Jcdp7CvIAjXrmJg== - -esbuild-linux-64@0.13.5: - version "0.13.5" - resolved "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.13.5.tgz#49bd1648fd2070594fe3aad31925108ee2916216" - integrity sha512-NmNFMXEthuFJTFaD4cLhAHCxg+y3uXzo7nqH/WNNSZ8PPY11jbeOvMbdArYlbo2Wy1N/mTHXMcK1synSJj+4Iw== - -esbuild-linux-arm64@0.13.5: - version "0.13.5" - resolved "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.13.5.tgz#78ef0f20d2b175403552075cc6d6af80f55a22d8" - integrity sha512-dOS5EZsZj8Lw0TgEj3zy1/slTBbfBw4v7uHEqZXP34dUaRq2oltNaUYIj735CtgB7I5/MXrXEUYkXLqcVfzJQQ== - -esbuild-linux-arm@0.13.5: - version "0.13.5" - resolved "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.13.5.tgz#27c4e92a6597376a8c3fe8c79177d72ba77f8500" - integrity sha512-69nQmbKLBRaAxf88diyaOyarrI7yIdBkZ8bmVzQ7XVWneY+nYIcGtugTSOs5znNGfPqGOElAjh1lX+0sGYHNpA== - -esbuild-linux-mips64le@0.13.5: - version "0.13.5" - resolved "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.13.5.tgz#4061cbef41f96e4a176bebf7e7b2d6d397e05e86" - integrity sha512-dmKA8ZI/nHwpxIQW/L5crk7Ac4wJJ2Kquvdo1CdXPW1UljMyKUDuHc4K7D1Iws5igqJmNO6U5vdRUKrdnIov6Q== - -esbuild-linux-ppc64le@0.13.5: - version "0.13.5" - resolved "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.13.5.tgz#290a5caca6751b8c80c5d075cafe857102263118" - integrity sha512-HkVGKkPL3XOhJqNOJ752Q1li5zeidrJHv+XWX6qCnCipNsVuGqaAGfxeWbL/+A/giolMlP7wvAuiKgoe+a5UAw== - -esbuild-openbsd-64@0.13.5: - version "0.13.5" - resolved "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.13.5.tgz#223eb2730a6fede7930a2b44b0b1d5b067a3cef5" - integrity sha512-BuOZzmdsdreSs0qDgbuiEhSbUDDW2Wyp4VtpNGBmaLwPMHftdprOJXLkeFud3HlnRB2n9qdiTVKg1B8YqMogSw== - -esbuild-sunos-64@0.13.5: - version "0.13.5" - resolved "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.13.5.tgz#6f121ac285c298f09467748607cc0496ebbfd23e" - integrity sha512-YJNB6Og1QYAPikvYDbqvk5xCqr6WL2i5cRWPGGgWOEItQPnq6gFsWogS3DiYM8TQKe50KRiD3Lwu7eNYsdPO4w== - -esbuild-windows-32@0.13.5: - version "0.13.5" - resolved "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.13.5.tgz#0da6d240152f76f3dd764c0bb0391d894acd403f" - integrity sha512-CigOlBSKsZ61IS+FyhD3luqCpl7LN9ntDaBZXumls/0IZ/8BJ5txqw4a6pv4LtnfIgt0ixGHSH7kAUmApw/HAw== - -esbuild-windows-64@0.13.5: - version "0.13.5" - resolved "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.13.5.tgz#330266a2c95b26c2f949e9de9b0c366924fec53f" - integrity sha512-pg2BZXLpcPcrIcmToGapLRExzj6sm0VmQlqlmnMOtIJh0YQV9c0CRbhfIT0gYvJqCz5JEGiRvYpArRlxWADN3Q== - -esbuild-windows-arm64@0.13.5: - version "0.13.5" - resolved "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.13.5.tgz#e0501e82b88f4165cce7cd017db83428f459f775" - integrity sha512-KKRDmUOIE4oCvJp0I4p4QyazK2X79spF29vsZr2U8qHhmxbTLSQWvYmb2WlF5Clb1URRsX0L013rhwHx1SEu0w== - -esbuild@^0.13.5: - version "0.13.5" - resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.13.5.tgz#f9add2c2c899a9023dd7f7b64c452320f008aa79" - integrity sha512-Q9/f1njsZaO+Qqe3dqAdtu4zGHNZIbcEtdg44/NooyPhqCerns4FeC1UPYeB4pKD08iDuWcmyINFJTqpdN+pqg== +esbuild-android-arm64@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.13.12.tgz#e1f199dc05405cdc6670c00fb6c793822bf8ae4c" + integrity sha512-TSVZVrb4EIXz6KaYjXfTzPyyRpXV5zgYIADXtQsIenjZ78myvDGaPi11o4ZSaHIwFHsuwkB6ne5SZRBwAQ7maw== + +esbuild-darwin-64@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.13.12.tgz#f5c59e622955c01f050e5a7ac9c1d41db714b94d" + integrity sha512-c51C+N+UHySoV2lgfWSwwmlnLnL0JWj/LzuZt9Ltk9ub1s2Y8cr6SQV5W3mqVH1egUceew6KZ8GyI4nwu+fhsw== + +esbuild-darwin-arm64@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.13.12.tgz#8abae74c2956a8aa568fc52c78829338c4a4b988" + integrity sha512-JvAMtshP45Hd8A8wOzjkY1xAnTKTYuP/QUaKp5eUQGX+76GIie3fCdUUr2ZEKdvpSImNqxiZSIMziEiGB5oUmQ== + +esbuild-freebsd-64@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.13.12.tgz#6ad2ab8c0364ee7dd2d6e324d876a8e60ae75d12" + integrity sha512-r6On/Skv9f0ZjTu6PW5o7pdXr8aOgtFOEURJZYf1XAJs0IQ+gW+o1DzXjVkIoT+n1cm3N/t1KRJfX71MPg/ZUA== + +esbuild-freebsd-arm64@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.13.12.tgz#6f38155f4c300ac4c8adde1fde3cc6a4440a8294" + integrity sha512-F6LmI2Q1gii073kmBE3NOTt/6zLL5zvZsxNLF8PMAwdHc+iBhD1vzfI8uQZMJA1IgXa3ocr3L3DJH9fLGXy6Yw== + +esbuild-linux-32@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.13.12.tgz#b1d15e330188a8c21de75c3f0058628a3eefade7" + integrity sha512-U1UZwG3UIwF7/V4tCVAo/nkBV9ag5KJiJTt+gaCmLVWH3bPLX7y+fNlhIWZy8raTMnXhMKfaTvWZ9TtmXzvkuQ== + +esbuild-linux-64@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.13.12.tgz#25bd64b66162b02348e32d8f12e4c9ee61f1d070" + integrity sha512-YpXSwtu2NxN3N4ifJxEdsgd6Q5d8LYqskrAwjmoCT6yQnEHJSF5uWcxv783HWN7lnGpJi9KUtDvYsnMdyGw71Q== + +esbuild-linux-arm64@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.13.12.tgz#ba582298457cc5c9ac823a275de117620c06537f" + integrity sha512-sgDNb8kb3BVodtAlcFGgwk+43KFCYjnFOaOfJibXnnIojNWuJHpL6aQJ4mumzNWw8Rt1xEtDQyuGK9f+Y24jGA== + +esbuild-linux-arm@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.13.12.tgz#6bc81c957bff22725688cc6359c29a25765be09b" + integrity sha512-SyiT/JKxU6J+DY2qUiSLZJqCAftIt3uoGejZ0HDnUM2MGJqEGSGh7p1ecVL2gna3PxS4P+j6WAehCwgkBPXNIw== + +esbuild-linux-mips64le@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.13.12.tgz#ef3c4aba3e585d847cbade5945a8b4a5c62c7ce2" + integrity sha512-qQJHlZBG+QwVIA8AbTEtbvF084QgDi4DaUsUnA+EolY1bxrG+UyOuGflM2ZritGhfS/k7THFjJbjH2wIeoKA2g== + +esbuild-linux-ppc64le@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.13.12.tgz#a21fb64e80c38bef06122e48283990fc6db578e1" + integrity sha512-2dSnm1ldL7Lppwlo04CGQUpwNn5hGqXI38OzaoPOkRsBRWFBozyGxTFSee/zHFS+Pdh3b28JJbRK3owrrRgWNw== + +esbuild-netbsd-64@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.13.12.tgz#1ea7fc8cfce88a20a4047b867ef184049a6641ae" + integrity sha512-D4raxr02dcRiQNbxOLzpqBzcJNFAdsDNxjUbKkDMZBkL54Z0vZh4LRndycdZAMcIdizC/l/Yp/ZsBdAFxc5nbA== + +esbuild-openbsd-64@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.13.12.tgz#adde32f2f1b05dc4bd4fc544d6ea5a4379f9ca4d" + integrity sha512-KuLCmYMb2kh05QuPJ+va60bKIH5wHL8ypDkmpy47lzwmdxNsuySeCMHuTv5o2Af1RUn5KLO5ZxaZeq4GEY7DaQ== + +esbuild-sunos-64@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.13.12.tgz#a7ecaf52b7364fbee76dc8aa707fa3e1cff3342c" + integrity sha512-jBsF+e0woK3miKI8ufGWKG3o3rY9DpHvCVRn5eburMIIE+2c+y3IZ1srsthKyKI6kkXLvV4Cf/E7w56kLipMXw== + +esbuild-windows-32@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.13.12.tgz#a8756033dc905c4b7bea19be69f7ee68809f8770" + integrity sha512-L9m4lLFQrFeR7F+eLZXG82SbXZfUhyfu6CexZEil6vm+lc7GDCE0Q8DiNutkpzjv1+RAbIGVva9muItQ7HVTkQ== + +esbuild-windows-64@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.13.12.tgz#ae694aa66ca078acb8509b2da31197ed1f40f798" + integrity sha512-k4tX4uJlSbSkfs78W5d9+I9gpd+7N95W7H2bgOMFPsYREVJs31+Q2gLLHlsnlY95zBoPQMIzHooUIsixQIBjaQ== + +esbuild-windows-arm64@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.13.12.tgz#782c5a8bd6d717ea55aaafe648f9926ca36a4a88" + integrity sha512-2tTv/BpYRIvuwHpp2M960nG7uvL+d78LFW/ikPItO+2GfK51CswIKSetSpDii+cjz8e9iSPgs+BU4o8nWICBwQ== + +esbuild@^0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.13.12.tgz#9cac641594bf03cf34145258c093d743ebbde7ca" + integrity sha512-vTKKUt+yoz61U/BbrnmlG9XIjwpdIxmHB8DlPR0AAW6OdS+nBQBci6LUHU2q9WbBobMEIQxxDpKbkmOGYvxsow== optionalDependencies: - esbuild-android-arm64 "0.13.5" - esbuild-darwin-64 "0.13.5" - esbuild-darwin-arm64 "0.13.5" - esbuild-freebsd-64 "0.13.5" - esbuild-freebsd-arm64 "0.13.5" - esbuild-linux-32 "0.13.5" - esbuild-linux-64 "0.13.5" - esbuild-linux-arm "0.13.5" - esbuild-linux-arm64 "0.13.5" - esbuild-linux-mips64le "0.13.5" - esbuild-linux-ppc64le "0.13.5" - esbuild-openbsd-64 "0.13.5" - esbuild-sunos-64 "0.13.5" - esbuild-windows-32 "0.13.5" - esbuild-windows-64 "0.13.5" - esbuild-windows-arm64 "0.13.5" + esbuild-android-arm64 "0.13.12" + esbuild-darwin-64 "0.13.12" + esbuild-darwin-arm64 "0.13.12" + esbuild-freebsd-64 "0.13.12" + esbuild-freebsd-arm64 "0.13.12" + esbuild-linux-32 "0.13.12" + esbuild-linux-64 "0.13.12" + esbuild-linux-arm "0.13.12" + esbuild-linux-arm64 "0.13.12" + esbuild-linux-mips64le "0.13.12" + esbuild-linux-ppc64le "0.13.12" + esbuild-netbsd-64 "0.13.12" + esbuild-openbsd-64 "0.13.12" + esbuild-sunos-64 "0.13.12" + esbuild-windows-32 "0.13.12" + esbuild-windows-64 "0.13.12" + esbuild-windows-arm64 "0.13.12" escalade@^3.1.1: version "3.1.1" @@ -4179,9 +4179,9 @@ eslint-import-resolver-typescript@^2.5.0: tsconfig-paths "^3.9.0" eslint-module-utils@^2.7.0: - version "2.7.0" - resolved "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.0.tgz#9e97c12688113401259b39d960e6a1f09f966435" - integrity sha512-hqSE88MmHl3ru9SYvDyGrlo0JwROlf9fiEMplEV7j/EAuq9iSlIlyCFbBT6pdULQBSnBYtYKiMLps+hKkyP7Gg== + version "2.7.1" + resolved "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.1.tgz#b435001c9f8dd4ab7f6d0efcae4b9696d4c24b7c" + integrity sha512-fjoetBXQZq2tSTWZ9yWVl2KuFrTZZH3V+9iD1V1RfpDgxzJR+mPd/KZmMiA8gbPqdBzpNiEHOuT7IYEWxrH0zQ== dependencies: debug "^3.2.7" find-up "^2.1.0" @@ -4360,9 +4360,9 @@ estraverse@^4.1.1, estraverse@^4.2.0: integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== estraverse@^5.1.0, estraverse@^5.2.0: - version "5.2.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" - integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== + version "5.3.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== esutils@^2.0.2: version "2.0.3" @@ -4523,14 +4523,14 @@ extsprintf@1.3.0: integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + version "1.4.1" + resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" + integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== -fast-check@^2.18.0: - version "2.18.0" - resolved "https://registry.npmjs.org/fast-check/-/fast-check-2.18.0.tgz#0337d82e7d7cb4eed5806c42b9e61ed0fb6592b2" - integrity sha512-7KKUw0wtAJOVrJ1DgmFILd9EmeqMLGtfe5HoEtkYZfYIxohm6Zy7zPq1Zl8t6tPL8A3e86YZrheyGg2m5j8cLA== +fast-check@^2.19.0: + version "2.19.0" + resolved "https://registry.npmjs.org/fast-check/-/fast-check-2.19.0.tgz#e87666450e417cd163a564bd546ee763d27c0f19" + integrity sha512-qY4Rc0Nljl2aJx2qgbK3o6wPBjL9QvhKdD/VqJgaKd5ewn8l4ViqgDpUHJq/JkHTBnFKomYYvkFkOYGDVTT8bw== dependencies: pure-rand "^5.0.0" @@ -4705,9 +4705,9 @@ flatted@^3.1.0: integrity sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA== follow-redirects@^1.11.0, follow-redirects@^1.14.0: - version "1.14.4" - resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz#838fdf48a8bbdd79e52ee51fb1c94e3ed98b9379" - integrity sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g== + version "1.14.5" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz#f09a5848981d3c772b5392309778523f8d85c381" + integrity sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA== for-in@^1.0.2: version "1.0.2" @@ -4821,7 +4821,7 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@^2.1.2, fsevents@^2.3.2: +fsevents@^2.1.2, fsevents@^2.3.2, fsevents@~2.3.2: version "2.3.2" resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== @@ -5012,7 +5012,7 @@ github-api@^3.4.0: js-base64 "^2.1.9" utf8 "^2.1.1" -glob-parent@^5.1.1, glob-parent@^5.1.2: +glob-parent@^5.1.1, glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -5037,9 +5037,9 @@ globals@^11.1.0: integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== globals@^13.6.0, globals@^13.9.0: - version "13.11.0" - resolved "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz#40ef678da117fe7bd2e28f1fab24951bd0255be7" - integrity sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g== + version "13.12.0" + resolved "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz#4d733760304230a0082ed96e21e5c565f898089e" + integrity sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg== dependencies: type-fest "^0.20.2" @@ -5297,10 +5297,10 @@ ignore@^4.0.6: resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -ignore@^5.1.1, ignore@^5.1.4, ignore@^5.1.8, ignore@~5.1.8: - version "5.1.8" - resolved "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" - integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== +ignore@^5.1.1, ignore@^5.1.4, ignore@^5.1.8, ignore@^5.1.9, ignore@~5.1.8: + version "5.1.9" + resolved "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz#9ec1a5cbe8e1446ec60d4420060d43aa6e7382fb" + integrity sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ== immediate@~3.0.5: version "3.0.6" @@ -5441,6 +5441,13 @@ is-bigint@^1.0.1: dependencies: has-bigints "^1.0.1" +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + is-boolean-object@^1.1.0: version "1.1.2" resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" @@ -5467,9 +5474,9 @@ is-ci@^2.0.0: ci-info "^2.0.0" is-core-module@^2.2.0, is-core-module@^2.5.0, is-core-module@^2.7.0: - version "2.7.0" - resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.7.0.tgz#3c0ef7d31b4acfc574f80c58409d568a836848e3" - integrity sha512-ByY+tjCciCr+9nLryBYcSD50EOGWt95c7tIsKTG1J2ixKKXPvF7Ej3AVd+UfDydAJom3biBGDBALaO79ktwgEQ== + version "2.8.0" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz#0321336c3d0925e497fd97f5d95cb114a5ccd548" + integrity sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw== dependencies: has "^1.0.3" @@ -5544,7 +5551,7 @@ is-generator-fn@^2.0.0: resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1, is-glob@^4.0.3: version "4.0.3" resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== @@ -5760,10 +5767,10 @@ isstream@~0.1.2: resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= -istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.0.0-alpha.1: - version "3.0.2" - resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.2.tgz#36786d4d82aad2ea5911007e255e2da6b5f80d86" - integrity sha512-o5+eTUYzCJ11/+JhW5/FUCdfsdoYVdQ/8I/OveE2XsjehYn5DdeSnNQAbjYaO8gQ6hvGTN6GM6ddQqpTVG5j8g== +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.0.0-alpha.1, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== istanbul-lib-hook@^3.0.0: version "3.0.0" @@ -5782,6 +5789,17 @@ istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: istanbul-lib-coverage "^3.0.0" semver "^6.3.0" +istanbul-lib-instrument@^5.0.4: + version "5.1.0" + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz#7b49198b657b27a730b8e9cb601f1e1bff24c59a" + integrity sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + istanbul-lib-processinfo@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz#e1426514662244b2f25df728e8fd1ba35fe53b9c" @@ -5814,9 +5832,9 @@ istanbul-lib-source-maps@^4.0.0: source-map "^0.6.1" istanbul-reports@^3.0.2: - version "3.0.4" - resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.4.tgz#5c38ce8136edf484c0fcfbf7514aafb0363ed1db" - integrity sha512-bFjUnc95rHjdCR63WMHUS7yfJJh8T9IPSWavvR02hhjVwezWALZ5axF9EqjmwZHpXqkzbgAMP8DmAtiyNxrdrQ== + version "3.0.5" + resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.5.tgz#a2580107e71279ea6d661ddede929ffc6d693384" + integrity sha512-5+19PlhnGabNWB7kOFnuxT8H3T/iIyQzIbQMxXsURmmvKg86P2sbkrGOT77VnHw0Qr0gc2XzRaRfMZYYbSQCJQ== dependencies: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" @@ -6692,57 +6710,57 @@ jsesc@^2.5.1: resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== -jsii-diff@^1.41.0: - version "1.41.0" - resolved "https://registry.npmjs.org/jsii-diff/-/jsii-diff-1.41.0.tgz#ef88aa98081e4bb41f13d24074fce9bee1574d24" - integrity sha512-LTfqGh0f0fUuWu8DBkEUgl0fteIBfzyEiExcqLBXbztg/8JRbt3DYUr63hHULJj4O/rnRTaaYNH7oT1sg4gpSQ== +jsii-diff@^1.42.0: + version "1.42.0" + resolved "https://registry.npmjs.org/jsii-diff/-/jsii-diff-1.42.0.tgz#08fab1b90575239daa5f3ae853e2e921d4d26e90" + integrity sha512-ErMGIBt14Z12b2/FGCv8/H8X19nKr/fcq0UA3xJ6/dIvJyATGNlzxcWHmTUcSoaIxlKjFHYErPvZNUrJslbH4Q== dependencies: - "@jsii/check-node" "1.41.0" - "@jsii/spec" "^1.41.0" + "@jsii/check-node" "1.42.0" + "@jsii/spec" "^1.42.0" fs-extra "^9.1.0" - jsii-reflect "^1.41.0" + jsii-reflect "^1.42.0" log4js "^6.3.0" typescript "~3.9.10" yargs "^16.2.0" -jsii-pacmak@^1.41.0: - version "1.41.0" - resolved "https://registry.npmjs.org/jsii-pacmak/-/jsii-pacmak-1.41.0.tgz#b94575f4a7c658d3fbd1c5f30876ce53a22ed126" - integrity sha512-B3ohEObc2xSnWoawK0q4qVkxa9Dh4A+x1y9K31AAS5jGbhdjbdS/FfphlUbukIoSR0NBJLgJg9pT+h/PIlUqdA== +jsii-pacmak@^1.42.0: + version "1.42.0" + resolved "https://registry.npmjs.org/jsii-pacmak/-/jsii-pacmak-1.42.0.tgz#eee5c15222042b85340ce8e497a70c8c4a48fba6" + integrity sha512-JqgvmI2gIEedB+BvfG7kXkxc5o38TI1VwdQTgUW5hbr0631AgKs/hrpWqcUQ9aNQFwTyzaKWPb0vF8bDitCF6A== dependencies: - "@jsii/check-node" "1.41.0" - "@jsii/spec" "^1.41.0" + "@jsii/check-node" "1.42.0" + "@jsii/spec" "^1.42.0" clone "^2.1.2" - codemaker "^1.41.0" + codemaker "^1.42.0" commonmark "^0.30.0" escape-string-regexp "^4.0.0" fs-extra "^9.1.0" - jsii-reflect "^1.41.0" - jsii-rosetta "^1.41.0" + jsii-reflect "^1.42.0" + jsii-rosetta "^1.42.0" semver "^7.3.5" spdx-license-list "^6.4.0" xmlbuilder "^15.1.1" yargs "^16.2.0" -jsii-reflect@^1.41.0: - version "1.41.0" - resolved "https://registry.npmjs.org/jsii-reflect/-/jsii-reflect-1.41.0.tgz#3c8fbcbbb7e2853b7c2a59384524ccbd2d9d832c" - integrity sha512-KQaAXQ38hyREs7IuBChZldSyvW1gezHRezGKGc6BZILwlIX330F3GIauJ2rJKJinh/Lo/DlMfd0k1mxdBz/W9A== +jsii-reflect@^1.42.0: + version "1.42.0" + resolved "https://registry.npmjs.org/jsii-reflect/-/jsii-reflect-1.42.0.tgz#cab5e6ef64b0ae678efaabf10cefdb76c55818b5" + integrity sha512-gwVZqk2vEnEEYfOU2awHaqZqJd9lA+rEBrlaiMlun42Ve2ZY5HMDBtP/DxgFJG68LCzdlS0xQuHleuBlLYWy0A== dependencies: - "@jsii/check-node" "1.41.0" - "@jsii/spec" "^1.41.0" + "@jsii/check-node" "1.42.0" + "@jsii/spec" "^1.42.0" colors "^1.4.0" fs-extra "^9.1.0" - oo-ascii-tree "^1.41.0" + oo-ascii-tree "^1.42.0" yargs "^16.2.0" -jsii-rosetta@^1.41.0: - version "1.41.0" - resolved "https://registry.npmjs.org/jsii-rosetta/-/jsii-rosetta-1.41.0.tgz#ddf3f49738489d8330aa4eff96f0a9c8c811792d" - integrity sha512-wSjMqRBhjBKB8kx+gIXE7YXoiOlTFH/ugksHz2K4UwqriPmEHue8b7LkV3d/mD8xuhXWS6ekGAz67Gd1RSB7Sg== +jsii-rosetta@^1.42.0: + version "1.42.0" + resolved "https://registry.npmjs.org/jsii-rosetta/-/jsii-rosetta-1.42.0.tgz#84f80a91446b0a6e4ed8c981b1807eb7fce0b79e" + integrity sha512-F7GLNdoHBAYN4eqw7c6Tv12lqGOoMazsjuXDJRubjjbbwZ0tM6a78rHhrZwE4w1XV7mIkTxKmkj4DnbSIPW8wg== dependencies: - "@jsii/check-node" "1.41.0" - "@jsii/spec" "^1.41.0" + "@jsii/check-node" "1.42.0" + "@jsii/spec" "^1.42.0" "@xmldom/xmldom" "^0.7.5" commonmark "^0.30.0" fs-extra "^9.1.0" @@ -6751,13 +6769,13 @@ jsii-rosetta@^1.41.0: workerpool "^6.1.5" yargs "^16.2.0" -jsii@^1.41.0: - version "1.41.0" - resolved "https://registry.npmjs.org/jsii/-/jsii-1.41.0.tgz#926e033d7ba57c65d6d070dee1d4d19da0fa9508" - integrity sha512-5pjfWjSaMzE+mkpW//llBSGLcXJGNjE0KFSf73USPZTfJC09dBEJ4KJM85SogCNnWHwG5QecEpZStxNvt8GI7g== +jsii@^1.42.0: + version "1.42.0" + resolved "https://registry.npmjs.org/jsii/-/jsii-1.42.0.tgz#2f8a534c9f981149f4455ec1272bfab7ba1fa6a3" + integrity sha512-Ctbaudn3t3wJ3ihsgCLuEjQGM5CfZl1PJDXfOlELUV6ELwTbvT3TCbyVdt/CCWTOObigQR8OftAB3jl7ymqd3w== dependencies: - "@jsii/check-node" "1.41.0" - "@jsii/spec" "^1.41.0" + "@jsii/check-node" "1.42.0" + "@jsii/spec" "^1.42.0" case "^1.6.3" colors "^1.4.0" deep-equal "^2.0.5" @@ -6951,9 +6969,9 @@ lambda-tester@^3.6.0: vandium-utils "^1.1.1" lazystream@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4" - integrity sha1-9plf4PggOS9hOWvolGJAe7dxaOQ= + version "1.0.1" + resolved "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz#494c831062f1f9408251ec44db1cba29242a2638" + integrity sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw== dependencies: readable-stream "^2.0.5" @@ -7293,12 +7311,12 @@ make-runnable@^1.3.10: bluebird "^3.5.0" yargs "^16.2.0" -makeerror@1.0.x: - version "1.0.11" - resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" - integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== dependencies: - tmpl "1.0.x" + tmpl "1.0.5" map-cache@^0.2.2: version "0.2.2" @@ -7450,10 +7468,10 @@ mime-types@^2.1.12, mime-types@~2.1.19: dependencies: mime-db "1.50.0" -mime@^2.5.2: - version "2.5.2" - resolved "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe" - integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg== +mime@^2.6.0: + version "2.6.0" + resolved "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" + integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== mimic-fn@^2.1.0: version "2.1.0" @@ -7707,10 +7725,10 @@ nise@^5.1.0: just-extend "^4.0.2" path-to-regexp "^1.7.0" -nock@^13.1.3: - version "13.1.3" - resolved "https://registry.npmjs.org/nock/-/nock-13.1.3.tgz#110b005965654a8ffb798e87bad18b467bff15f9" - integrity sha512-YKj0rKQWMGiiIO+Y65Ut8OEgYM3PplLU2+GAhnPmqZdBd6z5IskgdBqWmjzA6lH3RF0S2a3wiAlrMOF5Iv2Jeg== +nock@^13.1.4: + version "13.1.4" + resolved "https://registry.npmjs.org/nock/-/nock-13.1.4.tgz#367c917d4c532a889404b85ade92762c29e80262" + integrity sha512-hr5+mknLpIbTOXifB13lx9mAKF1zQPUCMh53Galx79ic5opvNOd55jiB0iGCp2xqh+hwnFbNE/ddBKHsJNQrbw== dependencies: debug "^4.1.0" json-stringify-safe "^5.0.1" @@ -7718,9 +7736,9 @@ nock@^13.1.3: propagate "^2.0.0" node-fetch@^2.6.1: - version "2.6.5" - resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz#42735537d7f080a7e5f78b6c549b7146be1742fd" - integrity sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ== + version "2.6.6" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz#1751a7c01834e8e1697758732e9efb6eeadfaf89" + integrity sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA== dependencies: whatwg-url "^5.0.0" @@ -7786,10 +7804,10 @@ node-preload@^0.2.1: dependencies: process-on-spawn "^1.0.0" -node-releases@^1.1.77: - version "1.1.77" - resolved "https://registry.npmjs.org/node-releases/-/node-releases-1.1.77.tgz#50b0cfede855dd374e7585bf228ff34e57c1c32e" - integrity sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ== +node-releases@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5" + integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA== nopt@^4.0.1: version "4.0.3" @@ -7833,7 +7851,7 @@ normalize-path@^2.1.1: dependencies: remove-trailing-separator "^1.0.1" -normalize-path@^3.0.0: +normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== @@ -8096,10 +8114,10 @@ onetime@^5.1.0, onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" -oo-ascii-tree@^1.41.0: - version "1.41.0" - resolved "https://registry.npmjs.org/oo-ascii-tree/-/oo-ascii-tree-1.41.0.tgz#88883d2b8446ded7082a96faf3294e1092aeeb46" - integrity sha512-WxQIFO+JMCIJBlIMUATsp+PW5kqDMy2CD7u5uC9qQk29XInUMO+RN7/QVZJsPHO3o73eJFN9CFc9XDWQJwVKBQ== +oo-ascii-tree@^1.42.0: + version "1.42.0" + resolved "https://registry.npmjs.org/oo-ascii-tree/-/oo-ascii-tree-1.42.0.tgz#e9ab47834b004ec2789a5e8b3e477b3fac770804" + integrity sha512-qlynjsWdGidfoWT2uEIr0iNsNmHU2ZhKwtjpJw4VSd3jlxoDpWDDmd5cud/ZBhFT2F1UFSbz+Gl9YtlPYMgQ5Q== open@^7.4.2: version "7.4.2" @@ -8471,12 +8489,12 @@ performance-now@^2.1.0: resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= -picocolors@^0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" - integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA== +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.0.4, picomatch@^2.2.3: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: version "2.3.0" resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== @@ -8886,6 +8904,13 @@ readdir-scoped-modules@^1.0.0: graceful-fs "^4.1.2" once "^1.3.0" +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + redent@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" @@ -9526,15 +9551,15 @@ stack-utils@^2.0.2, stack-utils@^2.0.3: dependencies: escape-string-regexp "^2.0.0" -standard-version@^9.3.1: - version "9.3.1" - resolved "https://registry.npmjs.org/standard-version/-/standard-version-9.3.1.tgz#786c16c318847f58a31a2434f97e8db33a635853" - integrity sha512-5qMxXw/FxLouC5nANyx/5RY1kiorJx9BppUso8gN07MG64q2uLRmrPb4KfXp3Ql4s/gxjZwZ89e0FwxeLubGww== +standard-version@^9.3.2: + version "9.3.2" + resolved "https://registry.npmjs.org/standard-version/-/standard-version-9.3.2.tgz#28db8c1be66fd2d736f28f7c5de7619e64cd6dab" + integrity sha512-u1rfKP4o4ew7Yjbfycv80aNMN2feTiqseAhUhrrx2XtdQGmu7gucpziXe68Z4YfHVqlxVEzo4aUA0Iu3VQOTgQ== dependencies: chalk "^2.4.2" conventional-changelog "3.1.24" conventional-changelog-config-spec "2.1.0" - conventional-changelog-conventionalcommits "4.5.0" + conventional-changelog-conventionalcommits "4.6.1" conventional-recommended-bump "6.1.0" detect-indent "^6.0.0" detect-newline "^3.1.0" @@ -9582,7 +9607,7 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -string-width@*, string-width@^1.0.1, "string-width@^1.0.2 || 2", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +string-width@*, string-width@^1.0.1, "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -9873,7 +9898,7 @@ tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" -tmpl@1.0.x: +tmpl@1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== @@ -9981,9 +10006,9 @@ ts-mock-imports@^1.3.7: integrity sha512-zy4B3QSGaOhjaX9j0h9YKwM1oHG4Kd1KIUJBeXlXIQrFnATNLgh4+NyRcaAHsPeqwe3TWeRtHXkNXPxySEKk3w== ts-node@^10.2.1: - version "10.3.0" - resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.3.0.tgz#a797f2ed3ff50c9a5d814ce400437cb0c1c048b4" - integrity sha512-RYIy3i8IgpFH45AX4fQHExrT8BxDeKTdC83QFJkNzkvt8uFB6QJ8XMyhynYiKMLxt9a7yuXaDBZNOYS3XjDcYw== + version "10.4.0" + resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.4.0.tgz#680f88945885f4e6cf450e7f0d6223dd404895f7" + integrity sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A== dependencies: "@cspotcode/source-map-support" "0.7.0" "@tsconfig/node10" "^1.0.7" @@ -10149,9 +10174,9 @@ uc.micro@^1.0.1, uc.micro@^1.0.5: integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== uglify-js@^3.1.4: - version "3.14.2" - resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.2.tgz#d7dd6a46ca57214f54a2d0a43cad0f35db82ac99" - integrity sha512-rtPMlmcO4agTUfz10CbgJ1k6UAoXM2gWb3GoMPPZB/+/Ackf8lNWk11K4rYi2D0apgoFRLtQOZhb+/iGNJq26A== + version "3.14.3" + resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.3.tgz#c0f25dfea1e8e5323eccf59610be08b6043c15cf" + integrity sha512-mic3aOdiq01DuSVx0TseaEzMIVqebMZ0Z3vaeDhFEh9bsc24hV1TFvN74reA2vs08D0ZWfNjAcJ3UbVLaBss+g== uid-number@0.0.6: version "0.0.6" @@ -10347,9 +10372,9 @@ verror@1.10.0: extsprintf "^1.2.0" vm2@^3.9.3: - version "3.9.4" - resolved "https://registry.npmjs.org/vm2/-/vm2-3.9.4.tgz#2e118290fefe7bd8ea09ebe2f5faf53730dbddaa" - integrity sha512-sOdharrJ7KEePIpHekiWaY1DwgueuiBeX/ZBJUPgETsVlJsXuEx0K0/naATq2haFvJrvZnRiORQRubR0b7Ye6g== + version "3.9.5" + resolved "https://registry.npmjs.org/vm2/-/vm2-3.9.5.tgz#5288044860b4bbace443101fcd3bddb2a0aa2496" + integrity sha512-LuCAHZN75H9tdrAiLFf030oW7nJV5xwNMuk1ymOZwopmuK3d2H4L1Kv4+GFHgarKiLfXXLFU+7LDABHnwOkWng== w3c-hr-time@^1.0.2: version "1.0.2" @@ -10366,11 +10391,11 @@ w3c-xmlserializer@^2.0.0: xml-name-validator "^3.0.0" walker@^1.0.7, walker@~1.0.5: - version "1.0.7" - resolved "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" - integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= + version "1.0.8" + resolved "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== dependencies: - makeerror "1.0.x" + makeerror "1.0.12" wcwidth@^1.0.0: version "1.0.1" @@ -10476,11 +10501,11 @@ which@^2.0.1, which@^2.0.2: isexe "^2.0.0" wide-align@^1.1.0: - version "1.1.3" - resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + version "1.1.5" + resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" + integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== dependencies: - string-width "^1.0.2 || 2" + string-width "^1.0.2 || 2 || 3 || 4" windows-release@^3.1.0: version "3.3.3"